Home | History | Annotate | Download | only in dri
      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 (at) 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 *
     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 *
     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
     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 *
     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
    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
    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
    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
    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
    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
    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
    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 *
    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 *
    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 *
    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 *
    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
    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
    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 *
    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