• 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 <string.h>
33 #include <errno.h>
34 #include <limits.h>
35 #include <assert.h>
36 
37 #include <sys/types.h>
38 #include <unistd.h>
39 #include <dlfcn.h>
40 #include <xf86drm.h>
41 
42 #include <GL/gl.h> /* dri_interface needs GL types */
43 #include <GL/internal/dri_interface.h>
44 
45 #include "gbm_driint.h"
46 
47 #include "gbmint.h"
48 #include "loader.h"
49 
50 /* For importing wl_buffer */
51 #if HAVE_WAYLAND_PLATFORM
52 #include "../../../egl/wayland/wayland-drm/wayland-drm.h"
53 #endif
54 
55 static __DRIimage *
dri_lookup_egl_image(__DRIscreen * screen,void * image,void * data)56 dri_lookup_egl_image(__DRIscreen *screen, void *image, void *data)
57 {
58    struct gbm_dri_device *dri = data;
59 
60    if (dri->lookup_image == NULL)
61       return NULL;
62 
63    return dri->lookup_image(screen, image, dri->lookup_user_data);
64 }
65 
66 static __DRIbuffer *
dri_get_buffers(__DRIdrawable * driDrawable,int * width,int * height,unsigned int * attachments,int count,int * out_count,void * data)67 dri_get_buffers(__DRIdrawable * driDrawable,
68 		 int *width, int *height,
69 		 unsigned int *attachments, int count,
70 		 int *out_count, void *data)
71 {
72    struct gbm_dri_surface *surf = data;
73    struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
74 
75    if (dri->get_buffers == NULL)
76       return NULL;
77 
78    return dri->get_buffers(driDrawable, width, height, attachments,
79                            count, out_count, surf->dri_private);
80 }
81 
82 static void
dri_flush_front_buffer(__DRIdrawable * driDrawable,void * data)83 dri_flush_front_buffer(__DRIdrawable * driDrawable, void *data)
84 {
85    struct gbm_dri_surface *surf = data;
86    struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
87 
88    if (dri->flush_front_buffer != NULL)
89       dri->flush_front_buffer(driDrawable, surf->dri_private);
90 }
91 
92 static __DRIbuffer *
dri_get_buffers_with_format(__DRIdrawable * driDrawable,int * width,int * height,unsigned int * attachments,int count,int * out_count,void * data)93 dri_get_buffers_with_format(__DRIdrawable * driDrawable,
94                             int *width, int *height,
95                             unsigned int *attachments, int count,
96                             int *out_count, void *data)
97 {
98    struct gbm_dri_surface *surf = data;
99    struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
100 
101    if (dri->get_buffers_with_format == NULL)
102       return NULL;
103 
104    return
105       dri->get_buffers_with_format(driDrawable, width, height, attachments,
106                                    count, out_count, surf->dri_private);
107 }
108 
109 static int
image_get_buffers(__DRIdrawable * driDrawable,unsigned int format,uint32_t * stamp,void * loaderPrivate,uint32_t buffer_mask,struct __DRIimageList * buffers)110 image_get_buffers(__DRIdrawable *driDrawable,
111                   unsigned int format,
112                   uint32_t *stamp,
113                   void *loaderPrivate,
114                   uint32_t buffer_mask,
115                   struct __DRIimageList *buffers)
116 {
117    struct gbm_dri_surface *surf = loaderPrivate;
118    struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
119 
120    if (dri->image_get_buffers == NULL)
121       return 0;
122 
123    return dri->image_get_buffers(driDrawable, format, stamp,
124                                  surf->dri_private, buffer_mask, buffers);
125 }
126 
127 static void
swrast_get_drawable_info(__DRIdrawable * driDrawable,int * x,int * y,int * width,int * height,void * loaderPrivate)128 swrast_get_drawable_info(__DRIdrawable *driDrawable,
129                          int           *x,
130                          int           *y,
131                          int           *width,
132                          int           *height,
133                          void          *loaderPrivate)
134 {
135    struct gbm_dri_surface *surf = loaderPrivate;
136 
137    *x = 0;
138    *y = 0;
139    *width = surf->base.width;
140    *height = surf->base.height;
141 }
142 
143 static void
swrast_put_image2(__DRIdrawable * driDrawable,int op,int x,int y,int width,int height,int stride,char * data,void * loaderPrivate)144 swrast_put_image2(__DRIdrawable *driDrawable,
145                   int            op,
146                   int            x,
147                   int            y,
148                   int            width,
149                   int            height,
150                   int            stride,
151                   char          *data,
152                   void          *loaderPrivate)
153 {
154    struct gbm_dri_surface *surf = loaderPrivate;
155    struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
156 
157    dri->swrast_put_image2(driDrawable,
158                           op, x, y,
159                           width, height, stride,
160                           data, surf->dri_private);
161 }
162 
163 static void
swrast_put_image(__DRIdrawable * driDrawable,int op,int x,int y,int width,int height,char * data,void * loaderPrivate)164 swrast_put_image(__DRIdrawable *driDrawable,
165                  int            op,
166                  int            x,
167                  int            y,
168                  int            width,
169                  int            height,
170                  char          *data,
171                  void          *loaderPrivate)
172 {
173    return swrast_put_image2(driDrawable, op, x, y, width, height,
174                             width * 4, data, loaderPrivate);
175 }
176 
177 static void
swrast_get_image(__DRIdrawable * driDrawable,int x,int y,int width,int height,char * data,void * loaderPrivate)178 swrast_get_image(__DRIdrawable *driDrawable,
179                  int            x,
180                  int            y,
181                  int            width,
182                  int            height,
183                  char          *data,
184                  void          *loaderPrivate)
185 {
186    struct gbm_dri_surface *surf = loaderPrivate;
187    struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
188 
189    dri->swrast_get_image(driDrawable,
190                          x, y,
191                          width, height,
192                          data, surf->dri_private);
193 }
194 
195 static const __DRIuseInvalidateExtension use_invalidate = {
196    .base = { __DRI_USE_INVALIDATE, 1 }
197 };
198 
199 static const __DRIimageLookupExtension image_lookup_extension = {
200    .base = { __DRI_IMAGE_LOOKUP, 1 },
201 
202    .lookupEGLImage          = dri_lookup_egl_image
203 };
204 
205 static const __DRIdri2LoaderExtension dri2_loader_extension = {
206    .base = { __DRI_DRI2_LOADER, 3 },
207 
208    .getBuffers              = dri_get_buffers,
209    .flushFrontBuffer        = dri_flush_front_buffer,
210    .getBuffersWithFormat    = dri_get_buffers_with_format,
211 };
212 
213 static const __DRIimageLoaderExtension image_loader_extension = {
214    .base = { __DRI_IMAGE_LOADER, 1 },
215 
216    .getBuffers          = image_get_buffers,
217    .flushFrontBuffer    = dri_flush_front_buffer,
218 };
219 
220 static const __DRIswrastLoaderExtension swrast_loader_extension = {
221    .base = { __DRI_SWRAST_LOADER, 2 },
222 
223    .getDrawableInfo = swrast_get_drawable_info,
224    .putImage        = swrast_put_image,
225    .getImage        = swrast_get_image,
226    .putImage2       = swrast_put_image2
227 };
228 
229 static const __DRIextension *gbm_dri_screen_extensions[] = {
230    &image_lookup_extension.base,
231    &use_invalidate.base,
232    &dri2_loader_extension.base,
233    &image_loader_extension.base,
234    &swrast_loader_extension.base,
235    NULL,
236 };
237 
238 struct dri_extension_match {
239    const char *name;
240    int version;
241    int offset;
242    int optional;
243 };
244 
245 static struct dri_extension_match dri_core_extensions[] = {
246    { __DRI2_FLUSH, 1, offsetof(struct gbm_dri_device, flush) },
247    { __DRI_IMAGE, 1, offsetof(struct gbm_dri_device, image) },
248    { __DRI2_FENCE, 1, offsetof(struct gbm_dri_device, fence), 1 },
249    { __DRI2_INTEROP, 1, offsetof(struct gbm_dri_device, interop), 1 },
250    { NULL, 0, 0 }
251 };
252 
253 static struct dri_extension_match gbm_dri_device_extensions[] = {
254    { __DRI_CORE, 1, offsetof(struct gbm_dri_device, core) },
255    { __DRI_DRI2, 1, offsetof(struct gbm_dri_device, dri2) },
256    { NULL, 0, 0 }
257 };
258 
259 static struct dri_extension_match gbm_swrast_device_extensions[] = {
260    { __DRI_CORE, 1, offsetof(struct gbm_dri_device, core), },
261    { __DRI_SWRAST, 1, offsetof(struct gbm_dri_device, swrast) },
262    { NULL, 0, 0 }
263 };
264 
265 static int
dri_bind_extensions(struct gbm_dri_device * dri,struct dri_extension_match * matches,const __DRIextension ** extensions)266 dri_bind_extensions(struct gbm_dri_device *dri,
267                     struct dri_extension_match *matches,
268                     const __DRIextension **extensions)
269 {
270    int i, j, ret = 0;
271    void *field;
272 
273    for (i = 0; extensions[i]; i++) {
274       for (j = 0; matches[j].name; j++) {
275          if (strcmp(extensions[i]->name, matches[j].name) == 0 &&
276              extensions[i]->version >= matches[j].version) {
277             field = ((char *) dri + matches[j].offset);
278             *(const __DRIextension **) field = extensions[i];
279          }
280       }
281    }
282 
283    for (j = 0; matches[j].name; j++) {
284       field = ((char *) dri + matches[j].offset);
285       if ((*(const __DRIextension **) field == NULL) && !matches[j].optional) {
286          ret = -1;
287       }
288    }
289 
290    return ret;
291 }
292 
293 static const __DRIextension **
dri_open_driver(struct gbm_dri_device * dri)294 dri_open_driver(struct gbm_dri_device *dri)
295 {
296    const __DRIextension **extensions = NULL;
297    char path[PATH_MAX], *search_paths, *p, *next, *end;
298    char *get_extensions_name;
299 
300    search_paths = NULL;
301    /* don't allow setuid apps to use LIBGL_DRIVERS_PATH or GBM_DRIVERS_PATH */
302    if (geteuid() == getuid()) {
303       /* Read GBM_DRIVERS_PATH first for compatibility, but LIBGL_DRIVERS_PATH
304        * is recommended over GBM_DRIVERS_PATH.
305        */
306       search_paths = getenv("GBM_DRIVERS_PATH");
307 
308       /* Read LIBGL_DRIVERS_PATH if GBM_DRIVERS_PATH was not set.
309        * LIBGL_DRIVERS_PATH is recommended over GBM_DRIVERS_PATH.
310        */
311       if (search_paths == NULL) {
312          search_paths = getenv("LIBGL_DRIVERS_PATH");
313       }
314    }
315    if (search_paths == NULL)
316       search_paths = DEFAULT_DRIVER_DIR;
317 
318    /* Temporarily work around dri driver libs that need symbols in libglapi
319     * but don't automatically link it in.
320     */
321    /* XXX: Library name differs on per platforms basis. Update this as
322     * osx/cygwin/windows/bsd gets support for GBM..
323     */
324    dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
325 
326    dri->driver = NULL;
327    end = search_paths + strlen(search_paths);
328    for (p = search_paths; p < end && dri->driver == NULL; p = next + 1) {
329       int len;
330       next = strchr(p, ':');
331       if (next == NULL)
332          next = end;
333 
334       len = next - p;
335 #if GLX_USE_TLS
336       snprintf(path, sizeof path,
337                "%.*s/tls/%s_dri.so", len, p, dri->base.driver_name);
338       dri->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
339 #endif
340       if (dri->driver == NULL) {
341          snprintf(path, sizeof path,
342                   "%.*s/%s_dri.so", len, p, dri->base.driver_name);
343          dri->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
344       }
345       /* not need continue to loop all paths once the driver is found */
346       if (dri->driver != NULL)
347          break;
348 
349 #ifdef ANDROID
350       snprintf(path, sizeof path, "%.*s/gallium_dri.so", len, p);
351       dri->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
352       if (dri->driver == NULL)
353          sprintf("failed to open %s: %s\n", path, dlerror());
354       else
355          break;
356 #endif
357    }
358 
359    if (dri->driver == NULL) {
360       fprintf(stderr, "gbm: failed to open any driver (search paths %s)\n",
361               search_paths);
362       fprintf(stderr, "gbm: Last dlopen error: %s\n", dlerror());
363       return NULL;
364    }
365 
366    get_extensions_name = loader_get_extensions_name(dri->base.driver_name);
367    if (get_extensions_name) {
368       const __DRIextension **(*get_extensions)(void);
369 
370       get_extensions = dlsym(dri->driver, get_extensions_name);
371       free(get_extensions_name);
372 
373       if (get_extensions)
374          extensions = get_extensions();
375    }
376 
377    if (!extensions)
378       extensions = dlsym(dri->driver, __DRI_DRIVER_EXTENSIONS);
379    if (extensions == NULL) {
380       fprintf(stderr, "gbm: driver exports no extensions (%s)", dlerror());
381       dlclose(dri->driver);
382    }
383 
384    return extensions;
385 }
386 
387 static int
dri_load_driver(struct gbm_dri_device * dri)388 dri_load_driver(struct gbm_dri_device *dri)
389 {
390    const __DRIextension **extensions;
391 
392    extensions = dri_open_driver(dri);
393    if (!extensions)
394       return -1;
395 
396    if (dri_bind_extensions(dri, gbm_dri_device_extensions, extensions) < 0) {
397       dlclose(dri->driver);
398       fprintf(stderr, "failed to bind extensions\n");
399       return -1;
400    }
401 
402    dri->driver_extensions = extensions;
403 
404    return 0;
405 }
406 
407 static int
dri_load_driver_swrast(struct gbm_dri_device * dri)408 dri_load_driver_swrast(struct gbm_dri_device *dri)
409 {
410    const __DRIextension **extensions;
411 
412    extensions = dri_open_driver(dri);
413    if (!extensions)
414       return -1;
415 
416    if (dri_bind_extensions(dri, gbm_swrast_device_extensions, extensions) < 0) {
417       dlclose(dri->driver);
418       fprintf(stderr, "failed to bind extensions\n");
419       return -1;
420    }
421 
422    dri->driver_extensions = extensions;
423 
424    return 0;
425 }
426 
427 static int
dri_screen_create_dri2(struct gbm_dri_device * dri,char * driver_name)428 dri_screen_create_dri2(struct gbm_dri_device *dri, char *driver_name)
429 {
430    const __DRIextension **extensions;
431    int ret = 0;
432 
433    dri->base.driver_name = driver_name;
434    if (dri->base.driver_name == NULL)
435       return -1;
436 
437    ret = dri_load_driver(dri);
438    if (ret) {
439       fprintf(stderr, "failed to load driver: %s\n", dri->base.driver_name);
440       return ret;
441    };
442 
443    dri->loader_extensions = gbm_dri_screen_extensions;
444 
445    if (dri->dri2 == NULL)
446       return -1;
447 
448    if (dri->dri2->base.version >= 4) {
449       dri->screen = dri->dri2->createNewScreen2(0, dri->base.base.fd,
450                                                 dri->loader_extensions,
451                                                 dri->driver_extensions,
452                                                 &dri->driver_configs, dri);
453    } else {
454       dri->screen = dri->dri2->createNewScreen(0, dri->base.base.fd,
455                                                dri->loader_extensions,
456                                                &dri->driver_configs, dri);
457    }
458    if (dri->screen == NULL)
459       return -1;
460 
461    extensions = dri->core->getExtensions(dri->screen);
462    if (dri_bind_extensions(dri, dri_core_extensions, extensions) < 0) {
463       ret = -1;
464       goto free_screen;
465    }
466 
467    dri->lookup_image = NULL;
468    dri->lookup_user_data = NULL;
469 
470    return 0;
471 
472 free_screen:
473    dri->core->destroyScreen(dri->screen);
474 
475    return ret;
476 }
477 
478 static int
dri_screen_create_swrast(struct gbm_dri_device * dri)479 dri_screen_create_swrast(struct gbm_dri_device *dri)
480 {
481    int ret;
482 
483    dri->base.driver_name = strdup("swrast");
484    if (dri->base.driver_name == NULL)
485       return -1;
486 
487    ret = dri_load_driver_swrast(dri);
488    if (ret) {
489       fprintf(stderr, "failed to load swrast driver\n");
490       return ret;
491    }
492 
493    dri->loader_extensions = gbm_dri_screen_extensions;
494 
495    if (dri->swrast == NULL)
496       return -1;
497 
498    if (dri->swrast->base.version >= 4) {
499       dri->screen = dri->swrast->createNewScreen2(0, dri->loader_extensions,
500                                                   dri->driver_extensions,
501                                                   &dri->driver_configs, dri);
502    } else {
503       dri->screen = dri->swrast->createNewScreen(0, dri->loader_extensions,
504                                                  &dri->driver_configs, dri);
505    }
506    if (dri->screen == NULL)
507       return -1;
508 
509    dri->lookup_image = NULL;
510    dri->lookup_user_data = NULL;
511 
512    return 0;
513 }
514 
515 static int
dri_screen_create(struct gbm_dri_device * dri)516 dri_screen_create(struct gbm_dri_device *dri)
517 {
518    char *driver_name;
519 
520    driver_name = loader_get_driver_for_fd(dri->base.base.fd);
521    if (!driver_name)
522       return -1;
523 
524    return dri_screen_create_dri2(dri, driver_name);
525 }
526 
527 static int
dri_screen_create_sw(struct gbm_dri_device * dri)528 dri_screen_create_sw(struct gbm_dri_device *dri)
529 {
530    char *driver_name;
531    int ret;
532 
533    driver_name = strdup("kms_swrast");
534    if (!driver_name)
535       return -errno;
536 
537    ret = dri_screen_create_dri2(dri, driver_name);
538    if (ret == 0)
539       return ret;
540 
541    return dri_screen_create_swrast(dri);
542 }
543 
544 static int
gbm_dri_is_format_supported(struct gbm_device * gbm,uint32_t format,uint32_t usage)545 gbm_dri_is_format_supported(struct gbm_device *gbm,
546                             uint32_t format,
547                             uint32_t usage)
548 {
549    switch (format) {
550    case GBM_BO_FORMAT_XRGB8888:
551    case GBM_FORMAT_XBGR8888:
552    case GBM_FORMAT_XRGB8888:
553       break;
554    case GBM_BO_FORMAT_ARGB8888:
555    case GBM_FORMAT_ARGB8888:
556       if (usage & GBM_BO_USE_SCANOUT)
557          return 0;
558       break;
559    default:
560       return 0;
561    }
562 
563    if (usage & GBM_BO_USE_CURSOR &&
564        usage & GBM_BO_USE_RENDERING)
565       return 0;
566 
567    return 1;
568 }
569 
570 static int
gbm_dri_bo_write(struct gbm_bo * _bo,const void * buf,size_t count)571 gbm_dri_bo_write(struct gbm_bo *_bo, const void *buf, size_t count)
572 {
573    struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
574 
575    if (bo->image != NULL) {
576       errno = EINVAL;
577       return -1;
578    }
579 
580    memcpy(bo->map, buf, count);
581 
582    return 0;
583 }
584 
585 static int
gbm_dri_bo_get_fd(struct gbm_bo * _bo)586 gbm_dri_bo_get_fd(struct gbm_bo *_bo)
587 {
588    struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
589    struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
590    int fd;
591 
592    if (bo->image == NULL)
593       return -1;
594 
595    if (!dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_FD, &fd))
596       return -1;
597 
598    return fd;
599 }
600 
601 static void
gbm_dri_bo_destroy(struct gbm_bo * _bo)602 gbm_dri_bo_destroy(struct gbm_bo *_bo)
603 {
604    struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
605    struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
606    struct drm_mode_destroy_dumb arg;
607 
608    if (bo->image != NULL) {
609       dri->image->destroyImage(bo->image);
610    } else {
611       gbm_dri_bo_unmap_dumb(bo);
612       memset(&arg, 0, sizeof(arg));
613       arg.handle = bo->handle;
614       drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
615    }
616 
617    free(bo);
618 }
619 
620 static uint32_t
gbm_dri_to_gbm_format(uint32_t dri_format)621 gbm_dri_to_gbm_format(uint32_t dri_format)
622 {
623    uint32_t ret = 0;
624 
625    switch (dri_format) {
626    case __DRI_IMAGE_FORMAT_RGB565:
627       ret = GBM_FORMAT_RGB565;
628       break;
629    case __DRI_IMAGE_FORMAT_XRGB8888:
630       ret = GBM_FORMAT_XRGB8888;
631       break;
632    case __DRI_IMAGE_FORMAT_ARGB8888:
633       ret = GBM_FORMAT_ARGB8888;
634       break;
635    case __DRI_IMAGE_FORMAT_XBGR8888:
636       ret = GBM_FORMAT_XBGR8888;
637       break;
638    case __DRI_IMAGE_FORMAT_ABGR8888:
639       ret = GBM_FORMAT_ABGR8888;
640       break;
641    default:
642       ret = 0;
643       break;
644    }
645 
646    return ret;
647 }
648 
649 static struct gbm_bo *
gbm_dri_bo_import(struct gbm_device * gbm,uint32_t type,void * buffer,uint32_t usage)650 gbm_dri_bo_import(struct gbm_device *gbm,
651                   uint32_t type, void *buffer, uint32_t usage)
652 {
653    struct gbm_dri_device *dri = gbm_dri_device(gbm);
654    struct gbm_dri_bo *bo;
655    __DRIimage *image;
656    unsigned dri_use = 0;
657    int gbm_format;
658 
659    /* Required for query image WIDTH & HEIGHT */
660    if (dri->image == NULL || dri->image->base.version < 4) {
661       errno = ENOSYS;
662       return NULL;
663    }
664 
665    switch (type) {
666 #if HAVE_WAYLAND_PLATFORM
667    case GBM_BO_IMPORT_WL_BUFFER:
668    {
669       struct wl_drm_buffer *wb;
670 
671       if (!dri->wl_drm) {
672          errno = EINVAL;
673          return NULL;
674       }
675 
676       wb = wayland_drm_buffer_get(dri->wl_drm, (struct wl_resource *) buffer);
677       if (!wb) {
678          errno = EINVAL;
679          return NULL;
680       }
681 
682       image = dri->image->dupImage(wb->driver_buffer, NULL);
683 
684       switch (wb->format) {
685       case WL_DRM_FORMAT_XRGB8888:
686          gbm_format = GBM_FORMAT_XRGB8888;
687          break;
688       case WL_DRM_FORMAT_ARGB8888:
689          gbm_format = GBM_FORMAT_ARGB8888;
690          break;
691       case WL_DRM_FORMAT_RGB565:
692          gbm_format = GBM_FORMAT_RGB565;
693          break;
694       case WL_DRM_FORMAT_YUYV:
695          gbm_format = GBM_FORMAT_YUYV;
696          break;
697       default:
698          return NULL;
699       }
700       break;
701    }
702 #endif
703 
704    case GBM_BO_IMPORT_EGL_IMAGE:
705    {
706       int dri_format;
707       if (dri->lookup_image == NULL) {
708          errno = EINVAL;
709          return NULL;
710       }
711 
712       image = dri->lookup_image(dri->screen, buffer, dri->lookup_user_data);
713       image = dri->image->dupImage(image, NULL);
714       dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &dri_format);
715       gbm_format = gbm_dri_to_gbm_format(dri_format);
716       if (gbm_format == 0) {
717          errno = EINVAL;
718          return NULL;
719       }
720       break;
721    }
722 
723    case GBM_BO_IMPORT_FD:
724    {
725       struct gbm_import_fd_data *fd_data = buffer;
726       int stride = fd_data->stride, offset = 0;
727       int dri_format;
728 
729       switch (fd_data->format) {
730       case GBM_BO_FORMAT_XRGB8888:
731          dri_format = GBM_FORMAT_XRGB8888;
732          break;
733       case GBM_BO_FORMAT_ARGB8888:
734          dri_format = GBM_FORMAT_ARGB8888;
735          break;
736       default:
737          dri_format = fd_data->format;
738       }
739 
740       image = dri->image->createImageFromFds(dri->screen,
741                                              fd_data->width,
742                                              fd_data->height,
743                                              dri_format,
744                                              &fd_data->fd, 1,
745                                              &stride, &offset,
746                                              NULL);
747       if (image == NULL) {
748          errno = EINVAL;
749          return NULL;
750       }
751       gbm_format = fd_data->format;
752       break;
753    }
754 
755    default:
756       errno = ENOSYS;
757       return NULL;
758    }
759 
760 
761    bo = calloc(1, sizeof *bo);
762    if (bo == NULL)
763       return NULL;
764 
765    bo->image = image;
766 
767    if (usage & GBM_BO_USE_SCANOUT)
768       dri_use |= __DRI_IMAGE_USE_SCANOUT;
769    if (usage & GBM_BO_USE_CURSOR)
770       dri_use |= __DRI_IMAGE_USE_CURSOR;
771    if (dri->image->base.version >= 2 &&
772        !dri->image->validateUsage(bo->image, dri_use)) {
773       errno = EINVAL;
774       free(bo);
775       return NULL;
776    }
777 
778    bo->base.base.gbm = gbm;
779    bo->base.base.format = gbm_format;
780 
781    dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_WIDTH,
782                           (int*)&bo->base.base.width);
783    dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HEIGHT,
784                           (int*)&bo->base.base.height);
785    dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
786                           (int*)&bo->base.base.stride);
787    dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
788                           &bo->base.base.handle.s32);
789 
790    return &bo->base.base;
791 }
792 
793 static struct gbm_bo *
create_dumb(struct gbm_device * gbm,uint32_t width,uint32_t height,uint32_t format,uint32_t usage)794 create_dumb(struct gbm_device *gbm,
795                   uint32_t width, uint32_t height,
796                   uint32_t format, uint32_t usage)
797 {
798    struct gbm_dri_device *dri = gbm_dri_device(gbm);
799    struct drm_mode_create_dumb create_arg;
800    struct gbm_dri_bo *bo;
801    struct drm_mode_destroy_dumb destroy_arg;
802    int ret;
803    int is_cursor, is_scanout;
804 
805    is_cursor = (usage & GBM_BO_USE_CURSOR) != 0 &&
806       format == GBM_FORMAT_ARGB8888;
807    is_scanout = (usage & GBM_BO_USE_SCANOUT) != 0 &&
808       format == GBM_FORMAT_XRGB8888;
809    if (!is_cursor && !is_scanout) {
810       errno = EINVAL;
811       return NULL;
812    }
813 
814    bo = calloc(1, sizeof *bo);
815    if (bo == NULL)
816       return NULL;
817 
818    memset(&create_arg, 0, sizeof(create_arg));
819    create_arg.bpp = 32;
820    create_arg.width = width;
821    create_arg.height = height;
822 
823    ret = drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
824    if (ret)
825       goto free_bo;
826 
827    bo->base.base.gbm = gbm;
828    bo->base.base.width = width;
829    bo->base.base.height = height;
830    bo->base.base.stride = create_arg.pitch;
831    bo->base.base.format = format;
832    bo->base.base.handle.u32 = create_arg.handle;
833    bo->handle = create_arg.handle;
834    bo->size = create_arg.size;
835 
836    if (gbm_dri_bo_map_dumb(bo) == NULL)
837       goto destroy_dumb;
838 
839    return &bo->base.base;
840 
841 destroy_dumb:
842    memset(&destroy_arg, 0, sizeof destroy_arg);
843    destroy_arg.handle = create_arg.handle;
844    drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
845 free_bo:
846    free(bo);
847 
848    return NULL;
849 }
850 
851 static struct gbm_bo *
gbm_dri_bo_create(struct gbm_device * gbm,uint32_t width,uint32_t height,uint32_t format,uint32_t usage)852 gbm_dri_bo_create(struct gbm_device *gbm,
853                   uint32_t width, uint32_t height,
854                   uint32_t format, uint32_t usage)
855 {
856    struct gbm_dri_device *dri = gbm_dri_device(gbm);
857    struct gbm_dri_bo *bo;
858    int dri_format;
859    unsigned dri_use = 0;
860 
861    if (usage & GBM_BO_USE_WRITE || dri->image == NULL)
862       return create_dumb(gbm, width, height, format, usage);
863 
864    bo = calloc(1, sizeof *bo);
865    if (bo == NULL)
866       return NULL;
867 
868    bo->base.base.gbm = gbm;
869    bo->base.base.width = width;
870    bo->base.base.height = height;
871    bo->base.base.format = format;
872 
873    switch (format) {
874    case GBM_FORMAT_R8:
875       dri_format = __DRI_IMAGE_FORMAT_R8;
876       break;
877    case GBM_FORMAT_GR88:
878       dri_format = __DRI_IMAGE_FORMAT_GR88;
879       break;
880    case GBM_FORMAT_RGB565:
881       dri_format = __DRI_IMAGE_FORMAT_RGB565;
882       break;
883    case GBM_FORMAT_XRGB8888:
884    case GBM_BO_FORMAT_XRGB8888:
885       dri_format = __DRI_IMAGE_FORMAT_XRGB8888;
886       break;
887    case GBM_FORMAT_ARGB8888:
888    case GBM_BO_FORMAT_ARGB8888:
889       dri_format = __DRI_IMAGE_FORMAT_ARGB8888;
890       break;
891    case GBM_FORMAT_ABGR8888:
892       dri_format = __DRI_IMAGE_FORMAT_ABGR8888;
893       break;
894    case GBM_FORMAT_XBGR8888:
895       dri_format = __DRI_IMAGE_FORMAT_XBGR8888;
896       break;
897    case GBM_FORMAT_ARGB2101010:
898       dri_format = __DRI_IMAGE_FORMAT_ARGB2101010;
899       break;
900    case GBM_FORMAT_XRGB2101010:
901       dri_format = __DRI_IMAGE_FORMAT_XRGB2101010;
902       break;
903    default:
904       errno = EINVAL;
905       goto failed;
906    }
907 
908    if (usage & GBM_BO_USE_SCANOUT)
909       dri_use |= __DRI_IMAGE_USE_SCANOUT;
910    if (usage & GBM_BO_USE_CURSOR)
911       dri_use |= __DRI_IMAGE_USE_CURSOR;
912    if (usage & GBM_BO_USE_LINEAR)
913       dri_use |= __DRI_IMAGE_USE_LINEAR;
914 
915    /* Gallium drivers requires shared in order to get the handle/stride */
916    dri_use |= __DRI_IMAGE_USE_SHARE;
917 
918    bo->image =
919       dri->image->createImage(dri->screen,
920                               width, height,
921                               dri_format, dri_use,
922                               bo);
923    if (bo->image == NULL)
924       goto failed;
925 
926    dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
927                           &bo->base.base.handle.s32);
928    dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
929                           (int *) &bo->base.base.stride);
930 
931    return &bo->base.base;
932 
933 failed:
934    free(bo);
935    return NULL;
936 }
937 
938 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)939 gbm_dri_bo_map(struct gbm_bo *_bo,
940               uint32_t x, uint32_t y,
941               uint32_t width, uint32_t height,
942               uint32_t flags, uint32_t *stride, void **map_data)
943 {
944    struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
945    struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
946 
947    /* If it's a dumb buffer, we already have a mapping */
948    if (bo->map) {
949       *map_data = (char *)bo->map + (bo->base.base.stride * y) + (x * 4);
950       *stride = bo->base.base.stride;
951       return *map_data;
952    }
953 
954    if (!dri->image || dri->image->base.version < 12 || !dri->image->mapImage) {
955       errno = ENOSYS;
956       return NULL;
957    }
958 
959    mtx_lock(&dri->mutex);
960    if (!dri->context)
961       dri->context = dri->dri2->createNewContext(dri->screen, NULL,
962                                                  NULL, NULL);
963    assert(dri->context);
964    mtx_unlock(&dri->mutex);
965 
966    /* GBM flags and DRI flags are the same, so just pass them on */
967    return dri->image->mapImage(dri->context, bo->image, x, y,
968                                width, height, flags, (int *)stride,
969                                map_data);
970 }
971 
972 static void
gbm_dri_bo_unmap(struct gbm_bo * _bo,void * map_data)973 gbm_dri_bo_unmap(struct gbm_bo *_bo, void *map_data)
974 {
975    struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
976    struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
977 
978    /* Check if it's a dumb buffer and check the pointer is in range */
979    if (bo->map) {
980       assert(map_data >= bo->map);
981       assert(map_data < (bo->map + bo->size));
982       return;
983    }
984 
985    if (!dri->context || !dri->image ||
986        dri->image->base.version < 12 || !dri->image->unmapImage)
987       return;
988 
989    dri->image->unmapImage(dri->context, bo->image, map_data);
990 
991    /*
992     * Not all DRI drivers use direct maps. They may queue up DMA operations
993     * on the mapping context. Since there is no explicit gbm flush
994     * mechanism, we need to flush here.
995     */
996    if (dri->flush->base.version >= 4)
997       dri->flush->flush_with_flags(dri->context, NULL, __DRI2_FLUSH_CONTEXT, 0);
998 }
999 
1000 
1001 static struct gbm_surface *
gbm_dri_surface_create(struct gbm_device * gbm,uint32_t width,uint32_t height,uint32_t format,uint32_t flags)1002 gbm_dri_surface_create(struct gbm_device *gbm,
1003                        uint32_t width, uint32_t height,
1004 		       uint32_t format, uint32_t flags)
1005 {
1006    struct gbm_dri_surface *surf;
1007 
1008    surf = calloc(1, sizeof *surf);
1009    if (surf == NULL)
1010       return NULL;
1011 
1012    surf->base.gbm = gbm;
1013    surf->base.width = width;
1014    surf->base.height = height;
1015    surf->base.format = format;
1016    surf->base.flags = flags;
1017 
1018    return &surf->base;
1019 }
1020 
1021 static void
gbm_dri_surface_destroy(struct gbm_surface * _surf)1022 gbm_dri_surface_destroy(struct gbm_surface *_surf)
1023 {
1024    struct gbm_dri_surface *surf = gbm_dri_surface(_surf);
1025 
1026    free(surf);
1027 }
1028 
1029 static void
dri_destroy(struct gbm_device * gbm)1030 dri_destroy(struct gbm_device *gbm)
1031 {
1032    struct gbm_dri_device *dri = gbm_dri_device(gbm);
1033    unsigned i;
1034 
1035    if (dri->context)
1036       dri->core->destroyContext(dri->context);
1037 
1038    dri->core->destroyScreen(dri->screen);
1039    for (i = 0; dri->driver_configs[i]; i++)
1040       free((__DRIconfig *) dri->driver_configs[i]);
1041    free(dri->driver_configs);
1042    dlclose(dri->driver);
1043    free(dri->base.driver_name);
1044 
1045    free(dri);
1046 }
1047 
1048 static struct gbm_device *
dri_device_create(int fd)1049 dri_device_create(int fd)
1050 {
1051    struct gbm_dri_device *dri;
1052    int ret, force_sw;
1053 
1054    dri = calloc(1, sizeof *dri);
1055    if (!dri)
1056       return NULL;
1057 
1058    dri->base.base.fd = fd;
1059    dri->base.base.bo_create = gbm_dri_bo_create;
1060    dri->base.base.bo_import = gbm_dri_bo_import;
1061    dri->base.base.bo_map = gbm_dri_bo_map;
1062    dri->base.base.bo_unmap = gbm_dri_bo_unmap;
1063    dri->base.base.is_format_supported = gbm_dri_is_format_supported;
1064    dri->base.base.bo_write = gbm_dri_bo_write;
1065    dri->base.base.bo_get_fd = gbm_dri_bo_get_fd;
1066    dri->base.base.bo_destroy = gbm_dri_bo_destroy;
1067    dri->base.base.destroy = dri_destroy;
1068    dri->base.base.surface_create = gbm_dri_surface_create;
1069    dri->base.base.surface_destroy = gbm_dri_surface_destroy;
1070 
1071    dri->base.type = GBM_DRM_DRIVER_TYPE_DRI;
1072    dri->base.base.name = "drm";
1073 
1074    mtx_init(&dri->mutex, mtx_plain);
1075 
1076    force_sw = getenv("GBM_ALWAYS_SOFTWARE") != NULL;
1077    if (!force_sw) {
1078       ret = dri_screen_create(dri);
1079       if (ret)
1080          ret = dri_screen_create_sw(dri);
1081    } else {
1082       ret = dri_screen_create_sw(dri);
1083    }
1084 
1085    if (ret)
1086       goto err_dri;
1087 
1088    return &dri->base.base;
1089 
1090 err_dri:
1091    free(dri);
1092 
1093    return NULL;
1094 }
1095 
1096 struct gbm_backend gbm_dri_backend = {
1097    .backend_name = "dri",
1098    .create_device = dri_device_create,
1099 };
1100