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