Subversion Repositories Kolibri OS

Rev

Rev 4401 | 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[64];
  178.  
  179.    snprintf(path, sizeof path,"/kolibrios/lib/%s_dri.drv", dri->base.driver_name);
  180.  
  181.    dri->driver = load_library(path);
  182.  
  183.    if (dri->driver == NULL) {
  184.       fprintf(stderr, "gbm: failed to open any driver (search paths %s)",
  185.               path);
  186.       return -1;
  187.    }
  188.  
  189.    extensions = get_proc_address(dri->driver, __DRI_DRIVER_EXTENSIONS);
  190.    if (extensions == NULL) {
  191.       fprintf(stderr, "gbm: driver exports no extensions\n");
  192. //      dlclose(dri->driver);
  193.       return -1;
  194.    }
  195.  
  196.  
  197.    if (dri_bind_extensions(dri, gbm_dri_device_extensions, extensions) < 0) {
  198. //      dlclose(dri->driver);
  199.       fprintf(stderr, "failed to bind extensions\n");
  200.       return -1;
  201.    }
  202.  
  203.    return 0;
  204. }
  205.  
  206. static int
  207. dri_screen_create(struct gbm_dri_device *dri)
  208. {
  209.    const __DRIextension **extensions;
  210.    int ret = 0;
  211.  
  212.    dri->base.driver_name = dri_fd_get_driver_name(dri->base.base.fd);
  213.    if (dri->base.driver_name == NULL)
  214.       return -1;
  215.  
  216.    ret = dri_load_driver(dri);
  217.    if (ret) {
  218.       fprintf(stderr, "failed to load driver: %s\n", dri->base.driver_name);
  219.       return ret;
  220.    };
  221.  
  222.    dri->extensions[0] = &image_lookup_extension.base;
  223.    dri->extensions[1] = &use_invalidate.base;
  224.    dri->extensions[2] = &dri2_loader_extension.base;
  225.    dri->extensions[3] = NULL;
  226.  
  227.    if (dri->dri2 == NULL)
  228.       return -1;
  229.  
  230.    dri->screen = dri->dri2->createNewScreen(0, dri->base.base.fd,
  231.                                             dri->extensions,
  232.                                             &dri->driver_configs, dri);
  233.    if (dri->screen == NULL)
  234.       return -1;
  235.  
  236.    extensions = dri->core->getExtensions(dri->screen);
  237.    if (dri_bind_extensions(dri, dri_core_extensions, extensions) < 0) {
  238.       ret = -1;
  239.       goto free_screen;
  240.    }
  241.  
  242.    dri->lookup_image = NULL;
  243.    dri->lookup_user_data = NULL;
  244.  
  245.    return 0;
  246.  
  247. free_screen:
  248.    dri->core->destroyScreen(dri->screen);
  249.  
  250.    return ret;
  251. }
  252.  
  253. static int
  254. gbm_dri_is_format_supported(struct gbm_device *gbm,
  255.                             uint32_t format,
  256.                             uint32_t usage)
  257. {
  258.    switch (format) {
  259.    case GBM_BO_FORMAT_XRGB8888:
  260.    case GBM_FORMAT_XRGB8888:
  261.       break;
  262.    case GBM_BO_FORMAT_ARGB8888:
  263.    case GBM_FORMAT_ARGB8888:
  264.       if (usage & GBM_BO_USE_SCANOUT)
  265.          return 0;
  266.       break;
  267.    default:
  268.       return 0;
  269.    }
  270.  
  271.    if (usage & GBM_BO_USE_CURSOR_64X64 &&
  272.        usage & GBM_BO_USE_RENDERING)
  273.       return 0;
  274.  
  275.    return 1;
  276. }
  277.  
  278. static int
  279. gbm_dri_bo_write(struct gbm_bo *_bo, const void *buf, size_t count)
  280. {
  281.    struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
  282.  
  283.    if (bo->image != NULL)
  284.       return -1;
  285.  
  286.    memcpy(bo->map, buf, count);
  287.  
  288.    return 0;
  289. }
  290.  
  291. static void
  292. gbm_dri_bo_destroy(struct gbm_bo *_bo)
  293. {
  294.    struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
  295.    struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
  296. //   struct drm_mode_destroy_dumb arg;
  297.  
  298.    if (bo->image != NULL) {
  299.       dri->image->destroyImage(bo->image);
  300.    } else {
  301. //      munmap(bo->map, bo->size);
  302. //      memset(&arg, 0, sizeof(arg));
  303. //      arg.handle = bo->handle;
  304. //      drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
  305.    }
  306.  
  307.    free(bo);
  308. }
  309.  
  310. static uint32_t
  311. gbm_dri_to_gbm_format(uint32_t dri_format)
  312. {
  313.    uint32_t ret = 0;
  314.  
  315.    switch (dri_format) {
  316.    case __DRI_IMAGE_FORMAT_RGB565:
  317.       ret = GBM_FORMAT_RGB565;
  318.       break;
  319.    case __DRI_IMAGE_FORMAT_XRGB8888:
  320.       ret = GBM_FORMAT_XRGB8888;
  321.       break;
  322.    case __DRI_IMAGE_FORMAT_ARGB8888:
  323.       ret = GBM_FORMAT_ARGB8888;
  324.       break;
  325.    case __DRI_IMAGE_FORMAT_ABGR8888:
  326.       ret = GBM_FORMAT_ABGR8888;
  327.       break;
  328.    default:
  329.       ret = 0;
  330.       break;
  331.    }
  332.  
  333.    return ret;
  334. }
  335.  
  336. static struct gbm_bo *
  337. gbm_dri_bo_import(struct gbm_device *gbm,
  338.                   uint32_t type, void *buffer, uint32_t usage)
  339. {
  340.    struct gbm_dri_device *dri = gbm_dri_device(gbm);
  341.    struct gbm_dri_bo *bo;
  342.    __DRIimage *image;
  343.    unsigned dri_use = 0;
  344.    int gbm_format;
  345.  
  346.    /* Required for query image WIDTH & HEIGHT */
  347.    if (dri->image->base.version < 4)
  348.       return NULL;
  349.  
  350.    switch (type) {
  351. #if HAVE_WAYLAND_PLATFORM
  352.    case GBM_BO_IMPORT_WL_BUFFER:
  353.    {
  354.       struct wl_drm_buffer *wb = (struct wl_drm_buffer *) buffer;
  355.  
  356.       if (dri->wl_drm == NULL)
  357.          return NULL;
  358.  
  359.       if (!wayland_buffer_is_drm(dri->wl_drm, buffer))
  360.          return NULL;
  361.  
  362.       image = wb->driver_buffer;
  363.  
  364.       switch (wb->format) {
  365.       case WL_DRM_FORMAT_XRGB8888:
  366.          gbm_format = GBM_FORMAT_XRGB8888;
  367.          break;
  368.       case WL_DRM_FORMAT_ARGB8888:
  369.          gbm_format = GBM_FORMAT_ARGB8888;
  370.          break;
  371.       case WL_DRM_FORMAT_YUYV:
  372.          gbm_format = GBM_FORMAT_YUYV;
  373.          break;
  374.       default:
  375.          return NULL;
  376.       }
  377.       break;
  378.    }
  379. #endif
  380.  
  381.    case GBM_BO_IMPORT_EGL_IMAGE:
  382.    {
  383.       int dri_format;
  384.       if (dri->lookup_image == NULL)
  385.          return NULL;
  386.  
  387.       image = dri->lookup_image(dri->screen, buffer, dri->lookup_user_data);
  388.       dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &dri_format);
  389.       gbm_format = gbm_dri_to_gbm_format(dri_format);
  390.       if (gbm_format == 0)
  391.          return NULL;
  392.       break;
  393.    }
  394.  
  395.    default:
  396.       return NULL;
  397.    }
  398.  
  399.  
  400.    bo = calloc(1, sizeof *bo);
  401.    if (bo == NULL)
  402.       return NULL;
  403.  
  404.    bo->image = dri->image->dupImage(image, NULL);
  405.  
  406.    if (usage & GBM_BO_USE_SCANOUT)
  407.       dri_use |= __DRI_IMAGE_USE_SCANOUT;
  408.    if (usage & GBM_BO_USE_CURSOR_64X64)
  409.       dri_use |= __DRI_IMAGE_USE_CURSOR;
  410.    if (dri->image->base.version >= 2 &&
  411.        !dri->image->validateUsage(bo->image, dri_use)) {
  412.       free(bo);
  413.       return NULL;
  414.    }
  415.  
  416.    bo->base.base.gbm = gbm;
  417.    bo->base.base.format = gbm_format;
  418.  
  419.    dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_WIDTH,
  420.                           (int*)&bo->base.base.width);
  421.    dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HEIGHT,
  422.                           (int*)&bo->base.base.height);
  423.    dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
  424.                           (int*)&bo->base.base.stride);
  425.    dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
  426.                           &bo->base.base.handle.s32);
  427.  
  428.    return &bo->base.base;
  429. }
  430.  
  431. #if 0
  432. static struct gbm_bo *
  433. create_dumb(struct gbm_device *gbm,
  434.                   uint32_t width, uint32_t height,
  435.                   uint32_t format, uint32_t usage)
  436. {
  437.    struct gbm_dri_device *dri = gbm_dri_device(gbm);
  438.    struct drm_mode_create_dumb create_arg;
  439.    struct drm_mode_map_dumb map_arg;
  440.    struct gbm_dri_bo *bo;
  441.    struct drm_mode_destroy_dumb destroy_arg;
  442.    int ret;
  443.  
  444.    if (!(usage & GBM_BO_USE_CURSOR_64X64))
  445.       return NULL;
  446.    if (format != GBM_FORMAT_ARGB8888)
  447.       return NULL;
  448.  
  449.    bo = calloc(1, sizeof *bo);
  450.    if (bo == NULL)
  451.       return NULL;
  452.  
  453.    create_arg.bpp = 32;
  454.    create_arg.width = width;
  455.    create_arg.height = height;
  456.  
  457.    ret = drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
  458.    if (ret)
  459.       goto free_bo;
  460.  
  461.    bo->base.base.gbm = gbm;
  462.    bo->base.base.width = width;
  463.    bo->base.base.height = height;
  464.    bo->base.base.stride = create_arg.pitch;
  465.    bo->base.base.format = format;
  466.    bo->base.base.handle.u32 = create_arg.handle;
  467.    bo->handle = create_arg.handle;
  468.    bo->size = create_arg.size;
  469.  
  470.    memset(&map_arg, 0, sizeof(map_arg));
  471.    map_arg.handle = bo->handle;
  472.  
  473.    ret = drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
  474.    if (ret)
  475.       goto destroy_dumb;
  476.  
  477.    bo->map = mmap(0, bo->size, PROT_WRITE,
  478.                   MAP_SHARED, dri->base.base.fd, map_arg.offset);
  479.    if (bo->map == MAP_FAILED)
  480.       goto destroy_dumb;
  481.  
  482.    return &bo->base.base;
  483.  
  484. destroy_dumb:
  485.    memset(&destroy_arg, 0, sizeof destroy_arg);
  486.    destroy_arg.handle = create_arg.handle;
  487.    drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
  488. free_bo:
  489.    free(bo);
  490.  
  491.    return NULL;
  492. }
  493. #endif
  494.  
  495. static struct gbm_bo *
  496. gbm_dri_bo_create(struct gbm_device *gbm,
  497.                   uint32_t width, uint32_t height,
  498.                   uint32_t format, uint32_t usage)
  499. {
  500.    struct gbm_dri_device *dri = gbm_dri_device(gbm);
  501.    struct gbm_dri_bo *bo;
  502.    int dri_format;
  503.    unsigned dri_use = 0;
  504.  
  505. //   if (usage & GBM_BO_USE_WRITE)
  506. //      return create_dumb(gbm, width, height, format, usage);
  507.  
  508.    bo = calloc(1, sizeof *bo);
  509.    if (bo == NULL)
  510.       return NULL;
  511.  
  512.    bo->base.base.gbm = gbm;
  513.    bo->base.base.width = width;
  514.    bo->base.base.height = height;
  515.    bo->base.base.format = format;
  516.  
  517.    switch (format) {
  518.    case GBM_FORMAT_RGB565:
  519.       dri_format =__DRI_IMAGE_FORMAT_RGB565;
  520.       break;
  521.    case GBM_FORMAT_XRGB8888:
  522.    case GBM_BO_FORMAT_XRGB8888:
  523.       dri_format = __DRI_IMAGE_FORMAT_XRGB8888;
  524.       break;
  525.    case GBM_FORMAT_ARGB8888:
  526.    case GBM_BO_FORMAT_ARGB8888:
  527.       dri_format = __DRI_IMAGE_FORMAT_ARGB8888;
  528.       break;
  529.    case GBM_FORMAT_ABGR8888:
  530.       dri_format = __DRI_IMAGE_FORMAT_ABGR8888;
  531.       break;
  532.    default:
  533.       return NULL;
  534.    }
  535.  
  536.    if (usage & GBM_BO_USE_SCANOUT)
  537.       dri_use |= __DRI_IMAGE_USE_SCANOUT;
  538.    if (usage & GBM_BO_USE_CURSOR_64X64)
  539.       dri_use |= __DRI_IMAGE_USE_CURSOR;
  540.  
  541.    /* Gallium drivers requires shared in order to get the handle/stride */
  542.    dri_use |= __DRI_IMAGE_USE_SHARE;
  543.  
  544.    bo->image =
  545.       dri->image->createImage(dri->screen,
  546.                               width, height,
  547.                               dri_format, dri_use,
  548.                               bo);
  549.    if (bo->image == NULL)
  550.       return NULL;
  551.  
  552.    dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
  553.                           &bo->base.base.handle.s32);
  554.    dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
  555.                           (int *) &bo->base.base.stride);
  556.  
  557.    return &bo->base.base;
  558. }
  559.  
  560. static struct gbm_surface *
  561. gbm_dri_surface_create(struct gbm_device *gbm,
  562.                        uint32_t width, uint32_t height,
  563.                        uint32_t format, uint32_t flags)
  564. {
  565.    struct gbm_dri_surface *surf;
  566.  
  567.    surf = calloc(1, sizeof *surf);
  568.    if (surf == NULL)
  569.       return NULL;
  570.  
  571.    surf->base.gbm = gbm;
  572.    surf->base.width = width;
  573.    surf->base.height = height;
  574.    surf->base.format = format;
  575.    surf->base.flags = flags;
  576.  
  577.    return &surf->base;
  578. }
  579.  
  580. static void
  581. gbm_dri_surface_destroy(struct gbm_surface *_surf)
  582. {
  583.    struct gbm_dri_surface *surf = gbm_dri_surface(_surf);
  584.  
  585.    free(surf);
  586. }
  587.  
  588. static void
  589. dri_destroy(struct gbm_device *gbm)
  590. {
  591.    struct gbm_dri_device *dri = gbm_dri_device(gbm);
  592.  
  593.    dri->core->destroyScreen(dri->screen);
  594.    free(dri->driver_configs);
  595. //   dlclose(dri->driver);
  596.    free(dri->base.driver_name);
  597.  
  598.    free(dri);
  599. }
  600.  
  601. static struct gbm_device *
  602. dri_device_create(int fd)
  603. {
  604.    struct gbm_dri_device *dri;
  605.    int ret;
  606.  
  607.    dri = calloc(1, sizeof *dri);
  608.  
  609.    dri->base.base.fd = fd;
  610.    dri->base.base.bo_create = gbm_dri_bo_create;
  611.    dri->base.base.bo_import = gbm_dri_bo_import;
  612.    dri->base.base.is_format_supported = gbm_dri_is_format_supported;
  613.    dri->base.base.bo_write = gbm_dri_bo_write;
  614.    dri->base.base.bo_destroy = gbm_dri_bo_destroy;
  615.    dri->base.base.destroy = dri_destroy;
  616.    dri->base.base.surface_create = gbm_dri_surface_create;
  617.    dri->base.base.surface_destroy = gbm_dri_surface_destroy;
  618.  
  619.    dri->base.type = GBM_DRM_DRIVER_TYPE_DRI;
  620.    dri->base.base.name = "drm";
  621.  
  622.    ret = dri_screen_create(dri);
  623.    if (ret)
  624.       goto err_dri;
  625.  
  626.    return &dri->base.base;
  627.  
  628. err_dri:
  629.    free(dri);
  630.  
  631.    return NULL;
  632. }
  633.  
  634. struct gbm_backend gbm_dri_backend = {
  635.    .backend_name = "dri",
  636.    .create_device = dri_device_create,
  637. };
  638.