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