• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 #include <dlfcn.h>
24 #include "drm-uapi/drm_fourcc.h"
25 #include "util/u_memory.h"
26 #include "pipe/p_screen.h"
27 #include "state_tracker/st_texture.h"
28 #include "state_tracker/st_context.h"
29 #include "main/texobj.h"
30 
31 #include "dri_helpers.h"
32 
33 static bool
dri2_is_opencl_interop_loaded_locked(struct dri_screen * screen)34 dri2_is_opencl_interop_loaded_locked(struct dri_screen *screen)
35 {
36    return screen->opencl_dri_event_add_ref &&
37           screen->opencl_dri_event_release &&
38           screen->opencl_dri_event_wait &&
39           screen->opencl_dri_event_get_fence;
40 }
41 
42 static bool
dri2_load_opencl_interop(struct dri_screen * screen)43 dri2_load_opencl_interop(struct dri_screen *screen)
44 {
45 #if defined(RTLD_DEFAULT)
46    bool success;
47 
48    mtx_lock(&screen->opencl_func_mutex);
49 
50    if (dri2_is_opencl_interop_loaded_locked(screen)) {
51       mtx_unlock(&screen->opencl_func_mutex);
52       return true;
53    }
54 
55    screen->opencl_dri_event_add_ref =
56       dlsym(RTLD_DEFAULT, "opencl_dri_event_add_ref");
57    screen->opencl_dri_event_release =
58       dlsym(RTLD_DEFAULT, "opencl_dri_event_release");
59    screen->opencl_dri_event_wait =
60       dlsym(RTLD_DEFAULT, "opencl_dri_event_wait");
61    screen->opencl_dri_event_get_fence =
62       dlsym(RTLD_DEFAULT, "opencl_dri_event_get_fence");
63 
64    success = dri2_is_opencl_interop_loaded_locked(screen);
65    mtx_unlock(&screen->opencl_func_mutex);
66    return success;
67 #else
68    return false;
69 #endif
70 }
71 
72 struct dri2_fence {
73    struct dri_screen *driscreen;
74    struct pipe_fence_handle *pipe_fence;
75    void *cl_event;
76 };
77 
dri2_fence_get_caps(__DRIscreen * _screen)78 static unsigned dri2_fence_get_caps(__DRIscreen *_screen)
79 {
80    struct dri_screen *driscreen = dri_screen(_screen);
81    struct pipe_screen *screen = driscreen->base.screen;
82    unsigned caps = 0;
83 
84    if (screen->get_param(screen, PIPE_CAP_NATIVE_FENCE_FD))
85       caps |= __DRI_FENCE_CAP_NATIVE_FD;
86 
87    return caps;
88 }
89 
90 static void *
dri2_create_fence(__DRIcontext * _ctx)91 dri2_create_fence(__DRIcontext *_ctx)
92 {
93    struct st_context_iface *stapi = dri_context(_ctx)->st;
94    struct dri2_fence *fence = CALLOC_STRUCT(dri2_fence);
95 
96    if (!fence)
97       return NULL;
98 
99    stapi->flush(stapi, 0, &fence->pipe_fence, NULL, NULL);
100 
101    if (!fence->pipe_fence) {
102       FREE(fence);
103       return NULL;
104    }
105 
106    fence->driscreen = dri_screen(_ctx->driScreenPriv);
107    return fence;
108 }
109 
110 static void *
dri2_create_fence_fd(__DRIcontext * _ctx,int fd)111 dri2_create_fence_fd(__DRIcontext *_ctx, int fd)
112 {
113    struct st_context_iface *stapi = dri_context(_ctx)->st;
114    struct pipe_context *ctx = stapi->pipe;
115    struct dri2_fence *fence = CALLOC_STRUCT(dri2_fence);
116 
117    if (fd == -1) {
118       /* exporting driver created fence, flush: */
119       stapi->flush(stapi, ST_FLUSH_FENCE_FD, &fence->pipe_fence, NULL, NULL);
120    } else {
121       /* importing a foreign fence fd: */
122       ctx->create_fence_fd(ctx, &fence->pipe_fence, fd, PIPE_FD_TYPE_NATIVE_SYNC);
123    }
124    if (!fence->pipe_fence) {
125       FREE(fence);
126       return NULL;
127    }
128 
129    fence->driscreen = dri_screen(_ctx->driScreenPriv);
130    return fence;
131 }
132 
133 static int
dri2_get_fence_fd(__DRIscreen * _screen,void * _fence)134 dri2_get_fence_fd(__DRIscreen *_screen, void *_fence)
135 {
136    struct dri_screen *driscreen = dri_screen(_screen);
137    struct pipe_screen *screen = driscreen->base.screen;
138    struct dri2_fence *fence = (struct dri2_fence*)_fence;
139 
140    return screen->fence_get_fd(screen, fence->pipe_fence);
141 }
142 
143 static void *
dri2_get_fence_from_cl_event(__DRIscreen * _screen,intptr_t cl_event)144 dri2_get_fence_from_cl_event(__DRIscreen *_screen, intptr_t cl_event)
145 {
146    struct dri_screen *driscreen = dri_screen(_screen);
147    struct dri2_fence *fence;
148 
149    if (!dri2_load_opencl_interop(driscreen))
150       return NULL;
151 
152    fence = CALLOC_STRUCT(dri2_fence);
153    if (!fence)
154       return NULL;
155 
156    fence->cl_event = (void*)cl_event;
157 
158    if (!driscreen->opencl_dri_event_add_ref(fence->cl_event)) {
159       free(fence);
160       return NULL;
161    }
162 
163    fence->driscreen = driscreen;
164    return fence;
165 }
166 
167 static void
dri2_destroy_fence(__DRIscreen * _screen,void * _fence)168 dri2_destroy_fence(__DRIscreen *_screen, void *_fence)
169 {
170    struct dri_screen *driscreen = dri_screen(_screen);
171    struct pipe_screen *screen = driscreen->base.screen;
172    struct dri2_fence *fence = (struct dri2_fence*)_fence;
173 
174    if (fence->pipe_fence)
175       screen->fence_reference(screen, &fence->pipe_fence, NULL);
176    else if (fence->cl_event)
177       driscreen->opencl_dri_event_release(fence->cl_event);
178    else
179       assert(0);
180 
181    FREE(fence);
182 }
183 
184 static GLboolean
dri2_client_wait_sync(__DRIcontext * _ctx,void * _fence,unsigned flags,uint64_t timeout)185 dri2_client_wait_sync(__DRIcontext *_ctx, void *_fence, unsigned flags,
186                       uint64_t timeout)
187 {
188    struct dri2_fence *fence = (struct dri2_fence*)_fence;
189    struct dri_screen *driscreen = fence->driscreen;
190    struct pipe_screen *screen = driscreen->base.screen;
191 
192    /* No need to flush. The context was flushed when the fence was created. */
193 
194    if (fence->pipe_fence)
195       return screen->fence_finish(screen, NULL, fence->pipe_fence, timeout);
196    else if (fence->cl_event) {
197       struct pipe_fence_handle *pipe_fence =
198          driscreen->opencl_dri_event_get_fence(fence->cl_event);
199 
200       if (pipe_fence)
201          return screen->fence_finish(screen, NULL, pipe_fence, timeout);
202       else
203          return driscreen->opencl_dri_event_wait(fence->cl_event, timeout);
204    }
205    else {
206       assert(0);
207       return false;
208    }
209 }
210 
211 static void
dri2_server_wait_sync(__DRIcontext * _ctx,void * _fence,unsigned flags)212 dri2_server_wait_sync(__DRIcontext *_ctx, void *_fence, unsigned flags)
213 {
214    struct pipe_context *ctx = dri_context(_ctx)->st->pipe;
215    struct dri2_fence *fence = (struct dri2_fence*)_fence;
216 
217    /* We might be called here with a NULL fence as a result of WaitSyncKHR
218     * on a EGL_KHR_reusable_sync fence. Nothing to do here in such case.
219     */
220    if (!fence)
221       return;
222 
223    if (ctx->fence_server_sync)
224       ctx->fence_server_sync(ctx, fence->pipe_fence);
225 }
226 
227 const __DRI2fenceExtension dri2FenceExtension = {
228    .base = { __DRI2_FENCE, 2 },
229 
230    .create_fence = dri2_create_fence,
231    .get_fence_from_cl_event = dri2_get_fence_from_cl_event,
232    .destroy_fence = dri2_destroy_fence,
233    .client_wait_sync = dri2_client_wait_sync,
234    .server_wait_sync = dri2_server_wait_sync,
235    .get_capabilities = dri2_fence_get_caps,
236    .create_fence_fd = dri2_create_fence_fd,
237    .get_fence_fd = dri2_get_fence_fd,
238 };
239 
240 __DRIimage *
dri2_lookup_egl_image(struct dri_screen * screen,void * handle)241 dri2_lookup_egl_image(struct dri_screen *screen, void *handle)
242 {
243    const __DRIimageLookupExtension *loader = screen->sPriv->dri2.image;
244    __DRIimage *img;
245 
246    if (!loader->lookupEGLImage)
247       return NULL;
248 
249    img = loader->lookupEGLImage(screen->sPriv,
250 				handle, screen->sPriv->loaderPrivate);
251 
252    return img;
253 }
254 
255 boolean
dri2_validate_egl_image(struct dri_screen * screen,void * handle)256 dri2_validate_egl_image(struct dri_screen *screen, void *handle)
257 {
258    const __DRIimageLookupExtension *loader = screen->sPriv->dri2.image;
259 
260    return loader->validateEGLImage(handle, screen->sPriv->loaderPrivate);
261 }
262 
263 __DRIimage *
dri2_lookup_egl_image_validated(struct dri_screen * screen,void * handle)264 dri2_lookup_egl_image_validated(struct dri_screen *screen, void *handle)
265 {
266    const __DRIimageLookupExtension *loader = screen->sPriv->dri2.image;
267 
268    return loader->lookupEGLImageValidated(handle, screen->sPriv->loaderPrivate);
269 }
270 
271 __DRIimage *
dri2_create_image_from_renderbuffer2(__DRIcontext * context,int renderbuffer,void * loaderPrivate,unsigned * error)272 dri2_create_image_from_renderbuffer2(__DRIcontext *context,
273 				     int renderbuffer, void *loaderPrivate,
274                                      unsigned *error)
275 {
276    struct st_context *st_ctx = (struct st_context *)dri_context(context)->st;
277    struct gl_context *ctx = st_ctx->ctx;
278    struct pipe_context *p_ctx = st_ctx->pipe;
279    struct gl_renderbuffer *rb;
280    struct pipe_resource *tex;
281    __DRIimage *img;
282 
283    /* Section 3.9 (EGLImage Specification and Management) of the EGL 1.5
284     * specification says:
285     *
286     *   "If target is EGL_GL_RENDERBUFFER and buffer is not the name of a
287     *    renderbuffer object, or if buffer is the name of a multisampled
288     *    renderbuffer object, the error EGL_BAD_PARAMETER is generated."
289     *
290     *   "If target is EGL_GL_TEXTURE_2D , EGL_GL_TEXTURE_CUBE_MAP_*,
291     *    EGL_GL_RENDERBUFFER or EGL_GL_TEXTURE_3D and buffer refers to the
292     *    default GL texture object (0) for the corresponding GL target, the
293     *    error EGL_BAD_PARAMETER is generated."
294     *   (rely on _mesa_lookup_renderbuffer returning NULL in this case)
295     */
296    rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
297    if (!rb || rb->NumSamples > 0) {
298       *error = __DRI_IMAGE_ERROR_BAD_PARAMETER;
299       return NULL;
300    }
301 
302    tex = rb->texture;
303    if (!tex) {
304       *error = __DRI_IMAGE_ERROR_BAD_PARAMETER;
305       return NULL;
306    }
307 
308    img = CALLOC_STRUCT(__DRIimageRec);
309    if (!img) {
310       *error = __DRI_IMAGE_ERROR_BAD_ALLOC;
311       return NULL;
312    }
313 
314    img->dri_format = driGLFormatToImageFormat(rb->Format);
315    img->internal_format = rb->InternalFormat;
316    img->loader_private = loaderPrivate;
317    img->sPriv = context->driScreenPriv;
318    img->in_fence_fd = -1;
319 
320    pipe_resource_reference(&img->texture, tex);
321 
322    /* If the resource supports EGL_MESA_image_dma_buf_export, make sure that
323     * it's in a shareable state. Do this now while we still have the access to
324     * the context.
325     */
326    if (dri2_get_mapping_by_format(img->dri_format))
327       p_ctx->flush_resource(p_ctx, tex);
328 
329    ctx->Shared->HasExternallySharedImages = true;
330    *error = __DRI_IMAGE_ERROR_SUCCESS;
331    return img;
332 }
333 
334 __DRIimage *
dri2_create_image_from_renderbuffer(__DRIcontext * context,int renderbuffer,void * loaderPrivate)335 dri2_create_image_from_renderbuffer(__DRIcontext *context,
336 				    int renderbuffer, void *loaderPrivate)
337 {
338    unsigned error;
339    return dri2_create_image_from_renderbuffer2(context, renderbuffer,
340                                                loaderPrivate, &error);
341 }
342 
343 void
dri2_destroy_image(__DRIimage * img)344 dri2_destroy_image(__DRIimage *img)
345 {
346    const __DRIimageLoaderExtension *imgLoader = img->sPriv->image.loader;
347    const __DRIdri2LoaderExtension *dri2Loader = img->sPriv->dri2.loader;
348 
349    if (imgLoader && imgLoader->base.version >= 4 &&
350          imgLoader->destroyLoaderImageState) {
351       imgLoader->destroyLoaderImageState(img->loader_private);
352    } else if (dri2Loader && dri2Loader->base.version >= 5 &&
353          dri2Loader->destroyLoaderImageState) {
354       dri2Loader->destroyLoaderImageState(img->loader_private);
355    }
356 
357    pipe_resource_reference(&img->texture, NULL);
358 
359    if (img->in_fence_fd != -1)
360       close(img->in_fence_fd);
361 
362    FREE(img);
363 }
364 
365 
366 __DRIimage *
dri2_create_from_texture(__DRIcontext * context,int target,unsigned texture,int depth,int level,unsigned * error,void * loaderPrivate)367 dri2_create_from_texture(__DRIcontext *context, int target, unsigned texture,
368                          int depth, int level, unsigned *error,
369                          void *loaderPrivate)
370 {
371    __DRIimage *img;
372    struct st_context *st_ctx = (struct st_context *)dri_context(context)->st;
373    struct gl_context *ctx = st_ctx->ctx;
374    struct pipe_context *p_ctx = st_ctx->pipe;
375    struct gl_texture_object *obj;
376    struct pipe_resource *tex;
377    GLuint face = 0;
378 
379    obj = _mesa_lookup_texture(ctx, texture);
380    if (!obj || obj->Target != target) {
381       *error = __DRI_IMAGE_ERROR_BAD_PARAMETER;
382       return NULL;
383    }
384 
385    tex = st_get_texobj_resource(obj);
386    if (!tex) {
387       *error = __DRI_IMAGE_ERROR_BAD_PARAMETER;
388       return NULL;
389    }
390 
391    if (target == GL_TEXTURE_CUBE_MAP)
392       face = depth;
393 
394    _mesa_test_texobj_completeness(ctx, obj);
395    if (!obj->_BaseComplete || (level > 0 && !obj->_MipmapComplete)) {
396       *error = __DRI_IMAGE_ERROR_BAD_PARAMETER;
397       return NULL;
398    }
399 
400    if (level < obj->Attrib.BaseLevel || level > obj->_MaxLevel) {
401       *error = __DRI_IMAGE_ERROR_BAD_MATCH;
402       return NULL;
403    }
404 
405    if (target == GL_TEXTURE_3D && obj->Image[face][level]->Depth < depth) {
406       *error = __DRI_IMAGE_ERROR_BAD_MATCH;
407       return NULL;
408    }
409 
410    img = CALLOC_STRUCT(__DRIimageRec);
411    if (!img) {
412       *error = __DRI_IMAGE_ERROR_BAD_ALLOC;
413       return NULL;
414    }
415 
416    img->level = level;
417    img->layer = depth;
418    img->in_fence_fd = -1;
419    img->dri_format = driGLFormatToImageFormat(obj->Image[face][level]->TexFormat);
420    img->internal_format = obj->Image[face][level]->InternalFormat;
421 
422    img->loader_private = loaderPrivate;
423    img->sPriv = context->driScreenPriv;
424 
425    pipe_resource_reference(&img->texture, tex);
426 
427    /* If the resource supports EGL_MESA_image_dma_buf_export, make sure that
428     * it's in a shareable state. Do this now while we still have the access to
429     * the context.
430     */
431    if (dri2_get_mapping_by_format(img->dri_format))
432       p_ctx->flush_resource(p_ctx, tex);
433 
434    ctx->Shared->HasExternallySharedImages = true;
435    *error = __DRI_IMAGE_ERROR_SUCCESS;
436    return img;
437 }
438 
439 static const struct dri2_format_mapping dri2_format_table[] = {
440       { DRM_FORMAT_ABGR16161616F, __DRI_IMAGE_FORMAT_ABGR16161616F,
441         __DRI_IMAGE_COMPONENTS_RGBA,      PIPE_FORMAT_R16G16B16A16_FLOAT, 1,
442         { { 0, 0, 0, __DRI_IMAGE_FORMAT_ABGR16161616F } } },
443       { DRM_FORMAT_XBGR16161616F, __DRI_IMAGE_FORMAT_XBGR16161616F,
444         __DRI_IMAGE_COMPONENTS_RGB,       PIPE_FORMAT_R16G16B16X16_FLOAT, 1,
445         { { 0, 0, 0, __DRI_IMAGE_FORMAT_XBGR16161616F } } },
446       { DRM_FORMAT_ABGR16161616, __DRI_IMAGE_FORMAT_ABGR16161616,
447         __DRI_IMAGE_COMPONENTS_RGBA,      PIPE_FORMAT_R16G16B16A16_UNORM, 1,
448         { { 0, 0, 0, __DRI_IMAGE_FORMAT_ABGR16161616 } } },
449       { DRM_FORMAT_XBGR16161616, __DRI_IMAGE_FORMAT_XBGR16161616,
450         __DRI_IMAGE_COMPONENTS_RGB,      PIPE_FORMAT_R16G16B16X16_UNORM, 1,
451         { { 0, 0, 0, __DRI_IMAGE_FORMAT_XBGR16161616 } } },
452       { DRM_FORMAT_ARGB2101010,   __DRI_IMAGE_FORMAT_ARGB2101010,
453         __DRI_IMAGE_COMPONENTS_RGBA,      PIPE_FORMAT_B10G10R10A2_UNORM, 1,
454         { { 0, 0, 0, __DRI_IMAGE_FORMAT_ARGB2101010 } } },
455       { DRM_FORMAT_XRGB2101010,   __DRI_IMAGE_FORMAT_XRGB2101010,
456         __DRI_IMAGE_COMPONENTS_RGB,       PIPE_FORMAT_B10G10R10X2_UNORM, 1,
457         { { 0, 0, 0, __DRI_IMAGE_FORMAT_XRGB2101010 } } },
458       { DRM_FORMAT_ABGR2101010,   __DRI_IMAGE_FORMAT_ABGR2101010,
459         __DRI_IMAGE_COMPONENTS_RGBA,      PIPE_FORMAT_R10G10B10A2_UNORM, 1,
460         { { 0, 0, 0, __DRI_IMAGE_FORMAT_ABGR2101010 } } },
461       { DRM_FORMAT_XBGR2101010,   __DRI_IMAGE_FORMAT_XBGR2101010,
462         __DRI_IMAGE_COMPONENTS_RGB,       PIPE_FORMAT_R10G10B10X2_UNORM, 1,
463         { { 0, 0, 0, __DRI_IMAGE_FORMAT_XBGR2101010 } } },
464       { DRM_FORMAT_ARGB8888,      __DRI_IMAGE_FORMAT_ARGB8888,
465         __DRI_IMAGE_COMPONENTS_RGBA,      PIPE_FORMAT_BGRA8888_UNORM, 1,
466         { { 0, 0, 0, __DRI_IMAGE_FORMAT_ARGB8888 } } },
467       { DRM_FORMAT_ABGR8888,      __DRI_IMAGE_FORMAT_ABGR8888,
468         __DRI_IMAGE_COMPONENTS_RGBA,      PIPE_FORMAT_RGBA8888_UNORM, 1,
469         { { 0, 0, 0, __DRI_IMAGE_FORMAT_ABGR8888 } } },
470       { __DRI_IMAGE_FOURCC_SARGB8888,     __DRI_IMAGE_FORMAT_SARGB8,
471         __DRI_IMAGE_COMPONENTS_RGBA,      PIPE_FORMAT_BGRA8888_SRGB, 1,
472         { { 0, 0, 0, __DRI_IMAGE_FORMAT_SARGB8 } } },
473       { DRM_FORMAT_XRGB8888,      __DRI_IMAGE_FORMAT_XRGB8888,
474         __DRI_IMAGE_COMPONENTS_RGB,       PIPE_FORMAT_BGRX8888_UNORM, 1,
475         { { 0, 0, 0, __DRI_IMAGE_FORMAT_XRGB8888 } } },
476       { DRM_FORMAT_XBGR8888,      __DRI_IMAGE_FORMAT_XBGR8888,
477         __DRI_IMAGE_COMPONENTS_RGB,       PIPE_FORMAT_RGBX8888_UNORM, 1,
478         { { 0, 0, 0, __DRI_IMAGE_FORMAT_XBGR8888 } } },
479       { DRM_FORMAT_ARGB1555,      __DRI_IMAGE_FORMAT_ARGB1555,
480         __DRI_IMAGE_COMPONENTS_RGBA,      PIPE_FORMAT_B5G5R5A1_UNORM, 1,
481         { { 0, 0, 0, __DRI_IMAGE_FORMAT_ARGB1555 } } },
482       { DRM_FORMAT_RGB565,        __DRI_IMAGE_FORMAT_RGB565,
483         __DRI_IMAGE_COMPONENTS_RGB,       PIPE_FORMAT_B5G6R5_UNORM, 1,
484         { { 0, 0, 0, __DRI_IMAGE_FORMAT_RGB565 } } },
485       { DRM_FORMAT_R8,            __DRI_IMAGE_FORMAT_R8,
486         __DRI_IMAGE_COMPONENTS_R,         PIPE_FORMAT_R8_UNORM, 1,
487         { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8 } } },
488       { DRM_FORMAT_R16,           __DRI_IMAGE_FORMAT_R16,
489         __DRI_IMAGE_COMPONENTS_R,         PIPE_FORMAT_R16_UNORM, 1,
490         { { 0, 0, 0, __DRI_IMAGE_FORMAT_R16 } } },
491       { DRM_FORMAT_GR88,          __DRI_IMAGE_FORMAT_GR88,
492         __DRI_IMAGE_COMPONENTS_RG,        PIPE_FORMAT_RG88_UNORM, 1,
493         { { 0, 0, 0, __DRI_IMAGE_FORMAT_GR88 } } },
494       { DRM_FORMAT_GR1616,        __DRI_IMAGE_FORMAT_GR1616,
495         __DRI_IMAGE_COMPONENTS_RG,        PIPE_FORMAT_RG1616_UNORM, 1,
496         { { 0, 0, 0, __DRI_IMAGE_FORMAT_GR1616 } } },
497 
498       { DRM_FORMAT_YUV410, __DRI_IMAGE_FORMAT_NONE,
499         __DRI_IMAGE_COMPONENTS_Y_U_V,     PIPE_FORMAT_IYUV, 3,
500         { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8 },
501           { 1, 2, 2, __DRI_IMAGE_FORMAT_R8 },
502           { 2, 2, 2, __DRI_IMAGE_FORMAT_R8 } } },
503       { DRM_FORMAT_YUV411, __DRI_IMAGE_FORMAT_NONE,
504         __DRI_IMAGE_COMPONENTS_Y_U_V,     PIPE_FORMAT_IYUV, 3,
505         { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8 },
506           { 1, 2, 0, __DRI_IMAGE_FORMAT_R8 },
507           { 2, 2, 0, __DRI_IMAGE_FORMAT_R8 } } },
508       { DRM_FORMAT_YUV420,        __DRI_IMAGE_FORMAT_NONE,
509         __DRI_IMAGE_COMPONENTS_Y_U_V,     PIPE_FORMAT_IYUV, 3,
510         { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8 },
511           { 1, 1, 1, __DRI_IMAGE_FORMAT_R8 },
512           { 2, 1, 1, __DRI_IMAGE_FORMAT_R8 } } },
513       { DRM_FORMAT_YUV422,        __DRI_IMAGE_FORMAT_NONE,
514         __DRI_IMAGE_COMPONENTS_Y_U_V,     PIPE_FORMAT_IYUV, 3,
515         { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8 },
516           { 1, 1, 0, __DRI_IMAGE_FORMAT_R8 },
517           { 2, 1, 0, __DRI_IMAGE_FORMAT_R8 } } },
518       { DRM_FORMAT_YUV444,        __DRI_IMAGE_FORMAT_NONE,
519         __DRI_IMAGE_COMPONENTS_Y_U_V,     PIPE_FORMAT_IYUV, 3,
520         { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8 },
521           { 1, 0, 0, __DRI_IMAGE_FORMAT_R8 },
522           { 2, 0, 0, __DRI_IMAGE_FORMAT_R8 } } },
523 
524       { DRM_FORMAT_YVU410,        __DRI_IMAGE_FORMAT_NONE,
525         __DRI_IMAGE_COMPONENTS_Y_U_V,     PIPE_FORMAT_IYUV, 3,
526         { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8 },
527           { 2, 2, 2, __DRI_IMAGE_FORMAT_R8 },
528           { 1, 2, 2, __DRI_IMAGE_FORMAT_R8 } } },
529       { DRM_FORMAT_YVU411,        __DRI_IMAGE_FORMAT_NONE,
530         __DRI_IMAGE_COMPONENTS_Y_U_V,     PIPE_FORMAT_IYUV, 3,
531         { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8 },
532           { 2, 2, 0, __DRI_IMAGE_FORMAT_R8 },
533           { 1, 2, 0, __DRI_IMAGE_FORMAT_R8 } } },
534       { DRM_FORMAT_YVU420,        __DRI_IMAGE_FORMAT_NONE,
535         __DRI_IMAGE_COMPONENTS_Y_U_V,     PIPE_FORMAT_IYUV, 3,
536         { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8 },
537           { 2, 1, 1, __DRI_IMAGE_FORMAT_R8 },
538           { 1, 1, 1, __DRI_IMAGE_FORMAT_R8 } } },
539       { DRM_FORMAT_YVU422,        __DRI_IMAGE_FORMAT_NONE,
540         __DRI_IMAGE_COMPONENTS_Y_U_V,     PIPE_FORMAT_IYUV, 3,
541         { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8 },
542           { 2, 1, 0, __DRI_IMAGE_FORMAT_R8 },
543           { 1, 1, 0, __DRI_IMAGE_FORMAT_R8 } } },
544       { DRM_FORMAT_YVU444,        __DRI_IMAGE_FORMAT_NONE,
545         __DRI_IMAGE_COMPONENTS_Y_U_V,     PIPE_FORMAT_IYUV, 3,
546         { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8 },
547           { 2, 0, 0, __DRI_IMAGE_FORMAT_R8 },
548           { 1, 0, 0, __DRI_IMAGE_FORMAT_R8 } } },
549 
550       { DRM_FORMAT_NV12,          __DRI_IMAGE_FORMAT_NONE,
551         __DRI_IMAGE_COMPONENTS_Y_UV,      PIPE_FORMAT_NV12, 2,
552         { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8 },
553           { 1, 1, 1, __DRI_IMAGE_FORMAT_GR88 } } },
554 
555       { DRM_FORMAT_P010,          __DRI_IMAGE_FORMAT_NONE,
556         __DRI_IMAGE_COMPONENTS_Y_UV,      PIPE_FORMAT_P010, 2,
557         { { 0, 0, 0, __DRI_IMAGE_FORMAT_R16 },
558           { 1, 1, 1, __DRI_IMAGE_FORMAT_GR1616 } } },
559       { DRM_FORMAT_P012,          __DRI_IMAGE_FORMAT_NONE,
560         __DRI_IMAGE_COMPONENTS_Y_UV,      PIPE_FORMAT_P012, 2,
561         { { 0, 0, 0, __DRI_IMAGE_FORMAT_R16 },
562           { 1, 1, 1, __DRI_IMAGE_FORMAT_GR1616 } } },
563       { DRM_FORMAT_P016,          __DRI_IMAGE_FORMAT_NONE,
564         __DRI_IMAGE_COMPONENTS_Y_UV,      PIPE_FORMAT_P016, 2,
565         { { 0, 0, 0, __DRI_IMAGE_FORMAT_R16 },
566           { 1, 1, 1, __DRI_IMAGE_FORMAT_GR1616 } } },
567 
568       { DRM_FORMAT_NV16,          __DRI_IMAGE_FORMAT_NONE,
569         __DRI_IMAGE_COMPONENTS_Y_UV,      PIPE_FORMAT_NV12, 2,
570         { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8 },
571           { 1, 1, 0, __DRI_IMAGE_FORMAT_GR88 } } },
572 
573       { DRM_FORMAT_AYUV,      __DRI_IMAGE_FORMAT_ABGR8888,
574         __DRI_IMAGE_COMPONENTS_AYUV,      PIPE_FORMAT_AYUV, 1,
575         { { 0, 0, 0, __DRI_IMAGE_FORMAT_ABGR8888 } } },
576       { DRM_FORMAT_XYUV8888,      __DRI_IMAGE_FORMAT_XBGR8888,
577         __DRI_IMAGE_COMPONENTS_XYUV,      PIPE_FORMAT_XYUV, 1,
578         { { 0, 0, 0, __DRI_IMAGE_FORMAT_XBGR8888 } } },
579 
580       { DRM_FORMAT_Y410,          __DRI_IMAGE_FORMAT_ABGR2101010,
581         __DRI_IMAGE_COMPONENTS_AYUV,      PIPE_FORMAT_Y410, 1,
582         { { 0, 0, 0, __DRI_IMAGE_FORMAT_ABGR2101010 } } },
583 
584       /* Y412 is an unusual format.  It has the same layout as Y416 (i.e.,
585        * 16-bits of physical storage per channel), but the low 4 bits of each
586        * component are unused padding.  The writer is supposed to write zeros
587        * to these bits.
588        */
589       { DRM_FORMAT_Y412,          __DRI_IMAGE_FORMAT_ABGR16161616,
590         __DRI_IMAGE_COMPONENTS_AYUV,      PIPE_FORMAT_Y412, 1,
591         { { 0, 0, 0, __DRI_IMAGE_FORMAT_ABGR16161616 } } },
592       { DRM_FORMAT_Y416,          __DRI_IMAGE_FORMAT_ABGR16161616,
593         __DRI_IMAGE_COMPONENTS_AYUV,      PIPE_FORMAT_Y416, 1,
594         { { 0, 0, 0, __DRI_IMAGE_FORMAT_ABGR16161616 } } },
595 
596       /* For YUYV and UYVY buffers, we set up two overlapping DRI images
597        * and treat them as planar buffers in the compositors.
598        * Plane 0 is GR88 and samples YU or YV pairs and places Y into
599        * the R component, while plane 1 is ARGB/ABGR and samples YUYV/UYVY
600        * clusters and places pairs and places U into the G component and
601        * V into A.  This lets the texture sampler interpolate the Y
602        * components correctly when sampling from plane 0, and interpolate
603        * U and V correctly when sampling from plane 1. */
604       { DRM_FORMAT_YUYV,          __DRI_IMAGE_FORMAT_NONE,
605         __DRI_IMAGE_COMPONENTS_Y_XUXV,    PIPE_FORMAT_YUYV, 2,
606         { { 0, 0, 0, __DRI_IMAGE_FORMAT_GR88 },
607           { 0, 1, 0, __DRI_IMAGE_FORMAT_ARGB8888 } } },
608       { DRM_FORMAT_UYVY,          __DRI_IMAGE_FORMAT_NONE,
609         __DRI_IMAGE_COMPONENTS_Y_UXVX,    PIPE_FORMAT_UYVY, 2,
610         { { 0, 0, 0, __DRI_IMAGE_FORMAT_GR88 },
611           { 0, 1, 0, __DRI_IMAGE_FORMAT_ABGR8888 } } },
612 
613       /* The Y21x formats work in a similar fashion to the YUYV and UYVY
614        * formats.
615        */
616       { DRM_FORMAT_Y210,          __DRI_IMAGE_FORMAT_NONE,
617         __DRI_IMAGE_COMPONENTS_Y_XUXV,    PIPE_FORMAT_Y210, 2,
618         { { 0, 0, 0, __DRI_IMAGE_FORMAT_GR1616 },
619           { 0, 1, 0, __DRI_IMAGE_FORMAT_ABGR16161616 } } },
620       /* Y212 is an unusual format.  It has the same layout as Y216 (i.e.,
621        * 16-bits of physical storage per channel), but the low 4 bits of each
622        * component are unused padding.  The writer is supposed to write zeros
623        * to these bits.
624        */
625       { DRM_FORMAT_Y212,          __DRI_IMAGE_FORMAT_NONE,
626         __DRI_IMAGE_COMPONENTS_Y_XUXV,    PIPE_FORMAT_Y212, 2,
627         { { 0, 0, 0, __DRI_IMAGE_FORMAT_GR1616 },
628           { 0, 1, 0, __DRI_IMAGE_FORMAT_ABGR16161616 } } },
629       { DRM_FORMAT_Y216,          __DRI_IMAGE_FORMAT_NONE,
630         __DRI_IMAGE_COMPONENTS_Y_XUXV,    PIPE_FORMAT_Y216, 2,
631         { { 0, 0, 0, __DRI_IMAGE_FORMAT_GR1616 },
632           { 0, 1, 0, __DRI_IMAGE_FORMAT_ABGR16161616 } } },
633 };
634 
635 const struct dri2_format_mapping *
dri2_get_mapping_by_fourcc(int fourcc)636 dri2_get_mapping_by_fourcc(int fourcc)
637 {
638    for (unsigned i = 0; i < ARRAY_SIZE(dri2_format_table); i++) {
639       if (dri2_format_table[i].dri_fourcc == fourcc)
640          return &dri2_format_table[i];
641    }
642 
643    return NULL;
644 }
645 
646 const struct dri2_format_mapping *
dri2_get_mapping_by_format(int format)647 dri2_get_mapping_by_format(int format)
648 {
649    if (format == __DRI_IMAGE_FORMAT_NONE)
650       return NULL;
651 
652    for (unsigned i = 0; i < ARRAY_SIZE(dri2_format_table); i++) {
653       if (dri2_format_table[i].dri_format == format)
654          return &dri2_format_table[i];
655    }
656 
657    return NULL;
658 }
659 
660 enum pipe_format
dri2_get_pipe_format_for_dri_format(int format)661 dri2_get_pipe_format_for_dri_format(int format)
662 {
663    for (unsigned i = 0; i < ARRAY_SIZE(dri2_format_table); i++) {
664       if (dri2_format_table[i].dri_format == format)
665          return dri2_format_table[i].pipe_format;
666    }
667 
668    return PIPE_FORMAT_NONE;
669 }
670 
671 boolean
dri2_yuv_dma_buf_supported(struct dri_screen * screen,const struct dri2_format_mapping * map)672 dri2_yuv_dma_buf_supported(struct dri_screen *screen,
673                            const struct dri2_format_mapping *map)
674 {
675    struct pipe_screen *pscreen = screen->base.screen;
676 
677    for (unsigned i = 0; i < map->nplanes; i++) {
678       if (!pscreen->is_format_supported(pscreen,
679             dri2_get_pipe_format_for_dri_format(map->planes[i].dri_format),
680             screen->target, 0, 0, PIPE_BIND_SAMPLER_VIEW))
681          return false;
682    }
683    return true;
684 }
685 
686 boolean
dri2_query_dma_buf_formats(__DRIscreen * _screen,int max,int * formats,int * count)687 dri2_query_dma_buf_formats(__DRIscreen *_screen, int max, int *formats,
688                            int *count)
689 {
690    struct dri_screen *screen = dri_screen(_screen);
691    struct pipe_screen *pscreen = screen->base.screen;
692    int i, j;
693 
694    for (i = 0, j = 0; (i < ARRAY_SIZE(dri2_format_table)) &&
695          (j < max || max == 0); i++) {
696       const struct dri2_format_mapping *map = &dri2_format_table[i];
697 
698       /* The sRGB format is not a real FourCC as defined by drm_fourcc.h, so we
699        * must not leak it out to clients. */
700       if (dri2_format_table[i].dri_fourcc == __DRI_IMAGE_FOURCC_SARGB8888)
701          continue;
702 
703       if (pscreen->is_format_supported(pscreen, map->pipe_format,
704                                        screen->target, 0, 0,
705                                        PIPE_BIND_RENDER_TARGET) ||
706           pscreen->is_format_supported(pscreen, map->pipe_format,
707                                        screen->target, 0, 0,
708                                        PIPE_BIND_SAMPLER_VIEW) ||
709           dri2_yuv_dma_buf_supported(screen, map)) {
710          if (j < max)
711             formats[j] = map->dri_fourcc;
712          j++;
713       }
714    }
715    *count = j;
716    return true;
717 }
718 
719 /* vim: set sw=3 ts=8 sts=3 expandtab: */
720