• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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