xref: /aosp_15_r20/external/mesa3d/src/gallium/frontends/dri/drisw.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /**************************************************************************
2  *
3  * Copyright 2009, VMware, Inc.
4  * All Rights Reserved.
5  * Copyright 2010 George Sapountzis <[email protected]>
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the
9  * "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sub license, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice and this permission notice (including the
16  * next paragraph) shall be included in all copies or substantial portions
17  * of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
23  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  *
27  **************************************************************************/
28 
29 #include "mesa_interface.h"
30 #include "git_sha1.h"
31 #include "util/format/u_format.h"
32 #include "util/u_memory.h"
33 #include "util/u_inlines.h"
34 #include "util/box.h"
35 #include "pipe/p_context.h"
36 #include "pipe-loader/pipe_loader.h"
37 #include "frontend/drisw_api.h"
38 #include "state_tracker/st_context.h"
39 
40 #include "dri_screen.h"
41 #include "dri_context.h"
42 #include "dri_drawable.h"
43 #include "dri_helpers.h"
44 #include "dri_query_renderer.h"
45 
46 #include "util/libsync.h"
47 
48 #ifdef HAVE_LIBDRM
49 #include <xf86drm.h>
50 #endif
51 
52 DEBUG_GET_ONCE_BOOL_OPTION(swrast_no_present, "SWRAST_NO_PRESENT", false);
53 
54 static inline void
get_drawable_info(struct dri_drawable * drawable,int * x,int * y,int * w,int * h)55 get_drawable_info(struct dri_drawable *drawable, int *x, int *y, int *w, int *h)
56 {
57    const __DRIswrastLoaderExtension *loader = drawable->screen->swrast_loader;
58 
59    loader->getDrawableInfo(opaque_dri_drawable(drawable),
60                            x, y, w, h,
61                            drawable->loaderPrivate);
62 }
63 
64 static inline void
put_image(struct dri_drawable * drawable,void * data,unsigned width,unsigned height)65 put_image(struct dri_drawable *drawable, void *data, unsigned width, unsigned height)
66 {
67    const __DRIswrastLoaderExtension *loader = drawable->screen->swrast_loader;
68 
69    loader->putImage(opaque_dri_drawable(drawable), __DRI_SWRAST_IMAGE_OP_SWAP,
70                     0, 0, width, height,
71                     data, drawable->loaderPrivate);
72 }
73 
74 static inline void
put_image2(struct dri_drawable * drawable,void * data,int x,int y,unsigned width,unsigned height,unsigned stride)75 put_image2(struct dri_drawable *drawable, void *data, int x, int y,
76            unsigned width, unsigned height, unsigned stride)
77 {
78    const __DRIswrastLoaderExtension *loader = drawable->screen->swrast_loader;
79 
80    loader->putImage2(opaque_dri_drawable(drawable), __DRI_SWRAST_IMAGE_OP_SWAP,
81                      x, y, width, height, stride,
82                      data, drawable->loaderPrivate);
83 }
84 
85 static inline void
put_image_shm(struct dri_drawable * drawable,int shmid,char * shmaddr,unsigned offset,unsigned offset_x,int x,int y,unsigned width,unsigned height,unsigned stride)86 put_image_shm(struct dri_drawable *drawable, int shmid, char *shmaddr,
87               unsigned offset, unsigned offset_x, int x, int y,
88               unsigned width, unsigned height, unsigned stride)
89 {
90    const __DRIswrastLoaderExtension *loader = drawable->screen->swrast_loader;
91 
92    /* if we have the newer interface, don't have to add the offset_x here. */
93    if (loader->base.version > 4 && loader->putImageShm2)
94      loader->putImageShm2(opaque_dri_drawable(drawable), __DRI_SWRAST_IMAGE_OP_SWAP,
95                           x, y, width, height, stride,
96                           shmid, shmaddr, offset, drawable->loaderPrivate);
97    else
98      loader->putImageShm(opaque_dri_drawable(drawable), __DRI_SWRAST_IMAGE_OP_SWAP,
99                          x, y, width, height, stride,
100                          shmid, shmaddr, offset + offset_x, drawable->loaderPrivate);
101 }
102 
103 static inline void
get_image(struct dri_drawable * drawable,int x,int y,int width,int height,void * data)104 get_image(struct dri_drawable *drawable, int x, int y, int width, int height, void *data)
105 {
106    const __DRIswrastLoaderExtension *loader = drawable->screen->swrast_loader;
107 
108    loader->getImage(opaque_dri_drawable(drawable),
109                     x, y, width, height,
110                     data, drawable->loaderPrivate);
111 }
112 
113 static inline void
get_image2(struct dri_drawable * drawable,int x,int y,int width,int height,int stride,void * data)114 get_image2(struct dri_drawable *drawable, int x, int y, int width, int height, int stride, void *data)
115 {
116    const __DRIswrastLoaderExtension *loader = drawable->screen->swrast_loader;
117 
118    /* getImage2 support is only in version 3 or newer */
119    if (loader->base.version < 3)
120       return;
121 
122    loader->getImage2(opaque_dri_drawable(drawable),
123                      x, y, width, height, stride,
124                      data, drawable->loaderPrivate);
125 }
126 
127 static inline bool
get_image_shm(struct dri_drawable * drawable,int x,int y,int width,int height,struct pipe_resource * res)128 get_image_shm(struct dri_drawable *drawable, int x, int y, int width, int height,
129               struct pipe_resource *res)
130 {
131    const __DRIswrastLoaderExtension *loader = drawable->screen->swrast_loader;
132    struct winsys_handle whandle;
133 
134    whandle.type = WINSYS_HANDLE_TYPE_SHMID;
135 
136    if (loader->base.version < 4 || !loader->getImageShm)
137       return false;
138 
139    if (!res->screen->resource_get_handle(res->screen, NULL, res, &whandle, PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE))
140       return false;
141 
142    if (loader->base.version > 5 && loader->getImageShm2)
143       return loader->getImageShm2(opaque_dri_drawable(drawable), x, y, width, height, whandle.handle, drawable->loaderPrivate);
144 
145    loader->getImageShm(opaque_dri_drawable(drawable), x, y, width, height, whandle.handle, drawable->loaderPrivate);
146    return true;
147 }
148 
149 static void
drisw_update_drawable_info(struct dri_drawable * drawable)150 drisw_update_drawable_info(struct dri_drawable *drawable)
151 {
152    int x, y;
153 
154    get_drawable_info(drawable, &x, &y, &drawable->w, &drawable->h);
155 }
156 
157 static void
drisw_get_image(struct dri_drawable * drawable,int x,int y,unsigned width,unsigned height,unsigned stride,void * data)158 drisw_get_image(struct dri_drawable *drawable,
159                 int x, int y, unsigned width, unsigned height, unsigned stride,
160                 void *data)
161 {
162    int draw_x, draw_y, draw_w, draw_h;
163 
164    get_drawable_info(drawable, &draw_x, &draw_y, &draw_w, &draw_h);
165    get_image2(drawable, x, y, draw_w, draw_h, stride, data);
166 }
167 
168 static void
drisw_put_image(struct dri_drawable * drawable,void * data,unsigned width,unsigned height)169 drisw_put_image(struct dri_drawable *drawable,
170                 void *data, unsigned width, unsigned height)
171 {
172    put_image(drawable, data, width, height);
173 }
174 
175 static void
drisw_put_image2(struct dri_drawable * drawable,void * data,int x,int y,unsigned width,unsigned height,unsigned stride)176 drisw_put_image2(struct dri_drawable *drawable,
177                  void *data, int x, int y, unsigned width, unsigned height,
178                  unsigned stride)
179 {
180    put_image2(drawable, data, x, y, width, height, stride);
181 }
182 
183 static inline void
drisw_put_image_shm(struct dri_drawable * drawable,int shmid,char * shmaddr,unsigned offset,unsigned offset_x,int x,int y,unsigned width,unsigned height,unsigned stride)184 drisw_put_image_shm(struct dri_drawable *drawable,
185                     int shmid, char *shmaddr, unsigned offset,
186                     unsigned offset_x,
187                     int x, int y, unsigned width, unsigned height,
188                     unsigned stride)
189 {
190    put_image_shm(drawable, shmid, shmaddr, offset, offset_x, x, y, width, height, stride);
191 }
192 
193 static inline void
drisw_present_texture(struct pipe_context * pipe,struct dri_drawable * drawable,struct pipe_resource * ptex,unsigned nrects,struct pipe_box * sub_box)194 drisw_present_texture(struct pipe_context *pipe, struct dri_drawable *drawable,
195                       struct pipe_resource *ptex, unsigned nrects, struct pipe_box *sub_box)
196 {
197    struct dri_screen *screen = drawable->screen;
198 
199    if (screen->swrast_no_present)
200       return;
201 
202    screen->base.screen->flush_frontbuffer(screen->base.screen, pipe, ptex, 0, 0, drawable, nrects, sub_box);
203 }
204 
205 static inline void
drisw_invalidate_drawable(struct dri_drawable * drawable)206 drisw_invalidate_drawable(struct dri_drawable *drawable)
207 {
208    drawable->texture_stamp = drawable->lastStamp - 1;
209 
210    p_atomic_inc(&drawable->base.stamp);
211 }
212 
213 static inline void
drisw_copy_to_front(struct pipe_context * pipe,struct dri_drawable * drawable,struct pipe_resource * ptex,int nboxes,struct pipe_box * boxes)214 drisw_copy_to_front(struct pipe_context *pipe,
215                     struct dri_drawable *drawable,
216                     struct pipe_resource *ptex,
217                     int nboxes, struct pipe_box *boxes)
218 {
219    drisw_present_texture(pipe, drawable, ptex, nboxes, boxes);
220 
221    drisw_invalidate_drawable(drawable);
222 }
223 
224 /*
225  * Backend functions for pipe_frontend_drawable and swap_buffers.
226  */
227 
228 static void
drisw_swap_buffers_with_damage(struct dri_drawable * drawable,int nrects,const int * rects)229 drisw_swap_buffers_with_damage(struct dri_drawable *drawable, int nrects, const int *rects)
230 {
231    struct dri_context *ctx = dri_get_current();
232    struct dri_screen *screen = drawable->screen;
233    struct pipe_resource *ptex;
234 
235    if (!ctx)
236       return;
237 
238    /* Wait for glthread to finish because we can't use pipe_context from
239     * multiple threads.
240     */
241    _mesa_glthread_finish(ctx->st->ctx);
242 
243    ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT];
244 
245    if (ptex) {
246       struct pipe_fence_handle *fence = NULL;
247 
248       struct pipe_box stack_boxes[64];
249       if (nrects > ARRAY_SIZE(stack_boxes))
250          nrects = 0;
251       if (nrects) {
252          for (unsigned int i = 0; i < nrects; i++) {
253             const int *rect = &rects[i * 4];
254 
255             int w = MIN2(rect[2], ptex->width0);
256             int h = MIN2(rect[3], ptex->height0);
257             int x = CLAMP(rect[0], 0, ptex->width0);
258             int y = CLAMP(ptex->height0 - rect[1] - h, 0, ptex->height0);
259 
260             if (h > ptex->height0 - y)
261                h = ptex->height0 - y;
262 
263             u_box_2d(x, y, w, h, &stack_boxes[i]);
264          }
265       }
266 
267       if (ctx->pp)
268          pp_run(ctx->pp, ptex, ptex, drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]);
269 
270       if (ctx->hud)
271          hud_run(ctx->hud, ctx->st->cso_context, ptex);
272 
273       st_context_flush(ctx->st, ST_FLUSH_FRONT, &fence, NULL, NULL);
274 
275       if (drawable->stvis.samples > 1) {
276          /* Resolve the back buffer. */
277          dri_pipe_blit(ctx->st->pipe,
278                        drawable->textures[ST_ATTACHMENT_BACK_LEFT],
279                        drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]);
280       }
281 
282       screen->base.screen->fence_finish(screen->base.screen, ctx->st->pipe,
283                                         fence, OS_TIMEOUT_INFINITE);
284       screen->base.screen->fence_reference(screen->base.screen, &fence, NULL);
285       drisw_copy_to_front(ctx->st->pipe, drawable, ptex, nrects, nrects ? stack_boxes : NULL);
286       drawable->buffer_age = 1;
287 
288       /* TODO: remove this if the framebuffer state doesn't change. */
289       st_context_invalidate_state(ctx->st, ST_INVALIDATE_FB_STATE);
290    }
291 }
292 
293 static void
drisw_swap_buffers(struct dri_drawable * drawable)294 drisw_swap_buffers(struct dri_drawable *drawable)
295 {
296    drisw_swap_buffers_with_damage(drawable, 0, NULL);
297 }
298 
299 static void
drisw_copy_sub_buffer(struct dri_drawable * drawable,int x,int y,int w,int h)300 drisw_copy_sub_buffer(struct dri_drawable *drawable, int x, int y,
301                       int w, int h)
302 {
303    struct dri_context *ctx = dri_get_current();
304    struct dri_screen *screen = drawable->screen;
305    struct pipe_resource *ptex;
306    struct pipe_box box;
307    if (!ctx)
308       return;
309 
310    ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT];
311 
312    if (ptex) {
313       /* Wait for glthread to finish because we can't use pipe_context from
314        * multiple threads.
315        */
316       _mesa_glthread_finish(ctx->st->ctx);
317 
318       struct pipe_fence_handle *fence = NULL;
319       if (ctx->pp && drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL])
320          pp_run(ctx->pp, ptex, ptex, drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]);
321 
322       st_context_flush(ctx->st, ST_FLUSH_FRONT, &fence, NULL, NULL);
323 
324       screen->base.screen->fence_finish(screen->base.screen, ctx->st->pipe,
325                                         fence, OS_TIMEOUT_INFINITE);
326       screen->base.screen->fence_reference(screen->base.screen, &fence, NULL);
327 
328       if (drawable->stvis.samples > 1) {
329          /* Resolve the back buffer. */
330          dri_pipe_blit(ctx->st->pipe,
331                        drawable->textures[ST_ATTACHMENT_BACK_LEFT],
332                        drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]);
333       }
334 
335       u_box_2d(x, drawable->h - y - h, w, h, &box);
336       drisw_present_texture(ctx->st->pipe, drawable, ptex, 1, &box);
337    }
338 }
339 
340 static bool
drisw_flush_frontbuffer(struct dri_context * ctx,struct dri_drawable * drawable,enum st_attachment_type statt)341 drisw_flush_frontbuffer(struct dri_context *ctx,
342                         struct dri_drawable *drawable,
343                         enum st_attachment_type statt)
344 {
345    struct pipe_resource *ptex;
346 
347    if (!ctx || statt != ST_ATTACHMENT_FRONT_LEFT)
348       return false;
349 
350    /* Wait for glthread to finish because we can't use pipe_context from
351     * multiple threads.
352     */
353    _mesa_glthread_finish(ctx->st->ctx);
354 
355    if (drawable->stvis.samples > 1) {
356       /* Resolve the front buffer. */
357       dri_pipe_blit(ctx->st->pipe,
358                     drawable->textures[ST_ATTACHMENT_FRONT_LEFT],
359                     drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT]);
360    }
361    ptex = drawable->textures[statt];
362 
363    if (ptex) {
364       drisw_copy_to_front(ctx->st->pipe, ctx->draw, ptex, 0, NULL);
365    }
366 
367    return true;
368 }
369 
370 extern bool
371 dri_image_drawable_get_buffers(struct dri_drawable *drawable,
372                                struct __DRIimageList *images,
373                                const enum st_attachment_type *statts,
374                                unsigned statts_count);
375 
376 static void
handle_in_fence(struct dri_context * ctx,__DRIimage * img)377 handle_in_fence(struct dri_context *ctx, __DRIimage *img)
378 {
379    struct pipe_context *pipe = ctx->st->pipe;
380    struct pipe_fence_handle *fence;
381    int fd = img->in_fence_fd;
382 
383    if (fd == -1)
384       return;
385 
386    validate_fence_fd(fd);
387 
388    img->in_fence_fd = -1;
389 
390    pipe->create_fence_fd(pipe, &fence, fd, PIPE_FD_TYPE_NATIVE_SYNC);
391    pipe->fence_server_sync(pipe, fence);
392    pipe->screen->fence_reference(pipe->screen, &fence, NULL);
393 
394    close(fd);
395 }
396 
397 /**
398  * Allocate framebuffer attachments.
399  *
400  * During fixed-size operation, the function keeps allocating new attachments
401  * as they are requested. Unused attachments are not removed, not until the
402  * framebuffer is resized or destroyed.
403  */
404 static void
drisw_allocate_textures(struct dri_context * stctx,struct dri_drawable * drawable,const enum st_attachment_type * statts,unsigned count)405 drisw_allocate_textures(struct dri_context *stctx,
406                         struct dri_drawable *drawable,
407                         const enum st_attachment_type *statts,
408                         unsigned count)
409 {
410    struct dri_screen *screen = drawable->screen;
411    const __DRIswrastLoaderExtension *loader = drawable->screen->swrast_loader;
412    struct pipe_resource templ;
413    unsigned width, height;
414    bool resized;
415    unsigned i;
416    const __DRIimageLoaderExtension *image = screen->image.loader;
417    struct __DRIimageList images;
418    bool imported_buffers = true;
419 
420    /* Wait for glthread to finish because we can't use pipe_context from
421     * multiple threads.
422     */
423    _mesa_glthread_finish(stctx->st->ctx);
424 
425    /* First try to get the buffers from the loader */
426    if (image) {
427       if (!dri_image_drawable_get_buffers(drawable, &images,
428                                           statts, count))
429          imported_buffers = false;
430    }
431 
432    width  = drawable->w;
433    height = drawable->h;
434 
435    resized = (drawable->old_w != width ||
436               drawable->old_h != height);
437 
438    /* remove outdated textures */
439    if (resized) {
440       for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
441          pipe_resource_reference(&drawable->textures[i], NULL);
442          pipe_resource_reference(&drawable->msaa_textures[i], NULL);
443       }
444       drawable->buffer_age = 0;
445    }
446 
447    memset(&templ, 0, sizeof(templ));
448    templ.target = screen->target;
449    templ.width0 = width;
450    templ.height0 = height;
451    templ.depth0 = 1;
452    templ.array_size = 1;
453    templ.last_level = 0;
454 
455    if (imported_buffers && image) {
456       if (images.image_mask & __DRI_IMAGE_BUFFER_FRONT) {
457          struct pipe_resource **buf =
458             &drawable->textures[ST_ATTACHMENT_FRONT_LEFT];
459          struct pipe_resource *texture = images.front->texture;
460 
461          drawable->w = texture->width0;
462          drawable->h = texture->height0;
463 
464          pipe_resource_reference(buf, texture);
465          handle_in_fence(stctx, images.front);
466       }
467 
468       if (images.image_mask & __DRI_IMAGE_BUFFER_BACK) {
469          struct pipe_resource **buf =
470             &drawable->textures[ST_ATTACHMENT_BACK_LEFT];
471          struct pipe_resource *texture = images.back->texture;
472 
473          drawable->w = texture->width0;
474          drawable->h = texture->height0;
475 
476          pipe_resource_reference(buf, texture);
477          handle_in_fence(stctx, images.back);
478       }
479 
480       if (images.image_mask & __DRI_IMAGE_BUFFER_SHARED) {
481          struct pipe_resource **buf =
482             &drawable->textures[ST_ATTACHMENT_BACK_LEFT];
483          struct pipe_resource *texture = images.back->texture;
484 
485          drawable->w = texture->width0;
486          drawable->h = texture->height0;
487 
488          pipe_resource_reference(buf, texture);
489          handle_in_fence(stctx, images.back);
490       }
491 
492       /* Note: if there is both a back and a front buffer,
493        * then they have the same size.
494        */
495       templ.width0 = drawable->w;
496       templ.height0 = drawable->h;
497    } else {
498       for (i = 0; i < count; i++) {
499          enum pipe_format format;
500          unsigned bind;
501 
502          /* the texture already exists or not requested */
503          if (drawable->textures[statts[i]])
504             continue;
505 
506          dri_drawable_get_format(drawable, statts[i], &format, &bind);
507 
508          /* if we don't do any present, no need for display targets */
509          if (statts[i] != ST_ATTACHMENT_DEPTH_STENCIL && !screen->swrast_no_present)
510             bind |= PIPE_BIND_DISPLAY_TARGET;
511 
512          if (format == PIPE_FORMAT_NONE)
513             continue;
514 
515          templ.format = format;
516          templ.bind = bind;
517          templ.nr_samples = 0;
518          templ.nr_storage_samples = 0;
519 
520          if (statts[i] == ST_ATTACHMENT_FRONT_LEFT &&
521                     screen->base.screen->resource_create_front &&
522                     loader->base.version >= 3) {
523             drawable->textures[statts[i]] =
524                screen->base.screen->resource_create_front(screen->base.screen, &templ, (const void *)drawable);
525          } else
526             drawable->textures[statts[i]] =
527                screen->base.screen->resource_create(screen->base.screen, &templ);
528 
529          if (drawable->stvis.samples > 1) {
530             templ.bind = templ.bind &
531                ~(PIPE_BIND_SCANOUT | PIPE_BIND_SHARED | PIPE_BIND_DISPLAY_TARGET);
532             templ.nr_samples = drawable->stvis.samples;
533             templ.nr_storage_samples = drawable->stvis.samples;
534             drawable->msaa_textures[statts[i]] =
535                screen->base.screen->resource_create(screen->base.screen, &templ);
536 
537             dri_pipe_blit(stctx->st->pipe,
538                           drawable->msaa_textures[statts[i]],
539                           drawable->textures[statts[i]]);
540          }
541       }
542    }
543 
544    drawable->old_w = width;
545    drawable->old_h = height;
546 }
547 
548 void
drisw_update_tex_buffer(struct dri_drawable * drawable,struct dri_context * ctx,struct pipe_resource * res)549 drisw_update_tex_buffer(struct dri_drawable *drawable,
550                         struct dri_context *ctx,
551                         struct pipe_resource *res)
552 {
553    struct st_context *st_ctx = (struct st_context *)ctx->st;
554    struct pipe_context *pipe = st_ctx->pipe;
555    struct pipe_transfer *transfer;
556    char *map;
557    int x, y, w, h;
558    int ximage_stride, line;
559    int cpp = util_format_get_blocksize(res->format);
560 
561    /* Wait for glthread to finish because we can't use pipe_context from
562     * multiple threads.
563     */
564    _mesa_glthread_finish(ctx->st->ctx);
565 
566    get_drawable_info(drawable, &x, &y, &w, &h);
567 
568    map = pipe_texture_map(pipe, res,
569                            0, 0, // level, layer,
570                            PIPE_MAP_WRITE,
571                            x, y, w, h, &transfer);
572 
573    /* Copy the Drawable content to the mapped texture buffer */
574    if (!get_image_shm(drawable, x, y, w, h, res))
575       get_image(drawable, x, y, w, h, map);
576 
577    /* The pipe transfer has a pitch rounded up to the nearest 64 pixels.
578       get_image() has a pitch rounded up to 4 bytes.  */
579    ximage_stride = ((w * cpp) + 3) & -4;
580    for (line = h-1; line; --line) {
581       memmove(&map[line * transfer->stride],
582               &map[line * ximage_stride],
583               ximage_stride);
584    }
585 
586    pipe_texture_unmap(pipe, transfer);
587 }
588 
589 /*
590  * Backend function for init_screen.
591  */
592 
593 static const struct drisw_loader_funcs drisw_lf = {
594    .get_image = drisw_get_image,
595    .put_image = drisw_put_image,
596    .put_image2 = drisw_put_image2
597 };
598 
599 static const struct drisw_loader_funcs drisw_shm_lf = {
600    .get_image = drisw_get_image,
601    .put_image = drisw_put_image,
602    .put_image2 = drisw_put_image2,
603    .put_image_shm = drisw_put_image_shm
604 };
605 
606 void
drisw_init_drawable(struct dri_drawable * drawable,bool isPixmap,int alphaBits)607 drisw_init_drawable(struct dri_drawable *drawable, bool isPixmap, int alphaBits)
608 {
609    drawable->allocate_textures = drisw_allocate_textures;
610    drawable->update_drawable_info = drisw_update_drawable_info;
611    drawable->flush_frontbuffer = drisw_flush_frontbuffer;
612    drawable->update_tex_buffer = drisw_update_tex_buffer;
613    drawable->swap_buffers = drisw_swap_buffers;
614    drawable->swap_buffers_with_damage = drisw_swap_buffers_with_damage;
615 }
616 
617 struct pipe_screen *
drisw_init_screen(struct dri_screen * screen,bool driver_name_is_inferred)618 drisw_init_screen(struct dri_screen *screen, bool driver_name_is_inferred)
619 {
620    const __DRIswrastLoaderExtension *loader = screen->swrast_loader;
621    struct pipe_screen *pscreen = NULL;
622    const struct drisw_loader_funcs *lf = &drisw_lf;
623 
624    screen->swrast_no_present = debug_get_option_swrast_no_present();
625 
626    if (loader->base.version >= 4) {
627       if (loader->putImageShm)
628          lf = &drisw_shm_lf;
629    }
630 
631    bool success = false;
632 #ifdef HAVE_DRISW_KMS
633    if (screen->fd != -1)
634       success = pipe_loader_sw_probe_kms(&screen->dev, screen->fd);
635 #endif
636    if (!success)
637       success = pipe_loader_sw_probe_dri(&screen->dev, lf);
638 
639    if (success)
640       pscreen = pipe_loader_create_screen(screen->dev, driver_name_is_inferred);
641 
642    return pscreen;
643 }
644 
645 /* swrast copy sub buffer entrypoint. */
646 void
driswCopySubBuffer(__DRIdrawable * pdp,int x,int y,int w,int h)647 driswCopySubBuffer(__DRIdrawable *pdp, int x, int y, int w, int h)
648 {
649    struct dri_drawable *drawable = dri_drawable(pdp);
650 
651    assert(drawable->screen->swrast_loader);
652 
653    drisw_copy_sub_buffer(drawable, x, y, w, h);
654 }
655 
656 /* vim: set sw=3 ts=8 sts=3 expandtab: */
657