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