1 /*
2 * Copyright © 2011 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Benjamin Franzke <benjaminfranzke@googlemail.com>
26 */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <stddef.h>
31 #include <stdint.h>
32 #include <stdbool.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <limits.h>
36 #include <assert.h>
37
38 #include <sys/types.h>
39 #include <unistd.h>
40 #include <dlfcn.h>
41 #include <xf86drm.h>
42 #include "drm-uapi/drm_fourcc.h"
43
44 #include <GL/gl.h> /* dri_interface needs GL types */
45 #include <GL/internal/dri_interface.h>
46
47 #include "gbm_driint.h"
48
49 #include "gbmint.h"
50 #include "loader_dri_helper.h"
51 #include "kopper_interface.h"
52 #include "loader.h"
53 #include "util/debug.h"
54 #include "util/macros.h"
55
56 /* For importing wl_buffer */
57 #if HAVE_WAYLAND_PLATFORM
58 #include "wayland-drm.h"
59 #endif
60
61 static __DRIimage *
dri_lookup_egl_image(__DRIscreen * screen,void * image,void * data)62 dri_lookup_egl_image(__DRIscreen *screen, void *image, void *data)
63 {
64 struct gbm_dri_device *dri = data;
65
66 if (dri->lookup_image == NULL)
67 return NULL;
68
69 return dri->lookup_image(screen, image, dri->lookup_user_data);
70 }
71
72 static GLboolean
dri_validate_egl_image(void * image,void * data)73 dri_validate_egl_image(void *image, void *data)
74 {
75 struct gbm_dri_device *dri = data;
76
77 if (dri->validate_image == NULL)
78 return false;
79
80 return dri->validate_image(image, dri->lookup_user_data);
81 }
82
83 static __DRIimage *
dri_lookup_egl_image_validated(void * image,void * data)84 dri_lookup_egl_image_validated(void *image, void *data)
85 {
86 struct gbm_dri_device *dri = data;
87
88 if (dri->lookup_image_validated == NULL)
89 return NULL;
90
91 return dri->lookup_image_validated(image, dri->lookup_user_data);
92 }
93
94 static __DRIbuffer *
dri_get_buffers(__DRIdrawable * driDrawable,int * width,int * height,unsigned int * attachments,int count,int * out_count,void * data)95 dri_get_buffers(__DRIdrawable * driDrawable,
96 int *width, int *height,
97 unsigned int *attachments, int count,
98 int *out_count, void *data)
99 {
100 struct gbm_dri_surface *surf = data;
101 struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
102
103 if (dri->get_buffers == NULL)
104 return NULL;
105
106 return dri->get_buffers(driDrawable, width, height, attachments,
107 count, out_count, surf->dri_private);
108 }
109
110 static void
dri_flush_front_buffer(__DRIdrawable * driDrawable,void * data)111 dri_flush_front_buffer(__DRIdrawable * driDrawable, void *data)
112 {
113 struct gbm_dri_surface *surf = data;
114 struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
115
116 if (dri->flush_front_buffer != NULL)
117 dri->flush_front_buffer(driDrawable, surf->dri_private);
118 }
119
120 static __DRIbuffer *
dri_get_buffers_with_format(__DRIdrawable * driDrawable,int * width,int * height,unsigned int * attachments,int count,int * out_count,void * data)121 dri_get_buffers_with_format(__DRIdrawable * driDrawable,
122 int *width, int *height,
123 unsigned int *attachments, int count,
124 int *out_count, void *data)
125 {
126 struct gbm_dri_surface *surf = data;
127 struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
128
129 if (dri->get_buffers_with_format == NULL)
130 return NULL;
131
132 return
133 dri->get_buffers_with_format(driDrawable, width, height, attachments,
134 count, out_count, surf->dri_private);
135 }
136
137 static unsigned
dri_get_capability(void * loaderPrivate,enum dri_loader_cap cap)138 dri_get_capability(void *loaderPrivate, enum dri_loader_cap cap)
139 {
140 /* Note: loaderPrivate is _EGLDisplay* */
141 switch (cap) {
142 case DRI_LOADER_CAP_FP16:
143 return 1;
144 default:
145 return 0;
146 }
147 }
148
149 static int
image_get_buffers(__DRIdrawable * driDrawable,unsigned int format,uint32_t * stamp,void * loaderPrivate,uint32_t buffer_mask,struct __DRIimageList * buffers)150 image_get_buffers(__DRIdrawable *driDrawable,
151 unsigned int format,
152 uint32_t *stamp,
153 void *loaderPrivate,
154 uint32_t buffer_mask,
155 struct __DRIimageList *buffers)
156 {
157 struct gbm_dri_surface *surf = loaderPrivate;
158 struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
159
160 if (dri->image_get_buffers == NULL)
161 return 0;
162
163 return dri->image_get_buffers(driDrawable, format, stamp,
164 surf->dri_private, buffer_mask, buffers);
165 }
166
167 static void
swrast_get_drawable_info(__DRIdrawable * driDrawable,int * x,int * y,int * width,int * height,void * loaderPrivate)168 swrast_get_drawable_info(__DRIdrawable *driDrawable,
169 int *x,
170 int *y,
171 int *width,
172 int *height,
173 void *loaderPrivate)
174 {
175 struct gbm_dri_surface *surf = loaderPrivate;
176
177 *x = 0;
178 *y = 0;
179 *width = surf->base.v0.width;
180 *height = surf->base.v0.height;
181 }
182
183 static void
swrast_put_image2(__DRIdrawable * driDrawable,int op,int x,int y,int width,int height,int stride,char * data,void * loaderPrivate)184 swrast_put_image2(__DRIdrawable *driDrawable,
185 int op,
186 int x,
187 int y,
188 int width,
189 int height,
190 int stride,
191 char *data,
192 void *loaderPrivate)
193 {
194 struct gbm_dri_surface *surf = loaderPrivate;
195 struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
196
197 dri->swrast_put_image2(driDrawable,
198 op, x, y,
199 width, height, stride,
200 data, surf->dri_private);
201 }
202
203 static void
swrast_put_image(__DRIdrawable * driDrawable,int op,int x,int y,int width,int height,char * data,void * loaderPrivate)204 swrast_put_image(__DRIdrawable *driDrawable,
205 int op,
206 int x,
207 int y,
208 int width,
209 int height,
210 char *data,
211 void *loaderPrivate)
212 {
213 swrast_put_image2(driDrawable, op, x, y, width, height,
214 width * 4, data, loaderPrivate);
215 }
216
217 static void
swrast_get_image(__DRIdrawable * driDrawable,int x,int y,int width,int height,char * data,void * loaderPrivate)218 swrast_get_image(__DRIdrawable *driDrawable,
219 int x,
220 int y,
221 int width,
222 int height,
223 char *data,
224 void *loaderPrivate)
225 {
226 struct gbm_dri_surface *surf = loaderPrivate;
227 struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
228
229 dri->swrast_get_image(driDrawable,
230 x, y,
231 width, height,
232 data, surf->dri_private);
233 }
234
235 static const __DRIuseInvalidateExtension use_invalidate = {
236 .base = { __DRI_USE_INVALIDATE, 1 }
237 };
238
239 static const __DRIimageLookupExtension image_lookup_extension = {
240 .base = { __DRI_IMAGE_LOOKUP, 2 },
241
242 .lookupEGLImage = dri_lookup_egl_image,
243 .validateEGLImage = dri_validate_egl_image,
244 .lookupEGLImageValidated = dri_lookup_egl_image_validated,
245 };
246
247 static const __DRIdri2LoaderExtension dri2_loader_extension = {
248 .base = { __DRI_DRI2_LOADER, 4 },
249
250 .getBuffers = dri_get_buffers,
251 .flushFrontBuffer = dri_flush_front_buffer,
252 .getBuffersWithFormat = dri_get_buffers_with_format,
253 .getCapability = dri_get_capability,
254 };
255
256 static const __DRIimageLoaderExtension image_loader_extension = {
257 .base = { __DRI_IMAGE_LOADER, 2 },
258
259 .getBuffers = image_get_buffers,
260 .flushFrontBuffer = dri_flush_front_buffer,
261 .getCapability = dri_get_capability,
262 };
263
264 static const __DRIswrastLoaderExtension swrast_loader_extension = {
265 .base = { __DRI_SWRAST_LOADER, 2 },
266
267 .getDrawableInfo = swrast_get_drawable_info,
268 .putImage = swrast_put_image,
269 .getImage = swrast_get_image,
270 .putImage2 = swrast_put_image2
271 };
272
273 static const __DRIkopperLoaderExtension kopper_loader_extension = {
274 .base = { __DRI_KOPPER_LOADER, 1 },
275
276 .SetSurfaceCreateInfo = NULL,
277 };
278
279 static const __DRIextension *gbm_dri_screen_extensions[] = {
280 &image_lookup_extension.base,
281 &use_invalidate.base,
282 &dri2_loader_extension.base,
283 &image_loader_extension.base,
284 &swrast_loader_extension.base,
285 &kopper_loader_extension.base,
286 NULL,
287 };
288
289 struct dri_extension_match {
290 const char *name;
291 int version;
292 int offset;
293 bool optional;
294 };
295
296 static struct dri_extension_match dri_core_extensions[] = {
297 { __DRI2_FLUSH, 1, offsetof(struct gbm_dri_device, flush), false },
298 { __DRI_IMAGE, 1, offsetof(struct gbm_dri_device, image), false },
299 { __DRI2_FENCE, 1, offsetof(struct gbm_dri_device, fence), true },
300 };
301
302 static struct dri_extension_match gbm_dri_device_extensions[] = {
303 { __DRI_CORE, 1, offsetof(struct gbm_dri_device, core), false },
304 { __DRI_DRI2, 1, offsetof(struct gbm_dri_device, dri2), false },
305 };
306
307 static struct dri_extension_match gbm_swrast_device_extensions[] = {
308 { __DRI_CORE, 1, offsetof(struct gbm_dri_device, core), false },
309 { __DRI_SWRAST, 1, offsetof(struct gbm_dri_device, swrast), false },
310 { __DRI_KOPPER, 1, offsetof(struct gbm_dri_device, kopper), true },
311 };
312
313 static bool
dri_bind_extensions(struct gbm_dri_device * dri,struct dri_extension_match * matches,size_t num_matches,const __DRIextension ** extensions)314 dri_bind_extensions(struct gbm_dri_device *dri,
315 struct dri_extension_match *matches, size_t num_matches,
316 const __DRIextension **extensions)
317 {
318 bool ret = true;
319 void *field;
320
321 for (size_t i = 0; extensions[i]; i++) {
322 for (size_t j = 0; j < num_matches; j++) {
323 if (strcmp(extensions[i]->name, matches[j].name) == 0 &&
324 extensions[i]->version >= matches[j].version) {
325 field = ((char *) dri + matches[j].offset);
326 *(const __DRIextension **) field = extensions[i];
327 }
328 }
329 }
330
331 for (size_t j = 0; j < num_matches; j++) {
332 field = ((char *) dri + matches[j].offset);
333 if ((*(const __DRIextension **) field == NULL) && !matches[j].optional) {
334 fprintf(stderr, "gbm: did not find extension %s version %d\n",
335 matches[j].name, matches[j].version);
336 ret = false;
337 }
338 }
339
340 return ret;
341 }
342
343 static const __DRIextension **
dri_open_driver(struct gbm_dri_device * dri)344 dri_open_driver(struct gbm_dri_device *dri)
345 {
346 /* Temporarily work around dri driver libs that need symbols in libglapi
347 * but don't automatically link it in.
348 */
349 /* XXX: Library name differs on per platforms basis. Update this as
350 * osx/cygwin/windows/bsd gets support for GBM..
351 */
352 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
353
354 static const char *search_path_vars[] = {
355 /* Read GBM_DRIVERS_PATH first for compatibility, but LIBGL_DRIVERS_PATH
356 * is recommended over GBM_DRIVERS_PATH.
357 */
358 "GBM_DRIVERS_PATH",
359 /* Read LIBGL_DRIVERS_PATH if GBM_DRIVERS_PATH was not set.
360 * LIBGL_DRIVERS_PATH is recommended over GBM_DRIVERS_PATH.
361 */
362 "LIBGL_DRIVERS_PATH",
363 NULL
364 };
365 return loader_open_driver(dri->driver_name, &dri->driver, search_path_vars);
366 }
367
368 static int
dri_load_driver(struct gbm_dri_device * dri)369 dri_load_driver(struct gbm_dri_device *dri)
370 {
371 const __DRIextension **extensions;
372
373 extensions = dri_open_driver(dri);
374 if (!extensions)
375 return -1;
376
377 if (!dri_bind_extensions(dri, gbm_dri_device_extensions,
378 ARRAY_SIZE(gbm_dri_device_extensions),
379 extensions)) {
380 dlclose(dri->driver);
381 fprintf(stderr, "failed to bind extensions\n");
382 return -1;
383 }
384
385 dri->driver_extensions = extensions;
386
387 return 0;
388 }
389
390 static int
dri_load_driver_swrast(struct gbm_dri_device * dri)391 dri_load_driver_swrast(struct gbm_dri_device *dri)
392 {
393 const __DRIextension **extensions;
394
395 extensions = dri_open_driver(dri);
396 if (!extensions)
397 return -1;
398
399 if (!dri_bind_extensions(dri, gbm_swrast_device_extensions,
400 ARRAY_SIZE(gbm_swrast_device_extensions),
401 extensions)) {
402 dlclose(dri->driver);
403 fprintf(stderr, "failed to bind extensions\n");
404 return -1;
405 }
406
407 dri->driver_extensions = extensions;
408
409 return 0;
410 }
411
412 static int
dri_screen_create_dri2(struct gbm_dri_device * dri,char * driver_name)413 dri_screen_create_dri2(struct gbm_dri_device *dri, char *driver_name)
414 {
415 const __DRIextension **extensions;
416 int ret = 0;
417
418 dri->driver_name = driver_name;
419 if (dri->driver_name == NULL)
420 return -1;
421
422 ret = dri_load_driver(dri);
423 if (ret) {
424 fprintf(stderr, "failed to load driver: %s\n", dri->driver_name);
425 return ret;
426 }
427
428 dri->loader_extensions = gbm_dri_screen_extensions;
429
430 if (dri->dri2 == NULL)
431 return -1;
432
433 if (dri->dri2->base.version >= 4) {
434 dri->screen = dri->dri2->createNewScreen2(0, dri->base.v0.fd,
435 dri->loader_extensions,
436 dri->driver_extensions,
437 &dri->driver_configs, dri);
438 } else {
439 dri->screen = dri->dri2->createNewScreen(0, dri->base.v0.fd,
440 dri->loader_extensions,
441 &dri->driver_configs, dri);
442 }
443 if (dri->screen == NULL)
444 return -1;
445
446 extensions = dri->core->getExtensions(dri->screen);
447 if (!dri_bind_extensions(dri, dri_core_extensions,
448 ARRAY_SIZE(dri_core_extensions),
449 extensions)) {
450 ret = -1;
451 goto free_screen;
452 }
453
454 dri->lookup_image = NULL;
455 dri->lookup_user_data = NULL;
456
457 return 0;
458
459 free_screen:
460 dri->core->destroyScreen(dri->screen);
461
462 return ret;
463 }
464
465 static int
dri_screen_create_swrast(struct gbm_dri_device * dri)466 dri_screen_create_swrast(struct gbm_dri_device *dri)
467 {
468 int ret;
469
470 dri->driver_name = strdup("swrast");
471 if (dri->driver_name == NULL)
472 return -1;
473
474 ret = dri_load_driver_swrast(dri);
475 if (ret) {
476 fprintf(stderr, "failed to load swrast driver\n");
477 return ret;
478 }
479
480 dri->loader_extensions = gbm_dri_screen_extensions;
481
482 if (dri->swrast == NULL)
483 return -1;
484
485 if (dri->swrast->base.version >= 4) {
486 dri->screen = dri->swrast->createNewScreen2(0, dri->loader_extensions,
487 dri->driver_extensions,
488 &dri->driver_configs, dri);
489 } else {
490 dri->screen = dri->swrast->createNewScreen(0, dri->loader_extensions,
491 &dri->driver_configs, dri);
492 }
493 if (dri->screen == NULL)
494 return -1;
495
496 dri->lookup_image = NULL;
497 dri->lookup_user_data = NULL;
498
499 return 0;
500 }
501
502 static int
dri_screen_create(struct gbm_dri_device * dri)503 dri_screen_create(struct gbm_dri_device *dri)
504 {
505 char *driver_name;
506
507 driver_name = loader_get_driver_for_fd(dri->base.v0.fd);
508 if (!driver_name)
509 return -1;
510
511 return dri_screen_create_dri2(dri, driver_name);
512 }
513
514 static int
dri_screen_create_sw(struct gbm_dri_device * dri)515 dri_screen_create_sw(struct gbm_dri_device *dri)
516 {
517 char *driver_name;
518 int ret;
519
520 driver_name = strdup("zink");
521 if (!driver_name)
522 return -errno;
523
524 ret = dri_screen_create_dri2(dri, driver_name);
525 if (ret != 0) {
526 driver_name = strdup("kms_swrast");
527 if (!driver_name)
528 return -errno;
529
530 ret = dri_screen_create_dri2(dri, driver_name);
531 if (ret != 0)
532 ret = dri_screen_create_swrast(dri);
533 if (ret != 0)
534 return ret;
535 }
536
537 dri->software = true;
538 return 0;
539 }
540
541 static const struct gbm_dri_visual gbm_dri_visuals_table[] = {
542 {
543 GBM_FORMAT_R8, __DRI_IMAGE_FORMAT_R8,
544 { 0, -1, -1, -1 },
545 { 8, 0, 0, 0 },
546 },
547 {
548 GBM_FORMAT_R16, __DRI_IMAGE_FORMAT_R16,
549 { 0, -1, -1, -1 },
550 { 16, 0, 0, 0 },
551 },
552 {
553 GBM_FORMAT_GR88, __DRI_IMAGE_FORMAT_GR88,
554 { 0, 8, -1, -1 },
555 { 8, 8, 0, 0 },
556 },
557 {
558 GBM_FORMAT_GR1616, __DRI_IMAGE_FORMAT_GR1616,
559 { 0, 16, -1, -1 },
560 { 16, 16, 0, 0 },
561 },
562 {
563 GBM_FORMAT_ARGB1555, __DRI_IMAGE_FORMAT_ARGB1555,
564 { 10, 5, 0, 11 },
565 { 5, 5, 5, 1 },
566 },
567 {
568 GBM_FORMAT_RGB565, __DRI_IMAGE_FORMAT_RGB565,
569 { 11, 5, 0, -1 },
570 { 5, 6, 5, 0 },
571 },
572 {
573 GBM_FORMAT_XRGB8888, __DRI_IMAGE_FORMAT_XRGB8888,
574 { 16, 8, 0, -1 },
575 { 8, 8, 8, 0 },
576 },
577 {
578 GBM_FORMAT_ARGB8888, __DRI_IMAGE_FORMAT_ARGB8888,
579 { 16, 8, 0, 24 },
580 { 8, 8, 8, 8 },
581 },
582 {
583 GBM_FORMAT_XBGR8888, __DRI_IMAGE_FORMAT_XBGR8888,
584 { 0, 8, 16, -1 },
585 { 8, 8, 8, 0 },
586 },
587 {
588 GBM_FORMAT_ABGR8888, __DRI_IMAGE_FORMAT_ABGR8888,
589 { 0, 8, 16, 24 },
590 { 8, 8, 8, 8 },
591 },
592 {
593 GBM_FORMAT_XRGB2101010, __DRI_IMAGE_FORMAT_XRGB2101010,
594 { 20, 10, 0, -1 },
595 { 10, 10, 10, 0 },
596 },
597 {
598 GBM_FORMAT_ARGB2101010, __DRI_IMAGE_FORMAT_ARGB2101010,
599 { 20, 10, 0, 30 },
600 { 10, 10, 10, 2 },
601 },
602 {
603 GBM_FORMAT_XBGR2101010, __DRI_IMAGE_FORMAT_XBGR2101010,
604 { 0, 10, 20, -1 },
605 { 10, 10, 10, 0 },
606 },
607 {
608 GBM_FORMAT_ABGR2101010, __DRI_IMAGE_FORMAT_ABGR2101010,
609 { 0, 10, 20, 30 },
610 { 10, 10, 10, 2 },
611 },
612 {
613 GBM_FORMAT_XBGR16161616, __DRI_IMAGE_FORMAT_XBGR16161616,
614 { 0, 16, 32, -1 },
615 { 16, 16, 16, 0 },
616 },
617 {
618 GBM_FORMAT_ABGR16161616, __DRI_IMAGE_FORMAT_ABGR16161616,
619 { 0, 16, 32, 48 },
620 { 16, 16, 16, 16 },
621 },
622 {
623 GBM_FORMAT_XBGR16161616F, __DRI_IMAGE_FORMAT_XBGR16161616F,
624 { 0, 16, 32, -1 },
625 { 16, 16, 16, 0 },
626 true,
627 },
628 {
629 GBM_FORMAT_ABGR16161616F, __DRI_IMAGE_FORMAT_ABGR16161616F,
630 { 0, 16, 32, 48 },
631 { 16, 16, 16, 16 },
632 true,
633 },
634 };
635
636 static int
gbm_format_to_dri_format(uint32_t gbm_format)637 gbm_format_to_dri_format(uint32_t gbm_format)
638 {
639 gbm_format = gbm_core.v0.format_canonicalize(gbm_format);
640 for (size_t i = 0; i < ARRAY_SIZE(gbm_dri_visuals_table); i++) {
641 if (gbm_dri_visuals_table[i].gbm_format == gbm_format)
642 return gbm_dri_visuals_table[i].dri_image_format;
643 }
644
645 return 0;
646 }
647
648 static uint32_t
gbm_dri_to_gbm_format(int dri_format)649 gbm_dri_to_gbm_format(int dri_format)
650 {
651 for (size_t i = 0; i < ARRAY_SIZE(gbm_dri_visuals_table); i++) {
652 if (gbm_dri_visuals_table[i].dri_image_format == dri_format)
653 return gbm_dri_visuals_table[i].gbm_format;
654 }
655
656 return 0;
657 }
658
659 static int
gbm_dri_is_format_supported(struct gbm_device * gbm,uint32_t format,uint32_t usage)660 gbm_dri_is_format_supported(struct gbm_device *gbm,
661 uint32_t format,
662 uint32_t usage)
663 {
664 struct gbm_dri_device *dri = gbm_dri_device(gbm);
665 int count;
666
667 if ((usage & GBM_BO_USE_CURSOR) && (usage & GBM_BO_USE_RENDERING))
668 return 0;
669
670 format = gbm_core.v0.format_canonicalize(format);
671 if (gbm_format_to_dri_format(format) == 0)
672 return 0;
673
674 /* If there is no query, fall back to the small table which was originally
675 * here. */
676 if (dri->image->base.version <= 15 || !dri->image->queryDmaBufModifiers) {
677 switch (format) {
678 case GBM_FORMAT_XRGB8888:
679 case GBM_FORMAT_ARGB8888:
680 case GBM_FORMAT_XBGR8888:
681 return 1;
682 default:
683 return 0;
684 }
685 }
686
687 /* This returns false if the format isn't supported */
688 if (!dri->image->queryDmaBufModifiers(dri->screen, format, 0, NULL, NULL,
689 &count))
690 return 0;
691
692 return 1;
693 }
694
695 static int
gbm_dri_get_format_modifier_plane_count(struct gbm_device * gbm,uint32_t format,uint64_t modifier)696 gbm_dri_get_format_modifier_plane_count(struct gbm_device *gbm,
697 uint32_t format,
698 uint64_t modifier)
699 {
700 struct gbm_dri_device *dri = gbm_dri_device(gbm);
701 uint64_t plane_count;
702
703 if (dri->image->base.version < 16 ||
704 !dri->image->queryDmaBufFormatModifierAttribs)
705 return -1;
706
707 format = gbm_core.v0.format_canonicalize(format);
708 if (gbm_format_to_dri_format(format) == 0)
709 return -1;
710
711 if (!dri->image->queryDmaBufFormatModifierAttribs(
712 dri->screen, format, modifier,
713 __DRI_IMAGE_FORMAT_MODIFIER_ATTRIB_PLANE_COUNT, &plane_count))
714 return -1;
715
716 return plane_count;
717 }
718
719 static int
gbm_dri_bo_write(struct gbm_bo * _bo,const void * buf,size_t count)720 gbm_dri_bo_write(struct gbm_bo *_bo, const void *buf, size_t count)
721 {
722 struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
723
724 if (bo->image != NULL) {
725 errno = EINVAL;
726 return -1;
727 }
728
729 memcpy(bo->map, buf, count);
730
731 return 0;
732 }
733
734 static int
gbm_dri_bo_get_fd(struct gbm_bo * _bo)735 gbm_dri_bo_get_fd(struct gbm_bo *_bo)
736 {
737 struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
738 struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
739 int fd;
740
741 if (bo->image == NULL)
742 return -1;
743
744 if (!dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_FD, &fd))
745 return -1;
746
747 return fd;
748 }
749
750 static int
get_number_planes(struct gbm_dri_device * dri,__DRIimage * image)751 get_number_planes(struct gbm_dri_device *dri, __DRIimage *image)
752 {
753 int num_planes = 0;
754
755 /* Dumb buffers are single-plane only. */
756 if (!image)
757 return 1;
758
759 dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_NUM_PLANES, &num_planes);
760
761 if (num_planes <= 0)
762 num_planes = 1;
763
764 return num_planes;
765 }
766
767 static int
gbm_dri_bo_get_planes(struct gbm_bo * _bo)768 gbm_dri_bo_get_planes(struct gbm_bo *_bo)
769 {
770 struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
771 struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
772
773 return get_number_planes(dri, bo->image);
774 }
775
776 static union gbm_bo_handle
gbm_dri_bo_get_handle_for_plane(struct gbm_bo * _bo,int plane)777 gbm_dri_bo_get_handle_for_plane(struct gbm_bo *_bo, int plane)
778 {
779 struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
780 struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
781 union gbm_bo_handle ret;
782 ret.s32 = -1;
783
784 if (!dri->image || dri->image->base.version < 13 || !dri->image->fromPlanar) {
785 /* Preserve legacy behavior if plane is 0 */
786 if (plane == 0) {
787 /* NOTE: return _bo->handle, *NOT* bo->handle which is invalid at this point */
788 return _bo->v0.handle;
789 }
790
791 errno = ENOSYS;
792 return ret;
793 }
794
795 if (plane >= get_number_planes(dri, bo->image)) {
796 errno = EINVAL;
797 return ret;
798 }
799
800 /* dumb BOs can only utilize non-planar formats */
801 if (!bo->image) {
802 assert(plane == 0);
803 ret.s32 = bo->handle;
804 return ret;
805 }
806
807 __DRIimage *image = dri->image->fromPlanar(bo->image, plane, NULL);
808 if (image) {
809 dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_HANDLE, &ret.s32);
810 dri->image->destroyImage(image);
811 } else {
812 assert(plane == 0);
813 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE, &ret.s32);
814 }
815
816 return ret;
817 }
818
819 static int
gbm_dri_bo_get_plane_fd(struct gbm_bo * _bo,int plane)820 gbm_dri_bo_get_plane_fd(struct gbm_bo *_bo, int plane)
821 {
822 struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
823 struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
824 int fd = -1;
825
826 if (!dri->image || dri->image->base.version < 13 || !dri->image->fromPlanar) {
827 /* Preserve legacy behavior if plane is 0 */
828 if (plane == 0)
829 return gbm_dri_bo_get_fd(_bo);
830
831 errno = ENOSYS;
832 return -1;
833 }
834
835 /* dumb BOs can only utilize non-planar formats */
836 if (!bo->image) {
837 errno = EINVAL;
838 return -1;
839 }
840
841 if (plane >= get_number_planes(dri, bo->image)) {
842 errno = EINVAL;
843 return -1;
844 }
845
846 __DRIimage *image = dri->image->fromPlanar(bo->image, plane, NULL);
847 if (image) {
848 dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &fd);
849 dri->image->destroyImage(image);
850 } else {
851 assert(plane == 0);
852 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_FD, &fd);
853 }
854
855 return fd;
856 }
857
858 static uint32_t
gbm_dri_bo_get_stride(struct gbm_bo * _bo,int plane)859 gbm_dri_bo_get_stride(struct gbm_bo *_bo, int plane)
860 {
861 struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
862 struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
863 __DRIimage *image;
864 int stride = 0;
865
866 if (!dri->image || dri->image->base.version < 11 || !dri->image->fromPlanar) {
867 /* Preserve legacy behavior if plane is 0 */
868 if (plane == 0)
869 return _bo->v0.stride;
870
871 errno = ENOSYS;
872 return 0;
873 }
874
875 if (plane >= get_number_planes(dri, bo->image)) {
876 errno = EINVAL;
877 return 0;
878 }
879
880 if (bo->image == NULL) {
881 assert(plane == 0);
882 return _bo->v0.stride;
883 }
884
885 image = dri->image->fromPlanar(bo->image, plane, NULL);
886 if (image) {
887 dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
888 dri->image->destroyImage(image);
889 } else {
890 assert(plane == 0);
891 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
892 }
893
894 return (uint32_t)stride;
895 }
896
897 static uint32_t
gbm_dri_bo_get_offset(struct gbm_bo * _bo,int plane)898 gbm_dri_bo_get_offset(struct gbm_bo *_bo, int plane)
899 {
900 struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
901 struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
902 int offset = 0;
903
904 /* These error cases do not actually return an error code, as the user
905 * will also fail to obtain the handle/FD from the BO. In that case, the
906 * offset is irrelevant, as they have no buffer to offset into, so
907 * returning 0 is harmless.
908 */
909 if (!dri->image || dri->image->base.version < 13 || !dri->image->fromPlanar)
910 return 0;
911
912 if (plane >= get_number_planes(dri, bo->image))
913 return 0;
914
915 /* Dumb images have no offset */
916 if (bo->image == NULL) {
917 assert(plane == 0);
918 return 0;
919 }
920
921 __DRIimage *image = dri->image->fromPlanar(bo->image, plane, NULL);
922 if (image) {
923 dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_OFFSET, &offset);
924 dri->image->destroyImage(image);
925 } else {
926 assert(plane == 0);
927 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_OFFSET, &offset);
928 }
929
930 return (uint32_t)offset;
931 }
932
933 static uint64_t
gbm_dri_bo_get_modifier(struct gbm_bo * _bo)934 gbm_dri_bo_get_modifier(struct gbm_bo *_bo)
935 {
936 struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
937 struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
938
939 if (!dri->image || dri->image->base.version < 14) {
940 errno = ENOSYS;
941 return DRM_FORMAT_MOD_INVALID;
942 }
943
944 /* Dumb buffers have no modifiers */
945 if (!bo->image)
946 return DRM_FORMAT_MOD_LINEAR;
947
948 uint64_t ret = 0;
949 int mod;
950 if (!dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_MODIFIER_UPPER,
951 &mod))
952 return DRM_FORMAT_MOD_INVALID;
953
954 ret = (uint64_t)mod << 32;
955
956 if (!dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_MODIFIER_LOWER,
957 &mod))
958 return DRM_FORMAT_MOD_INVALID;
959
960 ret |= (uint64_t)(mod & 0xffffffff);
961
962 return ret;
963 }
964
965 static void
gbm_dri_bo_destroy(struct gbm_bo * _bo)966 gbm_dri_bo_destroy(struct gbm_bo *_bo)
967 {
968 struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
969 struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
970 struct drm_mode_destroy_dumb arg;
971
972 if (bo->image != NULL) {
973 dri->image->destroyImage(bo->image);
974 } else {
975 gbm_dri_bo_unmap_dumb(bo);
976 memset(&arg, 0, sizeof(arg));
977 arg.handle = bo->handle;
978 drmIoctl(dri->base.v0.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
979 }
980
981 free(bo);
982 }
983
984 static struct gbm_bo *
gbm_dri_bo_import(struct gbm_device * gbm,uint32_t type,void * buffer,uint32_t usage)985 gbm_dri_bo_import(struct gbm_device *gbm,
986 uint32_t type, void *buffer, uint32_t usage)
987 {
988 struct gbm_dri_device *dri = gbm_dri_device(gbm);
989 struct gbm_dri_bo *bo;
990 __DRIimage *image;
991 unsigned dri_use = 0;
992 int gbm_format;
993
994 /* Required for query image WIDTH & HEIGHT */
995 if (dri->image == NULL || dri->image->base.version < 4) {
996 errno = ENOSYS;
997 return NULL;
998 }
999
1000 switch (type) {
1001 #if HAVE_WAYLAND_PLATFORM
1002 case GBM_BO_IMPORT_WL_BUFFER:
1003 {
1004 struct wl_drm_buffer *wb;
1005
1006 if (!dri->wl_drm) {
1007 errno = EINVAL;
1008 return NULL;
1009 }
1010
1011 wb = wayland_drm_buffer_get(dri->wl_drm, (struct wl_resource *) buffer);
1012 if (!wb) {
1013 errno = EINVAL;
1014 return NULL;
1015 }
1016
1017 image = dri->image->dupImage(wb->driver_buffer, NULL);
1018
1019 /* GBM_FORMAT_* is identical to WL_DRM_FORMAT_*, so no conversion
1020 * required. */
1021 gbm_format = wb->format;
1022 break;
1023 }
1024 #endif
1025
1026 case GBM_BO_IMPORT_EGL_IMAGE:
1027 {
1028 int dri_format;
1029 if (dri->lookup_image == NULL) {
1030 errno = EINVAL;
1031 return NULL;
1032 }
1033
1034 image = dri->lookup_image(dri->screen, buffer, dri->lookup_user_data);
1035 image = dri->image->dupImage(image, NULL);
1036 dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &dri_format);
1037 gbm_format = gbm_dri_to_gbm_format(dri_format);
1038 if (gbm_format == 0) {
1039 errno = EINVAL;
1040 dri->image->destroyImage(image);
1041 return NULL;
1042 }
1043 break;
1044 }
1045
1046 case GBM_BO_IMPORT_FD:
1047 {
1048 struct gbm_import_fd_data *fd_data = buffer;
1049 int stride = fd_data->stride, offset = 0;
1050 int fourcc;
1051
1052 /* GBM's GBM_FORMAT_* tokens are a strict superset of the DRI FourCC
1053 * tokens accepted by createImageFromFds, except for not supporting
1054 * the sARGB format. */
1055 fourcc = gbm_core.v0.format_canonicalize(fd_data->format);
1056
1057 image = dri->image->createImageFromFds(dri->screen,
1058 fd_data->width,
1059 fd_data->height,
1060 fourcc,
1061 &fd_data->fd, 1,
1062 &stride, &offset,
1063 NULL);
1064 if (image == NULL) {
1065 errno = EINVAL;
1066 return NULL;
1067 }
1068 gbm_format = fd_data->format;
1069 break;
1070 }
1071
1072 case GBM_BO_IMPORT_FD_MODIFIER:
1073 {
1074 struct gbm_import_fd_modifier_data *fd_data = buffer;
1075 unsigned int error;
1076 int fourcc;
1077
1078 /* Import with modifier requires createImageFromDmaBufs2 */
1079 if (dri->image == NULL || dri->image->base.version < 15 ||
1080 dri->image->createImageFromDmaBufs2 == NULL) {
1081 errno = ENOSYS;
1082 return NULL;
1083 }
1084
1085 /* GBM's GBM_FORMAT_* tokens are a strict superset of the DRI FourCC
1086 * tokens accepted by createImageFromDmaBufs2, except for not supporting
1087 * the sARGB format. */
1088 fourcc = gbm_core.v0.format_canonicalize(fd_data->format);
1089
1090 image = dri->image->createImageFromDmaBufs2(dri->screen, fd_data->width,
1091 fd_data->height, fourcc,
1092 fd_data->modifier,
1093 fd_data->fds,
1094 fd_data->num_fds,
1095 fd_data->strides,
1096 fd_data->offsets,
1097 0, 0, 0, 0,
1098 &error, NULL);
1099 if (image == NULL) {
1100 errno = ENOSYS;
1101 return NULL;
1102 }
1103
1104 gbm_format = fourcc;
1105 break;
1106 }
1107
1108 default:
1109 errno = ENOSYS;
1110 return NULL;
1111 }
1112
1113
1114 bo = calloc(1, sizeof *bo);
1115 if (bo == NULL) {
1116 dri->image->destroyImage(image);
1117 return NULL;
1118 }
1119
1120 bo->image = image;
1121
1122 if (usage & GBM_BO_USE_SCANOUT)
1123 dri_use |= __DRI_IMAGE_USE_SCANOUT;
1124 if (usage & GBM_BO_USE_CURSOR)
1125 dri_use |= __DRI_IMAGE_USE_CURSOR;
1126 if (dri->image->base.version >= 2 &&
1127 !dri->image->validateUsage(bo->image, dri_use)) {
1128 errno = EINVAL;
1129 dri->image->destroyImage(bo->image);
1130 free(bo);
1131 return NULL;
1132 }
1133
1134 bo->base.gbm = gbm;
1135 bo->base.v0.format = gbm_format;
1136
1137 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_WIDTH,
1138 (int*)&bo->base.v0.width);
1139 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HEIGHT,
1140 (int*)&bo->base.v0.height);
1141 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
1142 (int*)&bo->base.v0.stride);
1143 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
1144 &bo->base.v0.handle.s32);
1145
1146 return &bo->base;
1147 }
1148
1149 static struct gbm_bo *
create_dumb(struct gbm_device * gbm,uint32_t width,uint32_t height,uint32_t format,uint32_t usage)1150 create_dumb(struct gbm_device *gbm,
1151 uint32_t width, uint32_t height,
1152 uint32_t format, uint32_t usage)
1153 {
1154 struct gbm_dri_device *dri = gbm_dri_device(gbm);
1155 struct drm_mode_create_dumb create_arg;
1156 struct gbm_dri_bo *bo;
1157 struct drm_mode_destroy_dumb destroy_arg;
1158 int ret;
1159 int is_cursor, is_scanout;
1160
1161 is_cursor = (usage & GBM_BO_USE_CURSOR) != 0 &&
1162 format == GBM_FORMAT_ARGB8888;
1163 is_scanout = (usage & GBM_BO_USE_SCANOUT) != 0 &&
1164 (format == GBM_FORMAT_XRGB8888 || format == GBM_FORMAT_XBGR8888);
1165 if (!is_cursor && !is_scanout) {
1166 errno = EINVAL;
1167 return NULL;
1168 }
1169
1170 bo = calloc(1, sizeof *bo);
1171 if (bo == NULL)
1172 return NULL;
1173
1174 memset(&create_arg, 0, sizeof(create_arg));
1175 create_arg.bpp = 32;
1176 create_arg.width = width;
1177 create_arg.height = height;
1178
1179 ret = drmIoctl(dri->base.v0.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
1180 if (ret)
1181 goto free_bo;
1182
1183 bo->base.gbm = gbm;
1184 bo->base.v0.width = width;
1185 bo->base.v0.height = height;
1186 bo->base.v0.stride = create_arg.pitch;
1187 bo->base.v0.format = format;
1188 bo->base.v0.handle.u32 = create_arg.handle;
1189 bo->handle = create_arg.handle;
1190 bo->size = create_arg.size;
1191
1192 if (gbm_dri_bo_map_dumb(bo) == NULL)
1193 goto destroy_dumb;
1194
1195 return &bo->base;
1196
1197 destroy_dumb:
1198 memset(&destroy_arg, 0, sizeof destroy_arg);
1199 destroy_arg.handle = create_arg.handle;
1200 drmIoctl(dri->base.v0.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
1201 free_bo:
1202 free(bo);
1203
1204 return NULL;
1205 }
1206
1207 static struct gbm_bo *
gbm_dri_bo_create(struct gbm_device * gbm,uint32_t width,uint32_t height,uint32_t format,uint32_t usage,const uint64_t * modifiers,const unsigned int count)1208 gbm_dri_bo_create(struct gbm_device *gbm,
1209 uint32_t width, uint32_t height,
1210 uint32_t format, uint32_t usage,
1211 const uint64_t *modifiers,
1212 const unsigned int count)
1213 {
1214 struct gbm_dri_device *dri = gbm_dri_device(gbm);
1215 struct gbm_dri_bo *bo;
1216 int dri_format;
1217 unsigned dri_use = 0;
1218
1219 format = gbm_core.v0.format_canonicalize(format);
1220
1221 if (usage & GBM_BO_USE_WRITE || dri->image == NULL)
1222 return create_dumb(gbm, width, height, format, usage);
1223
1224 bo = calloc(1, sizeof *bo);
1225 if (bo == NULL)
1226 return NULL;
1227
1228 bo->base.gbm = gbm;
1229 bo->base.v0.width = width;
1230 bo->base.v0.height = height;
1231 bo->base.v0.format = format;
1232
1233 dri_format = gbm_format_to_dri_format(format);
1234 if (dri_format == 0) {
1235 errno = EINVAL;
1236 goto failed;
1237 }
1238
1239 if (usage & GBM_BO_USE_SCANOUT)
1240 dri_use |= __DRI_IMAGE_USE_SCANOUT;
1241 if (usage & GBM_BO_USE_CURSOR)
1242 dri_use |= __DRI_IMAGE_USE_CURSOR;
1243 if (usage & GBM_BO_USE_LINEAR)
1244 dri_use |= __DRI_IMAGE_USE_LINEAR;
1245 if (usage & GBM_BO_USE_PROTECTED)
1246 dri_use |= __DRI_IMAGE_USE_PROTECTED;
1247
1248 /* Gallium drivers requires shared in order to get the handle/stride */
1249 dri_use |= __DRI_IMAGE_USE_SHARE;
1250
1251 if (modifiers && (dri->image->base.version < 14 ||
1252 !dri->image->createImageWithModifiers)) {
1253 errno = ENOSYS;
1254 goto failed;
1255 }
1256
1257 bo->image = loader_dri_create_image(dri->screen, dri->image, width, height,
1258 dri_format, dri_use, modifiers, count,
1259 bo);
1260 if (bo->image == NULL)
1261 goto failed;
1262
1263 if (modifiers)
1264 assert(gbm_dri_bo_get_modifier(&bo->base) != DRM_FORMAT_MOD_INVALID);
1265
1266 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
1267 &bo->base.v0.handle.s32);
1268 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
1269 (int *) &bo->base.v0.stride);
1270
1271 return &bo->base;
1272
1273 failed:
1274 free(bo);
1275 return NULL;
1276 }
1277
1278 static void *
gbm_dri_bo_map(struct gbm_bo * _bo,uint32_t x,uint32_t y,uint32_t width,uint32_t height,uint32_t flags,uint32_t * stride,void ** map_data)1279 gbm_dri_bo_map(struct gbm_bo *_bo,
1280 uint32_t x, uint32_t y,
1281 uint32_t width, uint32_t height,
1282 uint32_t flags, uint32_t *stride, void **map_data)
1283 {
1284 struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
1285 struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
1286
1287 /* If it's a dumb buffer, we already have a mapping */
1288 if (bo->map) {
1289 *map_data = (char *)bo->map + (bo->base.v0.stride * y) + (x * 4);
1290 *stride = bo->base.v0.stride;
1291 return *map_data;
1292 }
1293
1294 if (!dri->image || dri->image->base.version < 12 || !dri->image->mapImage) {
1295 errno = ENOSYS;
1296 return NULL;
1297 }
1298
1299 mtx_lock(&dri->mutex);
1300 if (!dri->context)
1301 dri->context = dri->dri2->createNewContext(dri->screen, NULL,
1302 NULL, NULL);
1303 assert(dri->context);
1304 mtx_unlock(&dri->mutex);
1305
1306 /* GBM flags and DRI flags are the same, so just pass them on */
1307 return dri->image->mapImage(dri->context, bo->image, x, y,
1308 width, height, flags, (int *)stride,
1309 map_data);
1310 }
1311
1312 static void
gbm_dri_bo_unmap(struct gbm_bo * _bo,void * map_data)1313 gbm_dri_bo_unmap(struct gbm_bo *_bo, void *map_data)
1314 {
1315 struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
1316 struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
1317
1318 /* Check if it's a dumb buffer and check the pointer is in range */
1319 if (bo->map) {
1320 assert(map_data >= bo->map);
1321 assert(map_data < (bo->map + bo->size));
1322 return;
1323 }
1324
1325 if (!dri->context || !dri->image ||
1326 dri->image->base.version < 12 || !dri->image->unmapImage)
1327 return;
1328
1329 dri->image->unmapImage(dri->context, bo->image, map_data);
1330
1331 /*
1332 * Not all DRI drivers use direct maps. They may queue up DMA operations
1333 * on the mapping context. Since there is no explicit gbm flush
1334 * mechanism, we need to flush here.
1335 */
1336 if (dri->flush->base.version >= 4)
1337 dri->flush->flush_with_flags(dri->context, NULL, __DRI2_FLUSH_CONTEXT, 0);
1338 }
1339
1340
1341 static struct gbm_surface *
gbm_dri_surface_create(struct gbm_device * gbm,uint32_t width,uint32_t height,uint32_t format,uint32_t flags,const uint64_t * modifiers,const unsigned count)1342 gbm_dri_surface_create(struct gbm_device *gbm,
1343 uint32_t width, uint32_t height,
1344 uint32_t format, uint32_t flags,
1345 const uint64_t *modifiers, const unsigned count)
1346 {
1347 struct gbm_dri_device *dri = gbm_dri_device(gbm);
1348 struct gbm_dri_surface *surf;
1349
1350 if (modifiers &&
1351 (!dri->image || dri->image->base.version < 14 ||
1352 !dri->image->createImageWithModifiers)) {
1353 errno = ENOSYS;
1354 return NULL;
1355 }
1356
1357 if (count)
1358 assert(modifiers);
1359
1360 /* It's acceptable to create an image with INVALID modifier in the list,
1361 * but it cannot be on the only modifier (since it will certainly fail
1362 * later). While we could easily catch this after modifier creation, doing
1363 * the check here is a convenient debug check likely pointing at whatever
1364 * interface the client is using to build its modifier list.
1365 */
1366 if (count == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID) {
1367 fprintf(stderr, "Only invalid modifier specified\n");
1368 errno = EINVAL;
1369 }
1370
1371 surf = calloc(1, sizeof *surf);
1372 if (surf == NULL) {
1373 errno = ENOMEM;
1374 return NULL;
1375 }
1376
1377 surf->base.gbm = gbm;
1378 surf->base.v0.width = width;
1379 surf->base.v0.height = height;
1380 surf->base.v0.format = gbm_core.v0.format_canonicalize(format);
1381 surf->base.v0.flags = flags;
1382 if (!modifiers) {
1383 assert(!count);
1384 return &surf->base;
1385 }
1386
1387 surf->base.v0.modifiers = calloc(count, sizeof(*modifiers));
1388 if (count && !surf->base.v0.modifiers) {
1389 errno = ENOMEM;
1390 free(surf);
1391 return NULL;
1392 }
1393
1394 /* TODO: We are deferring validation of modifiers until the image is actually
1395 * created. This deferred creation can fail due to a modifier-format
1396 * mismatch. The result is the client has a surface but no object to back it.
1397 */
1398 surf->base.v0.count = count;
1399 memcpy(surf->base.v0.modifiers, modifiers, count * sizeof(*modifiers));
1400
1401 return &surf->base;
1402 }
1403
1404 static void
gbm_dri_surface_destroy(struct gbm_surface * _surf)1405 gbm_dri_surface_destroy(struct gbm_surface *_surf)
1406 {
1407 struct gbm_dri_surface *surf = gbm_dri_surface(_surf);
1408
1409 free(surf->base.v0.modifiers);
1410 free(surf);
1411 }
1412
1413 static void
dri_destroy(struct gbm_device * gbm)1414 dri_destroy(struct gbm_device *gbm)
1415 {
1416 struct gbm_dri_device *dri = gbm_dri_device(gbm);
1417 unsigned i;
1418
1419 if (dri->context)
1420 dri->core->destroyContext(dri->context);
1421
1422 dri->core->destroyScreen(dri->screen);
1423 for (i = 0; dri->driver_configs[i]; i++)
1424 free((__DRIconfig *) dri->driver_configs[i]);
1425 free(dri->driver_configs);
1426 dlclose(dri->driver);
1427 free(dri->driver_name);
1428
1429 free(dri);
1430 }
1431
1432 static struct gbm_device *
dri_device_create(int fd,uint32_t gbm_backend_version)1433 dri_device_create(int fd, uint32_t gbm_backend_version)
1434 {
1435 struct gbm_dri_device *dri;
1436 int ret;
1437 bool force_sw;
1438
1439 /*
1440 * Since the DRI backend is built-in to the loader, the loader ABI version is
1441 * guaranteed to match this backend's ABI version
1442 */
1443 assert(gbm_core.v0.core_version == GBM_BACKEND_ABI_VERSION);
1444 assert(gbm_core.v0.core_version == gbm_backend_version);
1445
1446 dri = calloc(1, sizeof *dri);
1447 if (!dri)
1448 return NULL;
1449
1450 dri->base.v0.fd = fd;
1451 dri->base.v0.backend_version = gbm_backend_version;
1452 dri->base.v0.bo_create = gbm_dri_bo_create;
1453 dri->base.v0.bo_import = gbm_dri_bo_import;
1454 dri->base.v0.bo_map = gbm_dri_bo_map;
1455 dri->base.v0.bo_unmap = gbm_dri_bo_unmap;
1456 dri->base.v0.is_format_supported = gbm_dri_is_format_supported;
1457 dri->base.v0.get_format_modifier_plane_count =
1458 gbm_dri_get_format_modifier_plane_count;
1459 dri->base.v0.bo_write = gbm_dri_bo_write;
1460 dri->base.v0.bo_get_fd = gbm_dri_bo_get_fd;
1461 dri->base.v0.bo_get_planes = gbm_dri_bo_get_planes;
1462 dri->base.v0.bo_get_handle = gbm_dri_bo_get_handle_for_plane;
1463 dri->base.v0.bo_get_plane_fd = gbm_dri_bo_get_plane_fd;
1464 dri->base.v0.bo_get_stride = gbm_dri_bo_get_stride;
1465 dri->base.v0.bo_get_offset = gbm_dri_bo_get_offset;
1466 dri->base.v0.bo_get_modifier = gbm_dri_bo_get_modifier;
1467 dri->base.v0.bo_destroy = gbm_dri_bo_destroy;
1468 dri->base.v0.destroy = dri_destroy;
1469 dri->base.v0.surface_create = gbm_dri_surface_create;
1470 dri->base.v0.surface_destroy = gbm_dri_surface_destroy;
1471
1472 dri->base.v0.name = "drm";
1473
1474 dri->visual_table = gbm_dri_visuals_table;
1475 dri->num_visuals = ARRAY_SIZE(gbm_dri_visuals_table);
1476
1477 mtx_init(&dri->mutex, mtx_plain);
1478
1479 force_sw = env_var_as_boolean("GBM_ALWAYS_SOFTWARE", false);
1480 if (!force_sw) {
1481 ret = dri_screen_create(dri);
1482 if (ret)
1483 ret = dri_screen_create_sw(dri);
1484 } else {
1485 ret = dri_screen_create_sw(dri);
1486 }
1487
1488 if (ret)
1489 goto err_dri;
1490
1491 return &dri->base;
1492
1493 err_dri:
1494 free(dri);
1495
1496 return NULL;
1497 }
1498
1499 struct gbm_backend gbm_dri_backend = {
1500 .v0.backend_version = GBM_BACKEND_ABI_VERSION,
1501 .v0.backend_name = "dri",
1502 .v0.create_device = dri_device_create,
1503 };
1504