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