Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

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