xref: /aosp_15_r20/external/mesa3d/src/gallium/frontends/dri/dri2.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Mesa 3-D graphics library
3  *
4  * Copyright 2009, VMware, Inc.
5  * All Rights Reserved.
6  * Copyright (C) 2010 LunarG Inc.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included
16  * in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
22  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24  * OTHER DEALINGS IN THE SOFTWARE.
25  *
26  * Authors:
27  *    Keith Whitwell <[email protected]> Jakob Bornecrantz
28  *    <[email protected]> Chia-I Wu <[email protected]>
29  */
30 
31 #include "util/libdrm.h"
32 #include "git_sha1.h"
33 #include "GL/mesa_glinterop.h"
34 #include "mesa_interface.h"
35 #include "util/disk_cache.h"
36 #include "util/u_memory.h"
37 #include "util/u_inlines.h"
38 #include "util/format/u_format.h"
39 #include "util/u_debug.h"
40 #include "util/libsync.h"
41 #include "util/os_file.h"
42 #include "util/log.h"
43 #include "frontend/drm_driver.h"
44 #include "state_tracker/st_format.h"
45 #include "state_tracker/st_cb_texture.h"
46 #include "state_tracker/st_texture.h"
47 #include "state_tracker/st_context.h"
48 #include "state_tracker/st_interop.h"
49 #include "pipe-loader/pipe_loader.h"
50 #include "main/bufferobj.h"
51 #include "main/texobj.h"
52 
53 #include "dri_util.h"
54 
55 #include "dri_helpers.h"
56 #include "dri_drawable.h"
57 #include "dri_query_renderer.h"
58 #include "loader_dri_helper.h"
59 
60 #include "drm-uapi/drm_fourcc.h"
61 
62 struct dri2_buffer
63 {
64    __DRIbuffer base;
65    struct pipe_resource *resource;
66 };
67 
68 static inline struct dri2_buffer *
dri2_buffer(__DRIbuffer * driBufferPriv)69 dri2_buffer(__DRIbuffer * driBufferPriv)
70 {
71    return (struct dri2_buffer *) driBufferPriv;
72 }
73 
74 /**
75  * Invalidate the drawable.
76  *
77  * How we get here is listed below.
78  *
79  * 1. Called by these SwapBuffers implementations where the context is known:
80  *       loader_dri3_swap_buffers_msc
81  *       EGL: droid_swap_buffers
82  *       EGL: dri2_drm_swap_buffers
83  *       EGL: dri2_wl_swap_buffers_with_damage
84  *       EGL: dri2_x11_swap_buffers_msc
85  *
86  * 2. Other callers where the context is known:
87  *       st_manager_flush_frontbuffer -> dri2_flush_frontbuffer
88  *          -> EGL droid_display_shared_buffer
89  *
90  * 3. Other callers where the context is unknown:
91  *       loader: dri3_handle_present_event - XCB_PRESENT_CONFIGURE_NOTIFY
92  *       eglQuerySurface -> dri3_query_surface
93  *          -> loader_dri3_update_drawable_geometry
94  *       EGL: wl_egl_window::resize_callback (called outside Mesa)
95  */
96 void
dri_invalidate_drawable(__DRIdrawable * dPriv)97 dri_invalidate_drawable(__DRIdrawable *dPriv)
98 {
99    struct dri_drawable *drawable = dri_drawable(dPriv);
100 
101    drawable->lastStamp++;
102    drawable->texture_mask = 0; /* mark all attachments as invalid */
103 
104    p_atomic_inc(&drawable->base.stamp);
105 }
106 
107 /**
108  * Retrieve __DRIbuffer from the DRI loader.
109  */
110 static __DRIbuffer *
dri2_drawable_get_buffers(struct dri_drawable * drawable,const enum st_attachment_type * atts,unsigned * count)111 dri2_drawable_get_buffers(struct dri_drawable *drawable,
112                           const enum st_attachment_type *atts,
113                           unsigned *count)
114 {
115    const __DRIdri2LoaderExtension *loader = drawable->screen->dri2.loader;
116    bool with_format;
117    __DRIbuffer *buffers;
118    int num_buffers;
119    unsigned attachments[__DRI_BUFFER_COUNT];
120    unsigned num_attachments, i;
121 
122    assert(loader);
123    assert(*count <= __DRI_BUFFER_COUNT);
124    with_format = dri_with_format(drawable->screen);
125 
126    num_attachments = 0;
127 
128    /* for Xserver 1.6.0 (DRI2 version 1) we always need to ask for the front */
129    if (!with_format)
130       attachments[num_attachments++] = __DRI_BUFFER_FRONT_LEFT;
131 
132    for (i = 0; i < *count; i++) {
133       enum pipe_format format;
134       unsigned bind;
135       int att, depth;
136 
137       dri_drawable_get_format(drawable, atts[i], &format, &bind);
138       if (format == PIPE_FORMAT_NONE)
139          continue;
140 
141       switch (atts[i]) {
142       case ST_ATTACHMENT_FRONT_LEFT:
143          /* already added */
144          if (!with_format)
145             continue;
146          att = __DRI_BUFFER_FRONT_LEFT;
147          break;
148       case ST_ATTACHMENT_BACK_LEFT:
149          att = __DRI_BUFFER_BACK_LEFT;
150          break;
151       case ST_ATTACHMENT_FRONT_RIGHT:
152          att = __DRI_BUFFER_FRONT_RIGHT;
153          break;
154       case ST_ATTACHMENT_BACK_RIGHT:
155          att = __DRI_BUFFER_BACK_RIGHT;
156          break;
157       default:
158          continue;
159       }
160 
161       /*
162        * In this switch statement we must support all formats that
163        * may occur as the stvis->color_format.
164        */
165       switch(format) {
166       case PIPE_FORMAT_R16G16B16A16_FLOAT:
167          depth = 64;
168          break;
169       case PIPE_FORMAT_R16G16B16X16_FLOAT:
170          depth = 48;
171          break;
172       case PIPE_FORMAT_B10G10R10A2_UNORM:
173       case PIPE_FORMAT_R10G10B10A2_UNORM:
174       case PIPE_FORMAT_BGRA8888_UNORM:
175       case PIPE_FORMAT_RGBA8888_UNORM:
176 	 depth = 32;
177 	 break;
178       case PIPE_FORMAT_R10G10B10X2_UNORM:
179       case PIPE_FORMAT_B10G10R10X2_UNORM:
180          depth = 30;
181          break;
182       case PIPE_FORMAT_BGRX8888_UNORM:
183       case PIPE_FORMAT_RGBX8888_UNORM:
184 	 depth = 24;
185 	 break;
186       case PIPE_FORMAT_B5G6R5_UNORM:
187 	 depth = 16;
188 	 break;
189       default:
190 	 depth = util_format_get_blocksizebits(format);
191 	 assert(!"Unexpected format in dri2_drawable_get_buffers()");
192       }
193 
194       attachments[num_attachments++] = att;
195       if (with_format) {
196          attachments[num_attachments++] = depth;
197       }
198    }
199 
200    if (with_format) {
201       num_attachments /= 2;
202       buffers = loader->getBuffersWithFormat(opaque_dri_drawable(drawable),
203             &drawable->w, &drawable->h,
204             attachments, num_attachments,
205             &num_buffers, drawable->loaderPrivate);
206    }
207    else {
208       buffers = loader->getBuffers(opaque_dri_drawable(drawable),
209             &drawable->w, &drawable->h,
210             attachments, num_attachments,
211             &num_buffers, drawable->loaderPrivate);
212    }
213 
214    if (buffers)
215       *count = num_buffers;
216 
217    return buffers;
218 }
219 
220 bool
221 dri_image_drawable_get_buffers(struct dri_drawable *drawable,
222                                struct __DRIimageList *images,
223                                const enum st_attachment_type *statts,
224                                unsigned statts_count);
225 bool
dri_image_drawable_get_buffers(struct dri_drawable * drawable,struct __DRIimageList * images,const enum st_attachment_type * statts,unsigned statts_count)226 dri_image_drawable_get_buffers(struct dri_drawable *drawable,
227                                struct __DRIimageList *images,
228                                const enum st_attachment_type *statts,
229                                unsigned statts_count)
230 {
231    enum pipe_format color_format = PIPE_FORMAT_NONE;
232    uint32_t buffer_mask = 0;
233    unsigned i;
234 
235    for (i = 0; i < statts_count; i++) {
236       enum pipe_format pf;
237       unsigned bind;
238 
239       dri_drawable_get_format(drawable, statts[i], &pf, &bind);
240       if (pf == PIPE_FORMAT_NONE)
241          continue;
242 
243       switch (statts[i]) {
244       case ST_ATTACHMENT_FRONT_LEFT:
245          buffer_mask |= __DRI_IMAGE_BUFFER_FRONT;
246          color_format = pf;
247          break;
248       case ST_ATTACHMENT_BACK_LEFT:
249          buffer_mask |= __DRI_IMAGE_BUFFER_BACK;
250          color_format = pf;
251          break;
252       default:
253          break;
254       }
255    }
256 
257    /* Stamp usage behavior in the getBuffers callback:
258     *
259     * 1. DRI3 (EGL and GLX):
260     *       This calls loader_dri3_get_buffers, which saves the stamp pointer
261     *       in loader_dri3_drawable::stamp, which is only changed (incremented)
262     *       by loader_dri3_swap_buffers_msc.
263     *
264     * 2. EGL Android, Device, Surfaceless, Wayland:
265     *       The stamp is unused.
266     *
267     * How do we get here:
268     *    dri_set_tex_buffer2 (GLX_EXT_texture_from_pixmap)
269     *    st_api_make_current
270     *    st_manager_validate_framebuffers (part of st_validate_state)
271     */
272    return drawable->screen->image.loader->getBuffers(
273                                           opaque_dri_drawable(drawable),
274                                           color_format,
275                                           (uint32_t *)&drawable->base.stamp,
276                                           drawable->loaderPrivate, buffer_mask,
277                                           images);
278 }
279 
280 static __DRIbuffer *
dri2_allocate_buffer(struct dri_screen * screen,unsigned attachment,unsigned format,int width,int height)281 dri2_allocate_buffer(struct dri_screen *screen,
282                      unsigned attachment, unsigned format,
283                      int width, int height)
284 {
285    struct dri2_buffer *buffer;
286    struct pipe_resource templ;
287    enum pipe_format pf;
288    unsigned bind = 0;
289    struct winsys_handle whandle;
290 
291    /* struct pipe_resource height0 is 16-bit, avoid overflow */
292    if (height > 0xffff)
293       return NULL;
294 
295    switch (attachment) {
296       case __DRI_BUFFER_FRONT_LEFT:
297       case __DRI_BUFFER_FAKE_FRONT_LEFT:
298          bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
299          break;
300       case __DRI_BUFFER_BACK_LEFT:
301          bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
302          break;
303       case __DRI_BUFFER_DEPTH:
304       case __DRI_BUFFER_DEPTH_STENCIL:
305       case __DRI_BUFFER_STENCIL:
306             bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */
307          break;
308    }
309 
310    /* because we get the handle and stride */
311    bind |= PIPE_BIND_SHARED;
312 
313    switch (format) {
314       case 64:
315          pf = PIPE_FORMAT_R16G16B16A16_FLOAT;
316          break;
317       case 48:
318          pf = PIPE_FORMAT_R16G16B16X16_FLOAT;
319          break;
320       case 32:
321          pf = PIPE_FORMAT_BGRA8888_UNORM;
322          break;
323       case 30:
324          pf = PIPE_FORMAT_B10G10R10X2_UNORM;
325          break;
326       case 24:
327          pf = PIPE_FORMAT_BGRX8888_UNORM;
328          break;
329       case 16:
330          pf = PIPE_FORMAT_Z16_UNORM;
331          break;
332       default:
333          return NULL;
334    }
335 
336    buffer = CALLOC_STRUCT(dri2_buffer);
337    if (!buffer)
338       return NULL;
339 
340    memset(&templ, 0, sizeof(templ));
341    templ.bind = bind;
342    templ.format = pf;
343    templ.target = PIPE_TEXTURE_2D;
344    templ.last_level = 0;
345    templ.width0 = width;
346    templ.height0 = height;
347    templ.depth0 = 1;
348    templ.array_size = 1;
349 
350    buffer->resource =
351       screen->base.screen->resource_create(screen->base.screen, &templ);
352    if (!buffer->resource) {
353       FREE(buffer);
354       return NULL;
355    }
356 
357    memset(&whandle, 0, sizeof(whandle));
358    if (screen->can_share_buffer)
359       whandle.type = WINSYS_HANDLE_TYPE_SHARED;
360    else
361       whandle.type = WINSYS_HANDLE_TYPE_KMS;
362 
363    screen->base.screen->resource_get_handle(screen->base.screen, NULL,
364          buffer->resource, &whandle,
365          PIPE_HANDLE_USAGE_EXPLICIT_FLUSH);
366 
367    buffer->base.attachment = attachment;
368    buffer->base.name = whandle.handle;
369    buffer->base.cpp = util_format_get_blocksize(pf);
370    buffer->base.pitch = whandle.stride;
371 
372    return &buffer->base;
373 }
374 
375 static void
dri2_release_buffer(__DRIbuffer * bPriv)376 dri2_release_buffer(__DRIbuffer *bPriv)
377 {
378    struct dri2_buffer *buffer = dri2_buffer(bPriv);
379 
380    pipe_resource_reference(&buffer->resource, NULL);
381    FREE(buffer);
382 }
383 
384 void
dri2_set_in_fence_fd(__DRIimage * img,int fd)385 dri2_set_in_fence_fd(__DRIimage *img, int fd)
386 {
387    validate_fence_fd(fd);
388    validate_fence_fd(img->in_fence_fd);
389    sync_accumulate("dri", &img->in_fence_fd, fd);
390 }
391 
392 /*
393  * Backend functions for pipe_frontend_drawable.
394  */
395 
396 static void
dri2_allocate_textures(struct dri_context * ctx,struct dri_drawable * drawable,const enum st_attachment_type * statts,unsigned statts_count)397 dri2_allocate_textures(struct dri_context *ctx,
398                        struct dri_drawable *drawable,
399                        const enum st_attachment_type *statts,
400                        unsigned statts_count)
401 {
402    struct dri_screen *screen = drawable->screen;
403    struct pipe_resource templ;
404    bool alloc_depthstencil = false;
405    unsigned i, j, bind;
406    const __DRIimageLoaderExtension *image = screen->image.loader;
407    /* Image specific variables */
408    struct __DRIimageList images;
409    /* Dri2 specific variables */
410    __DRIbuffer *buffers = NULL;
411    struct winsys_handle whandle;
412    unsigned num_buffers = statts_count;
413 
414    assert(num_buffers <= __DRI_BUFFER_COUNT);
415 
416    /* Wait for glthread to finish because we can't use pipe_context from
417     * multiple threads.
418     */
419    _mesa_glthread_finish(ctx->st->ctx);
420 
421    /* First get the buffers from the loader */
422    if (image) {
423       if (!dri_image_drawable_get_buffers(drawable, &images,
424                                           statts, statts_count))
425          return;
426    }
427    else {
428       buffers = dri2_drawable_get_buffers(drawable, statts, &num_buffers);
429       if (!buffers || (drawable->old_num == num_buffers &&
430                        drawable->old_w == drawable->w &&
431                        drawable->old_h == drawable->h &&
432                        memcmp(drawable->old, buffers,
433                               sizeof(__DRIbuffer) * num_buffers) == 0))
434          return;
435    }
436 
437    /* Second clean useless resources*/
438 
439    /* See if we need a depth-stencil buffer. */
440    for (i = 0; i < statts_count; i++) {
441       if (statts[i] == ST_ATTACHMENT_DEPTH_STENCIL) {
442          alloc_depthstencil = true;
443          break;
444       }
445    }
446 
447    /* Delete the resources we won't need. */
448    for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
449       /* Don't delete the depth-stencil buffer, we can reuse it. */
450       if (i == ST_ATTACHMENT_DEPTH_STENCIL && alloc_depthstencil)
451          continue;
452 
453       /* Flush the texture before unreferencing, so that other clients can
454        * see what the driver has rendered.
455        */
456       if (i != ST_ATTACHMENT_DEPTH_STENCIL && drawable->textures[i]) {
457          struct pipe_context *pipe = ctx->st->pipe;
458          pipe->flush_resource(pipe, drawable->textures[i]);
459       }
460 
461       pipe_resource_reference(&drawable->textures[i], NULL);
462    }
463 
464    if (drawable->stvis.samples > 1) {
465       for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
466          bool del = true;
467 
468          /* Don't delete MSAA resources for the attachments which are enabled,
469           * we can reuse them. */
470          for (j = 0; j < statts_count; j++) {
471             if (i == statts[j]) {
472                del = false;
473                break;
474             }
475          }
476 
477          if (del) {
478             pipe_resource_reference(&drawable->msaa_textures[i], NULL);
479          }
480       }
481    }
482 
483    /* Third use the buffers retrieved to fill the drawable info */
484 
485    memset(&templ, 0, sizeof(templ));
486    templ.target = screen->target;
487    templ.last_level = 0;
488    templ.depth0 = 1;
489    templ.array_size = 1;
490 
491    if (image) {
492       if (images.image_mask & __DRI_IMAGE_BUFFER_FRONT) {
493          struct pipe_resource **buf =
494             &drawable->textures[ST_ATTACHMENT_FRONT_LEFT];
495          struct pipe_resource *texture = images.front->texture;
496 
497          drawable->w = texture->width0;
498          drawable->h = texture->height0;
499 
500          pipe_resource_reference(buf, texture);
501          dri_image_fence_sync(ctx, images.front);
502       }
503 
504       if (images.image_mask & __DRI_IMAGE_BUFFER_BACK) {
505          struct pipe_resource **buf =
506             &drawable->textures[ST_ATTACHMENT_BACK_LEFT];
507          struct pipe_resource *texture = images.back->texture;
508 
509          drawable->w = texture->width0;
510          drawable->h = texture->height0;
511 
512          pipe_resource_reference(buf, texture);
513          dri_image_fence_sync(ctx, images.back);
514       }
515 
516       if (images.image_mask & __DRI_IMAGE_BUFFER_SHARED) {
517          struct pipe_resource **buf =
518             &drawable->textures[ST_ATTACHMENT_BACK_LEFT];
519          struct pipe_resource *texture = images.back->texture;
520 
521          drawable->w = texture->width0;
522          drawable->h = texture->height0;
523 
524          pipe_resource_reference(buf, texture);
525          dri_image_fence_sync(ctx, images.back);
526 
527          ctx->is_shared_buffer_bound = true;
528       } else {
529          ctx->is_shared_buffer_bound = false;
530       }
531 
532       /* Note: if there is both a back and a front buffer,
533        * then they have the same size.
534        */
535       templ.width0 = drawable->w;
536       templ.height0 = drawable->h;
537    }
538    else {
539       memset(&whandle, 0, sizeof(whandle));
540 
541       /* Process DRI-provided buffers and get pipe_resources. */
542       for (i = 0; i < num_buffers; i++) {
543          __DRIbuffer *buf = &buffers[i];
544          enum st_attachment_type statt;
545          enum pipe_format format;
546 
547          switch (buf->attachment) {
548          case __DRI_BUFFER_FRONT_LEFT:
549             if (!screen->auto_fake_front) {
550                continue; /* invalid attachment */
551             }
552             FALLTHROUGH;
553          case __DRI_BUFFER_FAKE_FRONT_LEFT:
554             statt = ST_ATTACHMENT_FRONT_LEFT;
555             break;
556          case __DRI_BUFFER_BACK_LEFT:
557             statt = ST_ATTACHMENT_BACK_LEFT;
558             break;
559          default:
560             continue; /* invalid attachment */
561          }
562 
563          dri_drawable_get_format(drawable, statt, &format, &bind);
564          if (format == PIPE_FORMAT_NONE)
565             continue;
566 
567          /* dri2_drawable_get_buffers has already filled dri_drawable->w
568           * and dri_drawable->h */
569          templ.width0 = drawable->w;
570          templ.height0 = drawable->h;
571          templ.format = format;
572          templ.bind = bind;
573          whandle.handle = buf->name;
574          whandle.stride = buf->pitch;
575          whandle.offset = 0;
576          whandle.format = format;
577          whandle.modifier = DRM_FORMAT_MOD_INVALID;
578          if (screen->can_share_buffer)
579             whandle.type = WINSYS_HANDLE_TYPE_SHARED;
580          else
581             whandle.type = WINSYS_HANDLE_TYPE_KMS;
582          drawable->textures[statt] =
583             screen->base.screen->resource_from_handle(screen->base.screen,
584                   &templ, &whandle,
585                   PIPE_HANDLE_USAGE_EXPLICIT_FLUSH);
586          assert(drawable->textures[statt]);
587       }
588    }
589 
590    /* Allocate private MSAA colorbuffers. */
591    if (drawable->stvis.samples > 1) {
592       for (i = 0; i < statts_count; i++) {
593          enum st_attachment_type statt = statts[i];
594 
595          if (statt == ST_ATTACHMENT_DEPTH_STENCIL)
596             continue;
597 
598          if (drawable->textures[statt]) {
599             templ.format = drawable->textures[statt]->format;
600             templ.bind = drawable->textures[statt]->bind &
601                          ~(PIPE_BIND_SCANOUT | PIPE_BIND_SHARED);
602             templ.nr_samples = drawable->stvis.samples;
603             templ.nr_storage_samples = drawable->stvis.samples;
604 
605             /* Try to reuse the resource.
606              * (the other resource parameters should be constant)
607              */
608             if (!drawable->msaa_textures[statt] ||
609                 drawable->msaa_textures[statt]->width0 != templ.width0 ||
610                 drawable->msaa_textures[statt]->height0 != templ.height0) {
611                /* Allocate a new one. */
612                pipe_resource_reference(&drawable->msaa_textures[statt], NULL);
613 
614                drawable->msaa_textures[statt] =
615                   screen->base.screen->resource_create(screen->base.screen,
616                                                        &templ);
617                assert(drawable->msaa_textures[statt]);
618 
619                /* If there are any MSAA resources, we should initialize them
620                 * such that they contain the same data as the single-sample
621                 * resources we just got from the X server.
622                 *
623                 * The reason for this is that the gallium frontend (and
624                 * therefore the app) can access the MSAA resources only.
625                 * The single-sample resources are not exposed
626                 * to the gallium frontend.
627                 *
628                 */
629                dri_pipe_blit(ctx->st->pipe,
630                              drawable->msaa_textures[statt],
631                              drawable->textures[statt]);
632             }
633          }
634          else {
635             pipe_resource_reference(&drawable->msaa_textures[statt], NULL);
636          }
637       }
638    }
639 
640    /* Allocate a private depth-stencil buffer. */
641    if (alloc_depthstencil) {
642       enum st_attachment_type statt = ST_ATTACHMENT_DEPTH_STENCIL;
643       struct pipe_resource **zsbuf;
644       enum pipe_format format;
645       unsigned bind;
646 
647       dri_drawable_get_format(drawable, statt, &format, &bind);
648 
649       if (format) {
650          templ.format = format;
651          templ.bind = bind & ~PIPE_BIND_SHARED;
652 
653          if (drawable->stvis.samples > 1) {
654             templ.nr_samples = drawable->stvis.samples;
655             templ.nr_storage_samples = drawable->stvis.samples;
656             zsbuf = &drawable->msaa_textures[statt];
657          }
658          else {
659             templ.nr_samples = 0;
660             templ.nr_storage_samples = 0;
661             zsbuf = &drawable->textures[statt];
662          }
663 
664          /* Try to reuse the resource.
665           * (the other resource parameters should be constant)
666           */
667          if (!*zsbuf ||
668              (*zsbuf)->width0 != templ.width0 ||
669              (*zsbuf)->height0 != templ.height0) {
670             /* Allocate a new one. */
671             pipe_resource_reference(zsbuf, NULL);
672             *zsbuf = screen->base.screen->resource_create(screen->base.screen,
673                                                           &templ);
674             assert(*zsbuf);
675          }
676       }
677       else {
678          pipe_resource_reference(&drawable->msaa_textures[statt], NULL);
679          pipe_resource_reference(&drawable->textures[statt], NULL);
680       }
681    }
682 
683    /* For DRI2, we may get the same buffers again from the server.
684     * To prevent useless imports of gem names, drawable->old* is used
685     * to bypass the import if we get the same buffers. This doesn't apply
686     * to DRI3/Wayland, users of image.loader, since the buffer is managed
687     * by the client (no import), and the back buffer is going to change
688     * at every redraw.
689     */
690    if (!image) {
691       drawable->old_num = num_buffers;
692       drawable->old_w = drawable->w;
693       drawable->old_h = drawable->h;
694       memcpy(drawable->old, buffers, sizeof(__DRIbuffer) * num_buffers);
695    }
696 }
697 
698 static bool
dri2_flush_frontbuffer(struct dri_context * ctx,struct dri_drawable * drawable,enum st_attachment_type statt)699 dri2_flush_frontbuffer(struct dri_context *ctx,
700                        struct dri_drawable *drawable,
701                        enum st_attachment_type statt)
702 {
703    const __DRIimageLoaderExtension *image = drawable->screen->image.loader;
704    const __DRIdri2LoaderExtension *loader = drawable->screen->dri2.loader;
705    const __DRImutableRenderBufferLoaderExtension *shared_buffer_loader =
706       drawable->screen->mutableRenderBuffer.loader;
707    struct pipe_context *pipe = ctx->st->pipe;
708    struct pipe_fence_handle *fence = NULL;
709    int fence_fd = -1;
710 
711    /* We need to flush for front buffer rendering when either we're using the
712     * front buffer at the GL API level, or when EGL_KHR_mutable_render_buffer
713     * has redirected GL_BACK to the front buffer.
714     */
715    if (statt != ST_ATTACHMENT_FRONT_LEFT &&
716        (!ctx->is_shared_buffer_bound || statt != ST_ATTACHMENT_BACK_LEFT))
717          return false;
718 
719    /* Wait for glthread to finish because we can't use pipe_context from
720     * multiple threads.
721     */
722    _mesa_glthread_finish(ctx->st->ctx);
723 
724    if (drawable->stvis.samples > 1) {
725       /* Resolve the buffer used for front rendering. */
726       dri_pipe_blit(ctx->st->pipe, drawable->textures[statt],
727                     drawable->msaa_textures[statt]);
728    }
729 
730    if (drawable->textures[statt]) {
731       pipe->flush_resource(pipe, drawable->textures[statt]);
732    }
733 
734    if (ctx->is_shared_buffer_bound) {
735       /* is_shared_buffer_bound should only be true with image extension: */
736       assert(image);
737       pipe->flush(pipe, &fence, PIPE_FLUSH_FENCE_FD);
738    } else {
739       pipe->flush(pipe, NULL, 0);
740    }
741 
742    if (image) {
743       image->flushFrontBuffer(opaque_dri_drawable(drawable),
744                               drawable->loaderPrivate);
745       if (ctx->is_shared_buffer_bound) {
746          if (fence)
747             fence_fd = pipe->screen->fence_get_fd(pipe->screen, fence);
748 
749          shared_buffer_loader->displaySharedBuffer(opaque_dri_drawable(drawable),
750                                                    fence_fd,
751                                                    drawable->loaderPrivate);
752 
753          pipe->screen->fence_reference(pipe->screen, &fence, NULL);
754       }
755    }
756    else if (loader->flushFrontBuffer) {
757       loader->flushFrontBuffer(opaque_dri_drawable(drawable),
758                                drawable->loaderPrivate);
759    }
760 
761    return true;
762 }
763 
764 /**
765  * The struct dri_drawable flush_swapbuffers callback
766  */
767 static void
dri2_flush_swapbuffers(struct dri_context * ctx,struct dri_drawable * drawable)768 dri2_flush_swapbuffers(struct dri_context *ctx,
769                        struct dri_drawable *drawable)
770 {
771    const __DRIimageLoaderExtension *image = drawable->screen->image.loader;
772 
773    if (image && image->flushSwapBuffers) {
774       image->flushSwapBuffers(opaque_dri_drawable(drawable),
775                               drawable->loaderPrivate);
776    }
777 }
778 
779 static void
dri2_update_tex_buffer(struct dri_drawable * drawable,struct dri_context * ctx,struct pipe_resource * res)780 dri2_update_tex_buffer(struct dri_drawable *drawable,
781                        struct dri_context *ctx,
782                        struct pipe_resource *res)
783 {
784    /* no-op */
785 }
786 
787 static const struct dri2_format_mapping r8_b8_g8_mapping = {
788    DRM_FORMAT_YVU420,
789    __DRI_IMAGE_FORMAT_NONE,
790    __DRI_IMAGE_COMPONENTS_Y_U_V,
791    PIPE_FORMAT_R8_B8_G8_420_UNORM,
792    3,
793    { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8 },
794      { 2, 1, 1, __DRI_IMAGE_FORMAT_R8 },
795      { 1, 1, 1, __DRI_IMAGE_FORMAT_R8 } }
796 };
797 
798 static const struct dri2_format_mapping r8_g8_b8_mapping = {
799    DRM_FORMAT_YUV420,
800    __DRI_IMAGE_FORMAT_NONE,
801    __DRI_IMAGE_COMPONENTS_Y_U_V,
802    PIPE_FORMAT_R8_G8_B8_420_UNORM,
803    3,
804    { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8 },
805      { 1, 1, 1, __DRI_IMAGE_FORMAT_R8 },
806      { 2, 1, 1, __DRI_IMAGE_FORMAT_R8 } }
807 };
808 
809 static const struct dri2_format_mapping r8_g8b8_mapping = {
810    DRM_FORMAT_NV12,
811    __DRI_IMAGE_FORMAT_NONE,
812    __DRI_IMAGE_COMPONENTS_Y_UV,
813    PIPE_FORMAT_R8_G8B8_420_UNORM,
814    2,
815    { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8 },
816      { 1, 1, 1, __DRI_IMAGE_FORMAT_GR88 } }
817 };
818 
819 static const struct dri2_format_mapping r8_b8g8_mapping = {
820    DRM_FORMAT_NV21,
821    __DRI_IMAGE_FORMAT_NONE,
822    __DRI_IMAGE_COMPONENTS_Y_UV,
823    PIPE_FORMAT_R8_B8G8_420_UNORM,
824    2,
825    { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8 },
826      { 1, 1, 1, __DRI_IMAGE_FORMAT_GR88 } }
827 };
828 
829 static const struct dri2_format_mapping r8g8_r8b8_mapping = {
830    DRM_FORMAT_YUYV,
831    __DRI_IMAGE_FORMAT_NONE,
832    __DRI_IMAGE_COMPONENTS_Y_XUXV,
833    PIPE_FORMAT_R8G8_R8B8_UNORM, 2,
834    { { 0, 0, 0, __DRI_IMAGE_FORMAT_GR88 },
835      { 0, 1, 0, __DRI_IMAGE_FORMAT_ARGB8888 } }
836 };
837 
838 static const struct dri2_format_mapping r8b8_r8g8_mapping = {
839    DRM_FORMAT_YVYU,
840    __DRI_IMAGE_FORMAT_NONE,
841    __DRI_IMAGE_COMPONENTS_Y_XUXV,
842    PIPE_FORMAT_R8B8_R8G8_UNORM, 2,
843    { { 0, 0, 0, __DRI_IMAGE_FORMAT_GR88 },
844      { 0, 1, 0, __DRI_IMAGE_FORMAT_ARGB8888 } }
845 };
846 
847 static const struct dri2_format_mapping b8r8_g8r8_mapping = {
848    DRM_FORMAT_VYUY,
849    __DRI_IMAGE_FORMAT_NONE,
850    __DRI_IMAGE_COMPONENTS_Y_XUXV,
851    PIPE_FORMAT_B8R8_G8R8_UNORM, 2,
852    { { 0, 0, 0, __DRI_IMAGE_FORMAT_GR88 },
853      { 0, 1, 0, __DRI_IMAGE_FORMAT_ABGR8888 } }
854 };
855 
856 static const struct dri2_format_mapping g8r8_b8r8_mapping = {
857    DRM_FORMAT_UYVY,
858    __DRI_IMAGE_FORMAT_NONE,
859    __DRI_IMAGE_COMPONENTS_Y_XUXV,
860    PIPE_FORMAT_G8R8_B8R8_UNORM, 2,
861    { { 0, 0, 0, __DRI_IMAGE_FORMAT_GR88 },
862      { 0, 1, 0, __DRI_IMAGE_FORMAT_ABGR8888 } }
863 };
864 
865 static enum __DRIFixedRateCompression
to_dri_compression_rate(uint32_t rate)866 to_dri_compression_rate(uint32_t rate)
867 {
868    switch (rate) {
869    case PIPE_COMPRESSION_FIXED_RATE_NONE:
870       return __DRI_FIXED_RATE_COMPRESSION_NONE;
871    case PIPE_COMPRESSION_FIXED_RATE_DEFAULT:
872       return __DRI_FIXED_RATE_COMPRESSION_DEFAULT;
873    case 1: return __DRI_FIXED_RATE_COMPRESSION_1BPC;
874    case 2: return __DRI_FIXED_RATE_COMPRESSION_2BPC;
875    case 3: return __DRI_FIXED_RATE_COMPRESSION_3BPC;
876    case 4: return __DRI_FIXED_RATE_COMPRESSION_4BPC;
877    case 5: return __DRI_FIXED_RATE_COMPRESSION_5BPC;
878    case 6: return __DRI_FIXED_RATE_COMPRESSION_6BPC;
879    case 7: return __DRI_FIXED_RATE_COMPRESSION_7BPC;
880    case 8: return __DRI_FIXED_RATE_COMPRESSION_8BPC;
881    case 9: return __DRI_FIXED_RATE_COMPRESSION_9BPC;
882    case 10: return __DRI_FIXED_RATE_COMPRESSION_10BPC;
883    case 11: return __DRI_FIXED_RATE_COMPRESSION_11BPC;
884    case 12: return __DRI_FIXED_RATE_COMPRESSION_12BPC;
885    default:
886       unreachable("invalid compression fixed-rate value");
887    }
888 }
889 
890 static uint32_t
from_dri_compression_rate(enum __DRIFixedRateCompression rate)891 from_dri_compression_rate(enum __DRIFixedRateCompression rate)
892 {
893    switch (rate) {
894    case __DRI_FIXED_RATE_COMPRESSION_NONE:
895       return PIPE_COMPRESSION_FIXED_RATE_NONE;
896    case __DRI_FIXED_RATE_COMPRESSION_DEFAULT:
897       return PIPE_COMPRESSION_FIXED_RATE_DEFAULT;
898    case __DRI_FIXED_RATE_COMPRESSION_1BPC: return 1;
899    case __DRI_FIXED_RATE_COMPRESSION_2BPC: return 2;
900    case __DRI_FIXED_RATE_COMPRESSION_3BPC: return 3;
901    case __DRI_FIXED_RATE_COMPRESSION_4BPC: return 4;
902    case __DRI_FIXED_RATE_COMPRESSION_5BPC: return 5;
903    case __DRI_FIXED_RATE_COMPRESSION_6BPC: return 6;
904    case __DRI_FIXED_RATE_COMPRESSION_7BPC: return 7;
905    case __DRI_FIXED_RATE_COMPRESSION_8BPC: return 8;
906    case __DRI_FIXED_RATE_COMPRESSION_9BPC: return 9;
907    case __DRI_FIXED_RATE_COMPRESSION_10BPC: return 10;
908    case __DRI_FIXED_RATE_COMPRESSION_11BPC: return 11;
909    case __DRI_FIXED_RATE_COMPRESSION_12BPC: return 12;
910    default:
911       unreachable("invalid compression fixed-rate value");
912    }
913 }
914 
915 static __DRIimage *
dri_create_image_from_winsys(__DRIscreen * _screen,int width,int height,const struct dri2_format_mapping * map,int num_handles,struct winsys_handle * whandle,unsigned bind,void * loaderPrivate)916 dri_create_image_from_winsys(__DRIscreen *_screen,
917                               int width, int height, const struct dri2_format_mapping *map,
918                               int num_handles, struct winsys_handle *whandle,
919                               unsigned bind,
920                               void *loaderPrivate)
921 {
922    struct dri_screen *screen = dri_screen(_screen);
923    struct pipe_screen *pscreen = screen->base.screen;
924    __DRIimage *img;
925    struct pipe_resource templ;
926    unsigned tex_usage = 0;
927    int i;
928    bool use_lowered = false;
929    const unsigned format_planes = util_format_get_num_planes(map->pipe_format);
930 
931    if (pscreen->is_format_supported(pscreen, map->pipe_format, screen->target, 0, 0,
932                                     PIPE_BIND_RENDER_TARGET))
933       tex_usage |= PIPE_BIND_RENDER_TARGET;
934    if (pscreen->is_format_supported(pscreen, map->pipe_format, screen->target, 0, 0,
935                                     PIPE_BIND_SAMPLER_VIEW))
936       tex_usage |= PIPE_BIND_SAMPLER_VIEW;
937 
938    /* For NV12, see if we have support for sampling r8_g8b8 */
939    if (!tex_usage && map->pipe_format == PIPE_FORMAT_NV12 &&
940        pscreen->is_format_supported(pscreen, PIPE_FORMAT_R8_G8B8_420_UNORM,
941                                     screen->target, 0, 0, PIPE_BIND_SAMPLER_VIEW)) {
942       map = &r8_g8b8_mapping;
943       tex_usage |= PIPE_BIND_SAMPLER_VIEW;
944    }
945 
946    /* For NV21, see if we have support for sampling r8_b8g8 */
947    if (!tex_usage && map->pipe_format == PIPE_FORMAT_NV21 &&
948        pscreen->is_format_supported(pscreen, PIPE_FORMAT_R8_B8G8_420_UNORM,
949                                     screen->target, 0, 0, PIPE_BIND_SAMPLER_VIEW)) {
950       map = &r8_b8g8_mapping;
951       tex_usage |= PIPE_BIND_SAMPLER_VIEW;
952    }
953 
954    /* For YV12 and I420, see if we have support for sampling r8_b8_g8 or r8_g8_b8 */
955    if (!tex_usage && map->pipe_format == PIPE_FORMAT_IYUV) {
956       if (map->dri_fourcc == DRM_FORMAT_YUV420 &&
957           pscreen->is_format_supported(pscreen, PIPE_FORMAT_R8_G8_B8_420_UNORM,
958                                        screen->target, 0, 0, PIPE_BIND_SAMPLER_VIEW)) {
959          map = &r8_g8_b8_mapping;
960          tex_usage |= PIPE_BIND_SAMPLER_VIEW;
961       } else if (map->dri_fourcc == DRM_FORMAT_YVU420 &&
962           pscreen->is_format_supported(pscreen, PIPE_FORMAT_R8_B8_G8_420_UNORM,
963                                        screen->target, 0, 0, PIPE_BIND_SAMPLER_VIEW)) {
964          map = &r8_b8_g8_mapping;
965          tex_usage |= PIPE_BIND_SAMPLER_VIEW;
966       }
967    }
968 
969    /* If the hardware supports R8G8_R8B8 style subsampled RGB formats, these
970     * can be used for YUYV and UYVY formats.
971     */
972    if (!tex_usage && map->pipe_format == PIPE_FORMAT_YUYV &&
973        pscreen->is_format_supported(pscreen, PIPE_FORMAT_R8G8_R8B8_UNORM,
974                                     screen->target, 0, 0, PIPE_BIND_SAMPLER_VIEW)) {
975       map = &r8g8_r8b8_mapping;
976       tex_usage |= PIPE_BIND_SAMPLER_VIEW;
977    }
978 
979    if (!tex_usage && map->pipe_format == PIPE_FORMAT_YVYU &&
980        pscreen->is_format_supported(pscreen, PIPE_FORMAT_R8B8_R8G8_UNORM,
981                                     screen->target, 0, 0, PIPE_BIND_SAMPLER_VIEW)) {
982       map = &r8b8_r8g8_mapping;
983       tex_usage |= PIPE_BIND_SAMPLER_VIEW;
984    }
985 
986    if (!tex_usage && map->pipe_format == PIPE_FORMAT_UYVY &&
987        pscreen->is_format_supported(pscreen, PIPE_FORMAT_G8R8_B8R8_UNORM,
988                                     screen->target, 0, 0, PIPE_BIND_SAMPLER_VIEW)) {
989       map = &g8r8_b8r8_mapping;
990       tex_usage |= PIPE_BIND_SAMPLER_VIEW;
991    }
992 
993    if (!tex_usage && map->pipe_format == PIPE_FORMAT_VYUY &&
994        pscreen->is_format_supported(pscreen, PIPE_FORMAT_B8R8_G8R8_UNORM,
995                                     screen->target, 0, 0, PIPE_BIND_SAMPLER_VIEW)) {
996       map = &b8r8_g8r8_mapping;
997       tex_usage |= PIPE_BIND_SAMPLER_VIEW;
998    }
999 
1000    if (!tex_usage && util_format_is_yuv(map->pipe_format)) {
1001       /* YUV format sampling can be emulated by the GL gallium frontend by
1002        * using multiple samplers of varying formats.
1003        * If no tex_usage is set and we detect a YUV format,
1004        * test for support of all planes' sampler formats and
1005        * add sampler view usage.
1006        */
1007       use_lowered = true;
1008       if (dri2_yuv_dma_buf_supported(screen, map))
1009          tex_usage |= PIPE_BIND_SAMPLER_VIEW;
1010    }
1011 
1012    if (!tex_usage)
1013       return NULL;
1014 
1015    img = CALLOC_STRUCT(__DRIimageRec);
1016    if (!img)
1017       return NULL;
1018 
1019    memset(&templ, 0, sizeof(templ));
1020    templ.bind = tex_usage | bind;
1021    templ.target = screen->target;
1022    templ.last_level = 0;
1023    templ.depth0 = 1;
1024    templ.array_size = 1;
1025    templ.width0 = width;
1026    templ.height0 = height;
1027 
1028    for (i = num_handles - 1; i >= format_planes; i--) {
1029       struct pipe_resource *tex;
1030 
1031       templ.next = img->texture;
1032 
1033       tex = pscreen->resource_from_handle(pscreen, &templ, &whandle[i],
1034                                           PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE);
1035       if (!tex) {
1036          pipe_resource_reference(&img->texture, NULL);
1037          FREE(img);
1038          return NULL;
1039       }
1040 
1041       img->texture = tex;
1042    }
1043 
1044    for (i = (use_lowered ? map->nplanes : format_planes) - 1; i >= 0; i--) {
1045       struct pipe_resource *tex;
1046 
1047       templ.next = img->texture;
1048       templ.width0 = width >> map->planes[i].width_shift;
1049       templ.height0 = height >> map->planes[i].height_shift;
1050       if (use_lowered)
1051          templ.format = dri2_get_pipe_format_for_dri_format(map->planes[i].dri_format);
1052       else
1053          templ.format = map->pipe_format;
1054       assert(templ.format != PIPE_FORMAT_NONE);
1055 
1056       tex = pscreen->resource_from_handle(pscreen,
1057                &templ, &whandle[use_lowered ? map->planes[i].buffer_index : i],
1058                PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE);
1059       if (!tex) {
1060          pipe_resource_reference(&img->texture, NULL);
1061          FREE(img);
1062          return NULL;
1063       }
1064 
1065       /* Reject image creation if there's an inconsistency between
1066        * content protection status of tex and img.
1067        */
1068       const struct driOptionCache *optionCache = &screen->dev->option_cache;
1069       if (driQueryOptionb(optionCache, "force_protected_content_check") &&
1070           (tex->bind & PIPE_BIND_PROTECTED) != (bind & PIPE_BIND_PROTECTED)) {
1071          pipe_resource_reference(&img->texture, NULL);
1072          pipe_resource_reference(&tex, NULL);
1073          FREE(img);
1074          return NULL;
1075       }
1076 
1077       img->texture = tex;
1078    }
1079 
1080    img->level = 0;
1081    img->layer = 0;
1082    img->use = 0;
1083    img->in_fence_fd = -1;
1084    img->loader_private = loaderPrivate;
1085    img->screen = screen;
1086 
1087    return img;
1088 }
1089 
1090 static unsigned
dri2_get_modifier_num_planes(__DRIscreen * _screen,uint64_t modifier,int fourcc)1091 dri2_get_modifier_num_planes(__DRIscreen *_screen,
1092                              uint64_t modifier, int fourcc)
1093 {
1094    struct pipe_screen *pscreen = dri_screen(_screen)->base.screen;
1095    const struct dri2_format_mapping *map = dri2_get_mapping_by_fourcc(fourcc);
1096 
1097    if (!map)
1098       return 0;
1099 
1100    switch (modifier) {
1101    case DRM_FORMAT_MOD_LINEAR:
1102    /* DRM_FORMAT_MOD_NONE is the same as LINEAR */
1103    case DRM_FORMAT_MOD_INVALID:
1104       return util_format_get_num_planes(map->pipe_format);
1105    default:
1106       if (!pscreen->is_dmabuf_modifier_supported ||
1107           !pscreen->is_dmabuf_modifier_supported(pscreen, modifier,
1108                                                  map->pipe_format, NULL)) {
1109          return 0;
1110       }
1111 
1112       if (pscreen->get_dmabuf_modifier_planes) {
1113          return pscreen->get_dmabuf_modifier_planes(pscreen, modifier,
1114                                                     map->pipe_format);
1115       }
1116 
1117       return map->nplanes;
1118    }
1119 }
1120 
1121 __DRIimage *
dri_create_image(__DRIscreen * _screen,int width,int height,int format,const uint64_t * modifiers,const unsigned _count,unsigned int use,void * loaderPrivate)1122 dri_create_image(__DRIscreen *_screen,
1123                   int width, int height,
1124                   int format,
1125                   const uint64_t *modifiers,
1126                   const unsigned _count,
1127                   unsigned int use,
1128                   void *loaderPrivate)
1129 {
1130    const struct dri2_format_mapping *map = dri2_get_mapping_by_format(format);
1131    struct dri_screen *screen = dri_screen(_screen);
1132    struct pipe_screen *pscreen = screen->base.screen;
1133    __DRIimage *img;
1134    struct pipe_resource templ;
1135    unsigned tex_usage = 0;
1136    unsigned count = _count;
1137 
1138    if (!map)
1139       return NULL;
1140 
1141    if (count == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID) {
1142       count = 0;
1143       modifiers = NULL;
1144    }
1145 
1146    if (!pscreen->resource_create_with_modifiers && count > 0) {
1147       bool invalid_ok = false;
1148       bool linear_ok = false;
1149 
1150       for (unsigned i = 0; i < _count; i++) {
1151          if (modifiers[i] == DRM_FORMAT_MOD_LINEAR)
1152             linear_ok = true;
1153          else if (modifiers[i] == DRM_FORMAT_MOD_INVALID)
1154             invalid_ok = true;
1155       }
1156 
1157       if (invalid_ok) {
1158          count = 0;
1159          modifiers = NULL;
1160       } else if (linear_ok) {
1161          count = 0;
1162          modifiers = NULL;
1163          use |= __DRI_IMAGE_USE_LINEAR;
1164       } else {
1165          return NULL;
1166       }
1167    }
1168 
1169    if (pscreen->is_format_supported(pscreen, map->pipe_format, screen->target,
1170                                     0, 0, PIPE_BIND_RENDER_TARGET))
1171       tex_usage |= PIPE_BIND_RENDER_TARGET;
1172    if (pscreen->is_format_supported(pscreen, map->pipe_format, screen->target,
1173                                     0, 0, PIPE_BIND_SAMPLER_VIEW))
1174       tex_usage |= PIPE_BIND_SAMPLER_VIEW;
1175 
1176    if (!tex_usage)
1177       return NULL;
1178 
1179    if (use & __DRI_IMAGE_USE_SCANOUT)
1180       tex_usage |= PIPE_BIND_SCANOUT;
1181    if (use & __DRI_IMAGE_USE_SHARE)
1182       tex_usage |= PIPE_BIND_SHARED;
1183    if (use & __DRI_IMAGE_USE_LINEAR)
1184       tex_usage |= PIPE_BIND_LINEAR;
1185    if (use & __DRI_IMAGE_USE_CURSOR) {
1186       if (width != 64 || height != 64)
1187          return NULL;
1188       tex_usage |= PIPE_BIND_CURSOR;
1189    }
1190    if (use & __DRI_IMAGE_USE_PROTECTED)
1191       tex_usage |= PIPE_BIND_PROTECTED;
1192    if (use & __DRI_IMAGE_USE_PRIME_BUFFER)
1193       tex_usage |= PIPE_BIND_PRIME_BLIT_DST;
1194    if (use & __DRI_IMAGE_USE_FRONT_RENDERING)
1195       tex_usage |= PIPE_BIND_USE_FRONT_RENDERING;
1196 
1197    img = CALLOC_STRUCT(__DRIimageRec);
1198    if (!img)
1199       return NULL;
1200 
1201    memset(&templ, 0, sizeof(templ));
1202    templ.bind = tex_usage;
1203    templ.format = map->pipe_format;
1204    templ.target = PIPE_TEXTURE_2D;
1205    templ.last_level = 0;
1206    templ.width0 = width;
1207    templ.height0 = height;
1208    templ.depth0 = 1;
1209    templ.array_size = 1;
1210 
1211    if (modifiers)
1212       img->texture =
1213          screen->base.screen
1214             ->resource_create_with_modifiers(screen->base.screen,
1215                                              &templ,
1216                                              modifiers,
1217                                              count);
1218    else
1219       img->texture =
1220          screen->base.screen->resource_create(screen->base.screen, &templ);
1221    if (!img->texture) {
1222       FREE(img);
1223       return NULL;
1224    }
1225 
1226    img->level = 0;
1227    img->layer = 0;
1228    img->dri_format = format;
1229    img->dri_fourcc = map->dri_fourcc;
1230    img->dri_components = 0;
1231    img->use = use;
1232    img->in_fence_fd = -1;
1233 
1234    img->loader_private = loaderPrivate;
1235    img->screen = screen;
1236    return img;
1237 }
1238 
1239 static bool
dri2_query_image_common(__DRIimage * image,int attrib,int * value)1240 dri2_query_image_common(__DRIimage *image, int attrib, int *value)
1241 {
1242    switch (attrib) {
1243    case __DRI_IMAGE_ATTRIB_WIDTH:
1244       *value = image->texture->width0;
1245       return true;
1246    case __DRI_IMAGE_ATTRIB_HEIGHT:
1247       *value = image->texture->height0;
1248       return true;
1249    case __DRI_IMAGE_ATTRIB_COMPONENTS:
1250       if (image->dri_components == 0)
1251          return false;
1252       *value = image->dri_components;
1253       return true;
1254    case __DRI_IMAGE_ATTRIB_FOURCC:
1255       if (image->dri_fourcc) {
1256          *value = image->dri_fourcc;
1257       } else {
1258          const struct dri2_format_mapping *map;
1259 
1260          map = dri2_get_mapping_by_format(image->dri_format);
1261          if (!map)
1262             return false;
1263 
1264          *value = map->dri_fourcc;
1265       }
1266       return true;
1267    case __DRI_IMAGE_ATTRIB_COMPRESSION_RATE:
1268       if (!image->texture)
1269          *value = __DRI_FIXED_RATE_COMPRESSION_NONE;
1270       else
1271          *value = to_dri_compression_rate(image->texture->compression_rate);
1272       return true;
1273 
1274    default:
1275       return false;
1276    }
1277 }
1278 
1279 static bool
dri2_query_image_by_resource_handle(__DRIimage * image,int attrib,int * value)1280 dri2_query_image_by_resource_handle(__DRIimage *image, int attrib, int *value)
1281 {
1282    struct pipe_screen *pscreen = image->texture->screen;
1283    struct winsys_handle whandle;
1284    struct pipe_resource *tex;
1285    unsigned usage;
1286    memset(&whandle, 0, sizeof(whandle));
1287    whandle.plane = image->plane;
1288    int i;
1289 
1290    switch (attrib) {
1291    case __DRI_IMAGE_ATTRIB_STRIDE:
1292    case __DRI_IMAGE_ATTRIB_OFFSET:
1293    case __DRI_IMAGE_ATTRIB_HANDLE:
1294       whandle.type = WINSYS_HANDLE_TYPE_KMS;
1295       break;
1296    case __DRI_IMAGE_ATTRIB_NAME:
1297       whandle.type = WINSYS_HANDLE_TYPE_SHARED;
1298       break;
1299    case __DRI_IMAGE_ATTRIB_FD:
1300       whandle.type = WINSYS_HANDLE_TYPE_FD;
1301       break;
1302    case __DRI_IMAGE_ATTRIB_NUM_PLANES:
1303       for (i = 0, tex = image->texture; tex; tex = tex->next)
1304          i++;
1305       *value = i;
1306       return true;
1307    case __DRI_IMAGE_ATTRIB_MODIFIER_UPPER:
1308    case __DRI_IMAGE_ATTRIB_MODIFIER_LOWER:
1309       whandle.type = WINSYS_HANDLE_TYPE_KMS;
1310       whandle.modifier = DRM_FORMAT_MOD_INVALID;
1311       break;
1312    default:
1313       return false;
1314    }
1315 
1316    usage = PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE;
1317 
1318    if (image->use & __DRI_IMAGE_USE_BACKBUFFER)
1319       usage |= PIPE_HANDLE_USAGE_EXPLICIT_FLUSH;
1320 
1321    if (!pscreen->resource_get_handle(pscreen, NULL, image->texture,
1322                                      &whandle, usage))
1323       return false;
1324 
1325    switch (attrib) {
1326    case __DRI_IMAGE_ATTRIB_STRIDE:
1327       *value = whandle.stride;
1328       return true;
1329    case __DRI_IMAGE_ATTRIB_OFFSET:
1330       *value = whandle.offset;
1331       return true;
1332    case __DRI_IMAGE_ATTRIB_HANDLE:
1333    case __DRI_IMAGE_ATTRIB_NAME:
1334    case __DRI_IMAGE_ATTRIB_FD:
1335       *value = whandle.handle;
1336       return true;
1337    case __DRI_IMAGE_ATTRIB_MODIFIER_UPPER:
1338       if (whandle.modifier == DRM_FORMAT_MOD_INVALID)
1339          return false;
1340       *value = (whandle.modifier >> 32) & 0xffffffff;
1341       return true;
1342    case __DRI_IMAGE_ATTRIB_MODIFIER_LOWER:
1343       if (whandle.modifier == DRM_FORMAT_MOD_INVALID)
1344          return false;
1345       *value = whandle.modifier & 0xffffffff;
1346       return true;
1347    default:
1348       return false;
1349    }
1350 }
1351 
1352 static bool
dri2_resource_get_param(__DRIimage * image,enum pipe_resource_param param,unsigned handle_usage,uint64_t * value)1353 dri2_resource_get_param(__DRIimage *image, enum pipe_resource_param param,
1354                         unsigned handle_usage, uint64_t *value)
1355 {
1356    struct pipe_screen *pscreen = image->texture->screen;
1357    if (!pscreen->resource_get_param)
1358       return false;
1359 
1360    if (image->use & __DRI_IMAGE_USE_BACKBUFFER)
1361       handle_usage |= PIPE_HANDLE_USAGE_EXPLICIT_FLUSH;
1362 
1363    return pscreen->resource_get_param(pscreen, NULL, image->texture,
1364                                       image->plane, 0, 0, param, handle_usage,
1365                                       value);
1366 }
1367 
1368 static bool
dri2_query_image_by_resource_param(__DRIimage * image,int attrib,int * value)1369 dri2_query_image_by_resource_param(__DRIimage *image, int attrib, int *value)
1370 {
1371    enum pipe_resource_param param;
1372    uint64_t res_param;
1373    unsigned handle_usage;
1374 
1375    if (!image->texture->screen->resource_get_param)
1376       return false;
1377 
1378    switch (attrib) {
1379    case __DRI_IMAGE_ATTRIB_STRIDE:
1380       param = PIPE_RESOURCE_PARAM_STRIDE;
1381       break;
1382    case __DRI_IMAGE_ATTRIB_OFFSET:
1383       param = PIPE_RESOURCE_PARAM_OFFSET;
1384       break;
1385    case __DRI_IMAGE_ATTRIB_NUM_PLANES:
1386       param = PIPE_RESOURCE_PARAM_NPLANES;
1387       break;
1388    case __DRI_IMAGE_ATTRIB_MODIFIER_UPPER:
1389    case __DRI_IMAGE_ATTRIB_MODIFIER_LOWER:
1390       param = PIPE_RESOURCE_PARAM_MODIFIER;
1391       break;
1392    case __DRI_IMAGE_ATTRIB_HANDLE:
1393       param = PIPE_RESOURCE_PARAM_HANDLE_TYPE_KMS;
1394       break;
1395    case __DRI_IMAGE_ATTRIB_NAME:
1396       param = PIPE_RESOURCE_PARAM_HANDLE_TYPE_SHARED;
1397       break;
1398    case __DRI_IMAGE_ATTRIB_FD:
1399       param = PIPE_RESOURCE_PARAM_HANDLE_TYPE_FD;
1400       break;
1401    default:
1402       return false;
1403    }
1404 
1405    handle_usage = PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE;
1406 
1407    if (!dri2_resource_get_param(image, param, handle_usage, &res_param))
1408       return false;
1409 
1410    switch (attrib) {
1411    case __DRI_IMAGE_ATTRIB_STRIDE:
1412    case __DRI_IMAGE_ATTRIB_OFFSET:
1413    case __DRI_IMAGE_ATTRIB_NUM_PLANES:
1414       if (res_param > INT_MAX)
1415          return false;
1416       *value = (int)res_param;
1417       return true;
1418    case __DRI_IMAGE_ATTRIB_HANDLE:
1419    case __DRI_IMAGE_ATTRIB_NAME:
1420    case __DRI_IMAGE_ATTRIB_FD:
1421       if (res_param > UINT_MAX)
1422          return false;
1423       *value = (int)res_param;
1424       return true;
1425    case __DRI_IMAGE_ATTRIB_MODIFIER_UPPER:
1426       if (res_param == DRM_FORMAT_MOD_INVALID)
1427          return false;
1428       *value = (res_param >> 32) & 0xffffffff;
1429       return true;
1430    case __DRI_IMAGE_ATTRIB_MODIFIER_LOWER:
1431       if (res_param == DRM_FORMAT_MOD_INVALID)
1432          return false;
1433       *value = res_param & 0xffffffff;
1434       return true;
1435    default:
1436       return false;
1437    }
1438 }
1439 
1440 GLboolean
dri2_query_image(__DRIimage * image,int attrib,int * value)1441 dri2_query_image(__DRIimage *image, int attrib, int *value)
1442 {
1443    if (dri2_query_image_common(image, attrib, value))
1444       return GL_TRUE;
1445    else if (dri2_query_image_by_resource_param(image, attrib, value))
1446       return GL_TRUE;
1447    else if (dri2_query_image_by_resource_handle(image, attrib, value))
1448       return GL_TRUE;
1449    else
1450       return GL_FALSE;
1451 }
1452 
1453 __DRIimage *
dri2_dup_image(__DRIimage * image,void * loaderPrivate)1454 dri2_dup_image(__DRIimage *image, void *loaderPrivate)
1455 {
1456    __DRIimage *img;
1457 
1458    img = CALLOC_STRUCT(__DRIimageRec);
1459    if (!img)
1460       return NULL;
1461 
1462    img->texture = NULL;
1463    pipe_resource_reference(&img->texture, image->texture);
1464    img->level = image->level;
1465    img->layer = image->layer;
1466    img->dri_format = image->dri_format;
1467    img->internal_format = image->internal_format;
1468    /* This should be 0 for sub images, but dup is also used for base images. */
1469    img->dri_components = image->dri_components;
1470    img->use = image->use;
1471    img->in_fence_fd = (image->in_fence_fd > 0) ?
1472          os_dupfd_cloexec(image->in_fence_fd) : -1;
1473    img->loader_private = loaderPrivate;
1474    img->screen = image->screen;
1475 
1476    return img;
1477 }
1478 
1479 GLboolean
dri2_validate_usage(__DRIimage * image,unsigned int use)1480 dri2_validate_usage(__DRIimage *image, unsigned int use)
1481 {
1482    if (!image || !image->texture)
1483       return false;
1484 
1485    struct pipe_screen *screen = image->texture->screen;
1486    if (!screen->check_resource_capability)
1487       return true;
1488 
1489    /* We don't want to check these:
1490     *   __DRI_IMAGE_USE_SHARE (all images are shareable)
1491     *   __DRI_IMAGE_USE_BACKBUFFER (all images support this)
1492     */
1493    unsigned bind = 0;
1494    if (use & __DRI_IMAGE_USE_SCANOUT)
1495       bind |= PIPE_BIND_SCANOUT;
1496    if (use & __DRI_IMAGE_USE_LINEAR)
1497       bind |= PIPE_BIND_LINEAR;
1498    if (use & __DRI_IMAGE_USE_CURSOR)
1499       bind |= PIPE_BIND_CURSOR;
1500 
1501    if (!bind)
1502       return true;
1503 
1504    return screen->check_resource_capability(screen, image->texture, bind);
1505 }
1506 
1507 __DRIimage *
dri2_from_names(__DRIscreen * screen,int width,int height,int fourcc,int * names,int num_names,int * strides,int * offsets,void * loaderPrivate)1508 dri2_from_names(__DRIscreen *screen, int width, int height, int fourcc,
1509                 int *names, int num_names, int *strides, int *offsets,
1510                 void *loaderPrivate)
1511 {
1512    const struct dri2_format_mapping *map = dri2_get_mapping_by_fourcc(fourcc);
1513    __DRIimage *img;
1514    struct winsys_handle whandle;
1515 
1516    if (!map)
1517       return NULL;
1518 
1519    if (num_names != 1)
1520       return NULL;
1521 
1522    memset(&whandle, 0, sizeof(whandle));
1523    whandle.type = WINSYS_HANDLE_TYPE_SHARED;
1524    whandle.handle = names[0];
1525    whandle.stride = strides[0];
1526    whandle.offset = offsets[0];
1527    whandle.format = map->pipe_format;
1528    whandle.modifier = DRM_FORMAT_MOD_INVALID;
1529 
1530    img = dri_create_image_from_winsys(screen, width, height, map,
1531                                        1, &whandle, 0, loaderPrivate);
1532    if (img == NULL)
1533       return NULL;
1534 
1535    img->dri_components = map->dri_components;
1536    img->dri_fourcc = map->dri_fourcc;
1537    img->dri_format = map->dri_format;
1538 
1539    return img;
1540 }
1541 
1542 __DRIimage *
dri2_from_planar(__DRIimage * image,int plane,void * loaderPrivate)1543 dri2_from_planar(__DRIimage *image, int plane, void *loaderPrivate)
1544 {
1545    __DRIimage *img;
1546 
1547    if (plane < 0) {
1548       return NULL;
1549    } else if (plane > 0) {
1550       uint64_t planes;
1551       if (!dri2_resource_get_param(image, PIPE_RESOURCE_PARAM_NPLANES, 0,
1552                                    &planes) ||
1553           plane >= planes) {
1554          return NULL;
1555       }
1556    }
1557 
1558    if (image->dri_components == 0) {
1559       uint64_t modifier;
1560       if (!dri2_resource_get_param(image, PIPE_RESOURCE_PARAM_MODIFIER, 0,
1561                                    &modifier) ||
1562           modifier == DRM_FORMAT_MOD_INVALID) {
1563          return NULL;
1564       }
1565    }
1566 
1567    img = dri2_dup_image(image, loaderPrivate);
1568    if (img == NULL)
1569       return NULL;
1570 
1571    if (img->texture->screen->resource_changed)
1572       img->texture->screen->resource_changed(img->texture->screen,
1573                                              img->texture);
1574 
1575    /* set this to 0 for sub images. */
1576    img->dri_components = 0;
1577    img->plane = plane;
1578    return img;
1579 }
1580 
1581 bool
dri_query_dma_buf_modifiers(__DRIscreen * _screen,int fourcc,int max,uint64_t * modifiers,unsigned int * external_only,int * count)1582 dri_query_dma_buf_modifiers(__DRIscreen *_screen, int fourcc, int max,
1583                              uint64_t *modifiers, unsigned int *external_only,
1584                              int *count)
1585 {
1586    struct dri_screen *screen = dri_screen(_screen);
1587    struct pipe_screen *pscreen = screen->base.screen;
1588    const struct dri2_format_mapping *map = dri2_get_mapping_by_fourcc(fourcc);
1589    enum pipe_format format;
1590 
1591    if (!map)
1592       return false;
1593 
1594    format = map->pipe_format;
1595 
1596    bool native_sampling = pscreen->is_format_supported(pscreen, format, screen->target, 0, 0,
1597                                                        PIPE_BIND_SAMPLER_VIEW);
1598    if (pscreen->is_format_supported(pscreen, format, screen->target, 0, 0,
1599                                     PIPE_BIND_RENDER_TARGET) ||
1600        native_sampling ||
1601        dri2_yuv_dma_buf_supported(screen, map))  {
1602       if (pscreen->query_dmabuf_modifiers != NULL) {
1603          pscreen->query_dmabuf_modifiers(pscreen, format, max, modifiers,
1604                                          external_only, count);
1605          if (!native_sampling && external_only) {
1606             /* To support it using YUV lowering, we need it to be samplerExternalOES.
1607              */
1608             for (int i = 0; i < *count; i++)
1609                external_only[i] = true;
1610          }
1611       } else {
1612          *count = 0;
1613       }
1614       return true;
1615    }
1616    return false;
1617 }
1618 
1619 bool
dri2_query_dma_buf_format_modifier_attribs(__DRIscreen * _screen,uint32_t fourcc,uint64_t modifier,int attrib,uint64_t * value)1620 dri2_query_dma_buf_format_modifier_attribs(__DRIscreen *_screen,
1621                                            uint32_t fourcc, uint64_t modifier,
1622                                            int attrib, uint64_t *value)
1623 {
1624    struct dri_screen *screen = dri_screen(_screen);
1625    struct pipe_screen *pscreen = screen->base.screen;
1626 
1627    if (!pscreen->query_dmabuf_modifiers)
1628       return false;
1629 
1630    switch (attrib) {
1631    case __DRI_IMAGE_FORMAT_MODIFIER_ATTRIB_PLANE_COUNT: {
1632       uint64_t mod_planes = dri2_get_modifier_num_planes(_screen, modifier,
1633                                                          fourcc);
1634       if (mod_planes > 0)
1635          *value = mod_planes;
1636       return mod_planes > 0;
1637    }
1638    default:
1639       return false;
1640    }
1641 }
1642 
1643 __DRIimage *
dri2_from_dma_bufs(__DRIscreen * screen,int width,int height,int fourcc,uint64_t modifier,int * fds,int num_fds,int * strides,int * offsets,enum __DRIYUVColorSpace yuv_color_space,enum __DRISampleRange sample_range,enum __DRIChromaSiting horizontal_siting,enum __DRIChromaSiting vertical_siting,uint32_t dri_flags,unsigned * error,void * loaderPrivate)1644 dri2_from_dma_bufs(__DRIscreen *screen,
1645                     int width, int height, int fourcc,
1646                     uint64_t modifier, int *fds, int num_fds,
1647                     int *strides, int *offsets,
1648                     enum __DRIYUVColorSpace yuv_color_space,
1649                     enum __DRISampleRange sample_range,
1650                     enum __DRIChromaSiting horizontal_siting,
1651                     enum __DRIChromaSiting vertical_siting,
1652                     uint32_t dri_flags,
1653                     unsigned *error,
1654                     void *loaderPrivate)
1655 {
1656    __DRIimage *img;
1657    const struct dri2_format_mapping *map = dri2_get_mapping_by_fourcc(fourcc);
1658 
1659    if (!dri_screen(screen)->dmabuf_import) {
1660       if (error)
1661          *error = __DRI_IMAGE_ERROR_BAD_PARAMETER;
1662       return NULL;
1663    }
1664 
1665    unsigned err = __DRI_IMAGE_ERROR_SUCCESS;
1666    /* Allow a NULL error arg since many callers don't care. */
1667    unsigned unused_error;
1668    if (!error)
1669       error = &unused_error;
1670 
1671    uint32_t flags = 0;
1672    if (dri_flags & __DRI_IMAGE_PROTECTED_CONTENT_FLAG)
1673       flags |= PIPE_BIND_PROTECTED;
1674    if (dri_flags & __DRI_IMAGE_PRIME_LINEAR_BUFFER)
1675       flags |= PIPE_BIND_PRIME_BLIT_DST;
1676 
1677    const int expected_num_fds = dri2_get_modifier_num_planes(screen, modifier, fourcc);
1678    if (!map || expected_num_fds == 0) {
1679       err = __DRI_IMAGE_ERROR_BAD_MATCH;
1680       goto exit;
1681    }
1682 
1683    if (num_fds != expected_num_fds) {
1684       err = __DRI_IMAGE_ERROR_BAD_MATCH;
1685       goto exit;
1686    }
1687 
1688    struct winsys_handle whandles[4];
1689    memset(whandles, 0, sizeof(whandles));
1690 
1691    for (int i = 0; i < num_fds; i++) {
1692       if (fds[i] < 0) {
1693          err = __DRI_IMAGE_ERROR_BAD_ALLOC;
1694          goto exit;
1695       }
1696 
1697       whandles[i].type = WINSYS_HANDLE_TYPE_FD;
1698       whandles[i].handle = (unsigned)fds[i];
1699       whandles[i].stride = (unsigned)strides[i];
1700       whandles[i].offset = (unsigned)offsets[i];
1701       whandles[i].format = map->pipe_format;
1702       whandles[i].modifier = modifier;
1703       whandles[i].plane = i;
1704    }
1705 
1706    img = dri_create_image_from_winsys(screen, width, height, map,
1707                                        num_fds, whandles, flags,
1708                                        loaderPrivate);
1709    if (img == NULL) {
1710       err = __DRI_IMAGE_ERROR_BAD_ALLOC;
1711       goto exit;
1712    }
1713 
1714    img->dri_components = map->dri_components;
1715    img->dri_fourcc = fourcc;
1716    img->dri_format = map->dri_format;
1717    img->imported_dmabuf = true;
1718    img->yuv_color_space = yuv_color_space;
1719    img->sample_range = sample_range;
1720    img->horizontal_siting = horizontal_siting;
1721    img->vertical_siting = vertical_siting;
1722 
1723    *error = __DRI_IMAGE_ERROR_SUCCESS;
1724    return img;
1725 
1726 exit:
1727    *error = err;
1728    return NULL;
1729 }
1730 
1731 bool
dri2_query_compression_rates(__DRIscreen * _screen,const __DRIconfig * config,int max,enum __DRIFixedRateCompression * rates,int * count)1732 dri2_query_compression_rates(__DRIscreen *_screen, const __DRIconfig *config, int max,
1733                              enum __DRIFixedRateCompression *rates, int *count)
1734 {
1735    struct dri_screen *screen = dri_screen(_screen);
1736    struct pipe_screen *pscreen = screen->base.screen;
1737    struct gl_config *gl_config = (struct gl_config *) config;
1738    enum pipe_format format = gl_config->color_format;
1739    uint32_t pipe_rates[max];
1740 
1741    if (!pscreen->is_format_supported(pscreen, format, screen->target, 0, 0,
1742                                      PIPE_BIND_RENDER_TARGET))
1743       return false;
1744 
1745    if (pscreen->query_compression_rates != NULL) {
1746       pscreen->query_compression_rates(pscreen, format, max, pipe_rates, count);
1747       for (int i = 0; i < *count && i < max; ++i)
1748          rates[i] = to_dri_compression_rate(pipe_rates[i]);
1749    } else {
1750       *count = 0;
1751    }
1752 
1753    return true;
1754 }
1755 
1756 bool
dri2_query_compression_modifiers(__DRIscreen * _screen,uint32_t fourcc,enum __DRIFixedRateCompression rate,int max,uint64_t * modifiers,int * count)1757 dri2_query_compression_modifiers(__DRIscreen *_screen, uint32_t fourcc,
1758                                  enum __DRIFixedRateCompression rate, int max,
1759                                  uint64_t *modifiers, int *count)
1760 {
1761    struct dri_screen *screen = dri_screen(_screen);
1762    struct pipe_screen *pscreen = screen->base.screen;
1763    const struct dri2_format_mapping *map = dri2_get_mapping_by_fourcc(fourcc);
1764    uint32_t pipe_rate = from_dri_compression_rate(rate);
1765 
1766    if (!map)
1767       return false;
1768 
1769    if (!pscreen->is_format_supported(pscreen, map->pipe_format, screen->target,
1770                                      0, 0, PIPE_BIND_RENDER_TARGET))
1771       return false;
1772 
1773    if (pscreen->query_compression_modifiers != NULL) {
1774       pscreen->query_compression_modifiers(pscreen, map->pipe_format, pipe_rate,
1775                                            max, modifiers, count);
1776    } else {
1777       *count = 0;
1778    }
1779 
1780    return true;
1781 }
1782 
1783 void
dri2_blit_image(__DRIcontext * context,__DRIimage * dst,__DRIimage * src,int dstx0,int dsty0,int dstwidth,int dstheight,int srcx0,int srcy0,int srcwidth,int srcheight,int flush_flag)1784 dri2_blit_image(__DRIcontext *context, __DRIimage *dst, __DRIimage *src,
1785                 int dstx0, int dsty0, int dstwidth, int dstheight,
1786                 int srcx0, int srcy0, int srcwidth, int srcheight,
1787                 int flush_flag)
1788 {
1789    struct dri_context *ctx = dri_context(context);
1790    struct pipe_context *pipe = ctx->st->pipe;
1791    struct pipe_screen *screen;
1792    struct pipe_fence_handle *fence;
1793    struct pipe_blit_info blit;
1794 
1795    if (!dst || !src)
1796       return;
1797 
1798    /* Wait for glthread to finish because we can't use pipe_context from
1799     * multiple threads.
1800     */
1801    _mesa_glthread_finish(ctx->st->ctx);
1802 
1803    dri_image_fence_sync(ctx, dst);
1804 
1805    memset(&blit, 0, sizeof(blit));
1806    blit.dst.resource = dst->texture;
1807    blit.dst.box.x = dstx0;
1808    blit.dst.box.y = dsty0;
1809    blit.dst.box.width = dstwidth;
1810    blit.dst.box.height = dstheight;
1811    blit.dst.box.depth = 1;
1812    blit.dst.format = dst->texture->format;
1813    blit.src.resource = src->texture;
1814    blit.src.box.x = srcx0;
1815    blit.src.box.y = srcy0;
1816    blit.src.box.width = srcwidth;
1817    blit.src.box.height = srcheight;
1818    blit.src.box.depth = 1;
1819    blit.src.format = src->texture->format;
1820    blit.mask = PIPE_MASK_RGBA;
1821    blit.filter = PIPE_TEX_FILTER_NEAREST;
1822 
1823    pipe->blit(pipe, &blit);
1824 
1825    if (flush_flag == __BLIT_FLAG_FLUSH) {
1826       pipe->flush_resource(pipe, dst->texture);
1827       st_context_flush(ctx->st, 0, NULL, NULL, NULL);
1828    } else if (flush_flag == __BLIT_FLAG_FINISH) {
1829       screen = ctx->screen->base.screen;
1830       pipe->flush_resource(pipe, dst->texture);
1831       st_context_flush(ctx->st, 0, &fence, NULL, NULL);
1832       (void) screen->fence_finish(screen, NULL, fence, OS_TIMEOUT_INFINITE);
1833       screen->fence_reference(screen, &fence, NULL);
1834    }
1835 }
1836 
1837 void *
dri2_map_image(__DRIcontext * context,__DRIimage * image,int x0,int y0,int width,int height,unsigned int flags,int * stride,void ** data)1838 dri2_map_image(__DRIcontext *context, __DRIimage *image,
1839                 int x0, int y0, int width, int height,
1840                 unsigned int flags, int *stride, void **data)
1841 {
1842    struct dri_context *ctx = dri_context(context);
1843    struct pipe_context *pipe = ctx->st->pipe;
1844    enum pipe_map_flags pipe_access = 0;
1845    struct pipe_transfer *trans;
1846    void *map;
1847 
1848    if (!image || !data || *data)
1849       return NULL;
1850 
1851    unsigned plane = image->plane;
1852    if (plane >= dri2_get_mapping_by_format(image->dri_format)->nplanes)
1853       return NULL;
1854 
1855    /* Wait for glthread to finish because we can't use pipe_context from
1856     * multiple threads.
1857     */
1858    _mesa_glthread_finish(ctx->st->ctx);
1859 
1860    dri_image_fence_sync(ctx, image);
1861 
1862    struct pipe_resource *resource = image->texture;
1863    while (plane--)
1864       resource = resource->next;
1865 
1866    if (flags & __DRI_IMAGE_TRANSFER_READ)
1867          pipe_access |= PIPE_MAP_READ;
1868    if (flags & __DRI_IMAGE_TRANSFER_WRITE)
1869          pipe_access |= PIPE_MAP_WRITE;
1870 
1871    map = pipe_texture_map(pipe, resource, 0, 0, pipe_access, x0, y0,
1872                            width, height, &trans);
1873    if (map) {
1874       *data = trans;
1875       *stride = trans->stride;
1876    }
1877 
1878    return map;
1879 }
1880 
1881 void
dri2_unmap_image(__DRIcontext * context,__DRIimage * image,void * data)1882 dri2_unmap_image(__DRIcontext *context, __DRIimage *image, void *data)
1883 {
1884    struct dri_context *ctx = dri_context(context);
1885    struct pipe_context *pipe = ctx->st->pipe;
1886 
1887    /* Wait for glthread to finish because we can't use pipe_context from
1888     * multiple threads.
1889     */
1890    _mesa_glthread_finish(ctx->st->ctx);
1891 
1892    pipe_texture_unmap(pipe, (struct pipe_transfer *)data);
1893 }
1894 
1895 int
dri2_get_capabilities(__DRIscreen * _screen)1896 dri2_get_capabilities(__DRIscreen *_screen)
1897 {
1898    struct dri_screen *screen = dri_screen(_screen);
1899 
1900    return (screen->can_share_buffer ? __DRI_IMAGE_CAP_GLOBAL_NAMES : 0);
1901 }
1902 
1903 int
dri_interop_query_device_info(__DRIcontext * _ctx,struct mesa_glinterop_device_info * out)1904 dri_interop_query_device_info(__DRIcontext *_ctx,
1905                                struct mesa_glinterop_device_info *out)
1906 {
1907    return st_interop_query_device_info(dri_context(_ctx)->st, out);
1908 }
1909 
1910 int
dri_interop_export_object(__DRIcontext * _ctx,struct mesa_glinterop_export_in * in,struct mesa_glinterop_export_out * out)1911 dri_interop_export_object(__DRIcontext *_ctx,
1912                            struct mesa_glinterop_export_in *in,
1913                            struct mesa_glinterop_export_out *out)
1914 {
1915    return st_interop_export_object(dri_context(_ctx)->st, in, out);
1916 }
1917 
1918 int
dri_interop_flush_objects(__DRIcontext * _ctx,unsigned count,struct mesa_glinterop_export_in * objects,struct mesa_glinterop_flush_out * out)1919 dri_interop_flush_objects(__DRIcontext *_ctx,
1920                            unsigned count, struct mesa_glinterop_export_in *objects,
1921                            struct mesa_glinterop_flush_out *out)
1922 {
1923    return st_interop_flush_objects(dri_context(_ctx)->st, count, objects, out);
1924 }
1925 
1926 /**
1927  * \brief the DRI2bufferDamageExtension set_damage_region method
1928  */
1929 void
dri_set_damage_region(__DRIdrawable * dPriv,unsigned int nrects,int * rects)1930 dri_set_damage_region(__DRIdrawable *dPriv, unsigned int nrects, int *rects)
1931 {
1932    struct dri_drawable *drawable = dri_drawable(dPriv);
1933    struct pipe_box *boxes = NULL;
1934 
1935    if (nrects) {
1936       boxes = CALLOC(nrects, sizeof(*boxes));
1937       assert(boxes);
1938 
1939       for (unsigned int i = 0; i < nrects; i++) {
1940          int *rect = &rects[i * 4];
1941 
1942          u_box_2d(rect[0], rect[1], rect[2], rect[3], &boxes[i]);
1943       }
1944    }
1945 
1946    FREE(drawable->damage_rects);
1947    drawable->damage_rects = boxes;
1948    drawable->num_damage_rects = nrects;
1949 
1950    /* Only apply the damage region if the BACK_LEFT texture is up-to-date. */
1951    if (drawable->texture_stamp == drawable->lastStamp &&
1952        (drawable->texture_mask & (1 << ST_ATTACHMENT_BACK_LEFT))) {
1953       struct pipe_screen *screen = drawable->screen->base.screen;
1954       struct pipe_resource *resource;
1955 
1956       if (drawable->stvis.samples > 1)
1957          resource = drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT];
1958       else
1959          resource = drawable->textures[ST_ATTACHMENT_BACK_LEFT];
1960 
1961       screen->set_damage_region(screen, resource,
1962                                 drawable->num_damage_rects,
1963                                 drawable->damage_rects);
1964    }
1965 }
1966 
1967 /**
1968  * \brief the DRI2blobExtension set_cache_funcs method
1969  */
1970 void
dri_set_blob_cache_funcs(__DRIscreen * sPriv,__DRIblobCacheSet set,__DRIblobCacheGet get)1971 dri_set_blob_cache_funcs(__DRIscreen *sPriv, __DRIblobCacheSet set,
1972                          __DRIblobCacheGet get)
1973 {
1974    struct dri_screen *screen = dri_screen(sPriv);
1975    struct pipe_screen *pscreen = screen->base.screen;
1976 
1977    if (!pscreen->get_disk_shader_cache)
1978       return;
1979 
1980    struct disk_cache *cache = pscreen->get_disk_shader_cache(pscreen);
1981 
1982    if (!cache)
1983       return;
1984 
1985    disk_cache_set_callbacks(cache, set, get);
1986 }
1987 
1988 /*
1989  * Backend function init_screen.
1990  */
1991 
1992 void
dri2_init_drawable(struct dri_drawable * drawable,bool isPixmap,int alphaBits)1993 dri2_init_drawable(struct dri_drawable *drawable, bool isPixmap, int alphaBits)
1994 {
1995    drawable->allocate_textures = dri2_allocate_textures;
1996    drawable->flush_frontbuffer = dri2_flush_frontbuffer;
1997    drawable->update_tex_buffer = dri2_update_tex_buffer;
1998    drawable->flush_swapbuffers = dri2_flush_swapbuffers;
1999 }
2000 
2001 /**
2002  * This is the driver specific part of the createNewScreen entry point.
2003  *
2004  * Returns the struct gl_config supported by this driver.
2005  */
2006 struct pipe_screen *
dri2_init_screen(struct dri_screen * screen,bool driver_name_is_inferred)2007 dri2_init_screen(struct dri_screen *screen, bool driver_name_is_inferred)
2008 {
2009    struct pipe_screen *pscreen = NULL;
2010 
2011    screen->can_share_buffer = true;
2012    screen->auto_fake_front = dri_with_format(screen);
2013 
2014 #ifdef HAVE_LIBDRM
2015    if (pipe_loader_drm_probe_fd(&screen->dev, screen->fd, false))
2016       pscreen = pipe_loader_create_screen(screen->dev, driver_name_is_inferred);
2017 #endif
2018 
2019    return pscreen;
2020 }
2021 
2022 /**
2023  * This is the driver specific part of the createNewScreen entry point.
2024  *
2025  * Returns the struct gl_config supported by this driver.
2026  */
2027 struct pipe_screen *
dri_swrast_kms_init_screen(struct dri_screen * screen,bool driver_name_is_inferred)2028 dri_swrast_kms_init_screen(struct dri_screen *screen, bool driver_name_is_inferred)
2029 {
2030    struct pipe_screen *pscreen = NULL;
2031    screen->can_share_buffer = false;
2032    screen->auto_fake_front = dri_with_format(screen);
2033 
2034 #if defined(HAVE_DRISW_KMS) && defined(HAVE_SWRAST)
2035    if (pipe_loader_sw_probe_kms(&screen->dev, screen->fd))
2036       pscreen = pipe_loader_create_screen(screen->dev, driver_name_is_inferred);
2037 #endif
2038 
2039    return pscreen;
2040 }
2041 
2042 int
dri_query_compatible_render_only_device_fd(int kms_only_fd)2043 dri_query_compatible_render_only_device_fd(int kms_only_fd)
2044 {
2045 #ifdef HAVE_LIBDRM
2046    return pipe_loader_get_compatible_render_capable_device_fd(kms_only_fd);
2047 #else
2048    return -1;
2049 #endif
2050 }
2051 /* vim: set sw=3 ts=8 sts=3 expandtab: */
2052