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