"Fossies" - the Fresh Open Source Software Archive

Member "mesa-20.1.8/src/egl/drivers/dri2/platform_drm.c" (16 Sep 2020, 24840 Bytes) of package /linux/misc/mesa-20.1.8.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "platform_drm.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 20.1.5_vs_20.2.0-rc1.

    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  *    Kristian Høgsberg <krh@bitplanet.net>
   26  */
   27 
   28 #include <stdint.h>
   29 #include <stdlib.h>
   30 #include <stdio.h>
   31 #include <string.h>
   32 #include <xf86drm.h>
   33 #include <dlfcn.h>
   34 #include <sys/types.h>
   35 #include <sys/stat.h>
   36 #include <fcntl.h>
   37 #include <unistd.h>
   38 
   39 #include "egl_dri2.h"
   40 #include "egl_dri2_fallbacks.h"
   41 #include "loader.h"
   42 
   43 static struct gbm_bo *
   44 lock_front_buffer(struct gbm_surface *_surf)
   45 {
   46    struct gbm_dri_surface *surf = gbm_dri_surface(_surf);
   47    struct dri2_egl_surface *dri2_surf = surf->dri_private;
   48    struct gbm_dri_device *device = gbm_dri_device(_surf->gbm);
   49    struct gbm_bo *bo;
   50 
   51    if (dri2_surf->current == NULL) {
   52       _eglError(EGL_BAD_SURFACE, "no front buffer");
   53       return NULL;
   54    }
   55 
   56    bo = dri2_surf->current->bo;
   57 
   58    if (device->dri2) {
   59       dri2_surf->current->locked = true;
   60       dri2_surf->current = NULL;
   61    }
   62 
   63    return bo;
   64 }
   65 
   66 static void
   67 release_buffer(struct gbm_surface *_surf, struct gbm_bo *bo)
   68 {
   69    struct gbm_dri_surface *surf = gbm_dri_surface(_surf);
   70    struct dri2_egl_surface *dri2_surf = surf->dri_private;
   71 
   72    for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
   73       if (dri2_surf->color_buffers[i].bo == bo) {
   74      dri2_surf->color_buffers[i].locked = false;
   75      break;
   76       }
   77    }
   78 }
   79 
   80 static int
   81 has_free_buffers(struct gbm_surface *_surf)
   82 {
   83    struct gbm_dri_surface *surf = gbm_dri_surface(_surf);
   84    struct dri2_egl_surface *dri2_surf = surf->dri_private;
   85 
   86    for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
   87       if (!dri2_surf->color_buffers[i].locked)
   88      return 1;
   89 
   90    return 0;
   91 }
   92 
   93 static bool
   94 dri2_drm_config_is_compatible(struct dri2_egl_display *dri2_dpy,
   95                               const __DRIconfig *config,
   96                               struct gbm_surface *surface)
   97 {
   98    const struct gbm_dri_visual *visual = NULL;
   99    int shifts[4];
  100    unsigned int sizes[4];
  101    bool is_float;
  102    int i;
  103 
  104    /* Check that the EGLConfig being used to render to the surface is
  105     * compatible with the surface format. Since mixing ARGB and XRGB of
  106     * otherwise-compatible formats is relatively common, explicitly allow
  107     * this.
  108     */
  109    dri2_get_shifts_and_sizes(dri2_dpy->core, config, shifts, sizes);
  110 
  111    dri2_get_render_type_float(dri2_dpy->core, config, &is_float);
  112 
  113    for (i = 0; i < dri2_dpy->gbm_dri->num_visuals; i++) {
  114       visual = &dri2_dpy->gbm_dri->visual_table[i];
  115       if (visual->gbm_format == surface->format)
  116          break;
  117    }
  118 
  119    if (i == dri2_dpy->gbm_dri->num_visuals)
  120       return false;
  121 
  122    if (shifts[0] != visual->rgba_shifts.red ||
  123        shifts[1] != visual->rgba_shifts.green ||
  124        shifts[2] != visual->rgba_shifts.blue ||
  125        (shifts[3] > -1 && visual->rgba_shifts.alpha > -1 &&
  126         shifts[3] != visual->rgba_shifts.alpha) ||
  127        sizes[0] != visual->rgba_sizes.red ||
  128        sizes[1] != visual->rgba_sizes.green ||
  129        sizes[2] != visual->rgba_sizes.blue ||
  130        (sizes[3] > 0 && visual->rgba_sizes.alpha > 0 &&
  131         sizes[3] != visual->rgba_sizes.alpha) ||
  132        is_float != visual->is_float) {
  133       return false;
  134    }
  135 
  136    return true;
  137 }
  138 
  139 static _EGLSurface *
  140 dri2_drm_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
  141                                _EGLConfig *conf, void *native_surface,
  142                                const EGLint *attrib_list)
  143 {
  144    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
  145    struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
  146    struct dri2_egl_surface *dri2_surf;
  147    struct gbm_surface *surface = native_surface;
  148    struct gbm_dri_surface *surf;
  149    const __DRIconfig *config;
  150 
  151    (void) drv;
  152 
  153    dri2_surf = calloc(1, sizeof *dri2_surf);
  154    if (!dri2_surf) {
  155       _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
  156       return NULL;
  157    }
  158 
  159    if (!dri2_init_surface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf,
  160                           attrib_list, false, native_surface))
  161       goto cleanup_surf;
  162 
  163    config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT,
  164                                 dri2_surf->base.GLColorspace);
  165 
  166    if (!config) {
  167       _eglError(EGL_BAD_MATCH, "Unsupported surfacetype/colorspace configuration");
  168       goto cleanup_surf;
  169    }
  170 
  171    if (!dri2_drm_config_is_compatible(dri2_dpy, config, surface)) {
  172       _eglError(EGL_BAD_MATCH, "EGL config not compatible with GBM format");
  173       goto cleanup_surf;
  174    }
  175 
  176    surf = gbm_dri_surface(surface);
  177    dri2_surf->gbm_surf = surf;
  178    dri2_surf->base.Width =  surf->base.width;
  179    dri2_surf->base.Height = surf->base.height;
  180    surf->dri_private = dri2_surf;
  181 
  182    if (!dri2_create_drawable(dri2_dpy, config, dri2_surf, dri2_surf->gbm_surf))
  183       goto cleanup_surf;
  184 
  185    return &dri2_surf->base;
  186 
  187  cleanup_surf:
  188    free(dri2_surf);
  189 
  190    return NULL;
  191 }
  192 
  193 static _EGLSurface *
  194 dri2_drm_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,
  195                                _EGLConfig *conf, void *native_window,
  196                                const EGLint *attrib_list)
  197 {
  198    /* From the EGL_MESA_platform_gbm spec, version 5:
  199     *
  200     *  It is not valid to call eglCreatePlatformPixmapSurfaceEXT with a <dpy>
  201     *  that belongs to the GBM platform. Any such call fails and generates
  202     *  EGL_BAD_PARAMETER.
  203     */
  204    _eglError(EGL_BAD_PARAMETER, "cannot create EGL pixmap surfaces on GBM");
  205    return NULL;
  206 }
  207 
  208 static EGLBoolean
  209 dri2_drm_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
  210 {
  211    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
  212    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
  213 
  214    dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
  215 
  216    for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
  217       if (dri2_surf->color_buffers[i].bo)
  218      gbm_bo_destroy(dri2_surf->color_buffers[i].bo);
  219    }
  220 
  221    dri2_egl_surface_free_local_buffers(dri2_surf);
  222 
  223    dri2_fini_surface(surf);
  224    free(surf);
  225 
  226    return EGL_TRUE;
  227 }
  228 
  229 static int
  230 get_back_bo(struct dri2_egl_surface *dri2_surf)
  231 {
  232    struct dri2_egl_display *dri2_dpy =
  233       dri2_egl_display(dri2_surf->base.Resource.Display);
  234    struct gbm_dri_surface *surf = dri2_surf->gbm_surf;
  235    int age = 0;
  236 
  237    if (dri2_surf->back == NULL) {
  238       for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
  239      if (!dri2_surf->color_buffers[i].locked &&
  240           dri2_surf->color_buffers[i].age >= age) {
  241         dri2_surf->back = &dri2_surf->color_buffers[i];
  242         age = dri2_surf->color_buffers[i].age;
  243      }
  244       }
  245    }
  246 
  247    if (dri2_surf->back == NULL)
  248       return -1;
  249    if (dri2_surf->back->bo == NULL) {
  250       if (surf->base.modifiers)
  251          dri2_surf->back->bo = gbm_bo_create_with_modifiers(&dri2_dpy->gbm_dri->base,
  252                                                             surf->base.width,
  253                                                             surf->base.height,
  254                                                             surf->base.format,
  255                                                             surf->base.modifiers,
  256                                                             surf->base.count);
  257       else
  258          dri2_surf->back->bo = gbm_bo_create(&dri2_dpy->gbm_dri->base,
  259                                              surf->base.width,
  260                                              surf->base.height,
  261                                              surf->base.format,
  262                                              surf->base.flags);
  263 
  264    }
  265    if (dri2_surf->back->bo == NULL)
  266       return -1;
  267 
  268    return 0;
  269 }
  270 
  271 static int
  272 get_swrast_front_bo(struct dri2_egl_surface *dri2_surf)
  273 {
  274    struct dri2_egl_display *dri2_dpy =
  275       dri2_egl_display(dri2_surf->base.Resource.Display);
  276    struct gbm_dri_surface *surf = dri2_surf->gbm_surf;
  277 
  278    if (dri2_surf->current == NULL) {
  279       assert(!dri2_surf->color_buffers[0].locked);
  280       dri2_surf->current = &dri2_surf->color_buffers[0];
  281    }
  282 
  283    if (dri2_surf->current->bo == NULL)
  284       dri2_surf->current->bo = gbm_bo_create(&dri2_dpy->gbm_dri->base,
  285                                              surf->base.width, surf->base.height,
  286                                              surf->base.format, surf->base.flags);
  287    if (dri2_surf->current->bo == NULL)
  288       return -1;
  289 
  290    return 0;
  291 }
  292 
  293 static void
  294 back_bo_to_dri_buffer(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer)
  295 {
  296    struct dri2_egl_display *dri2_dpy =
  297       dri2_egl_display(dri2_surf->base.Resource.Display);
  298    struct gbm_dri_bo *bo;
  299    int name, pitch;
  300 
  301    bo = gbm_dri_bo(dri2_surf->back->bo);
  302 
  303    dri2_dpy->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_NAME, &name);
  304    dri2_dpy->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch);
  305 
  306    buffer->attachment = __DRI_BUFFER_BACK_LEFT;
  307    buffer->name = name;
  308    buffer->pitch = pitch;
  309    buffer->cpp = 4;
  310    buffer->flags = 0;
  311 }
  312 
  313 static __DRIbuffer *
  314 dri2_drm_get_buffers_with_format(__DRIdrawable *driDrawable,
  315                                  int *width, int *height,
  316                                  unsigned int *attachments, int count,
  317                                  int *out_count, void *loaderPrivate)
  318 {
  319    struct dri2_egl_surface *dri2_surf = loaderPrivate;
  320    int i, j;
  321 
  322    for (i = 0, j = 0; i < 2 * count; i += 2, j++) {
  323       __DRIbuffer *local;
  324 
  325       assert(attachments[i] < __DRI_BUFFER_COUNT);
  326       assert(j < ARRAY_SIZE(dri2_surf->buffers));
  327 
  328       switch (attachments[i]) {
  329       case __DRI_BUFFER_BACK_LEFT:
  330      if (get_back_bo(dri2_surf) < 0) {
  331         _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer");
  332         return NULL;
  333      }
  334          back_bo_to_dri_buffer(dri2_surf, &dri2_surf->buffers[j]);
  335      break;
  336       default:
  337      local = dri2_egl_surface_alloc_local_buffer(dri2_surf, attachments[i],
  338                                                      attachments[i + 1]);
  339 
  340      if (!local) {
  341         _eglError(EGL_BAD_ALLOC, "failed to allocate local buffer");
  342         return NULL;
  343      }
  344      dri2_surf->buffers[j] = *local;
  345      break;
  346       }
  347    }
  348 
  349    *out_count = j;
  350    if (j == 0)
  351       return NULL;
  352 
  353    *width = dri2_surf->base.Width;
  354    *height = dri2_surf->base.Height;
  355 
  356    return dri2_surf->buffers;
  357 }
  358 
  359 static __DRIbuffer *
  360 dri2_drm_get_buffers(__DRIdrawable * driDrawable,
  361                      int *width, int *height,
  362                      unsigned int *attachments, int count,
  363                      int *out_count, void *loaderPrivate)
  364 {
  365    unsigned int *attachments_with_format;
  366    __DRIbuffer *buffer;
  367    const unsigned int format = 32;
  368 
  369    attachments_with_format = calloc(count, 2 * sizeof(unsigned int));
  370    if (!attachments_with_format) {
  371       *out_count = 0;
  372       return NULL;
  373    }
  374 
  375    for (int i = 0; i < count; ++i) {
  376       attachments_with_format[2*i] = attachments[i];
  377       attachments_with_format[2*i + 1] = format;
  378    }
  379 
  380    buffer =
  381       dri2_drm_get_buffers_with_format(driDrawable,
  382                                        width, height,
  383                                        attachments_with_format, count,
  384                                        out_count, loaderPrivate);
  385 
  386    free(attachments_with_format);
  387 
  388    return buffer;
  389 }
  390 
  391 static int
  392 dri2_drm_image_get_buffers(__DRIdrawable *driDrawable,
  393                            unsigned int format,
  394                            uint32_t *stamp,
  395                            void *loaderPrivate,
  396                            uint32_t buffer_mask,
  397                            struct __DRIimageList *buffers)
  398 {
  399    struct dri2_egl_surface *dri2_surf = loaderPrivate;
  400    struct gbm_dri_bo *bo;
  401 
  402    if (get_back_bo(dri2_surf) < 0)
  403       return 0;
  404 
  405    bo = gbm_dri_bo(dri2_surf->back->bo);
  406    buffers->image_mask = __DRI_IMAGE_BUFFER_BACK;
  407    buffers->back = bo->image;
  408 
  409    return 1;
  410 }
  411 
  412 static void
  413 dri2_drm_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
  414 {
  415    (void) driDrawable;
  416    (void) loaderPrivate;
  417 }
  418 
  419 static EGLBoolean
  420 dri2_drm_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
  421 {
  422    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
  423    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
  424 
  425    if (!dri2_dpy->flush) {
  426       dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable);
  427       return EGL_TRUE;
  428    }
  429 
  430    if (dri2_surf->current)
  431       _eglError(EGL_BAD_SURFACE, "dri2_swap_buffers");
  432    for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
  433       if (dri2_surf->color_buffers[i].age > 0)
  434          dri2_surf->color_buffers[i].age++;
  435 
  436    /* Make sure we have a back buffer in case we're swapping without
  437     * ever rendering. */
  438    if (get_back_bo(dri2_surf) < 0)
  439       return _eglError(EGL_BAD_ALLOC, "dri2_swap_buffers");
  440 
  441    dri2_surf->current = dri2_surf->back;
  442    dri2_surf->current->age = 1;
  443    dri2_surf->back = NULL;
  444 
  445    dri2_flush_drawable_for_swapbuffers(disp, draw);
  446    dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);
  447 
  448    return EGL_TRUE;
  449 }
  450 
  451 static EGLint
  452 dri2_drm_query_buffer_age(_EGLDriver *drv,
  453                           _EGLDisplay *disp, _EGLSurface *surface)
  454 {
  455    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);
  456 
  457    if (get_back_bo(dri2_surf) < 0) {
  458       _eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age");
  459       return -1;
  460    }
  461 
  462    return dri2_surf->back->age;
  463 }
  464 
  465 static _EGLImage *
  466 dri2_drm_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
  467                                  EGLClientBuffer buffer, const EGLint *attr_list)
  468 {
  469    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
  470    struct gbm_dri_bo *dri_bo = gbm_dri_bo((struct gbm_bo *) buffer);
  471    struct dri2_egl_image *dri2_img;
  472 
  473    dri2_img = malloc(sizeof *dri2_img);
  474    if (!dri2_img) {
  475       _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr_pixmap");
  476       return NULL;
  477    }
  478 
  479    _eglInitImage(&dri2_img->base, disp);
  480 
  481    dri2_img->dri_image = dri2_dpy->image->dupImage(dri_bo->image, dri2_img);
  482    if (dri2_img->dri_image == NULL) {
  483       free(dri2_img);
  484       _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr_pixmap");
  485       return NULL;
  486    }
  487 
  488    return &dri2_img->base;
  489 }
  490 
  491 static _EGLImage *
  492 dri2_drm_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
  493                           _EGLContext *ctx, EGLenum target,
  494                           EGLClientBuffer buffer, const EGLint *attr_list)
  495 {
  496    (void) drv;
  497 
  498    switch (target) {
  499    case EGL_NATIVE_PIXMAP_KHR:
  500       return dri2_drm_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
  501    default:
  502       return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list);
  503    }
  504 }
  505 
  506 static int
  507 dri2_drm_authenticate(_EGLDisplay *disp, uint32_t id)
  508 {
  509    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
  510 
  511    return drmAuthMagic(dri2_dpy->fd, id);
  512 }
  513 
  514 static void
  515 swrast_put_image2(__DRIdrawable *driDrawable,
  516                   int            op,
  517                   int            x,
  518                   int            y,
  519                   int            width,
  520                   int            height,
  521                   int            stride,
  522                   char          *data,
  523                   void          *loaderPrivate)
  524 {
  525    struct dri2_egl_surface *dri2_surf = loaderPrivate;
  526    int internal_stride;
  527    struct gbm_dri_bo *bo;
  528    uint32_t bpp;
  529    int x_bytes, width_bytes;
  530    char *src, *dst;
  531 
  532    if (op != __DRI_SWRAST_IMAGE_OP_DRAW &&
  533        op != __DRI_SWRAST_IMAGE_OP_SWAP)
  534       return;
  535 
  536    if (get_swrast_front_bo(dri2_surf) < 0)
  537       return;
  538 
  539    bo = gbm_dri_bo(dri2_surf->current->bo);
  540 
  541    bpp = gbm_bo_get_bpp(&bo->base);
  542    if (bpp == 0)
  543       return;
  544 
  545    x_bytes = x * (bpp >> 3);
  546    width_bytes = width * (bpp >> 3);
  547 
  548    if (gbm_dri_bo_map_dumb(bo) == NULL)
  549       return;
  550 
  551    internal_stride = bo->base.stride;
  552 
  553    dst = bo->map + x_bytes + (y * internal_stride);
  554    src = data;
  555 
  556    for (int i = 0; i < height; i++) {
  557       memcpy(dst, src, width_bytes);
  558       dst += internal_stride;
  559       src += stride;
  560    }
  561 
  562    gbm_dri_bo_unmap_dumb(bo);
  563 }
  564 
  565 static void
  566 swrast_get_image(__DRIdrawable *driDrawable,
  567                  int            x,
  568                  int            y,
  569                  int            width,
  570                  int            height,
  571                  char          *data,
  572                  void          *loaderPrivate)
  573 {
  574    struct dri2_egl_surface *dri2_surf = loaderPrivate;
  575    int internal_stride, stride;
  576    struct gbm_dri_bo *bo;
  577    uint32_t bpp;
  578    int x_bytes, width_bytes;
  579    char *src, *dst;
  580 
  581    if (get_swrast_front_bo(dri2_surf) < 0)
  582       return;
  583 
  584    bo = gbm_dri_bo(dri2_surf->current->bo);
  585 
  586    bpp = gbm_bo_get_bpp(&bo->base);
  587    if (bpp == 0)
  588       return;
  589 
  590    x_bytes = x * (bpp >> 3);
  591    width_bytes = width * (bpp >> 3);
  592 
  593    internal_stride = bo->base.stride;
  594    stride = width_bytes;
  595 
  596    if (gbm_dri_bo_map_dumb(bo) == NULL)
  597       return;
  598 
  599    dst = data;
  600    src = bo->map + x_bytes + (y * internal_stride);
  601 
  602    for (int i = 0; i < height; i++) {
  603       memcpy(dst, src, width_bytes);
  604       dst += stride;
  605       src += internal_stride;
  606    }
  607 
  608    gbm_dri_bo_unmap_dumb(bo);
  609 }
  610 
  611 static EGLBoolean
  612 drm_add_configs_for_visuals(_EGLDriver *drv, _EGLDisplay *disp)
  613 {
  614    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
  615    const struct gbm_dri_visual *visuals = dri2_dpy->gbm_dri->visual_table;
  616    int num_visuals = dri2_dpy->gbm_dri->num_visuals;
  617    unsigned int format_count[num_visuals];
  618    unsigned int config_count = 0;
  619 
  620    memset(format_count, 0, num_visuals * sizeof(unsigned int));
  621 
  622    for (unsigned i = 0; dri2_dpy->driver_configs[i]; i++) {
  623       const __DRIconfig *config = dri2_dpy->driver_configs[i];
  624       int shifts[4];
  625       unsigned int sizes[4];
  626       bool is_float;
  627 
  628       dri2_get_shifts_and_sizes(dri2_dpy->core, config, shifts, sizes);
  629 
  630       dri2_get_render_type_float(dri2_dpy->core, config, &is_float);
  631 
  632       for (unsigned j = 0; j < num_visuals; j++) {
  633          struct dri2_egl_config *dri2_conf;
  634 
  635          if (visuals[j].rgba_shifts.red != shifts[0] ||
  636              visuals[j].rgba_shifts.green != shifts[1] ||
  637              visuals[j].rgba_shifts.blue != shifts[2] ||
  638              visuals[j].rgba_shifts.alpha != shifts[3] ||
  639              visuals[j].rgba_sizes.red != sizes[0] ||
  640              visuals[j].rgba_sizes.green != sizes[1] ||
  641              visuals[j].rgba_sizes.blue != sizes[2] ||
  642              visuals[j].rgba_sizes.alpha != sizes[3] ||
  643              visuals[j].is_float != is_float)
  644             continue;
  645 
  646          const EGLint attr_list[] = {
  647             EGL_NATIVE_VISUAL_ID, visuals[j].gbm_format,
  648             EGL_NONE,
  649          };
  650 
  651          dri2_conf = dri2_add_config(disp, dri2_dpy->driver_configs[i],
  652                config_count + 1, EGL_WINDOW_BIT, attr_list, NULL, NULL);
  653          if (dri2_conf) {
  654             if (dri2_conf->base.ConfigID == config_count + 1)
  655                config_count++;
  656             format_count[j]++;
  657          }
  658       }
  659    }
  660 
  661    for (unsigned i = 0; i < ARRAY_SIZE(format_count); i++) {
  662       if (!format_count[i]) {
  663          struct gbm_format_name_desc desc;
  664          _eglLog(_EGL_DEBUG, "No DRI config supports native format %s",
  665                  gbm_format_get_name(visuals[i].gbm_format, &desc));
  666       }
  667    }
  668 
  669    return (config_count != 0);
  670 }
  671 
  672 static const struct dri2_egl_display_vtbl dri2_drm_display_vtbl = {
  673    .authenticate = dri2_drm_authenticate,
  674    .create_window_surface = dri2_drm_create_window_surface,
  675    .create_pixmap_surface = dri2_drm_create_pixmap_surface,
  676    .create_pbuffer_surface = dri2_fallback_create_pbuffer_surface,
  677    .destroy_surface = dri2_drm_destroy_surface,
  678    .create_image = dri2_drm_create_image_khr,
  679    .swap_buffers = dri2_drm_swap_buffers,
  680    .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage,
  681    .swap_buffers_region = dri2_fallback_swap_buffers_region,
  682    .post_sub_buffer = dri2_fallback_post_sub_buffer,
  683    .copy_buffers = dri2_fallback_copy_buffers,
  684    .query_buffer_age = dri2_drm_query_buffer_age,
  685    .create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image,
  686    .get_sync_values = dri2_fallback_get_sync_values,
  687    .get_dri_drawable = dri2_surface_get_dri_drawable,
  688 };
  689 
  690 EGLBoolean
  691 dri2_initialize_drm(_EGLDriver *drv, _EGLDisplay *disp)
  692 {
  693    _EGLDevice *dev;
  694    struct dri2_egl_display *dri2_dpy;
  695    struct gbm_device *gbm;
  696    const char *err;
  697 
  698    dri2_dpy = calloc(1, sizeof *dri2_dpy);
  699    if (!dri2_dpy)
  700       return _eglError(EGL_BAD_ALLOC, "eglInitialize");
  701 
  702    dri2_dpy->fd = -1;
  703    disp->DriverData = (void *) dri2_dpy;
  704 
  705    gbm = disp->PlatformDisplay;
  706    if (gbm == NULL) {
  707       char buf[64];
  708       int n = snprintf(buf, sizeof(buf), DRM_DEV_NAME, DRM_DIR_NAME, 0);
  709       if (n != -1 && n < sizeof(buf))
  710          dri2_dpy->fd = loader_open_device(buf);
  711       gbm = gbm_create_device(dri2_dpy->fd);
  712       if (gbm == NULL) {
  713          err = "DRI2: failed to create gbm device";
  714          goto cleanup;
  715       }
  716       dri2_dpy->own_device = true;
  717    } else {
  718       dri2_dpy->fd = fcntl(gbm_device_get_fd(gbm), F_DUPFD_CLOEXEC, 3);
  719       if (dri2_dpy->fd < 0) {
  720          err = "DRI2: failed to fcntl() existing gbm device";
  721          goto cleanup;
  722       }
  723    }
  724    dri2_dpy->gbm_dri = gbm_dri_device(gbm);
  725 
  726    if (strcmp(gbm_device_get_backend_name(gbm), "drm") != 0) {
  727       err = "DRI2: gbm device using incorrect/incompatible backend";
  728       goto cleanup;
  729    }
  730 
  731    dev = _eglAddDevice(dri2_dpy->fd, disp->Options.ForceSoftware);
  732    if (!dev) {
  733       err = "DRI2: failed to find EGLDevice";
  734       goto cleanup;
  735    }
  736 
  737    disp->Device = dev;
  738 
  739    dri2_dpy->driver_name = strdup(dri2_dpy->gbm_dri->driver_name);
  740    dri2_dpy->is_render_node = drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER;
  741 
  742    /* render nodes cannot use Gem names, and thus do not support
  743     * the __DRI_DRI2_LOADER extension */
  744    if (!dri2_dpy->is_render_node) {
  745       if (!dri2_load_driver(disp)) {
  746          err = "DRI2: failed to load driver";
  747          goto cleanup;
  748       }
  749    } else {
  750       if (!dri2_load_driver_dri3(disp)) {
  751          err = "DRI3: failed to load driver";
  752          goto cleanup;
  753       }
  754    }
  755 
  756    dri2_dpy->dri_screen = dri2_dpy->gbm_dri->screen;
  757    dri2_dpy->core = dri2_dpy->gbm_dri->core;
  758    dri2_dpy->dri2 = dri2_dpy->gbm_dri->dri2;
  759    dri2_dpy->swrast = dri2_dpy->gbm_dri->swrast;
  760    dri2_dpy->driver_configs = dri2_dpy->gbm_dri->driver_configs;
  761 
  762    dri2_dpy->gbm_dri->lookup_image = dri2_lookup_egl_image;
  763    dri2_dpy->gbm_dri->lookup_user_data = disp;
  764 
  765    dri2_dpy->gbm_dri->get_buffers = dri2_drm_get_buffers;
  766    dri2_dpy->gbm_dri->flush_front_buffer = dri2_drm_flush_front_buffer;
  767    dri2_dpy->gbm_dri->get_buffers_with_format = dri2_drm_get_buffers_with_format;
  768    dri2_dpy->gbm_dri->image_get_buffers = dri2_drm_image_get_buffers;
  769    dri2_dpy->gbm_dri->swrast_put_image2 = swrast_put_image2;
  770    dri2_dpy->gbm_dri->swrast_get_image = swrast_get_image;
  771 
  772    dri2_dpy->gbm_dri->base.surface_lock_front_buffer = lock_front_buffer;
  773    dri2_dpy->gbm_dri->base.surface_release_buffer = release_buffer;
  774    dri2_dpy->gbm_dri->base.surface_has_free_buffers = has_free_buffers;
  775 
  776    if (!dri2_setup_extensions(disp)) {
  777       err = "DRI2: failed to find required DRI extensions";
  778       goto cleanup;
  779    }
  780 
  781    dri2_setup_screen(disp);
  782 
  783    if (!drm_add_configs_for_visuals(drv, disp)) {
  784       err = "DRI2: failed to add configs";
  785       goto cleanup;
  786    }
  787 
  788    disp->Extensions.KHR_image_pixmap = EGL_TRUE;
  789    if (dri2_dpy->dri2)
  790       disp->Extensions.EXT_buffer_age = EGL_TRUE;
  791 
  792 #ifdef HAVE_WAYLAND_PLATFORM
  793    dri2_dpy->device_name = loader_get_device_name_for_fd(dri2_dpy->fd);
  794 #endif
  795    dri2_set_WL_bind_wayland_display(drv, disp);
  796 
  797    /* Fill vtbl last to prevent accidentally calling virtual function during
  798     * initialization.
  799     */
  800    dri2_dpy->vtbl = &dri2_drm_display_vtbl;
  801 
  802    return EGL_TRUE;
  803 
  804 cleanup:
  805    dri2_display_destroy(disp);
  806    return _eglError(EGL_NOT_INITIALIZED, err);
  807 }
  808 
  809 void
  810 dri2_teardown_drm(struct dri2_egl_display *dri2_dpy)
  811 {
  812    if (dri2_dpy->own_device)
  813       gbm_device_destroy(&dri2_dpy->gbm_dri->base);
  814 }