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 <limits.h>
34 
35 #include <sys/types.h>
36 #include <sys/mman.h>
37 #include <unistd.h>
38 #include <dlfcn.h>
39 #include <xf86drm.h>
40 
41 #include <GL/gl.h> /* dri_interface needs GL types */
42 #include <GL/internal/dri_interface.h>
43 
44 #include "gbm_driint.h"
45 
46 #include "gbmint.h"
47 
48 /* For importing wl_buffer */
49 #if HAVE_WAYLAND_PLATFORM
50 #include "../../../egl/wayland/wayland-drm/wayland-drm.h"
51 #endif
52 
53 static __DRIimage *
dri_lookup_egl_image(__DRIscreen * screen,void * image,void * data)54 dri_lookup_egl_image(__DRIscreen *screen, void *image, void *data)
55 {
56    struct gbm_dri_device *dri = data;
57 
58    if (dri->lookup_image == NULL)
59       return NULL;
60 
61    return dri->lookup_image(screen, image, dri->lookup_user_data);
62 }
63 
64 static __DRIbuffer *
dri_get_buffers(__DRIdrawable * driDrawable,int * width,int * height,unsigned int * attachments,int count,int * out_count,void * data)65 dri_get_buffers(__DRIdrawable * driDrawable,
66 		 int *width, int *height,
67 		 unsigned int *attachments, int count,
68 		 int *out_count, void *data)
69 {
70    struct gbm_dri_surface *surf = data;
71    struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
72 
73    if (dri->get_buffers == NULL)
74       return NULL;
75 
76    return dri->get_buffers(driDrawable, width, height, attachments,
77                            count, out_count, surf->dri_private);
78 }
79 
80 static void
dri_flush_front_buffer(__DRIdrawable * driDrawable,void * data)81 dri_flush_front_buffer(__DRIdrawable * driDrawable, void *data)
82 {
83    struct gbm_dri_surface *surf = data;
84    struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
85 
86    if (dri->flush_front_buffer != NULL)
87       dri->flush_front_buffer(driDrawable, surf->dri_private);
88 }
89 
90 static __DRIbuffer *
dri_get_buffers_with_format(__DRIdrawable * driDrawable,int * width,int * height,unsigned int * attachments,int count,int * out_count,void * data)91 dri_get_buffers_with_format(__DRIdrawable * driDrawable,
92                             int *width, int *height,
93                             unsigned int *attachments, int count,
94                             int *out_count, void *data)
95 {
96    struct gbm_dri_surface *surf = data;
97    struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
98 
99    if (dri->get_buffers_with_format == NULL)
100       return NULL;
101 
102    return
103       dri->get_buffers_with_format(driDrawable, width, height, attachments,
104                                    count, out_count, surf->dri_private);
105 }
106 
107 static const __DRIuseInvalidateExtension use_invalidate = {
108    { __DRI_USE_INVALIDATE, 1 }
109 };
110 
111 static const __DRIimageLookupExtension image_lookup_extension = {
112    { __DRI_IMAGE_LOOKUP, 1 },
113    dri_lookup_egl_image
114 };
115 
116 const __DRIdri2LoaderExtension dri2_loader_extension = {
117    { __DRI_DRI2_LOADER, 3 },
118    dri_get_buffers,
119    dri_flush_front_buffer,
120    dri_get_buffers_with_format,
121 };
122 
123 struct dri_extension_match {
124    const char *name;
125    int version;
126    int offset;
127 };
128 
129 static struct dri_extension_match dri_core_extensions[] = {
130    { __DRI2_FLUSH, 1, offsetof(struct gbm_dri_device, flush) },
131    { __DRI_IMAGE, 1, offsetof(struct gbm_dri_device, image) },
132    { NULL, 0, 0 }
133 };
134 
135 static struct dri_extension_match gbm_dri_device_extensions[] = {
136    { __DRI_CORE, 1, offsetof(struct gbm_dri_device, core) },
137    { __DRI_DRI2, 1, offsetof(struct gbm_dri_device, dri2) },
138    { NULL, 0, 0 }
139 };
140 
141 static int
dri_bind_extensions(struct gbm_dri_device * dri,struct dri_extension_match * matches,const __DRIextension ** extensions)142 dri_bind_extensions(struct gbm_dri_device *dri,
143                     struct dri_extension_match *matches,
144                     const __DRIextension **extensions)
145 {
146    int i, j, ret = 0;
147    void *field;
148 
149    for (i = 0; extensions[i]; i++) {
150       for (j = 0; matches[j].name; j++) {
151          if (strcmp(extensions[i]->name, matches[j].name) == 0 &&
152              extensions[i]->version >= matches[j].version) {
153             field = ((char *) dri + matches[j].offset);
154             *(const __DRIextension **) field = extensions[i];
155          }
156       }
157    }
158 
159    for (j = 0; matches[j].name; j++) {
160       field = ((char *) dri + matches[j].offset);
161       if (*(const __DRIextension **) field == NULL) {
162          ret = -1;
163       }
164    }
165 
166    return ret;
167 }
168 
169 static int
dri_load_driver(struct gbm_dri_device * dri)170 dri_load_driver(struct gbm_dri_device *dri)
171 {
172    const __DRIextension **extensions;
173    char path[PATH_MAX], *search_paths, *p, *next, *end;
174 
175    search_paths = NULL;
176    if (geteuid() == getuid()) {
177       /* don't allow setuid apps to use GBM_DRIVERS_PATH */
178       search_paths = getenv("GBM_DRIVERS_PATH");
179    }
180    if (search_paths == NULL)
181       search_paths = DEFAULT_DRIVER_DIR;
182 
183    dri->driver = NULL;
184    end = search_paths + strlen(search_paths);
185    for (p = search_paths; p < end && dri->driver == NULL; p = next + 1) {
186       int len;
187       next = strchr(p, ':');
188       if (next == NULL)
189          next = end;
190 
191       len = next - p;
192 #if GLX_USE_TLS
193       snprintf(path, sizeof path,
194                "%.*s/tls/%s_dri.so", len, p, dri->base.driver_name);
195       dri->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
196 #endif
197       if (dri->driver == NULL) {
198          snprintf(path, sizeof path,
199                   "%.*s/%s_dri.so", len, p, dri->base.driver_name);
200          dri->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
201          if (dri->driver == NULL)
202             fprintf(stderr, "failed to open %s: %s\n", path, dlerror());
203       }
204    }
205 
206    if (dri->driver == NULL) {
207       fprintf(stderr, "gbm: failed to open any driver (search paths %s)",
208               search_paths);
209       return -1;
210    }
211 
212    extensions = dlsym(dri->driver, __DRI_DRIVER_EXTENSIONS);
213    if (extensions == NULL) {
214       fprintf(stderr, "gbm: driver exports no extensions (%s)", dlerror());
215       dlclose(dri->driver);
216       return -1;
217    }
218 
219 
220    if (dri_bind_extensions(dri, gbm_dri_device_extensions, extensions) < 0) {
221       dlclose(dri->driver);
222       fprintf(stderr, "failed to bind extensions\n");
223       return -1;
224    }
225 
226    return 0;
227 }
228 
229 static int
dri_screen_create(struct gbm_dri_device * dri)230 dri_screen_create(struct gbm_dri_device *dri)
231 {
232    const __DRIextension **extensions;
233    int ret = 0;
234 
235    dri->base.driver_name = dri_fd_get_driver_name(dri->base.base.fd);
236    if (dri->base.driver_name == NULL)
237       return -1;
238 
239    ret = dri_load_driver(dri);
240    if (ret) {
241       fprintf(stderr, "failed to load driver: %s\n", dri->base.driver_name);
242       return ret;
243    };
244 
245    dri->extensions[0] = &image_lookup_extension.base;
246    dri->extensions[1] = &use_invalidate.base;
247    dri->extensions[2] = &dri2_loader_extension.base;
248    dri->extensions[3] = NULL;
249 
250    if (dri->dri2 == NULL)
251       return -1;
252 
253    dri->screen = dri->dri2->createNewScreen(0, dri->base.base.fd,
254                                             dri->extensions,
255                                             &dri->driver_configs, dri);
256    if (dri->screen == NULL)
257       return -1;
258 
259    extensions = dri->core->getExtensions(dri->screen);
260    if (dri_bind_extensions(dri, dri_core_extensions, extensions) < 0) {
261       ret = -1;
262       goto free_screen;
263    }
264 
265    dri->lookup_image = NULL;
266    dri->lookup_user_data = NULL;
267 
268    return 0;
269 
270 free_screen:
271    dri->core->destroyScreen(dri->screen);
272 
273    return ret;
274 }
275 
276 static int
gbm_dri_is_format_supported(struct gbm_device * gbm,uint32_t format,uint32_t usage)277 gbm_dri_is_format_supported(struct gbm_device *gbm,
278                             uint32_t format,
279                             uint32_t usage)
280 {
281    switch (format) {
282    case GBM_BO_FORMAT_XRGB8888:
283    case GBM_FORMAT_XRGB8888:
284       break;
285    case GBM_BO_FORMAT_ARGB8888:
286    case GBM_FORMAT_ARGB8888:
287       if (usage & GBM_BO_USE_SCANOUT)
288          return 0;
289       break;
290    default:
291       return 0;
292    }
293 
294    if (usage & GBM_BO_USE_CURSOR_64X64 &&
295        usage & GBM_BO_USE_RENDERING)
296       return 0;
297 
298    return 1;
299 }
300 
301 static int
gbm_dri_bo_write(struct gbm_bo * _bo,const void * buf,size_t count)302 gbm_dri_bo_write(struct gbm_bo *_bo, const void *buf, size_t count)
303 {
304    struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
305 
306    if (bo->image != NULL)
307       return -1;
308 
309    memcpy(bo->map, buf, count);
310 
311    return 0;
312 }
313 
314 static void
gbm_dri_bo_destroy(struct gbm_bo * _bo)315 gbm_dri_bo_destroy(struct gbm_bo *_bo)
316 {
317    struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
318    struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
319    struct drm_mode_destroy_dumb arg;
320 
321    if (bo->image != NULL) {
322       dri->image->destroyImage(bo->image);
323    } else {
324       munmap(bo->map, bo->size);
325       memset(&arg, 0, sizeof(arg));
326       arg.handle = bo->handle;
327       drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
328    }
329 
330    free(bo);
331 }
332 
333 static uint32_t
gbm_dri_to_gbm_format(uint32_t dri_format)334 gbm_dri_to_gbm_format(uint32_t dri_format)
335 {
336    uint32_t ret = 0;
337 
338    switch (dri_format) {
339    case __DRI_IMAGE_FORMAT_RGB565:
340       ret = GBM_FORMAT_RGB565;
341       break;
342    case __DRI_IMAGE_FORMAT_XRGB8888:
343       ret = GBM_FORMAT_XRGB8888;
344       break;
345    case __DRI_IMAGE_FORMAT_ARGB8888:
346       ret = GBM_FORMAT_ARGB8888;
347       break;
348    case __DRI_IMAGE_FORMAT_ABGR8888:
349       ret = GBM_FORMAT_ABGR8888;
350       break;
351    default:
352       ret = 0;
353       break;
354    }
355 
356    return ret;
357 }
358 
359 static struct gbm_bo *
gbm_dri_bo_import(struct gbm_device * gbm,uint32_t type,void * buffer,uint32_t usage)360 gbm_dri_bo_import(struct gbm_device *gbm,
361                   uint32_t type, void *buffer, uint32_t usage)
362 {
363    struct gbm_dri_device *dri = gbm_dri_device(gbm);
364    struct gbm_dri_bo *bo;
365    __DRIimage *image;
366    unsigned dri_use = 0;
367    int gbm_format;
368 
369    /* Required for query image WIDTH & HEIGHT */
370    if (dri->image->base.version < 4)
371       return NULL;
372 
373    switch (type) {
374 #if HAVE_WAYLAND_PLATFORM
375    case GBM_BO_IMPORT_WL_BUFFER:
376    {
377       struct wl_drm_buffer *wb = (struct wl_drm_buffer *) buffer;
378 
379       if (!wayland_buffer_is_drm(buffer))
380          return NULL;
381 
382       image = wb->driver_buffer;
383 
384       switch (wb->format) {
385       case WL_DRM_FORMAT_XRGB8888:
386          gbm_format = GBM_FORMAT_XRGB8888;
387          break;
388       case WL_DRM_FORMAT_ARGB8888:
389          gbm_format = GBM_FORMAT_ARGB8888;
390          break;
391       case WL_DRM_FORMAT_YUYV:
392          gbm_format = GBM_FORMAT_YUYV;
393          break;
394       default:
395          return NULL;
396       }
397       break;
398    }
399 #endif
400 
401    case GBM_BO_IMPORT_EGL_IMAGE:
402    {
403       int dri_format;
404       if (dri->lookup_image == NULL)
405          return NULL;
406 
407       image = dri->lookup_image(dri->screen, buffer, dri->lookup_user_data);
408       dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &dri_format);
409       gbm_format = gbm_dri_to_gbm_format(dri_format);
410       if (gbm_format == 0)
411          return NULL;
412       break;
413    }
414 
415    default:
416       return NULL;
417    }
418 
419 
420    bo = calloc(1, sizeof *bo);
421    if (bo == NULL)
422       return NULL;
423 
424    bo->image = dri->image->dupImage(image, NULL);
425 
426    if (usage & GBM_BO_USE_SCANOUT)
427       dri_use |= __DRI_IMAGE_USE_SCANOUT;
428    if (usage & GBM_BO_USE_CURSOR_64X64)
429       dri_use |= __DRI_IMAGE_USE_CURSOR;
430    if (dri->image->base.version >= 2 &&
431        !dri->image->validateUsage(bo->image, dri_use)) {
432       free(bo);
433       return NULL;
434    }
435 
436    bo->base.base.gbm = gbm;
437    bo->base.base.format = gbm_format;
438 
439    dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_WIDTH,
440                           (int*)&bo->base.base.width);
441    dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HEIGHT,
442                           (int*)&bo->base.base.height);
443    dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
444                           (int*)&bo->base.base.stride);
445    dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
446                           &bo->base.base.handle.s32);
447 
448    return &bo->base.base;
449 }
450 
451 static struct gbm_bo *
create_dumb(struct gbm_device * gbm,uint32_t width,uint32_t height,uint32_t format,uint32_t usage)452 create_dumb(struct gbm_device *gbm,
453                   uint32_t width, uint32_t height,
454                   uint32_t format, uint32_t usage)
455 {
456    struct gbm_dri_device *dri = gbm_dri_device(gbm);
457    struct drm_mode_create_dumb create_arg;
458    struct drm_mode_map_dumb map_arg;
459    struct gbm_dri_bo *bo;
460    struct drm_mode_destroy_dumb destroy_arg;
461    int ret;
462 
463    if (!(usage & GBM_BO_USE_CURSOR_64X64))
464       return NULL;
465    if (format != GBM_FORMAT_ARGB8888)
466       return NULL;
467 
468    bo = calloc(1, sizeof *bo);
469    if (bo == NULL)
470       return NULL;
471 
472    create_arg.bpp = 32;
473    create_arg.width = width;
474    create_arg.height = height;
475 
476    ret = drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
477    if (ret)
478       goto free_bo;
479 
480    bo->base.base.gbm = gbm;
481    bo->base.base.width = width;
482    bo->base.base.height = height;
483    bo->base.base.stride = create_arg.pitch;
484    bo->base.base.handle.u32 = create_arg.handle;
485    bo->handle = create_arg.handle;
486    bo->size = create_arg.size;
487 
488    memset(&map_arg, 0, sizeof(map_arg));
489    map_arg.handle = bo->handle;
490 
491    ret = drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
492    if (ret)
493       goto destroy_dumb;
494 
495    bo->map = mmap(0, bo->size, PROT_WRITE,
496                   MAP_SHARED, dri->base.base.fd, map_arg.offset);
497    if (bo->map == MAP_FAILED)
498       goto destroy_dumb;
499 
500    return &bo->base.base;
501 
502 destroy_dumb:
503    memset(&destroy_arg, 0, sizeof destroy_arg);
504    destroy_arg.handle = create_arg.handle;
505    drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
506 free_bo:
507    free(bo);
508 
509    return NULL;
510 }
511 
512 static struct gbm_bo *
gbm_dri_bo_create(struct gbm_device * gbm,uint32_t width,uint32_t height,uint32_t format,uint32_t usage)513 gbm_dri_bo_create(struct gbm_device *gbm,
514                   uint32_t width, uint32_t height,
515                   uint32_t format, uint32_t usage)
516 {
517    struct gbm_dri_device *dri = gbm_dri_device(gbm);
518    struct gbm_dri_bo *bo;
519    int dri_format;
520    unsigned dri_use = 0;
521 
522    if (usage & GBM_BO_USE_WRITE)
523       return create_dumb(gbm, width, height, format, usage);
524 
525    bo = calloc(1, sizeof *bo);
526    if (bo == NULL)
527       return NULL;
528 
529    bo->base.base.gbm = gbm;
530    bo->base.base.width = width;
531    bo->base.base.height = height;
532 
533    switch (format) {
534    case GBM_FORMAT_RGB565:
535       dri_format =__DRI_IMAGE_FORMAT_RGB565;
536       break;
537    case GBM_FORMAT_XRGB8888:
538    case GBM_BO_FORMAT_XRGB8888:
539       dri_format = __DRI_IMAGE_FORMAT_XRGB8888;
540       break;
541    case GBM_FORMAT_ARGB8888:
542    case GBM_BO_FORMAT_ARGB8888:
543       dri_format = __DRI_IMAGE_FORMAT_ARGB8888;
544       break;
545    case GBM_FORMAT_ABGR8888:
546       dri_format = __DRI_IMAGE_FORMAT_ABGR8888;
547       break;
548    default:
549       return NULL;
550    }
551 
552    if (usage & GBM_BO_USE_SCANOUT)
553       dri_use |= __DRI_IMAGE_USE_SCANOUT;
554    if (usage & GBM_BO_USE_CURSOR_64X64)
555       dri_use |= __DRI_IMAGE_USE_CURSOR;
556 
557    /* Gallium drivers requires shared in order to get the handle/stride */
558    dri_use |= __DRI_IMAGE_USE_SHARE;
559 
560    bo->image =
561       dri->image->createImage(dri->screen,
562                               width, height,
563                               dri_format, dri_use,
564                               bo);
565    if (bo->image == NULL)
566       return NULL;
567 
568    dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
569                           &bo->base.base.handle.s32);
570    dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
571                           (int *) &bo->base.base.stride);
572 
573    return &bo->base.base;
574 }
575 
576 static struct gbm_surface *
gbm_dri_surface_create(struct gbm_device * gbm,uint32_t width,uint32_t height,uint32_t format,uint32_t flags)577 gbm_dri_surface_create(struct gbm_device *gbm,
578                        uint32_t width, uint32_t height,
579 		       uint32_t format, uint32_t flags)
580 {
581    struct gbm_dri_surface *surf;
582 
583    surf = calloc(1, sizeof *surf);
584    if (surf == NULL)
585       return NULL;
586 
587    surf->base.gbm = gbm;
588    surf->base.width = width;
589    surf->base.height = height;
590    surf->base.format = format;
591    surf->base.flags = flags;
592 
593    return &surf->base;
594 }
595 
596 static void
gbm_dri_surface_destroy(struct gbm_surface * _surf)597 gbm_dri_surface_destroy(struct gbm_surface *_surf)
598 {
599    struct gbm_dri_surface *surf = gbm_dri_surface(_surf);
600 
601    free(surf);
602 }
603 
604 static void
dri_destroy(struct gbm_device * gbm)605 dri_destroy(struct gbm_device *gbm)
606 {
607    struct gbm_dri_device *dri = gbm_dri_device(gbm);
608 
609    dri->core->destroyScreen(dri->screen);
610    free(dri->driver_configs);
611    dlclose(dri->driver);
612    free(dri->base.driver_name);
613 
614    free(dri);
615 }
616 
617 static struct gbm_device *
dri_device_create(int fd)618 dri_device_create(int fd)
619 {
620    struct gbm_dri_device *dri;
621    int ret;
622 
623    dri = calloc(1, sizeof *dri);
624 
625    dri->base.base.fd = fd;
626    dri->base.base.bo_create = gbm_dri_bo_create;
627    dri->base.base.bo_import = gbm_dri_bo_import;
628    dri->base.base.is_format_supported = gbm_dri_is_format_supported;
629    dri->base.base.bo_write = gbm_dri_bo_write;
630    dri->base.base.bo_destroy = gbm_dri_bo_destroy;
631    dri->base.base.destroy = dri_destroy;
632    dri->base.base.surface_create = gbm_dri_surface_create;
633    dri->base.base.surface_destroy = gbm_dri_surface_destroy;
634 
635    dri->base.type = GBM_DRM_DRIVER_TYPE_DRI;
636    dri->base.base.name = "drm";
637 
638    ret = dri_screen_create(dri);
639    if (ret)
640       goto err_dri;
641 
642    return &dri->base.base;
643 
644 err_dri:
645    free(dri);
646 
647    return NULL;
648 }
649 
650 struct gbm_backend gbm_dri_backend = {
651    .backend_name = "dri",
652    .create_device = dri_device_create,
653 };
654