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