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