• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <keithw@vmware.com> Jakob Bornecrantz
28  *    <wallbraker@gmail.com> Chia-I Wu <olv@lunarg.com>
29  */
30 
31 #include <xf86drm.h>
32 #include "GL/mesa_glinterop.h"
33 #include "util/disk_cache.h"
34 #include "util/u_memory.h"
35 #include "util/u_inlines.h"
36 #include "util/format/u_format.h"
37 #include "util/u_debug.h"
38 #include "util/libsync.h"
39 #include "util/os_file.h"
40 #include "frontend/drm_driver.h"
41 #include "state_tracker/st_format.h"
42 #include "state_tracker/st_cb_texture.h"
43 #include "state_tracker/st_texture.h"
44 #include "state_tracker/st_context.h"
45 #include "pipe-loader/pipe_loader.h"
46 #include "main/bufferobj.h"
47 #include "main/texobj.h"
48 
49 #include "dri_util.h"
50 
51 #include "dri_helpers.h"
52 #include "dri_drawable.h"
53 #include "dri_query_renderer.h"
54 
55 #include "drm-uapi/drm_fourcc.h"
56 
57 struct dri2_buffer
58 {
59    __DRIbuffer base;
60    struct pipe_resource *resource;
61 };
62 
63 static inline struct dri2_buffer *
dri2_buffer(__DRIbuffer * driBufferPriv)64 dri2_buffer(__DRIbuffer * driBufferPriv)
65 {
66    return (struct dri2_buffer *) driBufferPriv;
67 }
68 
69 /**
70  * DRI2 flush extension.
71  */
72 static void
dri2_flush_drawable(__DRIdrawable * dPriv)73 dri2_flush_drawable(__DRIdrawable *dPriv)
74 {
75    dri_flush(dPriv->driContextPriv, dPriv, __DRI2_FLUSH_DRAWABLE, -1);
76 }
77 
78 static void
dri2_invalidate_drawable(__DRIdrawable * dPriv)79 dri2_invalidate_drawable(__DRIdrawable *dPriv)
80 {
81    struct dri_drawable *drawable = dri_drawable(dPriv);
82 
83    dPriv->dri2.stamp++;
84    drawable->dPriv->lastStamp = drawable->dPriv->dri2.stamp;
85    drawable->texture_mask = 0;
86 
87    p_atomic_inc(&drawable->base.stamp);
88 }
89 
90 static const __DRI2flushExtension dri2FlushExtension = {
91     .base = { __DRI2_FLUSH, 4 },
92 
93     .flush                = dri2_flush_drawable,
94     .invalidate           = dri2_invalidate_drawable,
95     .flush_with_flags     = dri_flush,
96 };
97 
98 /**
99  * Retrieve __DRIbuffer from the DRI loader.
100  */
101 static __DRIbuffer *
dri2_drawable_get_buffers(struct dri_drawable * drawable,const enum st_attachment_type * atts,unsigned * count)102 dri2_drawable_get_buffers(struct dri_drawable *drawable,
103                           const enum st_attachment_type *atts,
104                           unsigned *count)
105 {
106    __DRIdrawable *dri_drawable = drawable->dPriv;
107    const __DRIdri2LoaderExtension *loader = drawable->sPriv->dri2.loader;
108    boolean with_format;
109    __DRIbuffer *buffers;
110    int num_buffers;
111    unsigned attachments[__DRI_BUFFER_COUNT];
112    unsigned num_attachments, i;
113 
114    assert(loader);
115    assert(*count <= __DRI_BUFFER_COUNT);
116    with_format = dri_with_format(drawable->sPriv);
117 
118    num_attachments = 0;
119 
120    /* for Xserver 1.6.0 (DRI2 version 1) we always need to ask for the front */
121    if (!with_format)
122       attachments[num_attachments++] = __DRI_BUFFER_FRONT_LEFT;
123 
124    for (i = 0; i < *count; i++) {
125       enum pipe_format format;
126       unsigned bind;
127       int att, depth;
128 
129       dri_drawable_get_format(drawable, atts[i], &format, &bind);
130       if (format == PIPE_FORMAT_NONE)
131          continue;
132 
133       switch (atts[i]) {
134       case ST_ATTACHMENT_FRONT_LEFT:
135          /* already added */
136          if (!with_format)
137             continue;
138          att = __DRI_BUFFER_FRONT_LEFT;
139          break;
140       case ST_ATTACHMENT_BACK_LEFT:
141          att = __DRI_BUFFER_BACK_LEFT;
142          break;
143       case ST_ATTACHMENT_FRONT_RIGHT:
144          att = __DRI_BUFFER_FRONT_RIGHT;
145          break;
146       case ST_ATTACHMENT_BACK_RIGHT:
147          att = __DRI_BUFFER_BACK_RIGHT;
148          break;
149       default:
150          continue;
151       }
152 
153       /*
154        * In this switch statement we must support all formats that
155        * may occur as the stvis->color_format.
156        */
157       switch(format) {
158       case PIPE_FORMAT_R16G16B16A16_FLOAT:
159          depth = 64;
160          break;
161       case PIPE_FORMAT_R16G16B16X16_FLOAT:
162          depth = 48;
163          break;
164       case PIPE_FORMAT_B10G10R10A2_UNORM:
165       case PIPE_FORMAT_R10G10B10A2_UNORM:
166       case PIPE_FORMAT_BGRA8888_UNORM:
167       case PIPE_FORMAT_RGBA8888_UNORM:
168 	 depth = 32;
169 	 break;
170       case PIPE_FORMAT_R10G10B10X2_UNORM:
171       case PIPE_FORMAT_B10G10R10X2_UNORM:
172          depth = 30;
173          break;
174       case PIPE_FORMAT_BGRX8888_UNORM:
175       case PIPE_FORMAT_RGBX8888_UNORM:
176 	 depth = 24;
177 	 break;
178       case PIPE_FORMAT_B5G6R5_UNORM:
179 	 depth = 16;
180 	 break;
181       default:
182 	 depth = util_format_get_blocksizebits(format);
183 	 assert(!"Unexpected format in dri2_drawable_get_buffers()");
184       }
185 
186       attachments[num_attachments++] = att;
187       if (with_format) {
188          attachments[num_attachments++] = depth;
189       }
190    }
191 
192    if (with_format) {
193       num_attachments /= 2;
194       buffers = loader->getBuffersWithFormat(dri_drawable,
195             &dri_drawable->w, &dri_drawable->h,
196             attachments, num_attachments,
197             &num_buffers, dri_drawable->loaderPrivate);
198    }
199    else {
200       buffers = loader->getBuffers(dri_drawable,
201             &dri_drawable->w, &dri_drawable->h,
202             attachments, num_attachments,
203             &num_buffers, dri_drawable->loaderPrivate);
204    }
205 
206    if (buffers)
207       *count = num_buffers;
208 
209    return buffers;
210 }
211 
212 bool
213 dri_image_drawable_get_buffers(struct dri_drawable *drawable,
214                                struct __DRIimageList *images,
215                                const enum st_attachment_type *statts,
216                                unsigned statts_count);
217 bool
dri_image_drawable_get_buffers(struct dri_drawable * drawable,struct __DRIimageList * images,const enum st_attachment_type * statts,unsigned statts_count)218 dri_image_drawable_get_buffers(struct dri_drawable *drawable,
219                                struct __DRIimageList *images,
220                                const enum st_attachment_type *statts,
221                                unsigned statts_count)
222 {
223    __DRIdrawable *dPriv = drawable->dPriv;
224    __DRIscreen *sPriv = drawable->sPriv;
225    unsigned int image_format = __DRI_IMAGE_FORMAT_NONE;
226    enum pipe_format pf;
227    uint32_t buffer_mask = 0;
228    unsigned i, bind;
229 
230    for (i = 0; i < statts_count; i++) {
231       dri_drawable_get_format(drawable, statts[i], &pf, &bind);
232       if (pf == PIPE_FORMAT_NONE)
233          continue;
234 
235       switch (statts[i]) {
236       case ST_ATTACHMENT_FRONT_LEFT:
237          buffer_mask |= __DRI_IMAGE_BUFFER_FRONT;
238          break;
239       case ST_ATTACHMENT_BACK_LEFT:
240          buffer_mask |= __DRI_IMAGE_BUFFER_BACK;
241          break;
242       default:
243          continue;
244       }
245 
246       switch (pf) {
247       case PIPE_FORMAT_R16G16B16A16_FLOAT:
248          image_format = __DRI_IMAGE_FORMAT_ABGR16161616F;
249          break;
250       case PIPE_FORMAT_R16G16B16X16_FLOAT:
251          image_format = __DRI_IMAGE_FORMAT_XBGR16161616F;
252          break;
253       case PIPE_FORMAT_B5G5R5A1_UNORM:
254          image_format = __DRI_IMAGE_FORMAT_ARGB1555;
255          break;
256       case PIPE_FORMAT_B5G6R5_UNORM:
257          image_format = __DRI_IMAGE_FORMAT_RGB565;
258          break;
259       case PIPE_FORMAT_BGRX8888_UNORM:
260          image_format = __DRI_IMAGE_FORMAT_XRGB8888;
261          break;
262       case PIPE_FORMAT_BGRA8888_UNORM:
263          image_format = __DRI_IMAGE_FORMAT_ARGB8888;
264          break;
265       case PIPE_FORMAT_RGBX8888_UNORM:
266          image_format = __DRI_IMAGE_FORMAT_XBGR8888;
267          break;
268       case PIPE_FORMAT_RGBA8888_UNORM:
269          image_format = __DRI_IMAGE_FORMAT_ABGR8888;
270          break;
271       case PIPE_FORMAT_B10G10R10X2_UNORM:
272          image_format = __DRI_IMAGE_FORMAT_XRGB2101010;
273          break;
274       case PIPE_FORMAT_B10G10R10A2_UNORM:
275          image_format = __DRI_IMAGE_FORMAT_ARGB2101010;
276          break;
277       case PIPE_FORMAT_R10G10B10X2_UNORM:
278          image_format = __DRI_IMAGE_FORMAT_XBGR2101010;
279          break;
280       case PIPE_FORMAT_R10G10B10A2_UNORM:
281          image_format = __DRI_IMAGE_FORMAT_ABGR2101010;
282          break;
283       default:
284          image_format = __DRI_IMAGE_FORMAT_NONE;
285          break;
286       }
287    }
288 
289    return (*sPriv->image.loader->getBuffers) (dPriv, image_format,
290                                        (uint32_t *) &drawable->base.stamp,
291                                        dPriv->loaderPrivate, buffer_mask,
292                                        images);
293 }
294 
295 static __DRIbuffer *
dri2_allocate_buffer(__DRIscreen * sPriv,unsigned attachment,unsigned format,int width,int height)296 dri2_allocate_buffer(__DRIscreen *sPriv,
297                      unsigned attachment, unsigned format,
298                      int width, int height)
299 {
300    struct dri_screen *screen = dri_screen(sPriv);
301    struct dri2_buffer *buffer;
302    struct pipe_resource templ;
303    enum pipe_format pf;
304    unsigned bind = 0;
305    struct winsys_handle whandle;
306 
307    /* struct pipe_resource height0 is 16-bit, avoid overflow */
308    if (height > 0xffff)
309       return NULL;
310 
311    switch (attachment) {
312       case __DRI_BUFFER_FRONT_LEFT:
313       case __DRI_BUFFER_FAKE_FRONT_LEFT:
314          bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
315          break;
316       case __DRI_BUFFER_BACK_LEFT:
317          bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
318          break;
319       case __DRI_BUFFER_DEPTH:
320       case __DRI_BUFFER_DEPTH_STENCIL:
321       case __DRI_BUFFER_STENCIL:
322             bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */
323          break;
324    }
325 
326    /* because we get the handle and stride */
327    bind |= PIPE_BIND_SHARED;
328 
329    switch (format) {
330       case 64:
331          pf = PIPE_FORMAT_R16G16B16A16_FLOAT;
332          break;
333       case 48:
334          pf = PIPE_FORMAT_R16G16B16X16_FLOAT;
335          break;
336       case 32:
337          pf = PIPE_FORMAT_BGRA8888_UNORM;
338          break;
339       case 30:
340          pf = PIPE_FORMAT_B10G10R10X2_UNORM;
341          break;
342       case 24:
343          pf = PIPE_FORMAT_BGRX8888_UNORM;
344          break;
345       case 16:
346          pf = PIPE_FORMAT_Z16_UNORM;
347          break;
348       default:
349          return NULL;
350    }
351 
352    buffer = CALLOC_STRUCT(dri2_buffer);
353    if (!buffer)
354       return NULL;
355 
356    memset(&templ, 0, sizeof(templ));
357    templ.bind = bind;
358    templ.format = pf;
359    templ.target = PIPE_TEXTURE_2D;
360    templ.last_level = 0;
361    templ.width0 = width;
362    templ.height0 = height;
363    templ.depth0 = 1;
364    templ.array_size = 1;
365 
366    buffer->resource =
367       screen->base.screen->resource_create(screen->base.screen, &templ);
368    if (!buffer->resource) {
369       FREE(buffer);
370       return NULL;
371    }
372 
373    memset(&whandle, 0, sizeof(whandle));
374    if (screen->can_share_buffer)
375       whandle.type = WINSYS_HANDLE_TYPE_SHARED;
376    else
377       whandle.type = WINSYS_HANDLE_TYPE_KMS;
378 
379    screen->base.screen->resource_get_handle(screen->base.screen, NULL,
380          buffer->resource, &whandle,
381          PIPE_HANDLE_USAGE_EXPLICIT_FLUSH);
382 
383    buffer->base.attachment = attachment;
384    buffer->base.name = whandle.handle;
385    buffer->base.cpp = util_format_get_blocksize(pf);
386    buffer->base.pitch = whandle.stride;
387 
388    return &buffer->base;
389 }
390 
391 static void
dri2_release_buffer(__DRIscreen * sPriv,__DRIbuffer * bPriv)392 dri2_release_buffer(__DRIscreen *sPriv, __DRIbuffer *bPriv)
393 {
394    struct dri2_buffer *buffer = dri2_buffer(bPriv);
395 
396    pipe_resource_reference(&buffer->resource, NULL);
397    FREE(buffer);
398 }
399 
400 static void
dri2_set_in_fence_fd(__DRIimage * img,int fd)401 dri2_set_in_fence_fd(__DRIimage *img, int fd)
402 {
403    validate_fence_fd(fd);
404    validate_fence_fd(img->in_fence_fd);
405    sync_accumulate("dri", &img->in_fence_fd, fd);
406 }
407 
408 static void
handle_in_fence(__DRIcontext * context,__DRIimage * img)409 handle_in_fence(__DRIcontext *context, __DRIimage *img)
410 {
411    struct dri_context *ctx = dri_context(context);
412    struct pipe_context *pipe = ctx->st->pipe;
413    struct pipe_fence_handle *fence;
414    int fd = img->in_fence_fd;
415 
416    if (fd == -1)
417       return;
418 
419    validate_fence_fd(fd);
420 
421    img->in_fence_fd = -1;
422 
423    pipe->create_fence_fd(pipe, &fence, fd, PIPE_FD_TYPE_NATIVE_SYNC);
424    pipe->fence_server_sync(pipe, fence);
425    pipe->screen->fence_reference(pipe->screen, &fence, NULL);
426 
427    close(fd);
428 }
429 
430 /*
431  * Backend functions for st_framebuffer interface.
432  */
433 
434 static void
dri2_allocate_textures(struct dri_context * ctx,struct dri_drawable * drawable,const enum st_attachment_type * statts,unsigned statts_count)435 dri2_allocate_textures(struct dri_context *ctx,
436                        struct dri_drawable *drawable,
437                        const enum st_attachment_type *statts,
438                        unsigned statts_count)
439 {
440    __DRIscreen *sPriv = drawable->sPriv;
441    __DRIdrawable *dri_drawable = drawable->dPriv;
442    struct dri_screen *screen = dri_screen(sPriv);
443    struct pipe_resource templ;
444    boolean alloc_depthstencil = FALSE;
445    unsigned i, j, bind;
446    const __DRIimageLoaderExtension *image = sPriv->image.loader;
447    /* Image specific variables */
448    struct __DRIimageList images;
449    /* Dri2 specific variables */
450    __DRIbuffer *buffers = NULL;
451    struct winsys_handle whandle;
452    unsigned num_buffers = statts_count;
453 
454    assert(num_buffers <= __DRI_BUFFER_COUNT);
455 
456    /* First get the buffers from the loader */
457    if (image) {
458       if (!dri_image_drawable_get_buffers(drawable, &images,
459                                           statts, statts_count))
460          return;
461    }
462    else {
463       buffers = dri2_drawable_get_buffers(drawable, statts, &num_buffers);
464       if (!buffers || (drawable->old_num == num_buffers &&
465                        drawable->old_w == dri_drawable->w &&
466                        drawable->old_h == dri_drawable->h &&
467                        memcmp(drawable->old, buffers,
468                               sizeof(__DRIbuffer) * num_buffers) == 0))
469          return;
470    }
471 
472    /* Second clean useless resources*/
473 
474    /* See if we need a depth-stencil buffer. */
475    for (i = 0; i < statts_count; i++) {
476       if (statts[i] == ST_ATTACHMENT_DEPTH_STENCIL) {
477          alloc_depthstencil = TRUE;
478          break;
479       }
480    }
481 
482    /* Delete the resources we won't need. */
483    for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
484       /* Don't delete the depth-stencil buffer, we can reuse it. */
485       if (i == ST_ATTACHMENT_DEPTH_STENCIL && alloc_depthstencil)
486          continue;
487 
488       /* Flush the texture before unreferencing, so that other clients can
489        * see what the driver has rendered.
490        */
491       if (i != ST_ATTACHMENT_DEPTH_STENCIL && drawable->textures[i]) {
492          struct pipe_context *pipe = ctx->st->pipe;
493          pipe->flush_resource(pipe, drawable->textures[i]);
494       }
495 
496       pipe_resource_reference(&drawable->textures[i], NULL);
497    }
498 
499    if (drawable->stvis.samples > 1) {
500       for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
501          boolean del = TRUE;
502 
503          /* Don't delete MSAA resources for the attachments which are enabled,
504           * we can reuse them. */
505          for (j = 0; j < statts_count; j++) {
506             if (i == statts[j]) {
507                del = FALSE;
508                break;
509             }
510          }
511 
512          if (del) {
513             pipe_resource_reference(&drawable->msaa_textures[i], NULL);
514          }
515       }
516    }
517 
518    /* Third use the buffers retrieved to fill the drawable info */
519 
520    memset(&templ, 0, sizeof(templ));
521    templ.target = screen->target;
522    templ.last_level = 0;
523    templ.depth0 = 1;
524    templ.array_size = 1;
525 
526    if (image) {
527       if (images.image_mask & __DRI_IMAGE_BUFFER_FRONT) {
528          struct pipe_resource **buf =
529             &drawable->textures[ST_ATTACHMENT_FRONT_LEFT];
530          struct pipe_resource *texture = images.front->texture;
531 
532          dri_drawable->w = texture->width0;
533          dri_drawable->h = texture->height0;
534 
535          pipe_resource_reference(buf, texture);
536          handle_in_fence(ctx->cPriv, images.front);
537       }
538 
539       if (images.image_mask & __DRI_IMAGE_BUFFER_BACK) {
540          struct pipe_resource **buf =
541             &drawable->textures[ST_ATTACHMENT_BACK_LEFT];
542          struct pipe_resource *texture = images.back->texture;
543 
544          dri_drawable->w = texture->width0;
545          dri_drawable->h = texture->height0;
546 
547          pipe_resource_reference(buf, texture);
548          handle_in_fence(ctx->cPriv, images.back);
549       }
550 
551       if (images.image_mask & __DRI_IMAGE_BUFFER_SHARED) {
552          struct pipe_resource **buf =
553             &drawable->textures[ST_ATTACHMENT_BACK_LEFT];
554          struct pipe_resource *texture = images.back->texture;
555 
556          dri_drawable->w = texture->width0;
557          dri_drawable->h = texture->height0;
558 
559          pipe_resource_reference(buf, texture);
560          handle_in_fence(ctx->cPriv, images.back);
561 
562          ctx->is_shared_buffer_bound = true;
563       } else {
564          ctx->is_shared_buffer_bound = false;
565       }
566 
567       /* Note: if there is both a back and a front buffer,
568        * then they have the same size.
569        */
570       templ.width0 = dri_drawable->w;
571       templ.height0 = dri_drawable->h;
572    }
573    else {
574       memset(&whandle, 0, sizeof(whandle));
575 
576       /* Process DRI-provided buffers and get pipe_resources. */
577       for (i = 0; i < num_buffers; i++) {
578          __DRIbuffer *buf = &buffers[i];
579          enum st_attachment_type statt;
580          enum pipe_format format;
581 
582          switch (buf->attachment) {
583          case __DRI_BUFFER_FRONT_LEFT:
584             if (!screen->auto_fake_front) {
585                continue; /* invalid attachment */
586             }
587             FALLTHROUGH;
588          case __DRI_BUFFER_FAKE_FRONT_LEFT:
589             statt = ST_ATTACHMENT_FRONT_LEFT;
590             break;
591          case __DRI_BUFFER_BACK_LEFT:
592             statt = ST_ATTACHMENT_BACK_LEFT;
593             break;
594          default:
595             continue; /* invalid attachment */
596          }
597 
598          dri_drawable_get_format(drawable, statt, &format, &bind);
599          if (format == PIPE_FORMAT_NONE)
600             continue;
601 
602          /* dri2_drawable_get_buffers has already filled dri_drawable->w
603           * and dri_drawable->h */
604          templ.width0 = dri_drawable->w;
605          templ.height0 = dri_drawable->h;
606          templ.format = format;
607          templ.bind = bind;
608          whandle.handle = buf->name;
609          whandle.stride = buf->pitch;
610          whandle.offset = 0;
611          whandle.format = format;
612          whandle.modifier = DRM_FORMAT_MOD_INVALID;
613          if (screen->can_share_buffer)
614             whandle.type = WINSYS_HANDLE_TYPE_SHARED;
615          else
616             whandle.type = WINSYS_HANDLE_TYPE_KMS;
617          drawable->textures[statt] =
618             screen->base.screen->resource_from_handle(screen->base.screen,
619                   &templ, &whandle,
620                   PIPE_HANDLE_USAGE_EXPLICIT_FLUSH);
621          assert(drawable->textures[statt]);
622       }
623    }
624 
625    /* Allocate private MSAA colorbuffers. */
626    if (drawable->stvis.samples > 1) {
627       for (i = 0; i < statts_count; i++) {
628          enum st_attachment_type statt = statts[i];
629 
630          if (statt == ST_ATTACHMENT_DEPTH_STENCIL)
631             continue;
632 
633          if (drawable->textures[statt]) {
634             templ.format = drawable->textures[statt]->format;
635             templ.bind = drawable->textures[statt]->bind &
636                          ~(PIPE_BIND_SCANOUT | PIPE_BIND_SHARED);
637             templ.nr_samples = drawable->stvis.samples;
638             templ.nr_storage_samples = drawable->stvis.samples;
639 
640             /* Try to reuse the resource.
641              * (the other resource parameters should be constant)
642              */
643             if (!drawable->msaa_textures[statt] ||
644                 drawable->msaa_textures[statt]->width0 != templ.width0 ||
645                 drawable->msaa_textures[statt]->height0 != templ.height0) {
646                /* Allocate a new one. */
647                pipe_resource_reference(&drawable->msaa_textures[statt], NULL);
648 
649                drawable->msaa_textures[statt] =
650                   screen->base.screen->resource_create(screen->base.screen,
651                                                        &templ);
652                assert(drawable->msaa_textures[statt]);
653 
654                /* If there are any MSAA resources, we should initialize them
655                 * such that they contain the same data as the single-sample
656                 * resources we just got from the X server.
657                 *
658                 * The reason for this is that the gallium frontend (and
659                 * therefore the app) can access the MSAA resources only.
660                 * The single-sample resources are not exposed
661                 * to the gallium frontend.
662                 *
663                 */
664                dri_pipe_blit(ctx->st->pipe,
665                              drawable->msaa_textures[statt],
666                              drawable->textures[statt]);
667             }
668          }
669          else {
670             pipe_resource_reference(&drawable->msaa_textures[statt], NULL);
671          }
672       }
673    }
674 
675    /* Allocate a private depth-stencil buffer. */
676    if (alloc_depthstencil) {
677       enum st_attachment_type statt = ST_ATTACHMENT_DEPTH_STENCIL;
678       struct pipe_resource **zsbuf;
679       enum pipe_format format;
680       unsigned bind;
681 
682       dri_drawable_get_format(drawable, statt, &format, &bind);
683 
684       if (format) {
685          templ.format = format;
686          templ.bind = bind & ~PIPE_BIND_SHARED;
687 
688          if (drawable->stvis.samples > 1) {
689             templ.nr_samples = drawable->stvis.samples;
690             templ.nr_storage_samples = drawable->stvis.samples;
691             zsbuf = &drawable->msaa_textures[statt];
692          }
693          else {
694             templ.nr_samples = 0;
695             templ.nr_storage_samples = 0;
696             zsbuf = &drawable->textures[statt];
697          }
698 
699          /* Try to reuse the resource.
700           * (the other resource parameters should be constant)
701           */
702          if (!*zsbuf ||
703              (*zsbuf)->width0 != templ.width0 ||
704              (*zsbuf)->height0 != templ.height0) {
705             /* Allocate a new one. */
706             pipe_resource_reference(zsbuf, NULL);
707             *zsbuf = screen->base.screen->resource_create(screen->base.screen,
708                                                           &templ);
709             assert(*zsbuf);
710          }
711       }
712       else {
713          pipe_resource_reference(&drawable->msaa_textures[statt], NULL);
714          pipe_resource_reference(&drawable->textures[statt], NULL);
715       }
716    }
717 
718    /* For DRI2, we may get the same buffers again from the server.
719     * To prevent useless imports of gem names, drawable->old* is used
720     * to bypass the import if we get the same buffers. This doesn't apply
721     * to DRI3/Wayland, users of image.loader, since the buffer is managed
722     * by the client (no import), and the back buffer is going to change
723     * at every redraw.
724     */
725    if (!image) {
726       drawable->old_num = num_buffers;
727       drawable->old_w = dri_drawable->w;
728       drawable->old_h = dri_drawable->h;
729       memcpy(drawable->old, buffers, sizeof(__DRIbuffer) * num_buffers);
730    }
731 }
732 
733 static bool
dri2_flush_frontbuffer(struct dri_context * ctx,struct dri_drawable * drawable,enum st_attachment_type statt)734 dri2_flush_frontbuffer(struct dri_context *ctx,
735                        struct dri_drawable *drawable,
736                        enum st_attachment_type statt)
737 {
738    __DRIdrawable *dri_drawable = drawable->dPriv;
739    const __DRIimageLoaderExtension *image = drawable->sPriv->image.loader;
740    const __DRIdri2LoaderExtension *loader = drawable->sPriv->dri2.loader;
741    const __DRImutableRenderBufferLoaderExtension *shared_buffer_loader =
742       drawable->sPriv->mutableRenderBuffer.loader;
743    struct pipe_context *pipe = ctx->st->pipe;
744    struct pipe_fence_handle *fence = NULL;
745    int fence_fd = -1;
746 
747    /* We need to flush for front buffer rendering when either we're using the
748     * front buffer at the GL API level, or when EGL_KHR_mutable_render_buffer
749     * has redirected GL_BACK to the front buffer.
750     */
751    if (statt != ST_ATTACHMENT_FRONT_LEFT &&
752        (!ctx->is_shared_buffer_bound || statt != ST_ATTACHMENT_BACK_LEFT))
753          return false;
754 
755    if (drawable->stvis.samples > 1) {
756       /* Resolve the buffer used for front rendering. */
757       dri_pipe_blit(ctx->st->pipe, drawable->textures[statt],
758                     drawable->msaa_textures[statt]);
759    }
760 
761    if (drawable->textures[statt]) {
762       pipe->flush_resource(pipe, drawable->textures[statt]);
763    }
764 
765    if (ctx->is_shared_buffer_bound) {
766       /* is_shared_buffer_bound should only be true with image extension: */
767       assert(image);
768       pipe->flush(pipe, &fence, PIPE_FLUSH_FENCE_FD);
769    } else {
770       pipe->flush(pipe, NULL, 0);
771    }
772 
773    if (image) {
774       image->flushFrontBuffer(dri_drawable, dri_drawable->loaderPrivate);
775       if (ctx->is_shared_buffer_bound) {
776          if (fence)
777             fence_fd = pipe->screen->fence_get_fd(pipe->screen, fence);
778 
779          shared_buffer_loader->displaySharedBuffer(dri_drawable, fence_fd,
780                                                    dri_drawable->loaderPrivate);
781 
782          pipe->screen->fence_reference(pipe->screen, &fence, NULL);
783       }
784    }
785    else if (loader->flushFrontBuffer) {
786       loader->flushFrontBuffer(dri_drawable, dri_drawable->loaderPrivate);
787    }
788 
789    return true;
790 }
791 
792 /**
793  * The struct dri_drawable flush_swapbuffers callback
794  */
795 static void
dri2_flush_swapbuffers(struct dri_context * ctx,struct dri_drawable * drawable)796 dri2_flush_swapbuffers(struct dri_context *ctx,
797                        struct dri_drawable *drawable)
798 {
799    __DRIdrawable *dri_drawable = drawable->dPriv;
800    const __DRIimageLoaderExtension *image = drawable->sPriv->image.loader;
801 
802    if (image && image->base.version >= 3 && image->flushSwapBuffers) {
803       image->flushSwapBuffers(dri_drawable, dri_drawable->loaderPrivate);
804    }
805 }
806 
807 static void
dri2_update_tex_buffer(struct dri_drawable * drawable,struct dri_context * ctx,struct pipe_resource * res)808 dri2_update_tex_buffer(struct dri_drawable *drawable,
809                        struct dri_context *ctx,
810                        struct pipe_resource *res)
811 {
812    /* no-op */
813 }
814 
815 static const struct dri2_format_mapping r8_g8b8_mapping = {
816    DRM_FORMAT_NV12,
817    __DRI_IMAGE_FORMAT_NONE,
818    __DRI_IMAGE_COMPONENTS_Y_UV,
819    PIPE_FORMAT_R8_G8B8_420_UNORM,
820    2,
821    { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8 },
822      { 1, 1, 1, __DRI_IMAGE_FORMAT_GR88 } }
823 };
824 
825 static const struct dri2_format_mapping r8g8_r8b8_mapping = {
826    DRM_FORMAT_YUYV,
827    __DRI_IMAGE_FORMAT_NONE,
828    __DRI_IMAGE_COMPONENTS_Y_XUXV,
829    PIPE_FORMAT_R8G8_R8B8_UNORM, 2,
830    { { 0, 0, 0, __DRI_IMAGE_FORMAT_GR88 },
831      { 0, 1, 0, __DRI_IMAGE_FORMAT_ARGB8888 } }
832 };
833 
834 static const struct dri2_format_mapping g8r8_b8r8_mapping = {
835    DRM_FORMAT_UYVY,
836    __DRI_IMAGE_FORMAT_NONE,
837    __DRI_IMAGE_COMPONENTS_Y_XUXV,
838    PIPE_FORMAT_G8R8_B8R8_UNORM, 2,
839    { { 0, 0, 0, __DRI_IMAGE_FORMAT_GR88 },
840      { 0, 1, 0, __DRI_IMAGE_FORMAT_ABGR8888 } }
841 };
842 
843 static __DRIimage *
dri2_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)844 dri2_create_image_from_winsys(__DRIscreen *_screen,
845                               int width, int height, const struct dri2_format_mapping *map,
846                               int num_handles, struct winsys_handle *whandle,
847                               unsigned bind,
848                               void *loaderPrivate)
849 {
850    struct dri_screen *screen = dri_screen(_screen);
851    struct pipe_screen *pscreen = screen->base.screen;
852    __DRIimage *img;
853    struct pipe_resource templ;
854    unsigned tex_usage = 0;
855    int i;
856    bool use_lowered = false;
857    const unsigned format_planes = util_format_get_num_planes(map->pipe_format);
858 
859    if (pscreen->is_format_supported(pscreen, map->pipe_format, screen->target, 0, 0,
860                                     PIPE_BIND_RENDER_TARGET))
861       tex_usage |= PIPE_BIND_RENDER_TARGET;
862    if (pscreen->is_format_supported(pscreen, map->pipe_format, screen->target, 0, 0,
863                                     PIPE_BIND_SAMPLER_VIEW))
864       tex_usage |= PIPE_BIND_SAMPLER_VIEW;
865 
866    /* For NV12, see if we have support for sampling r8_b8g8 */
867    if (!tex_usage && map->pipe_format == PIPE_FORMAT_NV12 &&
868        pscreen->is_format_supported(pscreen, PIPE_FORMAT_R8_G8B8_420_UNORM,
869                                     screen->target, 0, 0, PIPE_BIND_SAMPLER_VIEW)) {
870       map = &r8_g8b8_mapping;
871       tex_usage |= PIPE_BIND_SAMPLER_VIEW;
872    }
873 
874    /* If the hardware supports R8G8_R8B8 style subsampled RGB formats, these
875     * can be used for YUYV and UYVY formats.
876     */
877    if (!tex_usage && map->pipe_format == PIPE_FORMAT_YUYV &&
878        pscreen->is_format_supported(pscreen, PIPE_FORMAT_R8G8_R8B8_UNORM,
879                                     screen->target, 0, 0, PIPE_BIND_SAMPLER_VIEW)) {
880       map = &r8g8_r8b8_mapping;
881       tex_usage |= PIPE_BIND_SAMPLER_VIEW;
882    }
883 
884    if (!tex_usage && map->pipe_format == PIPE_FORMAT_UYVY &&
885        pscreen->is_format_supported(pscreen, PIPE_FORMAT_G8R8_B8R8_UNORM,
886                                     screen->target, 0, 0, PIPE_BIND_SAMPLER_VIEW)) {
887       map = &g8r8_b8r8_mapping;
888       tex_usage |= PIPE_BIND_SAMPLER_VIEW;
889    }
890 
891    if (!tex_usage && util_format_is_yuv(map->pipe_format)) {
892       /* YUV format sampling can be emulated by the GL gallium frontend by
893        * using multiple samplers of varying formats.
894        * If no tex_usage is set and we detect a YUV format,
895        * test for support of all planes' sampler formats and
896        * add sampler view usage.
897        */
898       use_lowered = true;
899       if (dri2_yuv_dma_buf_supported(screen, map))
900          tex_usage |= PIPE_BIND_SAMPLER_VIEW;
901    }
902 
903    if (!tex_usage)
904       return NULL;
905 
906    img = CALLOC_STRUCT(__DRIimageRec);
907    if (!img)
908       return NULL;
909 
910    memset(&templ, 0, sizeof(templ));
911    templ.bind = tex_usage | bind;
912    templ.target = screen->target;
913    templ.last_level = 0;
914    templ.depth0 = 1;
915    templ.array_size = 1;
916    templ.width0 = width;
917    templ.height0 = height;
918 
919    for (i = num_handles - 1; i >= format_planes; i--) {
920       struct pipe_resource *tex;
921 
922       templ.next = img->texture;
923 
924       tex = pscreen->resource_from_handle(pscreen, &templ, &whandle[i],
925                                           PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE);
926       if (!tex) {
927          pipe_resource_reference(&img->texture, NULL);
928          FREE(img);
929          return NULL;
930       }
931 
932       img->texture = tex;
933    }
934 
935    for (i = (use_lowered ? map->nplanes : format_planes) - 1; i >= 0; i--) {
936       struct pipe_resource *tex;
937 
938       templ.next = img->texture;
939       templ.width0 = width >> map->planes[i].width_shift;
940       templ.height0 = height >> map->planes[i].height_shift;
941       if (use_lowered)
942          templ.format = dri2_get_pipe_format_for_dri_format(map->planes[i].dri_format);
943       else
944          templ.format = map->pipe_format;
945       assert(templ.format != PIPE_FORMAT_NONE);
946 
947       tex = pscreen->resource_from_handle(pscreen,
948                &templ, &whandle[use_lowered ? map->planes[i].buffer_index : i],
949                PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE);
950       if (!tex) {
951          pipe_resource_reference(&img->texture, NULL);
952          FREE(img);
953          return NULL;
954       }
955 
956       /* Reject image creation if there's an inconsistency between
957        * content protection status of tex and img.
958        */
959       const struct driOptionCache *optionCache = &screen->dev->option_cache;
960       if (!driQueryOptionb(optionCache, "disable_protected_content_check") &&
961           (tex->bind & PIPE_BIND_PROTECTED) != (bind & PIPE_BIND_PROTECTED)) {
962          pipe_resource_reference(&img->texture, NULL);
963          pipe_resource_reference(&tex, NULL);
964          FREE(img);
965          return NULL;
966       }
967 
968       img->texture = tex;
969    }
970 
971    img->level = 0;
972    img->layer = 0;
973    img->use = 0;
974    img->in_fence_fd = -1;
975    img->loader_private = loaderPrivate;
976    img->sPriv = _screen;
977 
978    return img;
979 }
980 
981 static __DRIimage *
dri2_create_image_from_name(__DRIscreen * _screen,int width,int height,int format,int name,int pitch,void * loaderPrivate)982 dri2_create_image_from_name(__DRIscreen *_screen,
983                             int width, int height, int format,
984                             int name, int pitch, void *loaderPrivate)
985 {
986    const struct dri2_format_mapping *map = dri2_get_mapping_by_format(format);
987    struct winsys_handle whandle;
988    __DRIimage *img;
989 
990    if (!map)
991       return NULL;
992 
993    memset(&whandle, 0, sizeof(whandle));
994    whandle.type = WINSYS_HANDLE_TYPE_SHARED;
995    whandle.handle = name;
996    whandle.format = map->pipe_format;
997    whandle.modifier = DRM_FORMAT_MOD_INVALID;
998 
999    whandle.stride = pitch * util_format_get_blocksize(map->pipe_format);
1000 
1001    img = dri2_create_image_from_winsys(_screen, width, height, map,
1002                                        1, &whandle, 0, loaderPrivate);
1003 
1004    if (!img)
1005       return NULL;
1006 
1007    img->dri_components = map->dri_components;
1008    img->dri_fourcc = map->dri_fourcc;
1009    img->dri_format = map->dri_format;
1010 
1011    return img;
1012 }
1013 
1014 static unsigned
dri2_get_modifier_num_planes(__DRIscreen * _screen,uint64_t modifier,int fourcc)1015 dri2_get_modifier_num_planes(__DRIscreen *_screen,
1016                              uint64_t modifier, int fourcc)
1017 {
1018    struct pipe_screen *pscreen = dri_screen(_screen)->base.screen;
1019    const struct dri2_format_mapping *map = dri2_get_mapping_by_fourcc(fourcc);
1020 
1021    if (!map)
1022       return 0;
1023 
1024    switch (modifier) {
1025    case DRM_FORMAT_MOD_LINEAR:
1026    /* DRM_FORMAT_MOD_NONE is the same as LINEAR */
1027    case DRM_FORMAT_MOD_INVALID:
1028       return util_format_get_num_planes(map->pipe_format);
1029    default:
1030       if (!pscreen->is_dmabuf_modifier_supported ||
1031           !pscreen->is_dmabuf_modifier_supported(pscreen, modifier,
1032                                                  map->pipe_format, NULL)) {
1033          return 0;
1034       }
1035 
1036       if (pscreen->get_dmabuf_modifier_planes) {
1037          return pscreen->get_dmabuf_modifier_planes(pscreen, modifier,
1038                                                     map->pipe_format);
1039       }
1040 
1041       return map->nplanes;
1042    }
1043 }
1044 
1045 static __DRIimage *
dri2_create_image_from_fd(__DRIscreen * _screen,int width,int height,int fourcc,uint64_t modifier,int * fds,int num_fds,int * strides,int * offsets,unsigned bind,unsigned * error,void * loaderPrivate)1046 dri2_create_image_from_fd(__DRIscreen *_screen,
1047                           int width, int height, int fourcc,
1048                           uint64_t modifier, int *fds, int num_fds,
1049                           int *strides, int *offsets,
1050                           unsigned bind, unsigned *error, void *loaderPrivate)
1051 {
1052    struct winsys_handle whandles[4];
1053    const struct dri2_format_mapping *map = dri2_get_mapping_by_fourcc(fourcc);
1054    __DRIimage *img = NULL;
1055    unsigned err = __DRI_IMAGE_ERROR_SUCCESS;
1056    int i;
1057    const int expected_num_fds = dri2_get_modifier_num_planes(_screen, modifier, fourcc);
1058 
1059    if (!map || expected_num_fds == 0) {
1060       err = __DRI_IMAGE_ERROR_BAD_MATCH;
1061       goto exit;
1062    }
1063 
1064    if (num_fds != expected_num_fds) {
1065       err = __DRI_IMAGE_ERROR_BAD_MATCH;
1066       goto exit;
1067    }
1068 
1069    memset(whandles, 0, sizeof(whandles));
1070 
1071    for (i = 0; i < num_fds; i++) {
1072       if (fds[i] < 0) {
1073          err = __DRI_IMAGE_ERROR_BAD_ALLOC;
1074          goto exit;
1075       }
1076 
1077       whandles[i].type = WINSYS_HANDLE_TYPE_FD;
1078       whandles[i].handle = (unsigned)fds[i];
1079       whandles[i].stride = (unsigned)strides[i];
1080       whandles[i].offset = (unsigned)offsets[i];
1081       whandles[i].format = map->pipe_format;
1082       whandles[i].modifier = modifier;
1083       whandles[i].plane = i;
1084    }
1085 
1086    img = dri2_create_image_from_winsys(_screen, width, height, map,
1087                                        num_fds, whandles, bind,
1088                                        loaderPrivate);
1089    if(img == NULL) {
1090       err = __DRI_IMAGE_ERROR_BAD_ALLOC;
1091       goto exit;
1092    }
1093 
1094    img->dri_components = map->dri_components;
1095    img->dri_fourcc = fourcc;
1096    img->dri_format = map->dri_format;
1097    img->imported_dmabuf = TRUE;
1098 
1099 exit:
1100    if (error)
1101       *error = err;
1102 
1103    return img;
1104 }
1105 
1106 static __DRIimage *
dri2_create_image_common(__DRIscreen * _screen,int width,int height,int format,unsigned int use,const uint64_t * modifiers,const unsigned count,void * loaderPrivate)1107 dri2_create_image_common(__DRIscreen *_screen,
1108                          int width, int height,
1109                          int format, unsigned int use,
1110                          const uint64_t *modifiers,
1111                          const unsigned count,
1112                          void *loaderPrivate)
1113 {
1114    const struct dri2_format_mapping *map = dri2_get_mapping_by_format(format);
1115    struct dri_screen *screen = dri_screen(_screen);
1116    struct pipe_screen *pscreen = screen->base.screen;
1117    __DRIimage *img;
1118    struct pipe_resource templ;
1119    unsigned tex_usage = 0;
1120 
1121    if (!map)
1122       return NULL;
1123 
1124    if (pscreen->is_format_supported(pscreen, map->pipe_format, screen->target,
1125                                     0, 0, PIPE_BIND_RENDER_TARGET))
1126       tex_usage |= PIPE_BIND_RENDER_TARGET;
1127    if (pscreen->is_format_supported(pscreen, map->pipe_format, screen->target,
1128                                     0, 0, PIPE_BIND_SAMPLER_VIEW))
1129       tex_usage |= PIPE_BIND_SAMPLER_VIEW;
1130 
1131    if (!tex_usage)
1132       return NULL;
1133 
1134    if (use & __DRI_IMAGE_USE_SCANOUT)
1135       tex_usage |= PIPE_BIND_SCANOUT;
1136    if (use & __DRI_IMAGE_USE_SHARE)
1137       tex_usage |= PIPE_BIND_SHARED;
1138    if (use & __DRI_IMAGE_USE_LINEAR)
1139       tex_usage |= PIPE_BIND_LINEAR;
1140    if (use & __DRI_IMAGE_USE_CURSOR) {
1141       if (width != 64 || height != 64)
1142          return NULL;
1143       tex_usage |= PIPE_BIND_CURSOR;
1144    }
1145    if (use & __DRI_IMAGE_USE_PROTECTED)
1146       tex_usage |= PIPE_BIND_PROTECTED;
1147    if (use & __DRI_IMAGE_USE_PRIME_BUFFER)
1148       tex_usage |= PIPE_BIND_PRIME_BLIT_DST;
1149 
1150    img = CALLOC_STRUCT(__DRIimageRec);
1151    if (!img)
1152       return NULL;
1153 
1154    memset(&templ, 0, sizeof(templ));
1155    templ.bind = tex_usage;
1156    templ.format = map->pipe_format;
1157    templ.target = PIPE_TEXTURE_2D;
1158    templ.last_level = 0;
1159    templ.width0 = width;
1160    templ.height0 = height;
1161    templ.depth0 = 1;
1162    templ.array_size = 1;
1163 
1164    if (modifiers)
1165       img->texture =
1166          screen->base.screen
1167             ->resource_create_with_modifiers(screen->base.screen,
1168                                              &templ,
1169                                              modifiers,
1170                                              count);
1171    else
1172       img->texture =
1173          screen->base.screen->resource_create(screen->base.screen, &templ);
1174    if (!img->texture) {
1175       FREE(img);
1176       return NULL;
1177    }
1178 
1179    img->level = 0;
1180    img->layer = 0;
1181    img->dri_format = format;
1182    img->dri_fourcc = map->dri_fourcc;
1183    img->dri_components = 0;
1184    img->use = use;
1185    img->in_fence_fd = -1;
1186 
1187    img->loader_private = loaderPrivate;
1188    img->sPriv = _screen;
1189    return img;
1190 }
1191 
1192 static __DRIimage *
dri2_create_image(__DRIscreen * _screen,int width,int height,int format,unsigned int use,void * loaderPrivate)1193 dri2_create_image(__DRIscreen *_screen,
1194                    int width, int height, int format,
1195                    unsigned int use, void *loaderPrivate)
1196 {
1197    return dri2_create_image_common(_screen, width, height, format, use,
1198                                    NULL /* modifiers */, 0 /* count */,
1199                                    loaderPrivate);
1200 }
1201 
1202 static __DRIimage *
dri2_create_image_with_modifiers(__DRIscreen * dri_screen,int width,int height,int format,const uint64_t * modifiers,const unsigned count,void * loaderPrivate)1203 dri2_create_image_with_modifiers(__DRIscreen *dri_screen,
1204                                  int width, int height, int format,
1205                                  const uint64_t *modifiers,
1206                                  const unsigned count,
1207                                  void *loaderPrivate)
1208 {
1209    return dri2_create_image_common(dri_screen, width, height, format,
1210                                    __DRI_IMAGE_USE_SHARE, modifiers, count,
1211                                    loaderPrivate);
1212 }
1213 
1214 static __DRIimage *
dri2_create_image_with_modifiers2(__DRIscreen * dri_screen,int width,int height,int format,const uint64_t * modifiers,const unsigned count,unsigned int use,void * loaderPrivate)1215 dri2_create_image_with_modifiers2(__DRIscreen *dri_screen,
1216                                  int width, int height, int format,
1217                                  const uint64_t *modifiers,
1218                                  const unsigned count, unsigned int use,
1219                                  void *loaderPrivate)
1220 {
1221    return dri2_create_image_common(dri_screen, width, height, format, use,
1222                                    modifiers, count, loaderPrivate);
1223 }
1224 
1225 static bool
dri2_query_image_common(__DRIimage * image,int attrib,int * value)1226 dri2_query_image_common(__DRIimage *image, int attrib, int *value)
1227 {
1228    switch (attrib) {
1229    case __DRI_IMAGE_ATTRIB_FORMAT:
1230       *value = image->dri_format;
1231       return true;
1232    case __DRI_IMAGE_ATTRIB_WIDTH:
1233       *value = image->texture->width0;
1234       return true;
1235    case __DRI_IMAGE_ATTRIB_HEIGHT:
1236       *value = image->texture->height0;
1237       return true;
1238    case __DRI_IMAGE_ATTRIB_COMPONENTS:
1239       if (image->dri_components == 0)
1240          return false;
1241       *value = image->dri_components;
1242       return true;
1243    case __DRI_IMAGE_ATTRIB_FOURCC:
1244       if (image->dri_fourcc) {
1245          *value = image->dri_fourcc;
1246       } else {
1247          const struct dri2_format_mapping *map;
1248 
1249          map = dri2_get_mapping_by_format(image->dri_format);
1250          if (!map)
1251             return false;
1252 
1253          *value = map->dri_fourcc;
1254       }
1255       return true;
1256    default:
1257       return false;
1258    }
1259 }
1260 
1261 static bool
dri2_query_image_by_resource_handle(__DRIimage * image,int attrib,int * value)1262 dri2_query_image_by_resource_handle(__DRIimage *image, int attrib, int *value)
1263 {
1264    struct pipe_screen *pscreen = image->texture->screen;
1265    struct winsys_handle whandle;
1266    struct pipe_resource *tex;
1267    unsigned usage;
1268    memset(&whandle, 0, sizeof(whandle));
1269    whandle.plane = image->plane;
1270    int i;
1271 
1272    switch (attrib) {
1273    case __DRI_IMAGE_ATTRIB_STRIDE:
1274    case __DRI_IMAGE_ATTRIB_OFFSET:
1275    case __DRI_IMAGE_ATTRIB_HANDLE:
1276       whandle.type = WINSYS_HANDLE_TYPE_KMS;
1277       break;
1278    case __DRI_IMAGE_ATTRIB_NAME:
1279       whandle.type = WINSYS_HANDLE_TYPE_SHARED;
1280       break;
1281    case __DRI_IMAGE_ATTRIB_FD:
1282       whandle.type = WINSYS_HANDLE_TYPE_FD;
1283       break;
1284    case __DRI_IMAGE_ATTRIB_NUM_PLANES:
1285       for (i = 0, tex = image->texture; tex; tex = tex->next)
1286          i++;
1287       *value = i;
1288       return true;
1289    case __DRI_IMAGE_ATTRIB_MODIFIER_UPPER:
1290    case __DRI_IMAGE_ATTRIB_MODIFIER_LOWER:
1291       whandle.type = WINSYS_HANDLE_TYPE_KMS;
1292       whandle.modifier = DRM_FORMAT_MOD_INVALID;
1293       break;
1294    default:
1295       return false;
1296    }
1297 
1298    usage = PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE;
1299 
1300    if (image->use & __DRI_IMAGE_USE_BACKBUFFER)
1301       usage |= PIPE_HANDLE_USAGE_EXPLICIT_FLUSH;
1302 
1303    if (!pscreen->resource_get_handle(pscreen, NULL, image->texture,
1304                                      &whandle, usage))
1305       return false;
1306 
1307    switch (attrib) {
1308    case __DRI_IMAGE_ATTRIB_STRIDE:
1309       *value = whandle.stride;
1310       return true;
1311    case __DRI_IMAGE_ATTRIB_OFFSET:
1312       *value = whandle.offset;
1313       return true;
1314    case __DRI_IMAGE_ATTRIB_HANDLE:
1315    case __DRI_IMAGE_ATTRIB_NAME:
1316    case __DRI_IMAGE_ATTRIB_FD:
1317       *value = whandle.handle;
1318       return true;
1319    case __DRI_IMAGE_ATTRIB_MODIFIER_UPPER:
1320       if (whandle.modifier == DRM_FORMAT_MOD_INVALID)
1321          return false;
1322       *value = (whandle.modifier >> 32) & 0xffffffff;
1323       return true;
1324    case __DRI_IMAGE_ATTRIB_MODIFIER_LOWER:
1325       if (whandle.modifier == DRM_FORMAT_MOD_INVALID)
1326          return false;
1327       *value = whandle.modifier & 0xffffffff;
1328       return true;
1329    default:
1330       return false;
1331    }
1332 }
1333 
1334 static bool
dri2_resource_get_param(__DRIimage * image,enum pipe_resource_param param,unsigned handle_usage,uint64_t * value)1335 dri2_resource_get_param(__DRIimage *image, enum pipe_resource_param param,
1336                         unsigned handle_usage, uint64_t *value)
1337 {
1338    struct pipe_screen *pscreen = image->texture->screen;
1339    if (!pscreen->resource_get_param)
1340       return false;
1341 
1342    if (image->use & __DRI_IMAGE_USE_BACKBUFFER)
1343       handle_usage |= PIPE_HANDLE_USAGE_EXPLICIT_FLUSH;
1344 
1345    return pscreen->resource_get_param(pscreen, NULL, image->texture,
1346                                       image->plane, 0, 0, param, handle_usage,
1347                                       value);
1348 }
1349 
1350 static bool
dri2_query_image_by_resource_param(__DRIimage * image,int attrib,int * value)1351 dri2_query_image_by_resource_param(__DRIimage *image, int attrib, int *value)
1352 {
1353    enum pipe_resource_param param;
1354    uint64_t res_param;
1355    unsigned handle_usage;
1356 
1357    if (!image->texture->screen->resource_get_param)
1358       return false;
1359 
1360    switch (attrib) {
1361    case __DRI_IMAGE_ATTRIB_STRIDE:
1362       param = PIPE_RESOURCE_PARAM_STRIDE;
1363       break;
1364    case __DRI_IMAGE_ATTRIB_OFFSET:
1365       param = PIPE_RESOURCE_PARAM_OFFSET;
1366       break;
1367    case __DRI_IMAGE_ATTRIB_NUM_PLANES:
1368       param = PIPE_RESOURCE_PARAM_NPLANES;
1369       break;
1370    case __DRI_IMAGE_ATTRIB_MODIFIER_UPPER:
1371    case __DRI_IMAGE_ATTRIB_MODIFIER_LOWER:
1372       param = PIPE_RESOURCE_PARAM_MODIFIER;
1373       break;
1374    case __DRI_IMAGE_ATTRIB_HANDLE:
1375       param = PIPE_RESOURCE_PARAM_HANDLE_TYPE_KMS;
1376       break;
1377    case __DRI_IMAGE_ATTRIB_NAME:
1378       param = PIPE_RESOURCE_PARAM_HANDLE_TYPE_SHARED;
1379       break;
1380    case __DRI_IMAGE_ATTRIB_FD:
1381       param = PIPE_RESOURCE_PARAM_HANDLE_TYPE_FD;
1382       break;
1383    default:
1384       return false;
1385    }
1386 
1387    handle_usage = PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE;
1388 
1389    if (!dri2_resource_get_param(image, param, handle_usage, &res_param))
1390       return false;
1391 
1392    switch (attrib) {
1393    case __DRI_IMAGE_ATTRIB_STRIDE:
1394    case __DRI_IMAGE_ATTRIB_OFFSET:
1395    case __DRI_IMAGE_ATTRIB_NUM_PLANES:
1396       if (res_param > INT_MAX)
1397          return false;
1398       *value = (int)res_param;
1399       return true;
1400    case __DRI_IMAGE_ATTRIB_HANDLE:
1401    case __DRI_IMAGE_ATTRIB_NAME:
1402    case __DRI_IMAGE_ATTRIB_FD:
1403       if (res_param > UINT_MAX)
1404          return false;
1405       *value = (int)res_param;
1406       return true;
1407    case __DRI_IMAGE_ATTRIB_MODIFIER_UPPER:
1408       if (res_param == DRM_FORMAT_MOD_INVALID)
1409          return false;
1410       *value = (res_param >> 32) & 0xffffffff;
1411       return true;
1412    case __DRI_IMAGE_ATTRIB_MODIFIER_LOWER:
1413       if (res_param == DRM_FORMAT_MOD_INVALID)
1414          return false;
1415       *value = res_param & 0xffffffff;
1416       return true;
1417    default:
1418       return false;
1419    }
1420 }
1421 
1422 static GLboolean
dri2_query_image(__DRIimage * image,int attrib,int * value)1423 dri2_query_image(__DRIimage *image, int attrib, int *value)
1424 {
1425    if (dri2_query_image_common(image, attrib, value))
1426       return GL_TRUE;
1427    else if (dri2_query_image_by_resource_param(image, attrib, value))
1428       return GL_TRUE;
1429    else if (dri2_query_image_by_resource_handle(image, attrib, value))
1430       return GL_TRUE;
1431    else
1432       return GL_FALSE;
1433 }
1434 
1435 static __DRIimage *
dri2_dup_image(__DRIimage * image,void * loaderPrivate)1436 dri2_dup_image(__DRIimage *image, void *loaderPrivate)
1437 {
1438    __DRIimage *img;
1439 
1440    img = CALLOC_STRUCT(__DRIimageRec);
1441    if (!img)
1442       return NULL;
1443 
1444    img->texture = NULL;
1445    pipe_resource_reference(&img->texture, image->texture);
1446    img->level = image->level;
1447    img->layer = image->layer;
1448    img->dri_format = image->dri_format;
1449    img->internal_format = image->internal_format;
1450    /* This should be 0 for sub images, but dup is also used for base images. */
1451    img->dri_components = image->dri_components;
1452    img->use = image->use;
1453    img->in_fence_fd = (image->in_fence_fd > 0) ?
1454          os_dupfd_cloexec(image->in_fence_fd) : -1;
1455    img->loader_private = loaderPrivate;
1456    img->sPriv = image->sPriv;
1457 
1458    return img;
1459 }
1460 
1461 static GLboolean
dri2_validate_usage(__DRIimage * image,unsigned int use)1462 dri2_validate_usage(__DRIimage *image, unsigned int use)
1463 {
1464    if (!image || !image->texture)
1465       return false;
1466 
1467    struct pipe_screen *screen = image->texture->screen;
1468    if (!screen->check_resource_capability)
1469       return true;
1470 
1471    /* We don't want to check these:
1472     *   __DRI_IMAGE_USE_SHARE (all images are shareable)
1473     *   __DRI_IMAGE_USE_BACKBUFFER (all images support this)
1474     */
1475    unsigned bind = 0;
1476    if (use & __DRI_IMAGE_USE_SCANOUT)
1477       bind |= PIPE_BIND_SCANOUT;
1478    if (use & __DRI_IMAGE_USE_LINEAR)
1479       bind |= PIPE_BIND_LINEAR;
1480    if (use & __DRI_IMAGE_USE_CURSOR)
1481       bind |= PIPE_BIND_CURSOR;
1482 
1483    if (!bind)
1484       return true;
1485 
1486    return screen->check_resource_capability(screen, image->texture, bind);
1487 }
1488 
1489 static __DRIimage *
dri2_from_names(__DRIscreen * screen,int width,int height,int format,int * names,int num_names,int * strides,int * offsets,void * loaderPrivate)1490 dri2_from_names(__DRIscreen *screen, int width, int height, int format,
1491                 int *names, int num_names, int *strides, int *offsets,
1492                 void *loaderPrivate)
1493 {
1494    const struct dri2_format_mapping *map = dri2_get_mapping_by_format(format);
1495    __DRIimage *img;
1496    struct winsys_handle whandle;
1497 
1498    if (!map)
1499       return NULL;
1500 
1501    if (num_names != 1)
1502       return NULL;
1503 
1504    memset(&whandle, 0, sizeof(whandle));
1505    whandle.type = WINSYS_HANDLE_TYPE_SHARED;
1506    whandle.handle = names[0];
1507    whandle.stride = strides[0];
1508    whandle.offset = offsets[0];
1509    whandle.format = map->pipe_format;
1510    whandle.modifier = DRM_FORMAT_MOD_INVALID;
1511 
1512    img = dri2_create_image_from_winsys(screen, width, height, map,
1513                                        1, &whandle, 0, loaderPrivate);
1514    if (img == NULL)
1515       return NULL;
1516 
1517    img->dri_components = map->dri_components;
1518    img->dri_fourcc = map->dri_fourcc;
1519    img->dri_format = map->pipe_format;
1520 
1521    return img;
1522 }
1523 
1524 static __DRIimage *
dri2_from_planar(__DRIimage * image,int plane,void * loaderPrivate)1525 dri2_from_planar(__DRIimage *image, int plane, void *loaderPrivate)
1526 {
1527    __DRIimage *img;
1528 
1529    if (plane < 0) {
1530       return NULL;
1531    } else if (plane > 0) {
1532       uint64_t planes;
1533       if (!dri2_resource_get_param(image, PIPE_RESOURCE_PARAM_NPLANES, 0,
1534                                    &planes) ||
1535           plane >= planes) {
1536          return NULL;
1537       }
1538    }
1539 
1540    if (image->dri_components == 0) {
1541       uint64_t modifier;
1542       if (!dri2_resource_get_param(image, PIPE_RESOURCE_PARAM_MODIFIER, 0,
1543                                    &modifier) ||
1544           modifier == DRM_FORMAT_MOD_INVALID) {
1545          return NULL;
1546       }
1547    }
1548 
1549    img = dri2_dup_image(image, loaderPrivate);
1550    if (img == NULL)
1551       return NULL;
1552 
1553    if (img->texture->screen->resource_changed)
1554       img->texture->screen->resource_changed(img->texture->screen,
1555                                              img->texture);
1556 
1557    /* set this to 0 for sub images. */
1558    img->dri_components = 0;
1559    img->plane = plane;
1560    return img;
1561 }
1562 
1563 static __DRIimage *
dri2_from_fds(__DRIscreen * screen,int width,int height,int fourcc,int * fds,int num_fds,int * strides,int * offsets,void * loaderPrivate)1564 dri2_from_fds(__DRIscreen *screen, int width, int height, int fourcc,
1565               int *fds, int num_fds, int *strides, int *offsets,
1566               void *loaderPrivate)
1567 {
1568    return dri2_create_image_from_fd(screen, width, height, fourcc,
1569                                    DRM_FORMAT_MOD_INVALID, fds, num_fds,
1570                                    strides, offsets, 0, NULL, loaderPrivate);
1571 }
1572 
1573 static __DRIimage *
dri2_from_fds2(__DRIscreen * screen,int width,int height,int fourcc,int * fds,int num_fds,uint32_t flags,int * strides,int * offsets,void * loaderPrivate)1574 dri2_from_fds2(__DRIscreen *screen, int width, int height, int fourcc,
1575               int *fds, int num_fds, uint32_t flags, int *strides,
1576               int *offsets, void *loaderPrivate)
1577 {
1578    unsigned bind = 0;
1579    if (flags & __DRI_IMAGE_PROTECTED_CONTENT_FLAG)
1580       bind |= PIPE_BIND_PROTECTED;
1581    if (flags & __DRI_IMAGE_PRIME_LINEAR_BUFFER)
1582       bind |= PIPE_BIND_PRIME_BLIT_DST;
1583 
1584    return dri2_create_image_from_fd(screen, width, height, fourcc,
1585                                    DRM_FORMAT_MOD_INVALID, fds, num_fds,
1586                                    strides, offsets, bind, NULL, loaderPrivate);
1587 }
1588 
1589 static boolean
dri2_query_dma_buf_modifiers(__DRIscreen * _screen,int fourcc,int max,uint64_t * modifiers,unsigned int * external_only,int * count)1590 dri2_query_dma_buf_modifiers(__DRIscreen *_screen, int fourcc, int max,
1591                              uint64_t *modifiers, unsigned int *external_only,
1592                              int *count)
1593 {
1594    struct dri_screen *screen = dri_screen(_screen);
1595    struct pipe_screen *pscreen = screen->base.screen;
1596    const struct dri2_format_mapping *map = dri2_get_mapping_by_fourcc(fourcc);
1597    enum pipe_format format;
1598 
1599    if (!map)
1600       return false;
1601 
1602    format = map->pipe_format;
1603 
1604    bool native_sampling = pscreen->is_format_supported(pscreen, format, screen->target, 0, 0,
1605                                                        PIPE_BIND_SAMPLER_VIEW);
1606    if (pscreen->is_format_supported(pscreen, format, screen->target, 0, 0,
1607                                     PIPE_BIND_RENDER_TARGET) ||
1608        native_sampling ||
1609        dri2_yuv_dma_buf_supported(screen, map))  {
1610       if (pscreen->query_dmabuf_modifiers != NULL) {
1611          pscreen->query_dmabuf_modifiers(pscreen, format, max, modifiers,
1612                                          external_only, count);
1613          if (!native_sampling && external_only) {
1614             /* To support it using YUV lowering, we need it to be samplerExternalOES.
1615              */
1616             for (int i = 0; i < *count; i++)
1617                external_only[i] = true;
1618          }
1619       } else {
1620          *count = 0;
1621       }
1622       return true;
1623    }
1624    return false;
1625 }
1626 
1627 static boolean
dri2_query_dma_buf_format_modifier_attribs(__DRIscreen * _screen,uint32_t fourcc,uint64_t modifier,int attrib,uint64_t * value)1628 dri2_query_dma_buf_format_modifier_attribs(__DRIscreen *_screen,
1629                                            uint32_t fourcc, uint64_t modifier,
1630                                            int attrib, uint64_t *value)
1631 {
1632    struct dri_screen *screen = dri_screen(_screen);
1633    struct pipe_screen *pscreen = screen->base.screen;
1634 
1635    if (!pscreen->query_dmabuf_modifiers)
1636       return false;
1637 
1638    switch (attrib) {
1639    case __DRI_IMAGE_FORMAT_MODIFIER_ATTRIB_PLANE_COUNT: {
1640       uint64_t mod_planes = dri2_get_modifier_num_planes(_screen, modifier,
1641                                                          fourcc);
1642       if (mod_planes > 0)
1643          *value = mod_planes;
1644       return mod_planes > 0;
1645    }
1646    default:
1647       return false;
1648    }
1649 }
1650 
1651 static __DRIimage *
dri2_from_dma_bufs(__DRIscreen * screen,int width,int height,int fourcc,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,unsigned * error,void * loaderPrivate)1652 dri2_from_dma_bufs(__DRIscreen *screen,
1653                    int width, int height, int fourcc,
1654                    int *fds, int num_fds,
1655                    int *strides, int *offsets,
1656                    enum __DRIYUVColorSpace yuv_color_space,
1657                    enum __DRISampleRange sample_range,
1658                    enum __DRIChromaSiting horizontal_siting,
1659                    enum __DRIChromaSiting vertical_siting,
1660                    unsigned *error,
1661                    void *loaderPrivate)
1662 {
1663    __DRIimage *img;
1664 
1665    img = dri2_create_image_from_fd(screen, width, height, fourcc,
1666                                    DRM_FORMAT_MOD_INVALID, fds, num_fds,
1667                                    strides, offsets, 0, error, loaderPrivate);
1668    if (img == NULL)
1669       return NULL;
1670 
1671    img->yuv_color_space = yuv_color_space;
1672    img->sample_range = sample_range;
1673    img->horizontal_siting = horizontal_siting;
1674    img->vertical_siting = vertical_siting;
1675 
1676    *error = __DRI_IMAGE_ERROR_SUCCESS;
1677    return img;
1678 }
1679 
1680 static __DRIimage *
dri2_from_dma_bufs2(__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,unsigned * error,void * loaderPrivate)1681 dri2_from_dma_bufs2(__DRIscreen *screen,
1682                     int width, int height, int fourcc,
1683                     uint64_t modifier, int *fds, int num_fds,
1684                     int *strides, int *offsets,
1685                     enum __DRIYUVColorSpace yuv_color_space,
1686                     enum __DRISampleRange sample_range,
1687                     enum __DRIChromaSiting horizontal_siting,
1688                     enum __DRIChromaSiting vertical_siting,
1689                     unsigned *error,
1690                     void *loaderPrivate)
1691 {
1692    __DRIimage *img;
1693 
1694    img = dri2_create_image_from_fd(screen, width, height, fourcc,
1695                                    modifier, fds, num_fds, strides, offsets,
1696                                    0, error, loaderPrivate);
1697    if (img == NULL)
1698       return NULL;
1699 
1700    img->yuv_color_space = yuv_color_space;
1701    img->sample_range = sample_range;
1702    img->horizontal_siting = horizontal_siting;
1703    img->vertical_siting = vertical_siting;
1704 
1705    *error = __DRI_IMAGE_ERROR_SUCCESS;
1706    return img;
1707 }
1708 
1709 static __DRIimage *
dri2_from_dma_bufs3(__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 flags,unsigned * error,void * loaderPrivate)1710 dri2_from_dma_bufs3(__DRIscreen *screen,
1711                     int width, int height, int fourcc,
1712                     uint64_t modifier, int *fds, int num_fds,
1713                     int *strides, int *offsets,
1714                     enum __DRIYUVColorSpace yuv_color_space,
1715                     enum __DRISampleRange sample_range,
1716                     enum __DRIChromaSiting horizontal_siting,
1717                     enum __DRIChromaSiting vertical_siting,
1718                     uint32_t flags,
1719                     unsigned *error,
1720                     void *loaderPrivate)
1721 {
1722    __DRIimage *img;
1723 
1724    img = dri2_create_image_from_fd(screen, width, height, fourcc,
1725                                    modifier, fds, num_fds, strides, offsets,
1726                                    (flags & __DRI_IMAGE_PROTECTED_CONTENT_FLAG) ?
1727                                       PIPE_BIND_PROTECTED : 0,
1728                                    error, loaderPrivate);
1729    if (img == NULL)
1730       return NULL;
1731 
1732    img->yuv_color_space = yuv_color_space;
1733    img->sample_range = sample_range;
1734    img->horizontal_siting = horizontal_siting;
1735    img->vertical_siting = vertical_siting;
1736 
1737    *error = __DRI_IMAGE_ERROR_SUCCESS;
1738    return img;
1739 }
1740 
1741 static 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)1742 dri2_blit_image(__DRIcontext *context, __DRIimage *dst, __DRIimage *src,
1743                 int dstx0, int dsty0, int dstwidth, int dstheight,
1744                 int srcx0, int srcy0, int srcwidth, int srcheight,
1745                 int flush_flag)
1746 {
1747    struct dri_context *ctx = dri_context(context);
1748    struct pipe_context *pipe = ctx->st->pipe;
1749    struct pipe_screen *screen;
1750    struct pipe_fence_handle *fence;
1751    struct pipe_blit_info blit;
1752 
1753    if (!dst || !src)
1754       return;
1755 
1756    handle_in_fence(context, dst);
1757 
1758    memset(&blit, 0, sizeof(blit));
1759    blit.dst.resource = dst->texture;
1760    blit.dst.box.x = dstx0;
1761    blit.dst.box.y = dsty0;
1762    blit.dst.box.width = dstwidth;
1763    blit.dst.box.height = dstheight;
1764    blit.dst.box.depth = 1;
1765    blit.dst.format = dst->texture->format;
1766    blit.src.resource = src->texture;
1767    blit.src.box.x = srcx0;
1768    blit.src.box.y = srcy0;
1769    blit.src.box.width = srcwidth;
1770    blit.src.box.height = srcheight;
1771    blit.src.box.depth = 1;
1772    blit.src.format = src->texture->format;
1773    blit.mask = PIPE_MASK_RGBA;
1774    blit.filter = PIPE_TEX_FILTER_NEAREST;
1775 
1776    pipe->blit(pipe, &blit);
1777 
1778    if (flush_flag == __BLIT_FLAG_FLUSH) {
1779       pipe->flush_resource(pipe, dst->texture);
1780       ctx->st->flush(ctx->st, 0, NULL, NULL, NULL);
1781    } else if (flush_flag == __BLIT_FLAG_FINISH) {
1782       screen = dri_screen(ctx->sPriv)->base.screen;
1783       pipe->flush_resource(pipe, dst->texture);
1784       ctx->st->flush(ctx->st, 0, &fence, NULL, NULL);
1785       (void) screen->fence_finish(screen, NULL, fence, PIPE_TIMEOUT_INFINITE);
1786       screen->fence_reference(screen, &fence, NULL);
1787    }
1788 }
1789 
1790 static void *
dri2_map_image(__DRIcontext * context,__DRIimage * image,int x0,int y0,int width,int height,unsigned int flags,int * stride,void ** data)1791 dri2_map_image(__DRIcontext *context, __DRIimage *image,
1792                 int x0, int y0, int width, int height,
1793                 unsigned int flags, int *stride, void **data)
1794 {
1795    struct dri_context *ctx = dri_context(context);
1796    struct pipe_context *pipe = ctx->st->pipe;
1797    enum pipe_map_flags pipe_access = 0;
1798    struct pipe_transfer *trans;
1799    void *map;
1800 
1801    if (!image || !data || *data)
1802       return NULL;
1803 
1804    unsigned plane = image->plane;
1805    if (plane >= dri2_get_mapping_by_format(image->dri_format)->nplanes)
1806       return NULL;
1807 
1808    handle_in_fence(context, image);
1809 
1810    struct pipe_resource *resource = image->texture;
1811    while (plane--)
1812       resource = resource->next;
1813 
1814    if (flags & __DRI_IMAGE_TRANSFER_READ)
1815          pipe_access |= PIPE_MAP_READ;
1816    if (flags & __DRI_IMAGE_TRANSFER_WRITE)
1817          pipe_access |= PIPE_MAP_WRITE;
1818 
1819    map = pipe_texture_map(pipe, resource, 0, 0, pipe_access, x0, y0,
1820                            width, height, &trans);
1821    if (map) {
1822       *data = trans;
1823       *stride = trans->stride;
1824    }
1825 
1826    return map;
1827 }
1828 
1829 static void
dri2_unmap_image(__DRIcontext * context,__DRIimage * image,void * data)1830 dri2_unmap_image(__DRIcontext *context, __DRIimage *image, void *data)
1831 {
1832    struct dri_context *ctx = dri_context(context);
1833    struct pipe_context *pipe = ctx->st->pipe;
1834 
1835    pipe_texture_unmap(pipe, (struct pipe_transfer *)data);
1836 }
1837 
1838 static int
dri2_get_capabilities(__DRIscreen * _screen)1839 dri2_get_capabilities(__DRIscreen *_screen)
1840 {
1841    struct dri_screen *screen = dri_screen(_screen);
1842 
1843    return (screen->can_share_buffer ? __DRI_IMAGE_CAP_GLOBAL_NAMES : 0);
1844 }
1845 
1846 /* The extension is modified during runtime if DRI_PRIME is detected */
1847 static const __DRIimageExtension dri2ImageExtensionTempl = {
1848     .base = { __DRI_IMAGE, 21 },
1849 
1850     .createImageFromName          = dri2_create_image_from_name,
1851     .createImageFromRenderbuffer  = dri2_create_image_from_renderbuffer,
1852     .destroyImage                 = dri2_destroy_image,
1853     .createImage                  = dri2_create_image,
1854     .queryImage                   = dri2_query_image,
1855     .dupImage                     = dri2_dup_image,
1856     .validateUsage                = dri2_validate_usage,
1857     .createImageFromNames         = dri2_from_names,
1858     .fromPlanar                   = dri2_from_planar,
1859     .createImageFromTexture       = dri2_create_from_texture,
1860     .createImageFromFds           = NULL,
1861     .createImageFromFds2          = NULL,
1862     .createImageFromDmaBufs       = NULL,
1863     .blitImage                    = dri2_blit_image,
1864     .getCapabilities              = dri2_get_capabilities,
1865     .mapImage                     = dri2_map_image,
1866     .unmapImage                   = dri2_unmap_image,
1867     .createImageWithModifiers     = NULL,
1868     .createImageFromDmaBufs2      = NULL,
1869     .createImageFromDmaBufs3      = NULL,
1870     .queryDmaBufFormats           = NULL,
1871     .queryDmaBufModifiers         = NULL,
1872     .queryDmaBufFormatModifierAttribs = NULL,
1873     .createImageFromRenderbuffer2 = dri2_create_image_from_renderbuffer2,
1874     .createImageWithModifiers2    = NULL,
1875 };
1876 
1877 const __DRIimageExtension driVkImageExtension = {
1878     .base = { __DRI_IMAGE, 20 },
1879 
1880     .createImageFromName          = dri2_create_image_from_name,
1881     .createImageFromRenderbuffer  = dri2_create_image_from_renderbuffer,
1882     .destroyImage                 = dri2_destroy_image,
1883     .createImage                  = dri2_create_image,
1884     .queryImage                   = dri2_query_image,
1885     .dupImage                     = dri2_dup_image,
1886     .validateUsage                = dri2_validate_usage,
1887     .createImageFromNames         = dri2_from_names,
1888     .fromPlanar                   = dri2_from_planar,
1889     .createImageFromTexture       = dri2_create_from_texture,
1890     .createImageFromFds           = dri2_from_fds,
1891     .createImageFromFds2          = dri2_from_fds2,
1892     .createImageFromDmaBufs       = dri2_from_dma_bufs,
1893     .blitImage                    = dri2_blit_image,
1894     .getCapabilities              = dri2_get_capabilities,
1895     .mapImage                     = dri2_map_image,
1896     .unmapImage                   = dri2_unmap_image,
1897     .createImageWithModifiers     = dri2_create_image_with_modifiers,
1898     .createImageFromDmaBufs2      = dri2_from_dma_bufs2,
1899     .createImageFromDmaBufs3      = dri2_from_dma_bufs3,
1900     .queryDmaBufFormats           = dri2_query_dma_buf_formats,
1901     .queryDmaBufModifiers         = dri2_query_dma_buf_modifiers,
1902     .queryDmaBufFormatModifierAttribs = dri2_query_dma_buf_format_modifier_attribs,
1903     .createImageFromRenderbuffer2 = dri2_create_image_from_renderbuffer2,
1904     .createImageWithModifiers2    = dri2_create_image_with_modifiers2,
1905 };
1906 
1907 const __DRIimageExtension driVkImageExtensionSw = {
1908     .base = { __DRI_IMAGE, 20 },
1909 
1910     .createImageFromName          = dri2_create_image_from_name,
1911     .createImageFromRenderbuffer  = dri2_create_image_from_renderbuffer,
1912     .destroyImage                 = dri2_destroy_image,
1913     .createImage                  = dri2_create_image,
1914     .queryImage                   = dri2_query_image,
1915     .dupImage                     = dri2_dup_image,
1916     .validateUsage                = dri2_validate_usage,
1917     .createImageFromNames         = dri2_from_names,
1918     .fromPlanar                   = dri2_from_planar,
1919     .createImageFromTexture       = dri2_create_from_texture,
1920     .createImageFromFds           = dri2_from_fds,
1921     .createImageFromFds2          = dri2_from_fds2,
1922     .blitImage                    = dri2_blit_image,
1923     .getCapabilities              = dri2_get_capabilities,
1924     .mapImage                     = dri2_map_image,
1925     .unmapImage                   = dri2_unmap_image,
1926     .createImageFromRenderbuffer2 = dri2_create_image_from_renderbuffer2,
1927 };
1928 
1929 static const __DRIrobustnessExtension dri2Robustness = {
1930    .base = { __DRI2_ROBUSTNESS, 1 }
1931 };
1932 
1933 static int
dri2_interop_query_device_info(__DRIcontext * _ctx,struct mesa_glinterop_device_info * out)1934 dri2_interop_query_device_info(__DRIcontext *_ctx,
1935                                struct mesa_glinterop_device_info *out)
1936 {
1937    struct pipe_screen *screen = dri_context(_ctx)->st->pipe->screen;
1938 
1939    /* There is no version 0, thus we do not support it */
1940    if (out->version == 0)
1941       return MESA_GLINTEROP_INVALID_VERSION;
1942 
1943    out->pci_segment_group = screen->get_param(screen, PIPE_CAP_PCI_GROUP);
1944    out->pci_bus = screen->get_param(screen, PIPE_CAP_PCI_BUS);
1945    out->pci_device = screen->get_param(screen, PIPE_CAP_PCI_DEVICE);
1946    out->pci_function = screen->get_param(screen, PIPE_CAP_PCI_FUNCTION);
1947 
1948    out->vendor_id = screen->get_param(screen, PIPE_CAP_VENDOR_ID);
1949    out->device_id = screen->get_param(screen, PIPE_CAP_DEVICE_ID);
1950 
1951    /* Instruct the caller that we support up-to version one of the interface */
1952    out->version = 1;
1953 
1954    return MESA_GLINTEROP_SUCCESS;
1955 }
1956 
1957 static int
dri2_interop_export_object(__DRIcontext * _ctx,struct mesa_glinterop_export_in * in,struct mesa_glinterop_export_out * out)1958 dri2_interop_export_object(__DRIcontext *_ctx,
1959                            struct mesa_glinterop_export_in *in,
1960                            struct mesa_glinterop_export_out *out)
1961 {
1962    struct st_context_iface *st = dri_context(_ctx)->st;
1963    struct pipe_screen *screen = st->pipe->screen;
1964    struct gl_context *ctx = ((struct st_context *)st)->ctx;
1965    struct pipe_resource *res = NULL;
1966    struct winsys_handle whandle;
1967    unsigned target, usage;
1968    boolean success;
1969 
1970    /* There is no version 0, thus we do not support it */
1971    if (in->version == 0 || out->version == 0)
1972       return MESA_GLINTEROP_INVALID_VERSION;
1973 
1974    /* Validate the target. */
1975    switch (in->target) {
1976    case GL_TEXTURE_BUFFER:
1977    case GL_TEXTURE_1D:
1978    case GL_TEXTURE_2D:
1979    case GL_TEXTURE_3D:
1980    case GL_TEXTURE_RECTANGLE:
1981    case GL_TEXTURE_1D_ARRAY:
1982    case GL_TEXTURE_2D_ARRAY:
1983    case GL_TEXTURE_CUBE_MAP_ARRAY:
1984    case GL_TEXTURE_CUBE_MAP:
1985    case GL_TEXTURE_2D_MULTISAMPLE:
1986    case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
1987    case GL_TEXTURE_EXTERNAL_OES:
1988    case GL_RENDERBUFFER:
1989    case GL_ARRAY_BUFFER:
1990       target = in->target;
1991       break;
1992    case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1993    case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1994    case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1995    case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1996    case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1997    case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1998       target = GL_TEXTURE_CUBE_MAP;
1999       break;
2000    default:
2001       return MESA_GLINTEROP_INVALID_TARGET;
2002    }
2003 
2004    /* Validate the simple case of miplevel. */
2005    if ((target == GL_RENDERBUFFER || target == GL_ARRAY_BUFFER) &&
2006        in->miplevel != 0)
2007       return MESA_GLINTEROP_INVALID_MIP_LEVEL;
2008 
2009    /* Validate the OpenGL object and get pipe_resource. */
2010    simple_mtx_lock(&ctx->Shared->Mutex);
2011 
2012    if (target == GL_ARRAY_BUFFER) {
2013       /* Buffer objects.
2014        *
2015        * The error checking is based on the documentation of
2016        * clCreateFromGLBuffer from OpenCL 2.0 SDK.
2017        */
2018       struct gl_buffer_object *buf = _mesa_lookup_bufferobj(ctx, in->obj);
2019 
2020       /* From OpenCL 2.0 SDK, clCreateFromGLBuffer:
2021        *  "CL_INVALID_GL_OBJECT if bufobj is not a GL buffer object or is
2022        *   a GL buffer object but does not have an existing data store or
2023        *   the size of the buffer is 0."
2024        */
2025       if (!buf || buf->Size == 0) {
2026          simple_mtx_unlock(&ctx->Shared->Mutex);
2027          return MESA_GLINTEROP_INVALID_OBJECT;
2028       }
2029 
2030       res = buf->buffer;
2031       if (!res) {
2032          /* this shouldn't happen */
2033          simple_mtx_unlock(&ctx->Shared->Mutex);
2034          return MESA_GLINTEROP_INVALID_OBJECT;
2035       }
2036 
2037       out->buf_offset = 0;
2038       out->buf_size = buf->Size;
2039 
2040       buf->UsageHistory |= USAGE_DISABLE_MINMAX_CACHE;
2041    } else if (target == GL_RENDERBUFFER) {
2042       /* Renderbuffers.
2043        *
2044        * The error checking is based on the documentation of
2045        * clCreateFromGLRenderbuffer from OpenCL 2.0 SDK.
2046        */
2047       struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, in->obj);
2048 
2049       /* From OpenCL 2.0 SDK, clCreateFromGLRenderbuffer:
2050        *   "CL_INVALID_GL_OBJECT if renderbuffer is not a GL renderbuffer
2051        *    object or if the width or height of renderbuffer is zero."
2052        */
2053       if (!rb || rb->Width == 0 || rb->Height == 0) {
2054          simple_mtx_unlock(&ctx->Shared->Mutex);
2055          return MESA_GLINTEROP_INVALID_OBJECT;
2056       }
2057 
2058       /* From OpenCL 2.0 SDK, clCreateFromGLRenderbuffer:
2059        *   "CL_INVALID_OPERATION if renderbuffer is a multi-sample GL
2060        *    renderbuffer object."
2061        */
2062       if (rb->NumSamples > 1) {
2063          simple_mtx_unlock(&ctx->Shared->Mutex);
2064          return MESA_GLINTEROP_INVALID_OPERATION;
2065       }
2066 
2067       /* From OpenCL 2.0 SDK, clCreateFromGLRenderbuffer:
2068        *   "CL_OUT_OF_RESOURCES if there is a failure to allocate resources
2069        *    required by the OpenCL implementation on the device."
2070        */
2071       res = rb->texture;
2072       if (!res) {
2073          simple_mtx_unlock(&ctx->Shared->Mutex);
2074          return MESA_GLINTEROP_OUT_OF_RESOURCES;
2075       }
2076 
2077       out->internal_format = rb->InternalFormat;
2078       out->view_minlevel = 0;
2079       out->view_numlevels = 1;
2080       out->view_minlayer = 0;
2081       out->view_numlayers = 1;
2082    } else {
2083       /* Texture objects.
2084        *
2085        * The error checking is based on the documentation of
2086        * clCreateFromGLTexture from OpenCL 2.0 SDK.
2087        */
2088       struct gl_texture_object *obj = _mesa_lookup_texture(ctx, in->obj);
2089 
2090       if (obj)
2091          _mesa_test_texobj_completeness(ctx, obj);
2092 
2093       /* From OpenCL 2.0 SDK, clCreateFromGLTexture:
2094        *   "CL_INVALID_GL_OBJECT if texture is not a GL texture object whose
2095        *    type matches texture_target, if the specified miplevel of texture
2096        *    is not defined, or if the width or height of the specified
2097        *    miplevel is zero or if the GL texture object is incomplete."
2098        */
2099       if (!obj ||
2100           obj->Target != target ||
2101           !obj->_BaseComplete ||
2102           (in->miplevel > 0 && !obj->_MipmapComplete)) {
2103          simple_mtx_unlock(&ctx->Shared->Mutex);
2104          return MESA_GLINTEROP_INVALID_OBJECT;
2105       }
2106 
2107       if (target == GL_TEXTURE_BUFFER) {
2108          struct gl_buffer_object *stBuf =
2109             obj->BufferObject;
2110 
2111          if (!stBuf || !stBuf->buffer) {
2112             /* this shouldn't happen */
2113             simple_mtx_unlock(&ctx->Shared->Mutex);
2114             return MESA_GLINTEROP_INVALID_OBJECT;
2115          }
2116          res = stBuf->buffer;
2117 
2118          out->internal_format = obj->BufferObjectFormat;
2119          out->buf_offset = obj->BufferOffset;
2120          out->buf_size = obj->BufferSize == -1 ? obj->BufferObject->Size :
2121                                                  obj->BufferSize;
2122 
2123          obj->BufferObject->UsageHistory |= USAGE_DISABLE_MINMAX_CACHE;
2124       } else {
2125          /* From OpenCL 2.0 SDK, clCreateFromGLTexture:
2126           *   "CL_INVALID_MIP_LEVEL if miplevel is less than the value of
2127           *    levelbase (for OpenGL implementations) or zero (for OpenGL ES
2128           *    implementations); or greater than the value of q (for both OpenGL
2129           *    and OpenGL ES). levelbase and q are defined for the texture in
2130           *    section 3.8.10 (Texture Completeness) of the OpenGL 2.1
2131           *    specification and section 3.7.10 of the OpenGL ES 2.0."
2132           */
2133          if (in->miplevel < obj->Attrib.BaseLevel || in->miplevel > obj->_MaxLevel) {
2134             simple_mtx_unlock(&ctx->Shared->Mutex);
2135             return MESA_GLINTEROP_INVALID_MIP_LEVEL;
2136          }
2137 
2138          if (!st_finalize_texture(ctx, st->pipe, obj, 0)) {
2139             simple_mtx_unlock(&ctx->Shared->Mutex);
2140             return MESA_GLINTEROP_OUT_OF_RESOURCES;
2141          }
2142 
2143          res = st_get_texobj_resource(obj);
2144          if (!res) {
2145             /* Incomplete texture buffer object? This shouldn't really occur. */
2146             simple_mtx_unlock(&ctx->Shared->Mutex);
2147             return MESA_GLINTEROP_INVALID_OBJECT;
2148          }
2149 
2150          out->internal_format = obj->Image[0][0]->InternalFormat;
2151          out->view_minlevel = obj->Attrib.MinLevel;
2152          out->view_numlevels = obj->Attrib.NumLevels;
2153          out->view_minlayer = obj->Attrib.MinLayer;
2154          out->view_numlayers = obj->Attrib.NumLayers;
2155       }
2156    }
2157 
2158    /* Get the handle. */
2159    switch (in->access) {
2160    case MESA_GLINTEROP_ACCESS_READ_ONLY:
2161       usage = 0;
2162       break;
2163    case MESA_GLINTEROP_ACCESS_READ_WRITE:
2164    case MESA_GLINTEROP_ACCESS_WRITE_ONLY:
2165       usage = PIPE_HANDLE_USAGE_SHADER_WRITE;
2166       break;
2167    default:
2168       usage = 0;
2169    }
2170 
2171    memset(&whandle, 0, sizeof(whandle));
2172    whandle.type = WINSYS_HANDLE_TYPE_FD;
2173 
2174    success = screen->resource_get_handle(screen, st->pipe, res, &whandle,
2175                                          usage);
2176    simple_mtx_unlock(&ctx->Shared->Mutex);
2177 
2178    if (!success)
2179       return MESA_GLINTEROP_OUT_OF_HOST_MEMORY;
2180 
2181    out->dmabuf_fd = whandle.handle;
2182    out->out_driver_data_written = 0;
2183 
2184    if (res->target == PIPE_BUFFER)
2185       out->buf_offset += whandle.offset;
2186 
2187    /* Instruct the caller that we support up-to version one of the interface */
2188    in->version = 1;
2189    out->version = 1;
2190 
2191    return MESA_GLINTEROP_SUCCESS;
2192 }
2193 
2194 static const __DRI2interopExtension dri2InteropExtension = {
2195    .base = { __DRI2_INTEROP, 1 },
2196    .query_device_info = dri2_interop_query_device_info,
2197    .export_object = dri2_interop_export_object
2198 };
2199 
2200 /**
2201  * \brief the DRI2bufferDamageExtension set_damage_region method
2202  */
2203 static void
dri2_set_damage_region(__DRIdrawable * dPriv,unsigned int nrects,int * rects)2204 dri2_set_damage_region(__DRIdrawable *dPriv, unsigned int nrects, int *rects)
2205 {
2206    struct dri_drawable *drawable = dri_drawable(dPriv);
2207    struct pipe_box *boxes = NULL;
2208 
2209    if (nrects) {
2210       boxes = CALLOC(nrects, sizeof(*boxes));
2211       assert(boxes);
2212 
2213       for (unsigned int i = 0; i < nrects; i++) {
2214          int *rect = &rects[i * 4];
2215 
2216          u_box_2d(rect[0], rect[1], rect[2], rect[3], &boxes[i]);
2217       }
2218    }
2219 
2220    FREE(drawable->damage_rects);
2221    drawable->damage_rects = boxes;
2222    drawable->num_damage_rects = nrects;
2223 
2224    /* Only apply the damage region if the BACK_LEFT texture is up-to-date. */
2225    if (drawable->texture_stamp == drawable->dPriv->lastStamp &&
2226        (drawable->texture_mask & (1 << ST_ATTACHMENT_BACK_LEFT))) {
2227       struct pipe_screen *screen = drawable->screen->base.screen;
2228       struct pipe_resource *resource;
2229 
2230       if (drawable->stvis.samples > 1)
2231          resource = drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT];
2232       else
2233          resource = drawable->textures[ST_ATTACHMENT_BACK_LEFT];
2234 
2235       screen->set_damage_region(screen, resource,
2236                                 drawable->num_damage_rects,
2237                                 drawable->damage_rects);
2238    }
2239 }
2240 
2241 static const __DRI2bufferDamageExtension dri2BufferDamageExtensionTempl = {
2242    .base = { __DRI2_BUFFER_DAMAGE, 1 },
2243 };
2244 
2245 /**
2246  * \brief the DRI2ConfigQueryExtension configQueryb method
2247  */
2248 static int
dri2GalliumConfigQueryb(__DRIscreen * sPriv,const char * var,unsigned char * val)2249 dri2GalliumConfigQueryb(__DRIscreen *sPriv, const char *var,
2250                         unsigned char *val)
2251 {
2252    struct dri_screen *screen = dri_screen(sPriv);
2253 
2254    if (!driCheckOption(&screen->dev->option_cache, var, DRI_BOOL))
2255       return dri2ConfigQueryExtension.configQueryb(sPriv, var, val);
2256 
2257    *val = driQueryOptionb(&screen->dev->option_cache, var);
2258 
2259    return 0;
2260 }
2261 
2262 /**
2263  * \brief the DRI2ConfigQueryExtension configQueryi method
2264  */
2265 static int
dri2GalliumConfigQueryi(__DRIscreen * sPriv,const char * var,int * val)2266 dri2GalliumConfigQueryi(__DRIscreen *sPriv, const char *var, int *val)
2267 {
2268    struct dri_screen *screen = dri_screen(sPriv);
2269 
2270    if (!driCheckOption(&screen->dev->option_cache, var, DRI_INT) &&
2271        !driCheckOption(&screen->dev->option_cache, var, DRI_ENUM))
2272       return dri2ConfigQueryExtension.configQueryi(sPriv, var, val);
2273 
2274     *val = driQueryOptioni(&screen->dev->option_cache, var);
2275 
2276     return 0;
2277 }
2278 
2279 /**
2280  * \brief the DRI2ConfigQueryExtension configQueryf method
2281  */
2282 static int
dri2GalliumConfigQueryf(__DRIscreen * sPriv,const char * var,float * val)2283 dri2GalliumConfigQueryf(__DRIscreen *sPriv, const char *var, float *val)
2284 {
2285    struct dri_screen *screen = dri_screen(sPriv);
2286 
2287    if (!driCheckOption(&screen->dev->option_cache, var, DRI_FLOAT))
2288       return dri2ConfigQueryExtension.configQueryf(sPriv, var, val);
2289 
2290     *val = driQueryOptionf(&screen->dev->option_cache, var);
2291 
2292     return 0;
2293 }
2294 
2295 /**
2296  * \brief the DRI2ConfigQueryExtension configQuerys method
2297  */
2298 static int
dri2GalliumConfigQuerys(__DRIscreen * sPriv,const char * var,char ** val)2299 dri2GalliumConfigQuerys(__DRIscreen *sPriv, const char *var, char **val)
2300 {
2301    struct dri_screen *screen = dri_screen(sPriv);
2302 
2303    if (!driCheckOption(&screen->dev->option_cache, var, DRI_STRING))
2304       return dri2ConfigQueryExtension.configQuerys(sPriv, var, val);
2305 
2306     *val = driQueryOptionstr(&screen->dev->option_cache, var);
2307 
2308     return 0;
2309 }
2310 
2311 /**
2312  * \brief the DRI2ConfigQueryExtension struct.
2313  *
2314  * We first query the driver option cache. Then the dri2 option cache.
2315  */
2316 static const __DRI2configQueryExtension dri2GalliumConfigQueryExtension = {
2317    .base = { __DRI2_CONFIG_QUERY, 2 },
2318 
2319    .configQueryb        = dri2GalliumConfigQueryb,
2320    .configQueryi        = dri2GalliumConfigQueryi,
2321    .configQueryf        = dri2GalliumConfigQueryf,
2322    .configQuerys        = dri2GalliumConfigQuerys,
2323 };
2324 
2325 /**
2326  * \brief the DRI2blobExtension set_cache_funcs method
2327  */
2328 static void
set_blob_cache_funcs(__DRIscreen * sPriv,__DRIblobCacheSet set,__DRIblobCacheGet get)2329 set_blob_cache_funcs(__DRIscreen *sPriv, __DRIblobCacheSet set,
2330                      __DRIblobCacheGet get)
2331 {
2332    struct dri_screen *screen = dri_screen(sPriv);
2333    struct pipe_screen *pscreen = screen->base.screen;
2334 
2335    if (!pscreen->get_disk_shader_cache)
2336       return;
2337 
2338    struct disk_cache *cache = pscreen->get_disk_shader_cache(pscreen);
2339 
2340    if (!cache)
2341       return;
2342 
2343    disk_cache_set_callbacks(cache, set, get);
2344 }
2345 
2346 static const __DRI2blobExtension driBlobExtension = {
2347    .base = { __DRI2_BLOB, 1 },
2348    .set_cache_funcs = set_blob_cache_funcs
2349 };
2350 
2351 static const __DRImutableRenderBufferDriverExtension driMutableRenderBufferExtension = {
2352    .base = { __DRI_MUTABLE_RENDER_BUFFER_DRIVER, 1 },
2353 };
2354 
2355 /*
2356  * Backend function init_screen.
2357  */
2358 
2359 static const __DRIextension *dri_screen_extensions_base[] = {
2360    &driTexBufferExtension.base,
2361    &dri2FlushExtension.base,
2362    &dri2RendererQueryExtension.base,
2363    &dri2GalliumConfigQueryExtension.base,
2364    &dri2ThrottleExtension.base,
2365    &dri2FenceExtension.base,
2366    &dri2InteropExtension.base,
2367    &driBlobExtension.base,
2368    &driMutableRenderBufferExtension.base,
2369    &dri2FlushControlExtension.base,
2370 };
2371 
2372 /**
2373  * Set up the DRI extension list for this screen based on its underlying
2374  * gallium screen's capabilities.
2375  */
2376 static void
dri2_init_screen_extensions(struct dri_screen * screen,struct pipe_screen * pscreen,bool is_kms_screen)2377 dri2_init_screen_extensions(struct dri_screen *screen,
2378                             struct pipe_screen *pscreen,
2379                             bool is_kms_screen)
2380 {
2381    const __DRIextension **nExt;
2382 
2383    STATIC_ASSERT(sizeof(screen->screen_extensions) >=
2384                  sizeof(dri_screen_extensions_base));
2385    memcpy(&screen->screen_extensions, dri_screen_extensions_base,
2386           sizeof(dri_screen_extensions_base));
2387    screen->sPriv->extensions = screen->screen_extensions;
2388 
2389    /* Point nExt at the end of the extension list */
2390    nExt = &screen->screen_extensions[ARRAY_SIZE(dri_screen_extensions_base)];
2391 
2392    screen->image_extension = dri2ImageExtensionTempl;
2393    if (pscreen->resource_create_with_modifiers) {
2394       screen->image_extension.createImageWithModifiers =
2395          dri2_create_image_with_modifiers;
2396       screen->image_extension.createImageWithModifiers2 =
2397          dri2_create_image_with_modifiers2;
2398    }
2399 
2400    if (pscreen->get_param(pscreen, PIPE_CAP_NATIVE_FENCE_FD)) {
2401       screen->image_extension.setInFenceFd = dri2_set_in_fence_fd;
2402    }
2403 
2404    if (pscreen->get_param(pscreen, PIPE_CAP_DMABUF)) {
2405       uint64_t cap;
2406 
2407       if (drmGetCap(screen->sPriv->fd, DRM_CAP_PRIME, &cap) == 0 &&
2408           (cap & DRM_PRIME_CAP_IMPORT)) {
2409          screen->image_extension.createImageFromFds = dri2_from_fds;
2410          screen->image_extension.createImageFromFds2 = dri2_from_fds2;
2411          screen->image_extension.createImageFromDmaBufs = dri2_from_dma_bufs;
2412          screen->image_extension.createImageFromDmaBufs2 = dri2_from_dma_bufs2;
2413          screen->image_extension.createImageFromDmaBufs3 = dri2_from_dma_bufs3;
2414          screen->image_extension.queryDmaBufFormats =
2415             dri2_query_dma_buf_formats;
2416          screen->image_extension.queryDmaBufModifiers =
2417             dri2_query_dma_buf_modifiers;
2418          if (!is_kms_screen) {
2419             screen->image_extension.queryDmaBufFormatModifierAttribs =
2420                dri2_query_dma_buf_format_modifier_attribs;
2421          }
2422       }
2423    }
2424    *nExt++ = &screen->image_extension.base;
2425 
2426    if (!is_kms_screen) {
2427       screen->buffer_damage_extension = dri2BufferDamageExtensionTempl;
2428       if (pscreen->set_damage_region)
2429          screen->buffer_damage_extension.set_damage_region =
2430             dri2_set_damage_region;
2431       *nExt++ = &screen->buffer_damage_extension.base;
2432 
2433       if (pscreen->get_param(pscreen, PIPE_CAP_DEVICE_RESET_STATUS_QUERY)) {
2434          *nExt++ = &dri2Robustness.base;
2435          screen->has_reset_status_query = true;
2436       }
2437    }
2438 
2439    /* Ensure the extension list didn't overrun its buffer and is still
2440     * NULL-terminated */
2441    assert(nExt - screen->screen_extensions <=
2442           ARRAY_SIZE(screen->screen_extensions) - 1);
2443    assert(!*nExt);
2444 }
2445 
2446 /**
2447  * This is the driver specific part of the createNewScreen entry point.
2448  *
2449  * Returns the struct gl_config supported by this driver.
2450  */
2451 static const __DRIconfig **
dri2_init_screen(__DRIscreen * sPriv)2452 dri2_init_screen(__DRIscreen * sPriv)
2453 {
2454    const __DRIconfig **configs;
2455    struct dri_screen *screen;
2456    struct pipe_screen *pscreen = NULL;
2457 
2458    screen = CALLOC_STRUCT(dri_screen);
2459    if (!screen)
2460       return NULL;
2461 
2462    screen->sPriv = sPriv;
2463    screen->fd = sPriv->fd;
2464    (void) mtx_init(&screen->opencl_func_mutex, mtx_plain);
2465 
2466    sPriv->driverPrivate = (void *)screen;
2467 
2468    if (pipe_loader_drm_probe_fd(&screen->dev, screen->fd)) {
2469       pscreen = pipe_loader_create_screen(screen->dev);
2470       dri_init_options(screen);
2471    }
2472 
2473    if (!pscreen)
2474        goto release_pipe;
2475 
2476    screen->throttle = pscreen->get_param(pscreen, PIPE_CAP_THROTTLE);
2477 
2478    dri2_init_screen_extensions(screen, pscreen, false);
2479 
2480    configs = dri_init_screen_helper(screen, pscreen);
2481    if (!configs)
2482       goto destroy_screen;
2483 
2484    screen->can_share_buffer = true;
2485    screen->auto_fake_front = dri_with_format(sPriv);
2486    screen->lookup_egl_image = dri2_lookup_egl_image;
2487 
2488    const __DRIimageLookupExtension *loader = sPriv->dri2.image;
2489    if (loader &&
2490        loader->base.version >= 2 &&
2491        loader->validateEGLImage &&
2492        loader->lookupEGLImageValidated) {
2493       screen->validate_egl_image = dri2_validate_egl_image;
2494       screen->lookup_egl_image_validated = dri2_lookup_egl_image_validated;
2495    }
2496 
2497    return configs;
2498 
2499 destroy_screen:
2500    dri_destroy_screen_helper(screen);
2501 
2502 release_pipe:
2503    if (screen->dev)
2504       pipe_loader_release(&screen->dev, 1);
2505 
2506    FREE(screen);
2507    return NULL;
2508 }
2509 
2510 /**
2511  * This is the driver specific part of the createNewScreen entry point.
2512  *
2513  * Returns the struct gl_config supported by this driver.
2514  */
2515 static const __DRIconfig **
dri_swrast_kms_init_screen(__DRIscreen * sPriv)2516 dri_swrast_kms_init_screen(__DRIscreen * sPriv)
2517 {
2518 #if defined(GALLIUM_SOFTPIPE)
2519    const __DRIconfig **configs;
2520    struct dri_screen *screen;
2521    struct pipe_screen *pscreen = NULL;
2522 
2523    screen = CALLOC_STRUCT(dri_screen);
2524    if (!screen)
2525       return NULL;
2526 
2527    screen->sPriv = sPriv;
2528    screen->fd = sPriv->fd;
2529 
2530    sPriv->driverPrivate = (void *)screen;
2531 
2532 #ifdef HAVE_DRISW_KMS
2533    if (pipe_loader_sw_probe_kms(&screen->dev, screen->fd)) {
2534       pscreen = pipe_loader_create_screen(screen->dev);
2535       dri_init_options(screen);
2536    }
2537 #endif
2538 
2539    if (!pscreen)
2540        goto release_pipe;
2541 
2542    dri2_init_screen_extensions(screen, pscreen, true);
2543 
2544    configs = dri_init_screen_helper(screen, pscreen);
2545    if (!configs)
2546       goto destroy_screen;
2547 
2548    screen->can_share_buffer = false;
2549    screen->auto_fake_front = dri_with_format(sPriv);
2550    screen->lookup_egl_image = dri2_lookup_egl_image;
2551 
2552    const __DRIimageLookupExtension *loader = sPriv->dri2.image;
2553    if (loader &&
2554        loader->base.version >= 2 &&
2555        loader->validateEGLImage &&
2556        loader->lookupEGLImageValidated) {
2557       screen->validate_egl_image = dri2_validate_egl_image;
2558       screen->lookup_egl_image_validated = dri2_lookup_egl_image_validated;
2559    }
2560 
2561    return configs;
2562 
2563 destroy_screen:
2564    dri_destroy_screen_helper(screen);
2565 
2566 release_pipe:
2567    if (screen->dev)
2568       pipe_loader_release(&screen->dev, 1);
2569 
2570    FREE(screen);
2571 #endif // GALLIUM_SOFTPIPE
2572    return NULL;
2573 }
2574 
2575 static boolean
dri2_create_buffer(__DRIscreen * sPriv,__DRIdrawable * dPriv,const struct gl_config * visual,boolean isPixmap)2576 dri2_create_buffer(__DRIscreen * sPriv,
2577                    __DRIdrawable * dPriv,
2578                    const struct gl_config * visual, boolean isPixmap)
2579 {
2580    struct dri_drawable *drawable = NULL;
2581 
2582    if (!dri_create_buffer(sPriv, dPriv, visual, isPixmap))
2583       return FALSE;
2584 
2585    drawable = dPriv->driverPrivate;
2586 
2587    drawable->allocate_textures = dri2_allocate_textures;
2588    drawable->flush_frontbuffer = dri2_flush_frontbuffer;
2589    drawable->update_tex_buffer = dri2_update_tex_buffer;
2590    drawable->flush_swapbuffers = dri2_flush_swapbuffers;
2591 
2592    return TRUE;
2593 }
2594 
2595 /**
2596  * DRI driver virtual function table.
2597  *
2598  * DRI versions differ in their implementation of init_screen and swap_buffers.
2599  */
2600 const struct __DriverAPIRec galliumdrm_driver_api = {
2601    .InitScreen = dri2_init_screen,
2602    .DestroyScreen = dri_destroy_screen,
2603    .CreateBuffer = dri2_create_buffer,
2604    .DestroyBuffer = dri_destroy_buffer,
2605 
2606    .AllocateBuffer = dri2_allocate_buffer,
2607    .ReleaseBuffer  = dri2_release_buffer,
2608 };
2609 
2610 static const struct __DRIDriverVtableExtensionRec galliumdrm_vtable = {
2611    .base = { __DRI_DRIVER_VTABLE, 1 },
2612    .vtable = &galliumdrm_driver_api,
2613 };
2614 
2615 /**
2616  * DRI driver virtual function table.
2617  *
2618  * KMS/DRM version of the DriverAPI above sporting a different InitScreen
2619  * hook. The latter is used to explicitly initialise the kms_swrast driver
2620  * rather than selecting the approapriate driver as suggested by the loader.
2621  */
2622 const struct __DriverAPIRec dri_swrast_kms_driver_api = {
2623    .InitScreen = dri_swrast_kms_init_screen,
2624    .DestroyScreen = dri_destroy_screen,
2625    .CreateBuffer = dri2_create_buffer,
2626    .DestroyBuffer = dri_destroy_buffer,
2627 
2628    .AllocateBuffer = dri2_allocate_buffer,
2629    .ReleaseBuffer  = dri2_release_buffer,
2630 };
2631 
2632 /* This is the table of extensions that the loader will dlsym() for. */
2633 const __DRIextension *galliumdrm_driver_extensions[] = {
2634     &driCoreExtension.base,
2635     &driImageDriverExtension.base,
2636     &driDRI2Extension.base,
2637     &gallium_config_options.base,
2638     &galliumdrm_vtable.base,
2639     NULL
2640 };
2641 
2642 static const struct __DRIDriverVtableExtensionRec dri_swrast_kms_vtable = {
2643    .base = { __DRI_DRIVER_VTABLE, 1 },
2644    .vtable = &dri_swrast_kms_driver_api,
2645 };
2646 
2647 const __DRIextension *dri_swrast_kms_driver_extensions[] = {
2648     &driCoreExtension.base,
2649     &driImageDriverExtension.base,
2650     &swkmsDRI2Extension.base,
2651     &gallium_config_options.base,
2652     &dri_swrast_kms_vtable.base,
2653     NULL
2654 };
2655 
2656 /* vim: set sw=3 ts=8 sts=3 expandtab: */
2657