• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Mesa 3-D graphics library
3  *
4  * Copyright 2009, VMware, Inc.
5  * All Rights Reserved.
6  * Copyright (C) 2010 LunarG Inc.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included
16  * in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
22  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24  * OTHER DEALINGS IN THE SOFTWARE.
25  *
26  * Authors:
27  *    Keith Whitwell <keithw@vmware.com> Jakob Bornecrantz
28  *    <wallbraker@gmail.com> Chia-I Wu <olv@lunarg.com>
29  */
30 
31 #include <xf86drm.h>
32 #include <dlfcn.h>
33 #include <fcntl.h>
34 #include "GL/mesa_glinterop.h"
35 #include "util/u_memory.h"
36 #include "util/u_inlines.h"
37 #include "util/u_format.h"
38 #include "util/u_debug.h"
39 #include "state_tracker/drm_driver.h"
40 #include "state_tracker/st_cb_bufferobjects.h"
41 #include "state_tracker/st_cb_fbo.h"
42 #include "state_tracker/st_cb_texture.h"
43 #include "state_tracker/st_texture.h"
44 #include "state_tracker/st_context.h"
45 #include "pipe-loader/pipe_loader.h"
46 #include "main/bufferobj.h"
47 #include "main/texobj.h"
48 
49 #include "dri_screen.h"
50 #include "dri_context.h"
51 #include "dri_drawable.h"
52 #include "dri_query_renderer.h"
53 #include "dri2_buffer.h"
54 
convert_fourcc(int format,int * dri_components_p)55 static int convert_fourcc(int format, int *dri_components_p)
56 {
57    int dri_components;
58    switch(format) {
59    case __DRI_IMAGE_FOURCC_RGB565:
60       format = __DRI_IMAGE_FORMAT_RGB565;
61       dri_components = __DRI_IMAGE_COMPONENTS_RGB;
62       break;
63    case __DRI_IMAGE_FOURCC_ARGB8888:
64       format = __DRI_IMAGE_FORMAT_ARGB8888;
65       dri_components = __DRI_IMAGE_COMPONENTS_RGBA;
66       break;
67    case __DRI_IMAGE_FOURCC_XRGB8888:
68       format = __DRI_IMAGE_FORMAT_XRGB8888;
69       dri_components = __DRI_IMAGE_COMPONENTS_RGB;
70       break;
71    case __DRI_IMAGE_FOURCC_ABGR8888:
72       format = __DRI_IMAGE_FORMAT_ABGR8888;
73       dri_components = __DRI_IMAGE_COMPONENTS_RGBA;
74       break;
75    case __DRI_IMAGE_FOURCC_XBGR8888:
76       format = __DRI_IMAGE_FORMAT_XBGR8888;
77       dri_components = __DRI_IMAGE_COMPONENTS_RGB;
78       break;
79    case __DRI_IMAGE_FOURCC_R8:
80       format = __DRI_IMAGE_FORMAT_R8;
81       dri_components = __DRI_IMAGE_COMPONENTS_R;
82       break;
83    case __DRI_IMAGE_FOURCC_GR88:
84       format = __DRI_IMAGE_FORMAT_GR88;
85       dri_components = __DRI_IMAGE_COMPONENTS_RG;
86       break;
87    /*
88     * For multi-planar YUV formats, we return the format of the first
89     * plane only.  Since there is only one caller which supports multi-
90     * planar YUV it gets to figure out the remaining planes on it's
91     * own.
92     */
93    case __DRI_IMAGE_FOURCC_YUV420:
94    case __DRI_IMAGE_FOURCC_YVU420:
95       format = __DRI_IMAGE_FORMAT_R8;
96       dri_components = __DRI_IMAGE_COMPONENTS_Y_U_V;
97       break;
98    case __DRI_IMAGE_FOURCC_NV12:
99       format = __DRI_IMAGE_FORMAT_R8;
100       dri_components = __DRI_IMAGE_COMPONENTS_Y_UV;
101       break;
102    default:
103       return -1;
104    }
105    *dri_components_p = dri_components;
106    return format;
107 }
108 
109 /* NOTE this probably isn't going to do the right thing for YUV images
110  * (but I think the same can be said for intel_query_image()).  I think
111  * only needed for exporting dmabuf's, so I think I won't loose much
112  * sleep over it.
113  */
convert_to_fourcc(int format)114 static int convert_to_fourcc(int format)
115 {
116    switch(format) {
117    case __DRI_IMAGE_FORMAT_RGB565:
118       format = __DRI_IMAGE_FOURCC_RGB565;
119       break;
120    case __DRI_IMAGE_FORMAT_ARGB8888:
121       format = __DRI_IMAGE_FOURCC_ARGB8888;
122       break;
123    case __DRI_IMAGE_FORMAT_XRGB8888:
124       format = __DRI_IMAGE_FOURCC_XRGB8888;
125       break;
126    case __DRI_IMAGE_FORMAT_ABGR8888:
127       format = __DRI_IMAGE_FOURCC_ABGR8888;
128       break;
129    case __DRI_IMAGE_FORMAT_XBGR8888:
130       format = __DRI_IMAGE_FOURCC_XBGR8888;
131       break;
132    case __DRI_IMAGE_FORMAT_R8:
133       format = __DRI_IMAGE_FOURCC_R8;
134       break;
135    case __DRI_IMAGE_FORMAT_GR88:
136       format = __DRI_IMAGE_FOURCC_GR88;
137       break;
138    default:
139       return -1;
140    }
141    return format;
142 }
143 
dri2_format_to_pipe_format(int format)144 static enum pipe_format dri2_format_to_pipe_format (int format)
145 {
146    enum pipe_format pf;
147 
148    switch (format) {
149    case __DRI_IMAGE_FORMAT_RGB565:
150       pf = PIPE_FORMAT_B5G6R5_UNORM;
151       break;
152    case __DRI_IMAGE_FORMAT_XRGB8888:
153       pf = PIPE_FORMAT_BGRX8888_UNORM;
154       break;
155    case __DRI_IMAGE_FORMAT_ARGB8888:
156       pf = PIPE_FORMAT_BGRA8888_UNORM;
157       break;
158    case __DRI_IMAGE_FORMAT_ABGR8888:
159       pf = PIPE_FORMAT_RGBA8888_UNORM;
160       break;
161    case __DRI_IMAGE_FORMAT_R8:
162       pf = PIPE_FORMAT_R8_UNORM;
163       break;
164    case __DRI_IMAGE_FORMAT_GR88:
165       pf = PIPE_FORMAT_RG88_UNORM;
166       break;
167    default:
168       pf = PIPE_FORMAT_NONE;
169       break;
170    }
171 
172    return pf;
173 }
174 
175 /**
176  * DRI2 flush extension.
177  */
178 static void
dri2_flush_drawable(__DRIdrawable * dPriv)179 dri2_flush_drawable(__DRIdrawable *dPriv)
180 {
181    dri_flush(dPriv->driContextPriv, dPriv, __DRI2_FLUSH_DRAWABLE, -1);
182 }
183 
184 static void
dri2_invalidate_drawable(__DRIdrawable * dPriv)185 dri2_invalidate_drawable(__DRIdrawable *dPriv)
186 {
187    struct dri_drawable *drawable = dri_drawable(dPriv);
188 
189    dri2InvalidateDrawable(dPriv);
190    drawable->dPriv->lastStamp = drawable->dPriv->dri2.stamp;
191    drawable->texture_mask = 0;
192 
193    p_atomic_inc(&drawable->base.stamp);
194 }
195 
196 static const __DRI2flushExtension dri2FlushExtension = {
197     .base = { __DRI2_FLUSH, 4 },
198 
199     .flush                = dri2_flush_drawable,
200     .invalidate           = dri2_invalidate_drawable,
201     .flush_with_flags     = dri_flush,
202 };
203 
204 /**
205  * Retrieve __DRIbuffer from the DRI loader.
206  */
207 static __DRIbuffer *
dri2_drawable_get_buffers(struct dri_drawable * drawable,const enum st_attachment_type * atts,unsigned * count)208 dri2_drawable_get_buffers(struct dri_drawable *drawable,
209                           const enum st_attachment_type *atts,
210                           unsigned *count)
211 {
212    __DRIdrawable *dri_drawable = drawable->dPriv;
213    const __DRIdri2LoaderExtension *loader = drawable->sPriv->dri2.loader;
214    boolean with_format;
215    __DRIbuffer *buffers;
216    int num_buffers;
217    unsigned attachments[10];
218    unsigned num_attachments, i;
219 
220    assert(loader);
221    with_format = dri_with_format(drawable->sPriv);
222 
223    num_attachments = 0;
224 
225    /* for Xserver 1.6.0 (DRI2 version 1) we always need to ask for the front */
226    if (!with_format)
227       attachments[num_attachments++] = __DRI_BUFFER_FRONT_LEFT;
228 
229    for (i = 0; i < *count; i++) {
230       enum pipe_format format;
231       unsigned bind;
232       int att, depth;
233 
234       dri_drawable_get_format(drawable, atts[i], &format, &bind);
235       if (format == PIPE_FORMAT_NONE)
236          continue;
237 
238       switch (atts[i]) {
239       case ST_ATTACHMENT_FRONT_LEFT:
240          /* already added */
241          if (!with_format)
242             continue;
243          att = __DRI_BUFFER_FRONT_LEFT;
244          break;
245       case ST_ATTACHMENT_BACK_LEFT:
246          att = __DRI_BUFFER_BACK_LEFT;
247          break;
248       case ST_ATTACHMENT_FRONT_RIGHT:
249          att = __DRI_BUFFER_FRONT_RIGHT;
250          break;
251       case ST_ATTACHMENT_BACK_RIGHT:
252          att = __DRI_BUFFER_BACK_RIGHT;
253          break;
254       default:
255          continue;
256       }
257 
258       /*
259        * In this switch statement we must support all formats that
260        * may occur as the stvis->color_format.
261        */
262       switch(format) {
263       case PIPE_FORMAT_BGRA8888_UNORM:
264 	 depth = 32;
265 	 break;
266       case PIPE_FORMAT_BGRX8888_UNORM:
267 	 depth = 24;
268 	 break;
269       case PIPE_FORMAT_B5G6R5_UNORM:
270 	 depth = 16;
271 	 break;
272       default:
273 	 depth = util_format_get_blocksizebits(format);
274 	 assert(!"Unexpected format in dri2_drawable_get_buffers()");
275       }
276 
277       attachments[num_attachments++] = att;
278       if (with_format) {
279          attachments[num_attachments++] = depth;
280       }
281    }
282 
283    if (with_format) {
284       num_attachments /= 2;
285       buffers = loader->getBuffersWithFormat(dri_drawable,
286             &dri_drawable->w, &dri_drawable->h,
287             attachments, num_attachments,
288             &num_buffers, dri_drawable->loaderPrivate);
289    }
290    else {
291       buffers = loader->getBuffers(dri_drawable,
292             &dri_drawable->w, &dri_drawable->h,
293             attachments, num_attachments,
294             &num_buffers, dri_drawable->loaderPrivate);
295    }
296 
297    if (buffers)
298       *count = num_buffers;
299 
300    return buffers;
301 }
302 
303 static bool
dri_image_drawable_get_buffers(struct dri_drawable * drawable,struct __DRIimageList * images,const enum st_attachment_type * statts,unsigned statts_count)304 dri_image_drawable_get_buffers(struct dri_drawable *drawable,
305                                struct __DRIimageList *images,
306                                const enum st_attachment_type *statts,
307                                unsigned statts_count)
308 {
309    __DRIdrawable *dPriv = drawable->dPriv;
310    __DRIscreen *sPriv = drawable->sPriv;
311    unsigned int image_format = __DRI_IMAGE_FORMAT_NONE;
312    enum pipe_format pf;
313    uint32_t buffer_mask = 0;
314    unsigned i, bind;
315 
316    for (i = 0; i < statts_count; i++) {
317       dri_drawable_get_format(drawable, statts[i], &pf, &bind);
318       if (pf == PIPE_FORMAT_NONE)
319          continue;
320 
321       switch (statts[i]) {
322       case ST_ATTACHMENT_FRONT_LEFT:
323          buffer_mask |= __DRI_IMAGE_BUFFER_FRONT;
324          break;
325       case ST_ATTACHMENT_BACK_LEFT:
326          buffer_mask |= __DRI_IMAGE_BUFFER_BACK;
327          break;
328       default:
329          continue;
330       }
331 
332       switch (pf) {
333       case PIPE_FORMAT_B5G6R5_UNORM:
334          image_format = __DRI_IMAGE_FORMAT_RGB565;
335          break;
336       case PIPE_FORMAT_BGRX8888_UNORM:
337          image_format = __DRI_IMAGE_FORMAT_XRGB8888;
338          break;
339       case PIPE_FORMAT_BGRA8888_UNORM:
340          image_format = __DRI_IMAGE_FORMAT_ARGB8888;
341          break;
342       case PIPE_FORMAT_RGBA8888_UNORM:
343          image_format = __DRI_IMAGE_FORMAT_ABGR8888;
344          break;
345       default:
346          image_format = __DRI_IMAGE_FORMAT_NONE;
347          break;
348       }
349    }
350 
351    return (*sPriv->image.loader->getBuffers) (dPriv, image_format,
352                                        (uint32_t *) &drawable->base.stamp,
353                                        dPriv->loaderPrivate, buffer_mask,
354                                        images);
355 }
356 
357 static __DRIbuffer *
dri2_allocate_buffer(__DRIscreen * sPriv,unsigned attachment,unsigned format,int width,int height)358 dri2_allocate_buffer(__DRIscreen *sPriv,
359                      unsigned attachment, unsigned format,
360                      int width, int height)
361 {
362    struct dri_screen *screen = dri_screen(sPriv);
363    struct dri2_buffer *buffer;
364    struct pipe_resource templ;
365    enum pipe_format pf;
366    unsigned bind = 0;
367    struct winsys_handle whandle;
368 
369    switch (attachment) {
370       case __DRI_BUFFER_FRONT_LEFT:
371       case __DRI_BUFFER_FAKE_FRONT_LEFT:
372          bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
373          break;
374       case __DRI_BUFFER_BACK_LEFT:
375          bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
376          break;
377       case __DRI_BUFFER_DEPTH:
378       case __DRI_BUFFER_DEPTH_STENCIL:
379       case __DRI_BUFFER_STENCIL:
380             bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */
381          break;
382    }
383 
384    /* because we get the handle and stride */
385    bind |= PIPE_BIND_SHARED;
386 
387    switch (format) {
388       case 32:
389          pf = PIPE_FORMAT_BGRA8888_UNORM;
390          break;
391       case 24:
392          pf = PIPE_FORMAT_BGRX8888_UNORM;
393          break;
394       case 16:
395          pf = PIPE_FORMAT_Z16_UNORM;
396          break;
397       default:
398          return NULL;
399    }
400 
401    buffer = CALLOC_STRUCT(dri2_buffer);
402    if (!buffer)
403       return NULL;
404 
405    memset(&templ, 0, sizeof(templ));
406    templ.bind = bind;
407    templ.format = pf;
408    templ.target = PIPE_TEXTURE_2D;
409    templ.last_level = 0;
410    templ.width0 = width;
411    templ.height0 = height;
412    templ.depth0 = 1;
413    templ.array_size = 1;
414 
415    buffer->resource =
416       screen->base.screen->resource_create(screen->base.screen, &templ);
417    if (!buffer->resource) {
418       FREE(buffer);
419       return NULL;
420    }
421 
422    memset(&whandle, 0, sizeof(whandle));
423    if (screen->can_share_buffer)
424       whandle.type = DRM_API_HANDLE_TYPE_SHARED;
425    else
426       whandle.type = DRM_API_HANDLE_TYPE_KMS;
427 
428    screen->base.screen->resource_get_handle(screen->base.screen, NULL,
429          buffer->resource, &whandle,
430          PIPE_HANDLE_USAGE_EXPLICIT_FLUSH | PIPE_HANDLE_USAGE_READ);
431 
432    buffer->base.attachment = attachment;
433    buffer->base.name = whandle.handle;
434    buffer->base.cpp = util_format_get_blocksize(pf);
435    buffer->base.pitch = whandle.stride;
436 
437    return &buffer->base;
438 }
439 
440 static void
dri2_release_buffer(__DRIscreen * sPriv,__DRIbuffer * bPriv)441 dri2_release_buffer(__DRIscreen *sPriv, __DRIbuffer *bPriv)
442 {
443    struct dri2_buffer *buffer = dri2_buffer(bPriv);
444 
445    pipe_resource_reference(&buffer->resource, NULL);
446    FREE(buffer);
447 }
448 
449 /*
450  * Backend functions for st_framebuffer interface.
451  */
452 
453 static void
dri2_allocate_textures(struct dri_context * ctx,struct dri_drawable * drawable,const enum st_attachment_type * statts,unsigned statts_count)454 dri2_allocate_textures(struct dri_context *ctx,
455                        struct dri_drawable *drawable,
456                        const enum st_attachment_type *statts,
457                        unsigned statts_count)
458 {
459    __DRIscreen *sPriv = drawable->sPriv;
460    __DRIdrawable *dri_drawable = drawable->dPriv;
461    struct dri_screen *screen = dri_screen(sPriv);
462    struct pipe_resource templ;
463    boolean alloc_depthstencil = FALSE;
464    unsigned i, j, bind;
465    const __DRIimageLoaderExtension *image = sPriv->image.loader;
466    /* Image specific variables */
467    struct __DRIimageList images;
468    /* Dri2 specific variables */
469    __DRIbuffer *buffers = NULL;
470    struct winsys_handle whandle;
471    unsigned num_buffers = statts_count;
472 
473    /* First get the buffers from the loader */
474    if (image) {
475       if (!dri_image_drawable_get_buffers(drawable, &images,
476                                           statts, statts_count))
477          return;
478    }
479    else {
480       buffers = dri2_drawable_get_buffers(drawable, statts, &num_buffers);
481       if (!buffers || (drawable->old_num == num_buffers &&
482                        drawable->old_w == dri_drawable->w &&
483                        drawable->old_h == dri_drawable->h &&
484                        memcmp(drawable->old, buffers,
485                               sizeof(__DRIbuffer) * num_buffers) == 0))
486          return;
487    }
488 
489    /* Second clean useless resources*/
490 
491    /* See if we need a depth-stencil buffer. */
492    for (i = 0; i < statts_count; i++) {
493       if (statts[i] == ST_ATTACHMENT_DEPTH_STENCIL) {
494          alloc_depthstencil = TRUE;
495          break;
496       }
497    }
498 
499    /* Delete the resources we won't need. */
500    for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
501       /* Don't delete the depth-stencil buffer, we can reuse it. */
502       if (i == ST_ATTACHMENT_DEPTH_STENCIL && alloc_depthstencil)
503          continue;
504 
505       /* Flush the texture before unreferencing, so that other clients can
506        * see what the driver has rendered.
507        */
508       if (i != ST_ATTACHMENT_DEPTH_STENCIL && drawable->textures[i]) {
509          struct pipe_context *pipe = ctx->st->pipe;
510          pipe->flush_resource(pipe, drawable->textures[i]);
511       }
512 
513       pipe_resource_reference(&drawable->textures[i], NULL);
514    }
515 
516    if (drawable->stvis.samples > 1) {
517       for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
518          boolean del = TRUE;
519 
520          /* Don't delete MSAA resources for the attachments which are enabled,
521           * we can reuse them. */
522          for (j = 0; j < statts_count; j++) {
523             if (i == statts[j]) {
524                del = FALSE;
525                break;
526             }
527          }
528 
529          if (del) {
530             pipe_resource_reference(&drawable->msaa_textures[i], NULL);
531          }
532       }
533    }
534 
535    /* Third use the buffers retrieved to fill the drawable info */
536 
537    memset(&templ, 0, sizeof(templ));
538    templ.target = screen->target;
539    templ.last_level = 0;
540    templ.depth0 = 1;
541    templ.array_size = 1;
542 
543    if (image) {
544       if (images.image_mask & __DRI_IMAGE_BUFFER_FRONT) {
545          struct pipe_resource **buf =
546             &drawable->textures[ST_ATTACHMENT_FRONT_LEFT];
547          struct pipe_resource *texture = images.front->texture;
548 
549          dri_drawable->w = texture->width0;
550          dri_drawable->h = texture->height0;
551 
552          pipe_resource_reference(buf, texture);
553       }
554 
555       if (images.image_mask & __DRI_IMAGE_BUFFER_BACK) {
556          struct pipe_resource **buf =
557             &drawable->textures[ST_ATTACHMENT_BACK_LEFT];
558          struct pipe_resource *texture = images.back->texture;
559 
560          dri_drawable->w = texture->width0;
561          dri_drawable->h = texture->height0;
562 
563          pipe_resource_reference(buf, texture);
564       }
565 
566       /* Note: if there is both a back and a front buffer,
567        * then they have the same size.
568        */
569       templ.width0 = dri_drawable->w;
570       templ.height0 = dri_drawable->h;
571    }
572    else {
573       memset(&whandle, 0, sizeof(whandle));
574 
575       /* Process DRI-provided buffers and get pipe_resources. */
576       for (i = 0; i < num_buffers; i++) {
577          __DRIbuffer *buf = &buffers[i];
578          enum st_attachment_type statt;
579          enum pipe_format format;
580 
581          switch (buf->attachment) {
582          case __DRI_BUFFER_FRONT_LEFT:
583             if (!screen->auto_fake_front) {
584                continue; /* invalid attachment */
585             }
586             /* fallthrough */
587          case __DRI_BUFFER_FAKE_FRONT_LEFT:
588             statt = ST_ATTACHMENT_FRONT_LEFT;
589             break;
590          case __DRI_BUFFER_BACK_LEFT:
591             statt = ST_ATTACHMENT_BACK_LEFT;
592             break;
593          default:
594             continue; /* invalid attachment */
595          }
596 
597          dri_drawable_get_format(drawable, statt, &format, &bind);
598          if (format == PIPE_FORMAT_NONE)
599             continue;
600 
601          /* dri2_drawable_get_buffers has already filled dri_drawable->w
602           * and dri_drawable->h */
603          templ.width0 = dri_drawable->w;
604          templ.height0 = dri_drawable->h;
605          templ.format = format;
606          templ.bind = bind;
607          whandle.handle = buf->name;
608          whandle.stride = buf->pitch;
609          whandle.offset = 0;
610          if (screen->can_share_buffer)
611             whandle.type = DRM_API_HANDLE_TYPE_SHARED;
612          else
613             whandle.type = DRM_API_HANDLE_TYPE_KMS;
614          drawable->textures[statt] =
615             screen->base.screen->resource_from_handle(screen->base.screen,
616                   &templ, &whandle,
617                   PIPE_HANDLE_USAGE_EXPLICIT_FLUSH | PIPE_HANDLE_USAGE_READ);
618          assert(drawable->textures[statt]);
619       }
620    }
621 
622    /* Allocate private MSAA colorbuffers. */
623    if (drawable->stvis.samples > 1) {
624       for (i = 0; i < statts_count; i++) {
625          enum st_attachment_type statt = statts[i];
626 
627          if (statt == ST_ATTACHMENT_DEPTH_STENCIL)
628             continue;
629 
630          if (drawable->textures[statt]) {
631             templ.format = drawable->textures[statt]->format;
632             templ.bind = drawable->textures[statt]->bind & ~PIPE_BIND_SCANOUT;
633             templ.nr_samples = drawable->stvis.samples;
634 
635             /* Try to reuse the resource.
636              * (the other resource parameters should be constant)
637              */
638             if (!drawable->msaa_textures[statt] ||
639                 drawable->msaa_textures[statt]->width0 != templ.width0 ||
640                 drawable->msaa_textures[statt]->height0 != templ.height0) {
641                /* Allocate a new one. */
642                pipe_resource_reference(&drawable->msaa_textures[statt], NULL);
643 
644                drawable->msaa_textures[statt] =
645                   screen->base.screen->resource_create(screen->base.screen,
646                                                        &templ);
647                assert(drawable->msaa_textures[statt]);
648 
649                /* If there are any MSAA resources, we should initialize them
650                 * such that they contain the same data as the single-sample
651                 * resources we just got from the X server.
652                 *
653                 * The reason for this is that the state tracker (and
654                 * therefore the app) can access the MSAA resources only.
655                 * The single-sample resources are not exposed
656                 * to the state tracker.
657                 *
658                 */
659                dri_pipe_blit(ctx->st->pipe,
660                              drawable->msaa_textures[statt],
661                              drawable->textures[statt]);
662             }
663          }
664          else {
665             pipe_resource_reference(&drawable->msaa_textures[statt], NULL);
666          }
667       }
668    }
669 
670    /* Allocate a private depth-stencil buffer. */
671    if (alloc_depthstencil) {
672       enum st_attachment_type statt = ST_ATTACHMENT_DEPTH_STENCIL;
673       struct pipe_resource **zsbuf;
674       enum pipe_format format;
675       unsigned bind;
676 
677       dri_drawable_get_format(drawable, statt, &format, &bind);
678 
679       if (format) {
680          templ.format = format;
681          templ.bind = bind;
682 
683          if (drawable->stvis.samples > 1) {
684             templ.nr_samples = drawable->stvis.samples;
685             zsbuf = &drawable->msaa_textures[statt];
686          }
687          else {
688             templ.nr_samples = 0;
689             zsbuf = &drawable->textures[statt];
690          }
691 
692          /* Try to reuse the resource.
693           * (the other resource parameters should be constant)
694           */
695          if (!*zsbuf ||
696              (*zsbuf)->width0 != templ.width0 ||
697              (*zsbuf)->height0 != templ.height0) {
698             /* Allocate a new one. */
699             pipe_resource_reference(zsbuf, NULL);
700             *zsbuf = screen->base.screen->resource_create(screen->base.screen,
701                                                           &templ);
702             assert(*zsbuf);
703          }
704       }
705       else {
706          pipe_resource_reference(&drawable->msaa_textures[statt], NULL);
707          pipe_resource_reference(&drawable->textures[statt], NULL);
708       }
709    }
710 
711    /* For DRI2, we may get the same buffers again from the server.
712     * To prevent useless imports of gem names, drawable->old* is used
713     * to bypass the import if we get the same buffers. This doesn't apply
714     * to DRI3/Wayland, users of image.loader, since the buffer is managed
715     * by the client (no import), and the back buffer is going to change
716     * at every redraw.
717     */
718    if (!image) {
719       drawable->old_num = num_buffers;
720       drawable->old_w = dri_drawable->w;
721       drawable->old_h = dri_drawable->h;
722       memcpy(drawable->old, buffers, sizeof(__DRIbuffer) * num_buffers);
723    }
724 }
725 
726 static void
dri2_flush_frontbuffer(struct dri_context * ctx,struct dri_drawable * drawable,enum st_attachment_type statt)727 dri2_flush_frontbuffer(struct dri_context *ctx,
728                        struct dri_drawable *drawable,
729                        enum st_attachment_type statt)
730 {
731    __DRIdrawable *dri_drawable = drawable->dPriv;
732    const __DRIimageLoaderExtension *image = drawable->sPriv->image.loader;
733    const __DRIdri2LoaderExtension *loader = drawable->sPriv->dri2.loader;
734    struct pipe_context *pipe = ctx->st->pipe;
735 
736    if (statt != ST_ATTACHMENT_FRONT_LEFT)
737       return;
738 
739    if (drawable->stvis.samples > 1) {
740       /* Resolve the front buffer. */
741       dri_pipe_blit(ctx->st->pipe,
742                     drawable->textures[ST_ATTACHMENT_FRONT_LEFT],
743                     drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT]);
744    }
745 
746    if (drawable->textures[ST_ATTACHMENT_FRONT_LEFT]) {
747       pipe->flush_resource(pipe, drawable->textures[ST_ATTACHMENT_FRONT_LEFT]);
748    }
749 
750    pipe->flush(pipe, NULL, 0);
751 
752    if (image) {
753       image->flushFrontBuffer(dri_drawable, dri_drawable->loaderPrivate);
754    }
755    else if (loader->flushFrontBuffer) {
756       loader->flushFrontBuffer(dri_drawable, dri_drawable->loaderPrivate);
757    }
758 }
759 
760 static void
dri2_update_tex_buffer(struct dri_drawable * drawable,struct dri_context * ctx,struct pipe_resource * res)761 dri2_update_tex_buffer(struct dri_drawable *drawable,
762                        struct dri_context *ctx,
763                        struct pipe_resource *res)
764 {
765    /* no-op */
766 }
767 
768 static __DRIimage *
dri2_lookup_egl_image(struct dri_screen * screen,void * handle)769 dri2_lookup_egl_image(struct dri_screen *screen, void *handle)
770 {
771    const __DRIimageLookupExtension *loader = screen->sPriv->dri2.image;
772    __DRIimage *img;
773 
774    if (!loader->lookupEGLImage)
775       return NULL;
776 
777    img = loader->lookupEGLImage(screen->sPriv,
778 				handle, screen->sPriv->loaderPrivate);
779 
780    return img;
781 }
782 
783 static __DRIimage *
dri2_create_image_from_winsys(__DRIscreen * _screen,int width,int height,int format,int num_handles,struct winsys_handle * whandle,void * loaderPrivate)784 dri2_create_image_from_winsys(__DRIscreen *_screen,
785                               int width, int height, int format,
786                               int num_handles, struct winsys_handle *whandle,
787                               void *loaderPrivate)
788 {
789    struct dri_screen *screen = dri_screen(_screen);
790    struct pipe_screen *pscreen = screen->base.screen;
791    __DRIimage *img;
792    struct pipe_resource templ;
793    unsigned tex_usage;
794    enum pipe_format pf;
795    int i;
796 
797    tex_usage = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
798 
799    pf = dri2_format_to_pipe_format (format);
800    if (pf == PIPE_FORMAT_NONE)
801       return NULL;
802 
803    img = CALLOC_STRUCT(__DRIimageRec);
804    if (!img)
805       return NULL;
806 
807    memset(&templ, 0, sizeof(templ));
808    templ.bind = tex_usage;
809    templ.target = screen->target;
810    templ.last_level = 0;
811    templ.depth0 = 1;
812    templ.array_size = 1;
813 
814    for (i = num_handles - 1; i >= 0; i--) {
815       struct pipe_resource *tex;
816 
817       /* TODO: something a lot less ugly */
818       switch (i) {
819       case 0:
820          templ.width0 = width;
821          templ.height0 = height;
822          templ.format = pf;
823          break;
824       case 1:
825          templ.width0 = width / 2;
826          templ.height0 = height / 2;
827          templ.format = (num_handles == 2) ?
828                PIPE_FORMAT_RG88_UNORM :   /* NV12, etc */
829                PIPE_FORMAT_R8_UNORM;      /* I420, etc */
830          break;
831       case 2:
832          templ.width0 = width / 2;
833          templ.height0 = height / 2;
834          templ.format = PIPE_FORMAT_R8_UNORM;
835          break;
836       default:
837          unreachable("too many planes!");
838       }
839 
840       tex = pscreen->resource_from_handle(pscreen,
841             &templ, &whandle[i], PIPE_HANDLE_USAGE_READ_WRITE);
842       if (!tex) {
843          pipe_resource_reference(&img->texture, NULL);
844          FREE(img);
845          return NULL;
846       }
847 
848       tex->next = img->texture;
849       img->texture = tex;
850    }
851 
852    img->level = 0;
853    img->layer = 0;
854    img->dri_format = format;
855    img->use = 0;
856    img->loader_private = loaderPrivate;
857 
858    return img;
859 }
860 
861 static __DRIimage *
dri2_create_image_from_name(__DRIscreen * _screen,int width,int height,int format,int name,int pitch,void * loaderPrivate)862 dri2_create_image_from_name(__DRIscreen *_screen,
863                             int width, int height, int format,
864                             int name, int pitch, void *loaderPrivate)
865 {
866    struct winsys_handle whandle;
867    enum pipe_format pf;
868 
869    memset(&whandle, 0, sizeof(whandle));
870    whandle.type = DRM_API_HANDLE_TYPE_SHARED;
871    whandle.handle = name;
872 
873    pf = dri2_format_to_pipe_format (format);
874    if (pf == PIPE_FORMAT_NONE)
875       return NULL;
876 
877    whandle.stride = pitch * util_format_get_blocksize(pf);
878 
879    return dri2_create_image_from_winsys(_screen, width, height, format,
880                                         1, &whandle, loaderPrivate);
881 }
882 
883 static __DRIimage *
dri2_create_image_from_fd(__DRIscreen * _screen,int width,int height,int fourcc,int * fds,int num_fds,int * strides,int * offsets,unsigned * error,int * dri_components,void * loaderPrivate)884 dri2_create_image_from_fd(__DRIscreen *_screen,
885                           int width, int height, int fourcc,
886                           int *fds, int num_fds, int *strides,
887                           int *offsets, unsigned *error,
888                           int *dri_components, void *loaderPrivate)
889 {
890    struct winsys_handle whandles[3];
891    int format;
892    __DRIimage *img = NULL;
893    unsigned err = __DRI_IMAGE_ERROR_SUCCESS;
894    int expected_num_fds, i;
895 
896    switch (fourcc) {
897    case __DRI_IMAGE_FOURCC_YUV420:
898    case __DRI_IMAGE_FOURCC_YVU420:
899       expected_num_fds = 3;
900       break;
901    case __DRI_IMAGE_FOURCC_NV12:
902       expected_num_fds = 2;
903       break;
904    default:
905       expected_num_fds = 1;
906       break;
907    }
908 
909    if (num_fds != expected_num_fds) {
910       err = __DRI_IMAGE_ERROR_BAD_MATCH;
911       goto exit;
912    }
913 
914    format = convert_fourcc(fourcc, dri_components);
915    if (format == -1) {
916       err = __DRI_IMAGE_ERROR_BAD_MATCH;
917       goto exit;
918    }
919 
920    memset(whandles, 0, sizeof(whandles));
921 
922    for (i = 0; i < num_fds; i++) {
923       if (fds[i] < 0) {
924          err = __DRI_IMAGE_ERROR_BAD_ALLOC;
925          goto exit;
926       }
927 
928       whandles[i].type = DRM_API_HANDLE_TYPE_FD;
929       whandles[i].handle = (unsigned)fds[i];
930       whandles[i].stride = (unsigned)strides[i];
931       whandles[i].offset = (unsigned)offsets[i];
932    }
933 
934    if (fourcc == __DRI_IMAGE_FOURCC_YVU420) {
935       /* convert to YUV420 by swapping 2nd and 3rd planes: */
936       struct winsys_handle tmp = whandles[1];
937       whandles[1] = whandles[2];
938       whandles[2] = tmp;
939       fourcc = __DRI_IMAGE_FOURCC_YUV420;
940    }
941 
942    img = dri2_create_image_from_winsys(_screen, width, height, format,
943                                        num_fds, whandles, loaderPrivate);
944    if(img == NULL)
945       err = __DRI_IMAGE_ERROR_BAD_ALLOC;
946 
947 exit:
948    if (error)
949       *error = err;
950 
951    return img;
952 }
953 
954 static __DRIimage *
dri2_create_image_from_renderbuffer(__DRIcontext * context,int renderbuffer,void * loaderPrivate)955 dri2_create_image_from_renderbuffer(__DRIcontext *context,
956 				    int renderbuffer, void *loaderPrivate)
957 {
958    struct dri_context *ctx = dri_context(context);
959 
960    if (!ctx->st->get_resource_for_egl_image)
961       return NULL;
962 
963    /* TODO */
964    return NULL;
965 }
966 
967 static __DRIimage *
dri2_create_image(__DRIscreen * _screen,int width,int height,int format,unsigned int use,void * loaderPrivate)968 dri2_create_image(__DRIscreen *_screen,
969                    int width, int height, int format,
970                    unsigned int use, void *loaderPrivate)
971 {
972    struct dri_screen *screen = dri_screen(_screen);
973    __DRIimage *img;
974    struct pipe_resource templ;
975    unsigned tex_usage;
976    enum pipe_format pf;
977 
978    tex_usage = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
979    if (use & __DRI_IMAGE_USE_SCANOUT)
980       tex_usage |= PIPE_BIND_SCANOUT;
981    if (use & __DRI_IMAGE_USE_SHARE)
982       tex_usage |= PIPE_BIND_SHARED;
983    if (use & __DRI_IMAGE_USE_LINEAR)
984       tex_usage |= PIPE_BIND_LINEAR;
985    if (use & __DRI_IMAGE_USE_CURSOR) {
986       if (width != 64 || height != 64)
987          return NULL;
988       tex_usage |= PIPE_BIND_CURSOR;
989    }
990 
991    pf = dri2_format_to_pipe_format (format);
992    if (pf == PIPE_FORMAT_NONE)
993       return NULL;
994 
995    img = CALLOC_STRUCT(__DRIimageRec);
996    if (!img)
997       return NULL;
998 
999    memset(&templ, 0, sizeof(templ));
1000    templ.bind = tex_usage;
1001    templ.format = pf;
1002    templ.target = PIPE_TEXTURE_2D;
1003    templ.last_level = 0;
1004    templ.width0 = width;
1005    templ.height0 = height;
1006    templ.depth0 = 1;
1007    templ.array_size = 1;
1008 
1009    img->texture = screen->base.screen->resource_create(screen->base.screen, &templ);
1010    if (!img->texture) {
1011       FREE(img);
1012       return NULL;
1013    }
1014 
1015    img->level = 0;
1016    img->layer = 0;
1017    img->dri_format = format;
1018    img->dri_components = 0;
1019    img->use = use;
1020 
1021    img->loader_private = loaderPrivate;
1022    return img;
1023 }
1024 
1025 static GLboolean
dri2_query_image(__DRIimage * image,int attrib,int * value)1026 dri2_query_image(__DRIimage *image, int attrib, int *value)
1027 {
1028    struct winsys_handle whandle;
1029    unsigned usage;
1030 
1031    if (image->use & __DRI_IMAGE_USE_BACKBUFFER)
1032       usage = PIPE_HANDLE_USAGE_EXPLICIT_FLUSH | PIPE_HANDLE_USAGE_READ;
1033    else
1034       usage = PIPE_HANDLE_USAGE_READ_WRITE;
1035 
1036    memset(&whandle, 0, sizeof(whandle));
1037 
1038    switch (attrib) {
1039    case __DRI_IMAGE_ATTRIB_STRIDE:
1040       whandle.type = DRM_API_HANDLE_TYPE_KMS;
1041       image->texture->screen->resource_get_handle(image->texture->screen,
1042             NULL, image->texture, &whandle, usage);
1043       *value = whandle.stride;
1044       return GL_TRUE;
1045    case __DRI_IMAGE_ATTRIB_HANDLE:
1046       whandle.type = DRM_API_HANDLE_TYPE_KMS;
1047       image->texture->screen->resource_get_handle(image->texture->screen,
1048          NULL, image->texture, &whandle, usage);
1049       *value = whandle.handle;
1050       return GL_TRUE;
1051    case __DRI_IMAGE_ATTRIB_NAME:
1052       whandle.type = DRM_API_HANDLE_TYPE_SHARED;
1053       image->texture->screen->resource_get_handle(image->texture->screen,
1054          NULL, image->texture, &whandle, usage);
1055       *value = whandle.handle;
1056       return GL_TRUE;
1057    case __DRI_IMAGE_ATTRIB_FD:
1058       whandle.type= DRM_API_HANDLE_TYPE_FD;
1059       if (!image->texture->screen->resource_get_handle(image->texture->screen,
1060             NULL, image->texture, &whandle, usage))
1061          return GL_FALSE;
1062 
1063       *value = whandle.handle;
1064       return GL_TRUE;
1065    case __DRI_IMAGE_ATTRIB_FORMAT:
1066       *value = image->dri_format;
1067       return GL_TRUE;
1068    case __DRI_IMAGE_ATTRIB_WIDTH:
1069       *value = image->texture->width0;
1070       return GL_TRUE;
1071    case __DRI_IMAGE_ATTRIB_HEIGHT:
1072       *value = image->texture->height0;
1073       return GL_TRUE;
1074    case __DRI_IMAGE_ATTRIB_COMPONENTS:
1075       if (image->dri_components == 0)
1076          return GL_FALSE;
1077       *value = image->dri_components;
1078       return GL_TRUE;
1079    case __DRI_IMAGE_ATTRIB_FOURCC:
1080       *value = convert_to_fourcc(image->dri_format);
1081       return GL_TRUE;
1082    case __DRI_IMAGE_ATTRIB_NUM_PLANES:
1083       *value = 1;
1084       return GL_TRUE;
1085    default:
1086       return GL_FALSE;
1087    }
1088 }
1089 
1090 static __DRIimage *
dri2_dup_image(__DRIimage * image,void * loaderPrivate)1091 dri2_dup_image(__DRIimage *image, void *loaderPrivate)
1092 {
1093    __DRIimage *img;
1094 
1095    img = CALLOC_STRUCT(__DRIimageRec);
1096    if (!img)
1097       return NULL;
1098 
1099    img->texture = NULL;
1100    pipe_resource_reference(&img->texture, image->texture);
1101    img->level = image->level;
1102    img->layer = image->layer;
1103    img->dri_format = image->dri_format;
1104    /* This should be 0 for sub images, but dup is also used for base images. */
1105    img->dri_components = image->dri_components;
1106    img->loader_private = loaderPrivate;
1107 
1108    return img;
1109 }
1110 
1111 static GLboolean
dri2_validate_usage(__DRIimage * image,unsigned int use)1112 dri2_validate_usage(__DRIimage *image, unsigned int use)
1113 {
1114    /*
1115     * Gallium drivers are bad at adding usages to the resources
1116     * once opened again in another process, which is the main use
1117     * case for this, so we have to lie.
1118     */
1119    if (image != NULL)
1120       return GL_TRUE;
1121    else
1122       return GL_FALSE;
1123 }
1124 
1125 static __DRIimage *
dri2_from_names(__DRIscreen * screen,int width,int height,int format,int * names,int num_names,int * strides,int * offsets,void * loaderPrivate)1126 dri2_from_names(__DRIscreen *screen, int width, int height, int format,
1127                 int *names, int num_names, int *strides, int *offsets,
1128                 void *loaderPrivate)
1129 {
1130    __DRIimage *img;
1131    int dri_components;
1132    struct winsys_handle whandle;
1133 
1134    if (num_names != 1)
1135       return NULL;
1136 
1137    format = convert_fourcc(format, &dri_components);
1138    if (format == -1)
1139       return NULL;
1140 
1141    memset(&whandle, 0, sizeof(whandle));
1142    whandle.type = DRM_API_HANDLE_TYPE_SHARED;
1143    whandle.handle = names[0];
1144    whandle.stride = strides[0];
1145    whandle.offset = offsets[0];
1146 
1147    img = dri2_create_image_from_winsys(screen, width, height, format,
1148                                        1, &whandle, loaderPrivate);
1149    if (img == NULL)
1150       return NULL;
1151 
1152    img->dri_components = dri_components;
1153    return img;
1154 }
1155 
1156 static __DRIimage *
dri2_from_planar(__DRIimage * image,int plane,void * loaderPrivate)1157 dri2_from_planar(__DRIimage *image, int plane, void *loaderPrivate)
1158 {
1159    __DRIimage *img;
1160 
1161    if (plane != 0)
1162       return NULL;
1163 
1164    if (image->dri_components == 0)
1165       return NULL;
1166 
1167    img = dri2_dup_image(image, loaderPrivate);
1168    if (img == NULL)
1169       return NULL;
1170 
1171    /* set this to 0 for sub images. */
1172    img->dri_components = 0;
1173    return img;
1174 }
1175 
1176 static __DRIimage *
dri2_create_from_texture(__DRIcontext * context,int target,unsigned texture,int depth,int level,unsigned * error,void * loaderPrivate)1177 dri2_create_from_texture(__DRIcontext *context, int target, unsigned texture,
1178                          int depth, int level, unsigned *error,
1179                          void *loaderPrivate)
1180 {
1181    __DRIimage *img;
1182    struct gl_context *ctx = ((struct st_context *)dri_context(context)->st)->ctx;
1183    struct gl_texture_object *obj;
1184    struct pipe_resource *tex;
1185    GLuint face = 0;
1186 
1187    obj = _mesa_lookup_texture(ctx, texture);
1188    if (!obj || obj->Target != target) {
1189       *error = __DRI_IMAGE_ERROR_BAD_PARAMETER;
1190       return NULL;
1191    }
1192 
1193    tex = st_get_texobj_resource(obj);
1194    if (!tex) {
1195       *error = __DRI_IMAGE_ERROR_BAD_PARAMETER;
1196       return NULL;
1197    }
1198 
1199    if (target == GL_TEXTURE_CUBE_MAP)
1200       face = depth;
1201 
1202    _mesa_test_texobj_completeness(ctx, obj);
1203    if (!obj->_BaseComplete || (level > 0 && !obj->_MipmapComplete)) {
1204       *error = __DRI_IMAGE_ERROR_BAD_PARAMETER;
1205       return NULL;
1206    }
1207 
1208    if (level < obj->BaseLevel || level > obj->_MaxLevel) {
1209       *error = __DRI_IMAGE_ERROR_BAD_MATCH;
1210       return NULL;
1211    }
1212 
1213    if (target == GL_TEXTURE_3D && obj->Image[face][level]->Depth < depth) {
1214       *error = __DRI_IMAGE_ERROR_BAD_MATCH;
1215       return NULL;
1216    }
1217 
1218    img = CALLOC_STRUCT(__DRIimageRec);
1219    if (!img) {
1220       *error = __DRI_IMAGE_ERROR_BAD_ALLOC;
1221       return NULL;
1222    }
1223 
1224    img->level = level;
1225    img->layer = depth;
1226    img->dri_format = driGLFormatToImageFormat(obj->Image[face][level]->TexFormat);
1227 
1228    img->loader_private = loaderPrivate;
1229 
1230    if (img->dri_format == __DRI_IMAGE_FORMAT_NONE) {
1231       *error = __DRI_IMAGE_ERROR_BAD_PARAMETER;
1232       free(img);
1233       return NULL;
1234    }
1235 
1236    pipe_resource_reference(&img->texture, tex);
1237 
1238    *error = __DRI_IMAGE_ERROR_SUCCESS;
1239    return img;
1240 }
1241 
1242 static __DRIimage *
dri2_from_fds(__DRIscreen * screen,int width,int height,int fourcc,int * fds,int num_fds,int * strides,int * offsets,void * loaderPrivate)1243 dri2_from_fds(__DRIscreen *screen, int width, int height, int fourcc,
1244               int *fds, int num_fds, int *strides, int *offsets,
1245               void *loaderPrivate)
1246 {
1247    __DRIimage *img;
1248    int dri_components;
1249 
1250    img = dri2_create_image_from_fd(screen, width, height, fourcc,
1251                                    fds, num_fds, strides, offsets, NULL,
1252                                    &dri_components, loaderPrivate);
1253    if (img == NULL)
1254       return NULL;
1255 
1256    img->dri_components = dri_components;
1257    return img;
1258 }
1259 
1260 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)1261 dri2_from_dma_bufs(__DRIscreen *screen,
1262                    int width, int height, int fourcc,
1263                    int *fds, int num_fds,
1264                    int *strides, int *offsets,
1265                    enum __DRIYUVColorSpace yuv_color_space,
1266                    enum __DRISampleRange sample_range,
1267                    enum __DRIChromaSiting horizontal_siting,
1268                    enum __DRIChromaSiting vertical_siting,
1269                    unsigned *error,
1270                    void *loaderPrivate)
1271 {
1272    __DRIimage *img;
1273    int dri_components;
1274 
1275    img = dri2_create_image_from_fd(screen, width, height, fourcc,
1276                                    fds, num_fds, strides, offsets, error,
1277                                    &dri_components, loaderPrivate);
1278    if (img == NULL)
1279       return NULL;
1280 
1281    img->yuv_color_space = yuv_color_space;
1282    img->sample_range = sample_range;
1283    img->horizontal_siting = horizontal_siting;
1284    img->vertical_siting = vertical_siting;
1285    img->dri_components = dri_components;
1286 
1287    *error = __DRI_IMAGE_ERROR_SUCCESS;
1288    return img;
1289 }
1290 
1291 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)1292 dri2_blit_image(__DRIcontext *context, __DRIimage *dst, __DRIimage *src,
1293                 int dstx0, int dsty0, int dstwidth, int dstheight,
1294                 int srcx0, int srcy0, int srcwidth, int srcheight,
1295                 int flush_flag)
1296 {
1297    struct dri_context *ctx = dri_context(context);
1298    struct pipe_context *pipe = ctx->st->pipe;
1299    struct pipe_screen *screen;
1300    struct pipe_fence_handle *fence;
1301    struct pipe_blit_info blit;
1302 
1303    if (!dst || !src)
1304       return;
1305 
1306    memset(&blit, 0, sizeof(blit));
1307    blit.dst.resource = dst->texture;
1308    blit.dst.box.x = dstx0;
1309    blit.dst.box.y = dsty0;
1310    blit.dst.box.width = dstwidth;
1311    blit.dst.box.height = dstheight;
1312    blit.dst.box.depth = 1;
1313    blit.dst.format = dst->texture->format;
1314    blit.src.resource = src->texture;
1315    blit.src.box.x = srcx0;
1316    blit.src.box.y = srcy0;
1317    blit.src.box.width = srcwidth;
1318    blit.src.box.height = srcheight;
1319    blit.src.box.depth = 1;
1320    blit.src.format = src->texture->format;
1321    blit.mask = PIPE_MASK_RGBA;
1322    blit.filter = PIPE_TEX_FILTER_NEAREST;
1323 
1324    pipe->blit(pipe, &blit);
1325 
1326    if (flush_flag == __BLIT_FLAG_FLUSH) {
1327       pipe->flush_resource(pipe, dst->texture);
1328       ctx->st->flush(ctx->st, 0, NULL);
1329    } else if (flush_flag == __BLIT_FLAG_FINISH) {
1330       screen = dri_screen(ctx->sPriv)->base.screen;
1331       pipe->flush_resource(pipe, dst->texture);
1332       ctx->st->flush(ctx->st, 0, &fence);
1333       (void) screen->fence_finish(screen, NULL, fence, PIPE_TIMEOUT_INFINITE);
1334       screen->fence_reference(screen, &fence, NULL);
1335    }
1336 }
1337 
1338 static void *
dri2_map_image(__DRIcontext * context,__DRIimage * image,int x0,int y0,int width,int height,unsigned int flags,int * stride,void ** data)1339 dri2_map_image(__DRIcontext *context, __DRIimage *image,
1340                 int x0, int y0, int width, int height,
1341                 unsigned int flags, int *stride, void **data)
1342 {
1343    struct dri_context *ctx = dri_context(context);
1344    struct pipe_context *pipe = ctx->st->pipe;
1345    enum pipe_transfer_usage pipe_access = 0;
1346    struct pipe_transfer *trans;
1347    void *map;
1348 
1349    if (!image || !data || *data)
1350       return NULL;
1351 
1352    if (flags & __DRI_IMAGE_TRANSFER_READ)
1353          pipe_access |= PIPE_TRANSFER_READ;
1354    if (flags & __DRI_IMAGE_TRANSFER_WRITE)
1355          pipe_access |= PIPE_TRANSFER_WRITE;
1356 
1357    map = pipe_transfer_map(pipe, image->texture,
1358                            0, 0, pipe_access, x0, y0, width, height,
1359                            &trans);
1360    if (map) {
1361       *data = trans;
1362       *stride = trans->stride;
1363    }
1364 
1365    return map;
1366 }
1367 
1368 static void
dri2_unmap_image(__DRIcontext * context,__DRIimage * image,void * data)1369 dri2_unmap_image(__DRIcontext *context, __DRIimage *image, void *data)
1370 {
1371    struct dri_context *ctx = dri_context(context);
1372    struct pipe_context *pipe = ctx->st->pipe;
1373 
1374    pipe_transfer_unmap(pipe, (struct pipe_transfer *)data);
1375 }
1376 
1377 static void
dri2_destroy_image(__DRIimage * img)1378 dri2_destroy_image(__DRIimage *img)
1379 {
1380    pipe_resource_reference(&img->texture, NULL);
1381    FREE(img);
1382 }
1383 
1384 static int
dri2_get_capabilities(__DRIscreen * _screen)1385 dri2_get_capabilities(__DRIscreen *_screen)
1386 {
1387    struct dri_screen *screen = dri_screen(_screen);
1388 
1389    return (screen->can_share_buffer ? __DRI_IMAGE_CAP_GLOBAL_NAMES : 0);
1390 }
1391 
1392 /* The extension is modified during runtime if DRI_PRIME is detected */
1393 static __DRIimageExtension dri2ImageExtension = {
1394     .base = { __DRI_IMAGE, 12 },
1395 
1396     .createImageFromName          = dri2_create_image_from_name,
1397     .createImageFromRenderbuffer  = dri2_create_image_from_renderbuffer,
1398     .destroyImage                 = dri2_destroy_image,
1399     .createImage                  = dri2_create_image,
1400     .queryImage                   = dri2_query_image,
1401     .dupImage                     = dri2_dup_image,
1402     .validateUsage                = dri2_validate_usage,
1403     .createImageFromNames         = dri2_from_names,
1404     .fromPlanar                   = dri2_from_planar,
1405     .createImageFromTexture       = dri2_create_from_texture,
1406     .createImageFromFds           = NULL,
1407     .createImageFromDmaBufs       = NULL,
1408     .blitImage                    = dri2_blit_image,
1409     .getCapabilities              = dri2_get_capabilities,
1410     .mapImage                     = dri2_map_image,
1411     .unmapImage                   = dri2_unmap_image,
1412 };
1413 
1414 
1415 static bool
dri2_is_opencl_interop_loaded_locked(struct dri_screen * screen)1416 dri2_is_opencl_interop_loaded_locked(struct dri_screen *screen)
1417 {
1418    return screen->opencl_dri_event_add_ref &&
1419           screen->opencl_dri_event_release &&
1420           screen->opencl_dri_event_wait &&
1421           screen->opencl_dri_event_get_fence;
1422 }
1423 
1424 static bool
dri2_load_opencl_interop(struct dri_screen * screen)1425 dri2_load_opencl_interop(struct dri_screen *screen)
1426 {
1427 #if defined(RTLD_DEFAULT)
1428    bool success;
1429 
1430    pipe_mutex_lock(screen->opencl_func_mutex);
1431 
1432    if (dri2_is_opencl_interop_loaded_locked(screen)) {
1433       pipe_mutex_unlock(screen->opencl_func_mutex);
1434       return true;
1435    }
1436 
1437    screen->opencl_dri_event_add_ref =
1438       dlsym(RTLD_DEFAULT, "opencl_dri_event_add_ref");
1439    screen->opencl_dri_event_release =
1440       dlsym(RTLD_DEFAULT, "opencl_dri_event_release");
1441    screen->opencl_dri_event_wait =
1442       dlsym(RTLD_DEFAULT, "opencl_dri_event_wait");
1443    screen->opencl_dri_event_get_fence =
1444       dlsym(RTLD_DEFAULT, "opencl_dri_event_get_fence");
1445 
1446    success = dri2_is_opencl_interop_loaded_locked(screen);
1447    pipe_mutex_unlock(screen->opencl_func_mutex);
1448    return success;
1449 #else
1450    return false;
1451 #endif
1452 }
1453 
1454 struct dri2_fence {
1455    struct dri_screen *driscreen;
1456    struct pipe_fence_handle *pipe_fence;
1457    void *cl_event;
1458 };
1459 
dri2_fence_get_caps(__DRIscreen * _screen)1460 static unsigned dri2_fence_get_caps(__DRIscreen *_screen)
1461 {
1462    struct dri_screen *driscreen = dri_screen(_screen);
1463    struct pipe_screen *screen = driscreen->base.screen;
1464    unsigned caps = 0;
1465 
1466    if (screen->get_param(screen, PIPE_CAP_NATIVE_FENCE_FD))
1467       caps |= __DRI_FENCE_CAP_NATIVE_FD;
1468 
1469    return caps;
1470 }
1471 
1472 static void *
dri2_create_fence(__DRIcontext * _ctx)1473 dri2_create_fence(__DRIcontext *_ctx)
1474 {
1475    struct pipe_context *ctx = dri_context(_ctx)->st->pipe;
1476    struct dri2_fence *fence = CALLOC_STRUCT(dri2_fence);
1477 
1478    if (!fence)
1479       return NULL;
1480 
1481    ctx->flush(ctx, &fence->pipe_fence, 0);
1482 
1483    if (!fence->pipe_fence) {
1484       FREE(fence);
1485       return NULL;
1486    }
1487 
1488    fence->driscreen = dri_screen(_ctx->driScreenPriv);
1489    return fence;
1490 }
1491 
1492 static void *
dri2_create_fence_fd(__DRIcontext * _ctx,int fd)1493 dri2_create_fence_fd(__DRIcontext *_ctx, int fd)
1494 {
1495    struct pipe_context *ctx = dri_context(_ctx)->st->pipe;
1496    struct dri2_fence *fence = CALLOC_STRUCT(dri2_fence);
1497 
1498    if (fd == -1) {
1499       /* exporting driver created fence, flush: */
1500       ctx->flush(ctx, &fence->pipe_fence,
1501                  PIPE_FLUSH_DEFERRED | PIPE_FLUSH_FENCE_FD);
1502    } else {
1503       /* importing a foreign fence fd: */
1504       ctx->create_fence_fd(ctx, &fence->pipe_fence, fd);
1505    }
1506    if (!fence->pipe_fence) {
1507       FREE(fence);
1508       return NULL;
1509    }
1510 
1511    fence->driscreen = dri_screen(_ctx->driScreenPriv);
1512    return fence;
1513 }
1514 
1515 static int
dri2_get_fence_fd(__DRIscreen * _screen,void * _fence)1516 dri2_get_fence_fd(__DRIscreen *_screen, void *_fence)
1517 {
1518    struct dri_screen *driscreen = dri_screen(_screen);
1519    struct pipe_screen *screen = driscreen->base.screen;
1520    struct dri2_fence *fence = (struct dri2_fence*)_fence;
1521 
1522    return screen->fence_get_fd(screen, fence->pipe_fence);
1523 }
1524 
1525 static void *
dri2_get_fence_from_cl_event(__DRIscreen * _screen,intptr_t cl_event)1526 dri2_get_fence_from_cl_event(__DRIscreen *_screen, intptr_t cl_event)
1527 {
1528    struct dri_screen *driscreen = dri_screen(_screen);
1529    struct dri2_fence *fence;
1530 
1531    if (!dri2_load_opencl_interop(driscreen))
1532       return NULL;
1533 
1534    fence = CALLOC_STRUCT(dri2_fence);
1535    if (!fence)
1536       return NULL;
1537 
1538    fence->cl_event = (void*)cl_event;
1539 
1540    if (!driscreen->opencl_dri_event_add_ref(fence->cl_event)) {
1541       free(fence);
1542       return NULL;
1543    }
1544 
1545    fence->driscreen = driscreen;
1546    return fence;
1547 }
1548 
1549 static void
dri2_destroy_fence(__DRIscreen * _screen,void * _fence)1550 dri2_destroy_fence(__DRIscreen *_screen, void *_fence)
1551 {
1552    struct dri_screen *driscreen = dri_screen(_screen);
1553    struct pipe_screen *screen = driscreen->base.screen;
1554    struct dri2_fence *fence = (struct dri2_fence*)_fence;
1555 
1556    if (fence->pipe_fence)
1557       screen->fence_reference(screen, &fence->pipe_fence, NULL);
1558    else if (fence->cl_event)
1559       driscreen->opencl_dri_event_release(fence->cl_event);
1560    else
1561       assert(0);
1562 
1563    FREE(fence);
1564 }
1565 
1566 static GLboolean
dri2_client_wait_sync(__DRIcontext * _ctx,void * _fence,unsigned flags,uint64_t timeout)1567 dri2_client_wait_sync(__DRIcontext *_ctx, void *_fence, unsigned flags,
1568                       uint64_t timeout)
1569 {
1570    struct dri2_fence *fence = (struct dri2_fence*)_fence;
1571    struct dri_screen *driscreen = fence->driscreen;
1572    struct pipe_screen *screen = driscreen->base.screen;
1573 
1574    /* No need to flush. The context was flushed when the fence was created. */
1575 
1576    if (fence->pipe_fence)
1577       return screen->fence_finish(screen, NULL, fence->pipe_fence, timeout);
1578    else if (fence->cl_event) {
1579       struct pipe_fence_handle *pipe_fence =
1580          driscreen->opencl_dri_event_get_fence(fence->cl_event);
1581 
1582       if (pipe_fence)
1583          return screen->fence_finish(screen, NULL, pipe_fence, timeout);
1584       else
1585          return driscreen->opencl_dri_event_wait(fence->cl_event, timeout);
1586    }
1587    else {
1588       assert(0);
1589       return false;
1590    }
1591 }
1592 
1593 static void
dri2_server_wait_sync(__DRIcontext * _ctx,void * _fence,unsigned flags)1594 dri2_server_wait_sync(__DRIcontext *_ctx, void *_fence, unsigned flags)
1595 {
1596    struct pipe_context *ctx = dri_context(_ctx)->st->pipe;
1597    struct dri2_fence *fence = (struct dri2_fence*)_fence;
1598 
1599    if (ctx->fence_server_sync)
1600       ctx->fence_server_sync(ctx, fence->pipe_fence);
1601 }
1602 
1603 static __DRI2fenceExtension dri2FenceExtension = {
1604    .base = { __DRI2_FENCE, 2 },
1605 
1606    .create_fence = dri2_create_fence,
1607    .get_fence_from_cl_event = dri2_get_fence_from_cl_event,
1608    .destroy_fence = dri2_destroy_fence,
1609    .client_wait_sync = dri2_client_wait_sync,
1610    .server_wait_sync = dri2_server_wait_sync,
1611    .get_capabilities = dri2_fence_get_caps,
1612    .create_fence_fd = dri2_create_fence_fd,
1613    .get_fence_fd = dri2_get_fence_fd,
1614 };
1615 
1616 static const __DRIrobustnessExtension dri2Robustness = {
1617    .base = { __DRI2_ROBUSTNESS, 1 }
1618 };
1619 
1620 static int
dri2_interop_query_device_info(__DRIcontext * _ctx,struct mesa_glinterop_device_info * out)1621 dri2_interop_query_device_info(__DRIcontext *_ctx,
1622                                struct mesa_glinterop_device_info *out)
1623 {
1624    struct pipe_screen *screen = dri_context(_ctx)->st->pipe->screen;
1625 
1626    /* There is no version 0, thus we do not support it */
1627    if (out->version == 0)
1628       return MESA_GLINTEROP_INVALID_VERSION;
1629 
1630    out->pci_segment_group = screen->get_param(screen, PIPE_CAP_PCI_GROUP);
1631    out->pci_bus = screen->get_param(screen, PIPE_CAP_PCI_BUS);
1632    out->pci_device = screen->get_param(screen, PIPE_CAP_PCI_DEVICE);
1633    out->pci_function = screen->get_param(screen, PIPE_CAP_PCI_FUNCTION);
1634 
1635    out->vendor_id = screen->get_param(screen, PIPE_CAP_VENDOR_ID);
1636    out->device_id = screen->get_param(screen, PIPE_CAP_DEVICE_ID);
1637 
1638    /* Instruct the caller that we support up-to version one of the interface */
1639    out->version = 1;
1640 
1641    return MESA_GLINTEROP_SUCCESS;
1642 }
1643 
1644 static int
dri2_interop_export_object(__DRIcontext * _ctx,struct mesa_glinterop_export_in * in,struct mesa_glinterop_export_out * out)1645 dri2_interop_export_object(__DRIcontext *_ctx,
1646                            struct mesa_glinterop_export_in *in,
1647                            struct mesa_glinterop_export_out *out)
1648 {
1649    struct st_context_iface *st = dri_context(_ctx)->st;
1650    struct pipe_screen *screen = st->pipe->screen;
1651    struct gl_context *ctx = ((struct st_context *)st)->ctx;
1652    struct pipe_resource *res = NULL;
1653    struct winsys_handle whandle;
1654    unsigned target, usage;
1655    boolean success;
1656 
1657    /* There is no version 0, thus we do not support it */
1658    if (in->version == 0 || out->version == 0)
1659       return MESA_GLINTEROP_INVALID_VERSION;
1660 
1661    /* Validate the target. */
1662    switch (in->target) {
1663    case GL_TEXTURE_BUFFER:
1664    case GL_TEXTURE_1D:
1665    case GL_TEXTURE_2D:
1666    case GL_TEXTURE_3D:
1667    case GL_TEXTURE_RECTANGLE:
1668    case GL_TEXTURE_1D_ARRAY:
1669    case GL_TEXTURE_2D_ARRAY:
1670    case GL_TEXTURE_CUBE_MAP_ARRAY:
1671    case GL_TEXTURE_CUBE_MAP:
1672    case GL_TEXTURE_2D_MULTISAMPLE:
1673    case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
1674    case GL_TEXTURE_EXTERNAL_OES:
1675    case GL_RENDERBUFFER:
1676    case GL_ARRAY_BUFFER:
1677       target = in->target;
1678       break;
1679    case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1680    case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1681    case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1682    case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1683    case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1684    case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1685       target = GL_TEXTURE_CUBE_MAP;
1686       break;
1687    default:
1688       return MESA_GLINTEROP_INVALID_TARGET;
1689    }
1690 
1691    /* Validate the simple case of miplevel. */
1692    if ((target == GL_RENDERBUFFER || target == GL_ARRAY_BUFFER) &&
1693        in->miplevel != 0)
1694       return MESA_GLINTEROP_INVALID_MIP_LEVEL;
1695 
1696    /* Validate the OpenGL object and get pipe_resource. */
1697    mtx_lock(&ctx->Shared->Mutex);
1698 
1699    if (target == GL_ARRAY_BUFFER) {
1700       /* Buffer objects.
1701        *
1702        * The error checking is based on the documentation of
1703        * clCreateFromGLBuffer from OpenCL 2.0 SDK.
1704        */
1705       struct gl_buffer_object *buf = _mesa_lookup_bufferobj(ctx, in->obj);
1706 
1707       /* From OpenCL 2.0 SDK, clCreateFromGLBuffer:
1708        *  "CL_INVALID_GL_OBJECT if bufobj is not a GL buffer object or is
1709        *   a GL buffer object but does not have an existing data store or
1710        *   the size of the buffer is 0."
1711        */
1712       if (!buf || buf->Size == 0) {
1713          mtx_unlock(&ctx->Shared->Mutex);
1714          return MESA_GLINTEROP_INVALID_OBJECT;
1715       }
1716 
1717       res = st_buffer_object(buf)->buffer;
1718       if (!res) {
1719          /* this shouldn't happen */
1720          mtx_unlock(&ctx->Shared->Mutex);
1721          return MESA_GLINTEROP_INVALID_OBJECT;
1722       }
1723 
1724       out->buf_offset = 0;
1725       out->buf_size = buf->Size;
1726 
1727       buf->UsageHistory |= USAGE_DISABLE_MINMAX_CACHE;
1728    } else if (target == GL_RENDERBUFFER) {
1729       /* Renderbuffers.
1730        *
1731        * The error checking is based on the documentation of
1732        * clCreateFromGLRenderbuffer from OpenCL 2.0 SDK.
1733        */
1734       struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, in->obj);
1735 
1736       /* From OpenCL 2.0 SDK, clCreateFromGLRenderbuffer:
1737        *   "CL_INVALID_GL_OBJECT if renderbuffer is not a GL renderbuffer
1738        *    object or if the width or height of renderbuffer is zero."
1739        */
1740       if (!rb || rb->Width == 0 || rb->Height == 0) {
1741          mtx_unlock(&ctx->Shared->Mutex);
1742          return MESA_GLINTEROP_INVALID_OBJECT;
1743       }
1744 
1745       /* From OpenCL 2.0 SDK, clCreateFromGLRenderbuffer:
1746        *   "CL_INVALID_OPERATION if renderbuffer is a multi-sample GL
1747        *    renderbuffer object."
1748        */
1749       if (rb->NumSamples > 1) {
1750          mtx_unlock(&ctx->Shared->Mutex);
1751          return MESA_GLINTEROP_INVALID_OPERATION;
1752       }
1753 
1754       /* From OpenCL 2.0 SDK, clCreateFromGLRenderbuffer:
1755        *   "CL_OUT_OF_RESOURCES if there is a failure to allocate resources
1756        *    required by the OpenCL implementation on the device."
1757        */
1758       res = st_renderbuffer(rb)->texture;
1759       if (!res) {
1760          mtx_unlock(&ctx->Shared->Mutex);
1761          return MESA_GLINTEROP_OUT_OF_RESOURCES;
1762       }
1763 
1764       out->internal_format = rb->InternalFormat;
1765       out->view_minlevel = 0;
1766       out->view_numlevels = 1;
1767       out->view_minlayer = 0;
1768       out->view_numlayers = 1;
1769    } else {
1770       /* Texture objects.
1771        *
1772        * The error checking is based on the documentation of
1773        * clCreateFromGLTexture from OpenCL 2.0 SDK.
1774        */
1775       struct gl_texture_object *obj = _mesa_lookup_texture(ctx, in->obj);
1776 
1777       if (obj)
1778          _mesa_test_texobj_completeness(ctx, obj);
1779 
1780       /* From OpenCL 2.0 SDK, clCreateFromGLTexture:
1781        *   "CL_INVALID_GL_OBJECT if texture is not a GL texture object whose
1782        *    type matches texture_target, if the specified miplevel of texture
1783        *    is not defined, or if the width or height of the specified
1784        *    miplevel is zero or if the GL texture object is incomplete."
1785        */
1786       if (!obj ||
1787           obj->Target != target ||
1788           !obj->_BaseComplete ||
1789           (in->miplevel > 0 && !obj->_MipmapComplete)) {
1790          mtx_unlock(&ctx->Shared->Mutex);
1791          return MESA_GLINTEROP_INVALID_OBJECT;
1792       }
1793 
1794       /* From OpenCL 2.0 SDK, clCreateFromGLTexture:
1795        *   "CL_INVALID_MIP_LEVEL if miplevel is less than the value of
1796        *    levelbase (for OpenGL implementations) or zero (for OpenGL ES
1797        *    implementations); or greater than the value of q (for both OpenGL
1798        *    and OpenGL ES). levelbase and q are defined for the texture in
1799        *    section 3.8.10 (Texture Completeness) of the OpenGL 2.1
1800        *    specification and section 3.7.10 of the OpenGL ES 2.0."
1801        */
1802       if (in->miplevel < obj->BaseLevel || in->miplevel > obj->_MaxLevel) {
1803          mtx_unlock(&ctx->Shared->Mutex);
1804          return MESA_GLINTEROP_INVALID_MIP_LEVEL;
1805       }
1806 
1807       if (!st_finalize_texture(ctx, st->pipe, obj, 0)) {
1808          mtx_unlock(&ctx->Shared->Mutex);
1809          return MESA_GLINTEROP_OUT_OF_RESOURCES;
1810       }
1811 
1812       res = st_get_texobj_resource(obj);
1813       if (!res) {
1814          /* Incomplete texture buffer object? This shouldn't really occur. */
1815          mtx_unlock(&ctx->Shared->Mutex);
1816          return MESA_GLINTEROP_INVALID_OBJECT;
1817       }
1818 
1819       if (target == GL_TEXTURE_BUFFER) {
1820          out->internal_format = obj->BufferObjectFormat;
1821          out->buf_offset = obj->BufferOffset;
1822          out->buf_size = obj->BufferSize == -1 ? obj->BufferObject->Size :
1823                                                  obj->BufferSize;
1824 
1825          obj->BufferObject->UsageHistory |= USAGE_DISABLE_MINMAX_CACHE;
1826       } else {
1827          out->internal_format = obj->Image[0][0]->InternalFormat;
1828          out->view_minlevel = obj->MinLevel;
1829          out->view_numlevels = obj->NumLevels;
1830          out->view_minlayer = obj->MinLayer;
1831          out->view_numlayers = obj->NumLayers;
1832       }
1833    }
1834 
1835    /* Get the handle. */
1836    switch (in->access) {
1837    case MESA_GLINTEROP_ACCESS_READ_WRITE:
1838       usage = PIPE_HANDLE_USAGE_READ_WRITE;
1839       break;
1840    case MESA_GLINTEROP_ACCESS_READ_ONLY:
1841       usage = PIPE_HANDLE_USAGE_READ;
1842       break;
1843    case MESA_GLINTEROP_ACCESS_WRITE_ONLY:
1844       usage = PIPE_HANDLE_USAGE_WRITE;
1845       break;
1846    default:
1847       usage = 0;
1848    }
1849 
1850    memset(&whandle, 0, sizeof(whandle));
1851    whandle.type = DRM_API_HANDLE_TYPE_FD;
1852 
1853    success = screen->resource_get_handle(screen, st->pipe, res, &whandle,
1854                                          usage);
1855    mtx_unlock(&ctx->Shared->Mutex);
1856 
1857    if (!success)
1858       return MESA_GLINTEROP_OUT_OF_HOST_MEMORY;
1859 
1860    out->dmabuf_fd = whandle.handle;
1861    out->out_driver_data_written = 0;
1862 
1863    if (res->target == PIPE_BUFFER)
1864       out->buf_offset += whandle.offset;
1865 
1866    /* Instruct the caller that we support up-to version one of the interface */
1867    in->version = 1;
1868    out->version = 1;
1869 
1870    return MESA_GLINTEROP_SUCCESS;
1871 }
1872 
1873 static const __DRI2interopExtension dri2InteropExtension = {
1874    .base = { __DRI2_INTEROP, 1 },
1875    .query_device_info = dri2_interop_query_device_info,
1876    .export_object = dri2_interop_export_object
1877 };
1878 
1879 /*
1880  * Backend function init_screen.
1881  */
1882 
1883 static const __DRIextension *dri_screen_extensions[] = {
1884    &driTexBufferExtension.base,
1885    &dri2FlushExtension.base,
1886    &dri2ImageExtension.base,
1887    &dri2RendererQueryExtension.base,
1888    &dri2ConfigQueryExtension.base,
1889    &dri2ThrottleExtension.base,
1890    &dri2FenceExtension.base,
1891    &dri2InteropExtension.base,
1892    NULL
1893 };
1894 
1895 static const __DRIextension *dri_robust_screen_extensions[] = {
1896    &driTexBufferExtension.base,
1897    &dri2FlushExtension.base,
1898    &dri2ImageExtension.base,
1899    &dri2RendererQueryExtension.base,
1900    &dri2ConfigQueryExtension.base,
1901    &dri2ThrottleExtension.base,
1902    &dri2FenceExtension.base,
1903    &dri2InteropExtension.base,
1904    &dri2Robustness.base,
1905    NULL
1906 };
1907 
1908 /**
1909  * This is the driver specific part of the createNewScreen entry point.
1910  *
1911  * Returns the struct gl_config supported by this driver.
1912  */
1913 static const __DRIconfig **
dri2_init_screen(__DRIscreen * sPriv)1914 dri2_init_screen(__DRIscreen * sPriv)
1915 {
1916    const __DRIconfig **configs;
1917    struct dri_screen *screen;
1918    struct pipe_screen *pscreen = NULL;
1919    const struct drm_conf_ret *throttle_ret;
1920    const struct drm_conf_ret *dmabuf_ret;
1921    int fd;
1922 
1923    screen = CALLOC_STRUCT(dri_screen);
1924    if (!screen)
1925       return NULL;
1926 
1927    screen->sPriv = sPriv;
1928    screen->fd = sPriv->fd;
1929    pipe_mutex_init(screen->opencl_func_mutex);
1930 
1931    sPriv->driverPrivate = (void *)screen;
1932 
1933    if (screen->fd < 0 || (fd = fcntl(screen->fd, F_DUPFD_CLOEXEC, 3)) < 0)
1934       goto free_screen;
1935 
1936    if (pipe_loader_drm_probe_fd(&screen->dev, fd))
1937       pscreen = pipe_loader_create_screen(screen->dev);
1938 
1939    if (!pscreen)
1940        goto release_pipe;
1941 
1942    throttle_ret = pipe_loader_configuration(screen->dev, DRM_CONF_THROTTLE);
1943    dmabuf_ret = pipe_loader_configuration(screen->dev, DRM_CONF_SHARE_FD);
1944 
1945    if (throttle_ret && throttle_ret->val.val_int != -1) {
1946       screen->throttling_enabled = TRUE;
1947       screen->default_throttle_frames = throttle_ret->val.val_int;
1948    }
1949 
1950    if (dmabuf_ret && dmabuf_ret->val.val_bool) {
1951       uint64_t cap;
1952 
1953       if (drmGetCap(sPriv->fd, DRM_CAP_PRIME, &cap) == 0 &&
1954           (cap & DRM_PRIME_CAP_IMPORT)) {
1955          dri2ImageExtension.createImageFromFds = dri2_from_fds;
1956          dri2ImageExtension.createImageFromDmaBufs = dri2_from_dma_bufs;
1957       }
1958    }
1959 
1960    if (pscreen->get_param(pscreen, PIPE_CAP_DEVICE_RESET_STATUS_QUERY)) {
1961       sPriv->extensions = dri_robust_screen_extensions;
1962       screen->has_reset_status_query = true;
1963    }
1964    else
1965       sPriv->extensions = dri_screen_extensions;
1966 
1967    configs = dri_init_screen_helper(screen, pscreen, screen->dev->driver_name);
1968    if (!configs)
1969       goto destroy_screen;
1970 
1971    screen->can_share_buffer = true;
1972    screen->auto_fake_front = dri_with_format(sPriv);
1973    screen->broken_invalidate = !sPriv->dri2.useInvalidate;
1974    screen->lookup_egl_image = dri2_lookup_egl_image;
1975 
1976    return configs;
1977 
1978 destroy_screen:
1979    dri_destroy_screen_helper(screen);
1980 
1981 release_pipe:
1982    if (screen->dev)
1983       pipe_loader_release(&screen->dev, 1);
1984    else
1985       close(fd);
1986 
1987 free_screen:
1988    FREE(screen);
1989    return NULL;
1990 }
1991 
1992 /**
1993  * This is the driver specific part of the createNewScreen entry point.
1994  *
1995  * Returns the struct gl_config supported by this driver.
1996  */
1997 static const __DRIconfig **
dri_kms_init_screen(__DRIscreen * sPriv)1998 dri_kms_init_screen(__DRIscreen * sPriv)
1999 {
2000 #if defined(GALLIUM_SOFTPIPE)
2001    const __DRIconfig **configs;
2002    struct dri_screen *screen;
2003    struct pipe_screen *pscreen = NULL;
2004    uint64_t cap;
2005    int fd;
2006 
2007    screen = CALLOC_STRUCT(dri_screen);
2008    if (!screen)
2009       return NULL;
2010 
2011    screen->sPriv = sPriv;
2012    screen->fd = sPriv->fd;
2013 
2014    sPriv->driverPrivate = (void *)screen;
2015 
2016    if (screen->fd < 0 || (fd = fcntl(screen->fd, F_DUPFD_CLOEXEC, 3)) < 0)
2017       goto free_screen;
2018 
2019    if (pipe_loader_sw_probe_kms(&screen->dev, fd))
2020       pscreen = pipe_loader_create_screen(screen->dev);
2021 
2022    if (!pscreen)
2023        goto release_pipe;
2024 
2025    if (drmGetCap(sPriv->fd, DRM_CAP_PRIME, &cap) == 0 &&
2026           (cap & DRM_PRIME_CAP_IMPORT)) {
2027       dri2ImageExtension.createImageFromFds = dri2_from_fds;
2028       dri2ImageExtension.createImageFromDmaBufs = dri2_from_dma_bufs;
2029    }
2030 
2031    sPriv->extensions = dri_screen_extensions;
2032 
2033    configs = dri_init_screen_helper(screen, pscreen, "swrast");
2034    if (!configs)
2035       goto destroy_screen;
2036 
2037    screen->can_share_buffer = false;
2038    screen->auto_fake_front = dri_with_format(sPriv);
2039    screen->broken_invalidate = !sPriv->dri2.useInvalidate;
2040    screen->lookup_egl_image = dri2_lookup_egl_image;
2041 
2042    return configs;
2043 
2044 destroy_screen:
2045    dri_destroy_screen_helper(screen);
2046 
2047 release_pipe:
2048    if (screen->dev)
2049       pipe_loader_release(&screen->dev, 1);
2050    else
2051       close(fd);
2052 
2053 free_screen:
2054    FREE(screen);
2055 #endif // GALLIUM_SOFTPIPE
2056    return NULL;
2057 }
2058 
2059 static boolean
dri2_create_buffer(__DRIscreen * sPriv,__DRIdrawable * dPriv,const struct gl_config * visual,boolean isPixmap)2060 dri2_create_buffer(__DRIscreen * sPriv,
2061                    __DRIdrawable * dPriv,
2062                    const struct gl_config * visual, boolean isPixmap)
2063 {
2064    struct dri_drawable *drawable = NULL;
2065 
2066    if (!dri_create_buffer(sPriv, dPriv, visual, isPixmap))
2067       return FALSE;
2068 
2069    drawable = dPriv->driverPrivate;
2070 
2071    drawable->allocate_textures = dri2_allocate_textures;
2072    drawable->flush_frontbuffer = dri2_flush_frontbuffer;
2073    drawable->update_tex_buffer = dri2_update_tex_buffer;
2074 
2075    return TRUE;
2076 }
2077 
2078 /**
2079  * DRI driver virtual function table.
2080  *
2081  * DRI versions differ in their implementation of init_screen and swap_buffers.
2082  */
2083 const struct __DriverAPIRec galliumdrm_driver_api = {
2084    .InitScreen = dri2_init_screen,
2085    .DestroyScreen = dri_destroy_screen,
2086    .CreateContext = dri_create_context,
2087    .DestroyContext = dri_destroy_context,
2088    .CreateBuffer = dri2_create_buffer,
2089    .DestroyBuffer = dri_destroy_buffer,
2090    .MakeCurrent = dri_make_current,
2091    .UnbindContext = dri_unbind_context,
2092 
2093    .AllocateBuffer = dri2_allocate_buffer,
2094    .ReleaseBuffer  = dri2_release_buffer,
2095 };
2096 
2097 /**
2098  * DRI driver virtual function table.
2099  *
2100  * KMS/DRM version of the DriverAPI above sporting a different InitScreen
2101  * hook. The latter is used to explicitly initialise the kms_swrast driver
2102  * rather than selecting the approapriate driver as suggested by the loader.
2103  */
2104 const struct __DriverAPIRec dri_kms_driver_api = {
2105    .InitScreen = dri_kms_init_screen,
2106    .DestroyScreen = dri_destroy_screen,
2107    .CreateContext = dri_create_context,
2108    .DestroyContext = dri_destroy_context,
2109    .CreateBuffer = dri2_create_buffer,
2110    .DestroyBuffer = dri_destroy_buffer,
2111    .MakeCurrent = dri_make_current,
2112    .UnbindContext = dri_unbind_context,
2113 
2114    .AllocateBuffer = dri2_allocate_buffer,
2115    .ReleaseBuffer  = dri2_release_buffer,
2116 };
2117 
2118 /* This is the table of extensions that the loader will dlsym() for. */
2119 const __DRIextension *galliumdrm_driver_extensions[] = {
2120     &driCoreExtension.base,
2121     &driImageDriverExtension.base,
2122     &driDRI2Extension.base,
2123     &gallium_config_options.base,
2124     &dri2FenceExtension.base,
2125     NULL
2126 };
2127 
2128 /* vim: set sw=3 ts=8 sts=3 expandtab: */
2129