tu: Implement fallback linear staging blit for CopyImage
[mesa.git] / src / gallium / state_trackers / dri / dri_helpers.c
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 "state_tracker/st_cb_fbo.h"
30 #include "main/texobj.h"
31
32 #include "dri_helpers.h"
33
34 static bool
35 dri2_is_opencl_interop_loaded_locked(struct dri_screen *screen)
36 {
37 return screen->opencl_dri_event_add_ref &&
38 screen->opencl_dri_event_release &&
39 screen->opencl_dri_event_wait &&
40 screen->opencl_dri_event_get_fence;
41 }
42
43 static bool
44 dri2_load_opencl_interop(struct dri_screen *screen)
45 {
46 #if defined(RTLD_DEFAULT)
47 bool success;
48
49 mtx_lock(&screen->opencl_func_mutex);
50
51 if (dri2_is_opencl_interop_loaded_locked(screen)) {
52 mtx_unlock(&screen->opencl_func_mutex);
53 return true;
54 }
55
56 screen->opencl_dri_event_add_ref =
57 dlsym(RTLD_DEFAULT, "opencl_dri_event_add_ref");
58 screen->opencl_dri_event_release =
59 dlsym(RTLD_DEFAULT, "opencl_dri_event_release");
60 screen->opencl_dri_event_wait =
61 dlsym(RTLD_DEFAULT, "opencl_dri_event_wait");
62 screen->opencl_dri_event_get_fence =
63 dlsym(RTLD_DEFAULT, "opencl_dri_event_get_fence");
64
65 success = dri2_is_opencl_interop_loaded_locked(screen);
66 mtx_unlock(&screen->opencl_func_mutex);
67 return success;
68 #else
69 return false;
70 #endif
71 }
72
73 struct dri2_fence {
74 struct dri_screen *driscreen;
75 struct pipe_fence_handle *pipe_fence;
76 void *cl_event;
77 };
78
79 static unsigned dri2_fence_get_caps(__DRIscreen *_screen)
80 {
81 struct dri_screen *driscreen = dri_screen(_screen);
82 struct pipe_screen *screen = driscreen->base.screen;
83 unsigned caps = 0;
84
85 if (screen->get_param(screen, PIPE_CAP_NATIVE_FENCE_FD))
86 caps |= __DRI_FENCE_CAP_NATIVE_FD;
87
88 return caps;
89 }
90
91 static void *
92 dri2_create_fence(__DRIcontext *_ctx)
93 {
94 struct st_context_iface *stapi = dri_context(_ctx)->st;
95 struct dri2_fence *fence = CALLOC_STRUCT(dri2_fence);
96
97 if (!fence)
98 return NULL;
99
100 stapi->flush(stapi, 0, &fence->pipe_fence, NULL, NULL);
101
102 if (!fence->pipe_fence) {
103 FREE(fence);
104 return NULL;
105 }
106
107 fence->driscreen = dri_screen(_ctx->driScreenPriv);
108 return fence;
109 }
110
111 static void *
112 dri2_create_fence_fd(__DRIcontext *_ctx, int fd)
113 {
114 struct st_context_iface *stapi = dri_context(_ctx)->st;
115 struct pipe_context *ctx = stapi->pipe;
116 struct dri2_fence *fence = CALLOC_STRUCT(dri2_fence);
117
118 if (fd == -1) {
119 /* exporting driver created fence, flush: */
120 stapi->flush(stapi, ST_FLUSH_FENCE_FD, &fence->pipe_fence, NULL, NULL);
121 } else {
122 /* importing a foreign fence fd: */
123 ctx->create_fence_fd(ctx, &fence->pipe_fence, fd, PIPE_FD_TYPE_NATIVE_SYNC);
124 }
125 if (!fence->pipe_fence) {
126 FREE(fence);
127 return NULL;
128 }
129
130 fence->driscreen = dri_screen(_ctx->driScreenPriv);
131 return fence;
132 }
133
134 static int
135 dri2_get_fence_fd(__DRIscreen *_screen, void *_fence)
136 {
137 struct dri_screen *driscreen = dri_screen(_screen);
138 struct pipe_screen *screen = driscreen->base.screen;
139 struct dri2_fence *fence = (struct dri2_fence*)_fence;
140
141 return screen->fence_get_fd(screen, fence->pipe_fence);
142 }
143
144 static void *
145 dri2_get_fence_from_cl_event(__DRIscreen *_screen, intptr_t cl_event)
146 {
147 struct dri_screen *driscreen = dri_screen(_screen);
148 struct dri2_fence *fence;
149
150 if (!dri2_load_opencl_interop(driscreen))
151 return NULL;
152
153 fence = CALLOC_STRUCT(dri2_fence);
154 if (!fence)
155 return NULL;
156
157 fence->cl_event = (void*)cl_event;
158
159 if (!driscreen->opencl_dri_event_add_ref(fence->cl_event)) {
160 free(fence);
161 return NULL;
162 }
163
164 fence->driscreen = driscreen;
165 return fence;
166 }
167
168 static void
169 dri2_destroy_fence(__DRIscreen *_screen, void *_fence)
170 {
171 struct dri_screen *driscreen = dri_screen(_screen);
172 struct pipe_screen *screen = driscreen->base.screen;
173 struct dri2_fence *fence = (struct dri2_fence*)_fence;
174
175 if (fence->pipe_fence)
176 screen->fence_reference(screen, &fence->pipe_fence, NULL);
177 else if (fence->cl_event)
178 driscreen->opencl_dri_event_release(fence->cl_event);
179 else
180 assert(0);
181
182 FREE(fence);
183 }
184
185 static GLboolean
186 dri2_client_wait_sync(__DRIcontext *_ctx, void *_fence, unsigned flags,
187 uint64_t timeout)
188 {
189 struct dri2_fence *fence = (struct dri2_fence*)_fence;
190 struct dri_screen *driscreen = fence->driscreen;
191 struct pipe_screen *screen = driscreen->base.screen;
192
193 /* No need to flush. The context was flushed when the fence was created. */
194
195 if (fence->pipe_fence)
196 return screen->fence_finish(screen, NULL, fence->pipe_fence, timeout);
197 else if (fence->cl_event) {
198 struct pipe_fence_handle *pipe_fence =
199 driscreen->opencl_dri_event_get_fence(fence->cl_event);
200
201 if (pipe_fence)
202 return screen->fence_finish(screen, NULL, pipe_fence, timeout);
203 else
204 return driscreen->opencl_dri_event_wait(fence->cl_event, timeout);
205 }
206 else {
207 assert(0);
208 return false;
209 }
210 }
211
212 static void
213 dri2_server_wait_sync(__DRIcontext *_ctx, void *_fence, unsigned flags)
214 {
215 struct pipe_context *ctx = dri_context(_ctx)->st->pipe;
216 struct dri2_fence *fence = (struct dri2_fence*)_fence;
217
218 /* We might be called here with a NULL fence as a result of WaitSyncKHR
219 * on a EGL_KHR_reusable_sync fence. Nothing to do here in such case.
220 */
221 if (!fence)
222 return;
223
224 if (ctx->fence_server_sync)
225 ctx->fence_server_sync(ctx, fence->pipe_fence);
226 }
227
228 const __DRI2fenceExtension dri2FenceExtension = {
229 .base = { __DRI2_FENCE, 2 },
230
231 .create_fence = dri2_create_fence,
232 .get_fence_from_cl_event = dri2_get_fence_from_cl_event,
233 .destroy_fence = dri2_destroy_fence,
234 .client_wait_sync = dri2_client_wait_sync,
235 .server_wait_sync = dri2_server_wait_sync,
236 .get_capabilities = dri2_fence_get_caps,
237 .create_fence_fd = dri2_create_fence_fd,
238 .get_fence_fd = dri2_get_fence_fd,
239 };
240
241 __DRIimage *
242 dri2_lookup_egl_image(struct dri_screen *screen, void *handle)
243 {
244 const __DRIimageLookupExtension *loader = screen->sPriv->dri2.image;
245 __DRIimage *img;
246
247 if (!loader->lookupEGLImage)
248 return NULL;
249
250 img = loader->lookupEGLImage(screen->sPriv,
251 handle, screen->sPriv->loaderPrivate);
252
253 return img;
254 }
255
256 __DRIimage *
257 dri2_create_image_from_renderbuffer2(__DRIcontext *context,
258 int renderbuffer, void *loaderPrivate,
259 unsigned *error)
260 {
261 struct gl_context *ctx = ((struct st_context *)dri_context(context)->st)->ctx;
262 struct gl_renderbuffer *rb;
263 struct pipe_resource *tex;
264 __DRIimage *img;
265
266 /* Section 3.9 (EGLImage Specification and Management) of the EGL 1.5
267 * specification says:
268 *
269 * "If target is EGL_GL_RENDERBUFFER and buffer is not the name of a
270 * renderbuffer object, or if buffer is the name of a multisampled
271 * renderbuffer object, the error EGL_BAD_PARAMETER is generated."
272 *
273 * "If target is EGL_GL_TEXTURE_2D , EGL_GL_TEXTURE_CUBE_MAP_*,
274 * EGL_GL_RENDERBUFFER or EGL_GL_TEXTURE_3D and buffer refers to the
275 * default GL texture object (0) for the corresponding GL target, the
276 * error EGL_BAD_PARAMETER is generated."
277 * (rely on _mesa_lookup_renderbuffer returning NULL in this case)
278 */
279 rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
280 if (!rb || rb->NumSamples > 0) {
281 *error = __DRI_IMAGE_ERROR_BAD_PARAMETER;
282 return NULL;
283 }
284
285 tex = st_get_renderbuffer_resource(rb);
286 if (!tex) {
287 *error = __DRI_IMAGE_ERROR_BAD_PARAMETER;
288 return NULL;
289 }
290
291 img = CALLOC_STRUCT(__DRIimageRec);
292 if (!img) {
293 *error = __DRI_IMAGE_ERROR_BAD_ALLOC;
294 return NULL;
295 }
296
297 img->dri_format = driGLFormatToImageFormat(rb->Format);
298 img->loader_private = loaderPrivate;
299
300 pipe_resource_reference(&img->texture, tex);
301
302 *error = __DRI_IMAGE_ERROR_SUCCESS;
303 return img;
304 }
305
306 __DRIimage *
307 dri2_create_image_from_renderbuffer(__DRIcontext *context,
308 int renderbuffer, void *loaderPrivate)
309 {
310 unsigned error;
311 return dri2_create_image_from_renderbuffer2(context, renderbuffer,
312 loaderPrivate, &error);
313 }
314
315 void
316 dri2_destroy_image(__DRIimage *img)
317 {
318 pipe_resource_reference(&img->texture, NULL);
319 FREE(img);
320 }
321
322
323 __DRIimage *
324 dri2_create_from_texture(__DRIcontext *context, int target, unsigned texture,
325 int depth, int level, unsigned *error,
326 void *loaderPrivate)
327 {
328 __DRIimage *img;
329 struct gl_context *ctx = ((struct st_context *)dri_context(context)->st)->ctx;
330 struct gl_texture_object *obj;
331 struct pipe_resource *tex;
332 GLuint face = 0;
333
334 obj = _mesa_lookup_texture(ctx, texture);
335 if (!obj || obj->Target != target) {
336 *error = __DRI_IMAGE_ERROR_BAD_PARAMETER;
337 return NULL;
338 }
339
340 tex = st_get_texobj_resource(obj);
341 if (!tex) {
342 *error = __DRI_IMAGE_ERROR_BAD_PARAMETER;
343 return NULL;
344 }
345
346 if (target == GL_TEXTURE_CUBE_MAP)
347 face = depth;
348
349 _mesa_test_texobj_completeness(ctx, obj);
350 if (!obj->_BaseComplete || (level > 0 && !obj->_MipmapComplete)) {
351 *error = __DRI_IMAGE_ERROR_BAD_PARAMETER;
352 return NULL;
353 }
354
355 if (level < obj->BaseLevel || level > obj->_MaxLevel) {
356 *error = __DRI_IMAGE_ERROR_BAD_MATCH;
357 return NULL;
358 }
359
360 if (target == GL_TEXTURE_3D && obj->Image[face][level]->Depth < depth) {
361 *error = __DRI_IMAGE_ERROR_BAD_MATCH;
362 return NULL;
363 }
364
365 img = CALLOC_STRUCT(__DRIimageRec);
366 if (!img) {
367 *error = __DRI_IMAGE_ERROR_BAD_ALLOC;
368 return NULL;
369 }
370
371 img->level = level;
372 img->layer = depth;
373 img->dri_format = driGLFormatToImageFormat(obj->Image[face][level]->TexFormat);
374
375 img->loader_private = loaderPrivate;
376
377 pipe_resource_reference(&img->texture, tex);
378
379 *error = __DRI_IMAGE_ERROR_SUCCESS;
380 return img;
381 }
382
383 static const struct dri2_format_mapping dri2_format_table[] = {
384 { DRM_FORMAT_ABGR16161616F, __DRI_IMAGE_FORMAT_ABGR16161616F,
385 __DRI_IMAGE_COMPONENTS_RGBA, PIPE_FORMAT_R16G16B16A16_FLOAT, 1,
386 { { 0, 0, 0, __DRI_IMAGE_FORMAT_ABGR16161616F, 4 } } },
387 { DRM_FORMAT_XBGR16161616F, __DRI_IMAGE_FORMAT_XBGR16161616F,
388 __DRI_IMAGE_COMPONENTS_RGB, PIPE_FORMAT_R16G16B16X16_FLOAT, 1,
389 { { 0, 0, 0, __DRI_IMAGE_FORMAT_XBGR16161616F, 4 } } },
390 { DRM_FORMAT_ARGB2101010, __DRI_IMAGE_FORMAT_ARGB2101010,
391 __DRI_IMAGE_COMPONENTS_RGBA, PIPE_FORMAT_B10G10R10A2_UNORM, 1,
392 { { 0, 0, 0, __DRI_IMAGE_FORMAT_ARGB2101010, 4 } } },
393 { DRM_FORMAT_XRGB2101010, __DRI_IMAGE_FORMAT_XRGB2101010,
394 __DRI_IMAGE_COMPONENTS_RGB, PIPE_FORMAT_B10G10R10X2_UNORM, 1,
395 { { 0, 0, 0, __DRI_IMAGE_FORMAT_XRGB2101010, 4 } } },
396 { DRM_FORMAT_ABGR2101010, __DRI_IMAGE_FORMAT_ABGR2101010,
397 __DRI_IMAGE_COMPONENTS_RGBA, PIPE_FORMAT_R10G10B10A2_UNORM, 1,
398 { { 0, 0, 0, __DRI_IMAGE_FORMAT_ABGR2101010, 4 } } },
399 { DRM_FORMAT_XBGR2101010, __DRI_IMAGE_FORMAT_XBGR2101010,
400 __DRI_IMAGE_COMPONENTS_RGB, PIPE_FORMAT_R10G10B10X2_UNORM, 1,
401 { { 0, 0, 0, __DRI_IMAGE_FORMAT_XBGR2101010, 4 } } },
402 { DRM_FORMAT_ARGB8888, __DRI_IMAGE_FORMAT_ARGB8888,
403 __DRI_IMAGE_COMPONENTS_RGBA, PIPE_FORMAT_BGRA8888_UNORM, 1,
404 { { 0, 0, 0, __DRI_IMAGE_FORMAT_ARGB8888, 4 } } },
405 { DRM_FORMAT_ABGR8888, __DRI_IMAGE_FORMAT_ABGR8888,
406 __DRI_IMAGE_COMPONENTS_RGBA, PIPE_FORMAT_RGBA8888_UNORM, 1,
407 { { 0, 0, 0, __DRI_IMAGE_FORMAT_ABGR8888, 4 } } },
408 { __DRI_IMAGE_FOURCC_SARGB8888, __DRI_IMAGE_FORMAT_SARGB8,
409 __DRI_IMAGE_COMPONENTS_RGBA, PIPE_FORMAT_BGRA8888_SRGB, 1,
410 { { 0, 0, 0, __DRI_IMAGE_FORMAT_SARGB8, 4 } } },
411 { DRM_FORMAT_XRGB8888, __DRI_IMAGE_FORMAT_XRGB8888,
412 __DRI_IMAGE_COMPONENTS_RGB, PIPE_FORMAT_BGRX8888_UNORM, 1,
413 { { 0, 0, 0, __DRI_IMAGE_FORMAT_XRGB8888, 4 }, } },
414 { DRM_FORMAT_XBGR8888, __DRI_IMAGE_FORMAT_XBGR8888,
415 __DRI_IMAGE_COMPONENTS_RGB, PIPE_FORMAT_RGBX8888_UNORM, 1,
416 { { 0, 0, 0, __DRI_IMAGE_FORMAT_XBGR8888, 4 }, } },
417 { DRM_FORMAT_ARGB1555, __DRI_IMAGE_FORMAT_ARGB1555,
418 __DRI_IMAGE_COMPONENTS_RGBA, PIPE_FORMAT_B5G5R5A1_UNORM, 1,
419 { { 0, 0, 0, __DRI_IMAGE_FORMAT_ARGB1555, 2 } } },
420 { DRM_FORMAT_RGB565, __DRI_IMAGE_FORMAT_RGB565,
421 __DRI_IMAGE_COMPONENTS_RGB, PIPE_FORMAT_B5G6R5_UNORM, 1,
422 { { 0, 0, 0, __DRI_IMAGE_FORMAT_RGB565, 2 } } },
423 { DRM_FORMAT_R8, __DRI_IMAGE_FORMAT_R8,
424 __DRI_IMAGE_COMPONENTS_R, PIPE_FORMAT_R8_UNORM, 1,
425 { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 }, } },
426 { DRM_FORMAT_R16, __DRI_IMAGE_FORMAT_R16,
427 __DRI_IMAGE_COMPONENTS_R, PIPE_FORMAT_R16_UNORM, 1,
428 { { 0, 0, 0, __DRI_IMAGE_FORMAT_R16, 1 }, } },
429 { DRM_FORMAT_GR88, __DRI_IMAGE_FORMAT_GR88,
430 __DRI_IMAGE_COMPONENTS_RG, PIPE_FORMAT_RG88_UNORM, 1,
431 { { 0, 0, 0, __DRI_IMAGE_FORMAT_GR88, 2 }, } },
432 { DRM_FORMAT_GR1616, __DRI_IMAGE_FORMAT_GR1616,
433 __DRI_IMAGE_COMPONENTS_RG, PIPE_FORMAT_RG1616_UNORM, 1,
434 { { 0, 0, 0, __DRI_IMAGE_FORMAT_GR1616, 2 }, } },
435
436 { DRM_FORMAT_YUV410, __DRI_IMAGE_FORMAT_NONE,
437 __DRI_IMAGE_COMPONENTS_Y_U_V, PIPE_FORMAT_IYUV, 3,
438 { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
439 { 1, 2, 2, __DRI_IMAGE_FORMAT_R8, 1 },
440 { 2, 2, 2, __DRI_IMAGE_FORMAT_R8, 1 } } },
441 { DRM_FORMAT_YUV411, __DRI_IMAGE_FORMAT_NONE,
442 __DRI_IMAGE_COMPONENTS_Y_U_V, PIPE_FORMAT_IYUV, 3,
443 { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
444 { 1, 2, 0, __DRI_IMAGE_FORMAT_R8, 1 },
445 { 2, 2, 0, __DRI_IMAGE_FORMAT_R8, 1 } } },
446 { DRM_FORMAT_YUV420, __DRI_IMAGE_FORMAT_NONE,
447 __DRI_IMAGE_COMPONENTS_Y_U_V, PIPE_FORMAT_IYUV, 3,
448 { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
449 { 1, 1, 1, __DRI_IMAGE_FORMAT_R8, 1 },
450 { 2, 1, 1, __DRI_IMAGE_FORMAT_R8, 1 } } },
451 { DRM_FORMAT_YUV422, __DRI_IMAGE_FORMAT_NONE,
452 __DRI_IMAGE_COMPONENTS_Y_U_V, PIPE_FORMAT_IYUV, 3,
453 { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
454 { 1, 1, 0, __DRI_IMAGE_FORMAT_R8, 1 },
455 { 2, 1, 0, __DRI_IMAGE_FORMAT_R8, 1 } } },
456 { DRM_FORMAT_YUV444, __DRI_IMAGE_FORMAT_NONE,
457 __DRI_IMAGE_COMPONENTS_Y_U_V, PIPE_FORMAT_IYUV, 3,
458 { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
459 { 1, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
460 { 2, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 } } },
461
462 { DRM_FORMAT_YVU410, __DRI_IMAGE_FORMAT_NONE,
463 __DRI_IMAGE_COMPONENTS_Y_U_V, PIPE_FORMAT_IYUV, 3,
464 { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
465 { 2, 2, 2, __DRI_IMAGE_FORMAT_R8, 1 },
466 { 1, 2, 2, __DRI_IMAGE_FORMAT_R8, 1 } } },
467 { DRM_FORMAT_YVU411, __DRI_IMAGE_FORMAT_NONE,
468 __DRI_IMAGE_COMPONENTS_Y_U_V, PIPE_FORMAT_IYUV, 3,
469 { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
470 { 2, 2, 0, __DRI_IMAGE_FORMAT_R8, 1 },
471 { 1, 2, 0, __DRI_IMAGE_FORMAT_R8, 1 } } },
472 { DRM_FORMAT_YVU420, __DRI_IMAGE_FORMAT_NONE,
473 __DRI_IMAGE_COMPONENTS_Y_U_V, PIPE_FORMAT_IYUV, 3,
474 { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
475 { 2, 1, 1, __DRI_IMAGE_FORMAT_R8, 1 },
476 { 1, 1, 1, __DRI_IMAGE_FORMAT_R8, 1 } } },
477 { DRM_FORMAT_YVU422, __DRI_IMAGE_FORMAT_NONE,
478 __DRI_IMAGE_COMPONENTS_Y_U_V, PIPE_FORMAT_IYUV, 3,
479 { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
480 { 2, 1, 0, __DRI_IMAGE_FORMAT_R8, 1 },
481 { 1, 1, 0, __DRI_IMAGE_FORMAT_R8, 1 } } },
482 { DRM_FORMAT_YVU444, __DRI_IMAGE_FORMAT_NONE,
483 __DRI_IMAGE_COMPONENTS_Y_U_V, PIPE_FORMAT_IYUV, 3,
484 { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
485 { 2, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
486 { 1, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 } } },
487
488 { DRM_FORMAT_NV12, __DRI_IMAGE_FORMAT_NONE,
489 __DRI_IMAGE_COMPONENTS_Y_UV, PIPE_FORMAT_NV12, 2,
490 { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
491 { 1, 1, 1, __DRI_IMAGE_FORMAT_GR88, 2 } } },
492
493 { DRM_FORMAT_P010, __DRI_IMAGE_FORMAT_NONE,
494 __DRI_IMAGE_COMPONENTS_Y_UV, PIPE_FORMAT_P016, 2,
495 { { 0, 0, 0, __DRI_IMAGE_FORMAT_R16, 2 },
496 { 1, 1, 1, __DRI_IMAGE_FORMAT_GR1616, 4 } } },
497 { DRM_FORMAT_P012, __DRI_IMAGE_FORMAT_NONE,
498 __DRI_IMAGE_COMPONENTS_Y_UV, PIPE_FORMAT_P016, 2,
499 { { 0, 0, 0, __DRI_IMAGE_FORMAT_R16, 2 },
500 { 1, 1, 1, __DRI_IMAGE_FORMAT_GR1616, 4 } } },
501 { DRM_FORMAT_P016, __DRI_IMAGE_FORMAT_NONE,
502 __DRI_IMAGE_COMPONENTS_Y_UV, PIPE_FORMAT_P016, 2,
503 { { 0, 0, 0, __DRI_IMAGE_FORMAT_R16, 2 },
504 { 1, 1, 1, __DRI_IMAGE_FORMAT_GR1616, 4 } } },
505
506 { DRM_FORMAT_NV16, __DRI_IMAGE_FORMAT_NONE,
507 __DRI_IMAGE_COMPONENTS_Y_UV, PIPE_FORMAT_NV12, 2,
508 { { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
509 { 1, 1, 0, __DRI_IMAGE_FORMAT_GR88, 2 } } },
510
511 { DRM_FORMAT_AYUV, __DRI_IMAGE_FORMAT_ABGR8888,
512 __DRI_IMAGE_COMPONENTS_AYUV, PIPE_FORMAT_AYUV, 1,
513 { { 0, 0, 0, __DRI_IMAGE_FORMAT_ABGR8888, 4 } } },
514 { DRM_FORMAT_XYUV8888, __DRI_IMAGE_FORMAT_XBGR8888,
515 __DRI_IMAGE_COMPONENTS_XYUV, PIPE_FORMAT_XYUV, 1,
516 { { 0, 0, 0, __DRI_IMAGE_FORMAT_XBGR8888, 4 } } },
517
518 /* For YUYV and UYVY buffers, we set up two overlapping DRI images
519 * and treat them as planar buffers in the compositors.
520 * Plane 0 is GR88 and samples YU or YV pairs and places Y into
521 * the R component, while plane 1 is ARGB/ABGR and samples YUYV/UYVY
522 * clusters and places pairs and places U into the G component and
523 * V into A. This lets the texture sampler interpolate the Y
524 * components correctly when sampling from plane 0, and interpolate
525 * U and V correctly when sampling from plane 1. */
526 { DRM_FORMAT_YUYV, __DRI_IMAGE_FORMAT_NONE,
527 __DRI_IMAGE_COMPONENTS_Y_XUXV, PIPE_FORMAT_YUYV, 2,
528 { { 0, 0, 0, __DRI_IMAGE_FORMAT_GR88, 2 },
529 { 0, 1, 0, __DRI_IMAGE_FORMAT_ARGB8888, 4 } } },
530 { DRM_FORMAT_UYVY, __DRI_IMAGE_FORMAT_NONE,
531 __DRI_IMAGE_COMPONENTS_Y_UXVX, PIPE_FORMAT_UYVY, 2,
532 { { 0, 0, 0, __DRI_IMAGE_FORMAT_GR88, 2 },
533 { 0, 1, 0, __DRI_IMAGE_FORMAT_ABGR8888, 4 } } }
534 };
535
536 const struct dri2_format_mapping *
537 dri2_get_mapping_by_fourcc(int fourcc)
538 {
539 for (unsigned i = 0; i < ARRAY_SIZE(dri2_format_table); i++) {
540 if (dri2_format_table[i].dri_fourcc == fourcc)
541 return &dri2_format_table[i];
542 }
543
544 return NULL;
545 }
546
547 const struct dri2_format_mapping *
548 dri2_get_mapping_by_format(int format)
549 {
550 for (unsigned i = 0; i < ARRAY_SIZE(dri2_format_table); i++) {
551 if (dri2_format_table[i].dri_format == format)
552 return &dri2_format_table[i];
553 }
554
555 return NULL;
556 }
557
558 enum pipe_format
559 dri2_get_pipe_format_for_dri_format(int format)
560 {
561 for (unsigned i = 0; i < ARRAY_SIZE(dri2_format_table); i++) {
562 if (dri2_format_table[i].dri_format == format)
563 return dri2_format_table[i].pipe_format;
564 }
565
566 return PIPE_FORMAT_NONE;
567 }
568
569 boolean
570 dri2_yuv_dma_buf_supported(struct dri_screen *screen,
571 const struct dri2_format_mapping *map)
572 {
573 struct pipe_screen *pscreen = screen->base.screen;
574
575 for (unsigned i = 0; i < map->nplanes; i++) {
576 if (!pscreen->is_format_supported(pscreen,
577 dri2_get_pipe_format_for_dri_format(map->planes[i].dri_format),
578 screen->target, 0, 0, PIPE_BIND_SAMPLER_VIEW))
579 return false;
580 }
581 return true;
582 }
583
584 boolean
585 dri2_query_dma_buf_formats(__DRIscreen *_screen, int max, int *formats,
586 int *count)
587 {
588 struct dri_screen *screen = dri_screen(_screen);
589 struct pipe_screen *pscreen = screen->base.screen;
590 int i, j;
591
592 for (i = 0, j = 0; (i < ARRAY_SIZE(dri2_format_table)) &&
593 (j < max || max == 0); i++) {
594 const struct dri2_format_mapping *map = &dri2_format_table[i];
595
596 /* The sRGB format is not a real FourCC as defined by drm_fourcc.h, so we
597 * must not leak it out to clients.
598 */
599 if (dri2_format_table[i].dri_fourcc == __DRI_IMAGE_FOURCC_SARGB8888)
600 continue;
601
602 if (pscreen->is_format_supported(pscreen, map->pipe_format,
603 screen->target, 0, 0,
604 PIPE_BIND_RENDER_TARGET) ||
605 pscreen->is_format_supported(pscreen, map->pipe_format,
606 screen->target, 0, 0,
607 PIPE_BIND_SAMPLER_VIEW) ||
608 dri2_yuv_dma_buf_supported(screen, map)) {
609 if (j < max)
610 formats[j] = map->dri_fourcc;
611 j++;
612 }
613 }
614 *count = j;
615 return true;
616 }
617
618 /* vim: set sw=3 ts=8 sts=3 expandtab: */