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