Home | History | Annotate | Download | only in dri2
      1 /*
      2  * Copyright  2011-2012 Intel Corporation
      3  * Copyright  2012 Collabora, Ltd.
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a
      6  * copy of this software and associated documentation files (the "Software"),
      7  * to deal in the Software without restriction, including without limitation
      8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      9  * and/or sell copies of the Software, and to permit persons to whom the
     10  * Software is furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice and this permission notice (including the next
     13  * paragraph) shall be included in all copies or substantial portions of the
     14  * Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
     20  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     21  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     23  * DEALINGS IN THE SOFTWARE.
     24  *
     25  * Authors:
     26  *    Kristian Hgsberg <krh (at) bitplanet.net>
     27  *    Benjamin Franzke <benjaminfranzke (at) googlemail.com>
     28  */
     29 
     30 #include <stdint.h>
     31 #include <stdlib.h>
     32 #include <string.h>
     33 #include <limits.h>
     34 #include <dlfcn.h>
     35 #include <errno.h>
     36 #include <unistd.h>
     37 #include <fcntl.h>
     38 #include <xf86drm.h>
     39 #include <drm_fourcc.h>
     40 #include <sys/mman.h>
     41 
     42 #include "egl_dri2.h"
     43 #include "egl_dri2_fallbacks.h"
     44 #include "loader.h"
     45 #include "util/u_vector.h"
     46 #include "eglglobals.h"
     47 
     48 #include <wayland-client.h>
     49 #include "wayland-drm-client-protocol.h"
     50 #include "linux-dmabuf-unstable-v1-client-protocol.h"
     51 
     52 #ifndef DRM_FORMAT_MOD_INVALID
     53 #define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
     54 #endif
     55 
     56 #ifndef DRM_FORMAT_MOD_LINEAR
     57 #define DRM_FORMAT_MOD_LINEAR 0
     58 #endif
     59 
     60 enum wl_drm_format_flags {
     61    HAS_ARGB8888 = 1,
     62    HAS_XRGB8888 = 2,
     63    HAS_RGB565 = 4,
     64    HAS_ARGB2101010 = 8,
     65    HAS_XRGB2101010 = 16,
     66 };
     67 
     68 static int
     69 roundtrip(struct dri2_egl_display *dri2_dpy)
     70 {
     71    return wl_display_roundtrip_queue(dri2_dpy->wl_dpy, dri2_dpy->wl_queue);
     72 }
     73 
     74 static void
     75 wl_buffer_release(void *data, struct wl_buffer *buffer)
     76 {
     77    struct dri2_egl_surface *dri2_surf = data;
     78    int i;
     79 
     80    for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); ++i)
     81       if (dri2_surf->color_buffers[i].wl_buffer == buffer)
     82          break;
     83 
     84    if (i == ARRAY_SIZE(dri2_surf->color_buffers)) {
     85       wl_buffer_destroy(buffer);
     86       return;
     87    }
     88 
     89    dri2_surf->color_buffers[i].locked = false;
     90 }
     91 
     92 static const struct wl_buffer_listener wl_buffer_listener = {
     93    .release = wl_buffer_release
     94 };
     95 
     96 static void
     97 resize_callback(struct wl_egl_window *wl_win, void *data)
     98 {
     99    struct dri2_egl_surface *dri2_surf = data;
    100    struct dri2_egl_display *dri2_dpy =
    101       dri2_egl_display(dri2_surf->base.Resource.Display);
    102 
    103    dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);
    104 }
    105 
    106 static void
    107 destroy_window_callback(void *data)
    108 {
    109    struct dri2_egl_surface *dri2_surf = data;
    110    dri2_surf->wl_win = NULL;
    111 }
    112 
    113 static struct wl_surface *
    114 get_wl_surface_proxy(struct wl_egl_window *window)
    115 {
    116     /* Version 3 of wl_egl_window introduced a version field at the same
    117      * location where a pointer to wl_surface was stored. Thus, if
    118      * window->version is dereferencable, we've been given an older version of
    119      * wl_egl_window, and window->version points to wl_surface */
    120    if (_eglPointerIsDereferencable((void *)(window->version))) {
    121       return wl_proxy_create_wrapper((void *)(window->version));
    122    }
    123    return wl_proxy_create_wrapper(window->surface);
    124 }
    125 
    126 /**
    127  * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
    128  */
    129 static _EGLSurface *
    130 dri2_wl_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
    131                               _EGLConfig *conf, void *native_window,
    132                               const EGLint *attrib_list)
    133 {
    134    __DRIcreateNewDrawableFunc createNewDrawable;
    135    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
    136    struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
    137    struct wl_egl_window *window = native_window;
    138    struct dri2_egl_surface *dri2_surf;
    139    const __DRIconfig *config;
    140 
    141    dri2_surf = calloc(1, sizeof *dri2_surf);
    142    if (!dri2_surf) {
    143       _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
    144       return NULL;
    145    }
    146 
    147    if (!dri2_init_surface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf, attrib_list, false))
    148       goto cleanup_surf;
    149 
    150    if (dri2_dpy->wl_dmabuf || dri2_dpy->wl_drm) {
    151       if (conf->RedSize == 5)
    152          dri2_surf->format = WL_DRM_FORMAT_RGB565;
    153       else if (conf->RedSize == 8 && conf->AlphaSize == 0)
    154          dri2_surf->format = WL_DRM_FORMAT_XRGB8888;
    155       else if (conf->RedSize == 8)
    156          dri2_surf->format = WL_DRM_FORMAT_ARGB8888;
    157       else if (conf->RedSize == 10 && conf->AlphaSize == 0)
    158          dri2_surf->format = WL_DRM_FORMAT_XRGB2101010;
    159       else if (conf->RedSize == 10)
    160          dri2_surf->format = WL_DRM_FORMAT_ARGB2101010;
    161    } else {
    162       assert(dri2_dpy->wl_shm);
    163       if (conf->RedSize == 5)
    164          dri2_surf->format = WL_SHM_FORMAT_RGB565;
    165       else if (conf->RedSize == 8 && conf->AlphaSize == 0)
    166          dri2_surf->format = WL_SHM_FORMAT_XRGB8888;
    167       else if (conf->RedSize == 8)
    168          dri2_surf->format = WL_SHM_FORMAT_ARGB8888;
    169       else if (conf->RedSize == 10 && conf->AlphaSize == 0)
    170          dri2_surf->format = WL_SHM_FORMAT_XRGB2101010;
    171       else if (conf->RedSize == 10)
    172          dri2_surf->format = WL_SHM_FORMAT_ARGB2101010;
    173    }
    174 
    175    dri2_surf->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
    176    if (!dri2_surf->wl_queue) {
    177       _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
    178       goto cleanup_surf;
    179    }
    180 
    181    if (dri2_dpy->wl_drm) {
    182       dri2_surf->wl_drm_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_drm);
    183       if (!dri2_surf->wl_drm_wrapper) {
    184          _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
    185          goto cleanup_queue;
    186       }
    187       wl_proxy_set_queue((struct wl_proxy *)dri2_surf->wl_drm_wrapper,
    188                          dri2_surf->wl_queue);
    189    }
    190 
    191    dri2_surf->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy);
    192    if (!dri2_surf->wl_dpy_wrapper) {
    193       _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
    194       goto cleanup_drm;
    195    }
    196    wl_proxy_set_queue((struct wl_proxy *)dri2_surf->wl_dpy_wrapper,
    197                       dri2_surf->wl_queue);
    198 
    199    dri2_surf->wl_surface_wrapper = get_wl_surface_proxy(window);
    200    if (!dri2_surf->wl_surface_wrapper) {
    201       _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
    202       goto cleanup_dpy_wrapper;
    203    }
    204    wl_proxy_set_queue((struct wl_proxy *)dri2_surf->wl_surface_wrapper,
    205                       dri2_surf->wl_queue);
    206 
    207    dri2_surf->wl_win = window;
    208    dri2_surf->wl_win->private = dri2_surf;
    209    dri2_surf->wl_win->destroy_window_callback = destroy_window_callback;
    210    if (dri2_dpy->flush)
    211       dri2_surf->wl_win->resize_callback = resize_callback;
    212 
    213    config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT,
    214                                 dri2_surf->base.GLColorspace);
    215 
    216    if (dri2_dpy->image_driver)
    217       createNewDrawable = dri2_dpy->image_driver->createNewDrawable;
    218    else if (dri2_dpy->dri2)
    219       createNewDrawable = dri2_dpy->dri2->createNewDrawable;
    220    else
    221       createNewDrawable = dri2_dpy->swrast->createNewDrawable;
    222 
    223    dri2_surf->dri_drawable = (*createNewDrawable)(dri2_dpy->dri_screen, config,
    224                                                   dri2_surf);
    225     if (dri2_surf->dri_drawable == NULL) {
    226       _eglError(EGL_BAD_ALLOC, "createNewDrawable");
    227        goto cleanup_surf_wrapper;
    228     }
    229 
    230    dri2_surf->base.SwapInterval = dri2_dpy->default_swap_interval;
    231 
    232    return &dri2_surf->base;
    233 
    234  cleanup_surf_wrapper:
    235    wl_proxy_wrapper_destroy(dri2_surf->wl_surface_wrapper);
    236  cleanup_dpy_wrapper:
    237    wl_proxy_wrapper_destroy(dri2_surf->wl_dpy_wrapper);
    238  cleanup_drm:
    239    if (dri2_surf->wl_drm_wrapper)
    240       wl_proxy_wrapper_destroy(dri2_surf->wl_drm_wrapper);
    241  cleanup_queue:
    242    wl_event_queue_destroy(dri2_surf->wl_queue);
    243  cleanup_surf:
    244    free(dri2_surf);
    245 
    246    return NULL;
    247 }
    248 
    249 static _EGLSurface *
    250 dri2_wl_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,
    251                               _EGLConfig *conf, void *native_window,
    252                               const EGLint *attrib_list)
    253 {
    254    /* From the EGL_EXT_platform_wayland spec, version 3:
    255     *
    256     *   It is not valid to call eglCreatePlatformPixmapSurfaceEXT with a <dpy>
    257     *   that belongs to Wayland. Any such call fails and generates
    258     *   EGL_BAD_PARAMETER.
    259     */
    260    _eglError(EGL_BAD_PARAMETER, "cannot create EGL pixmap surfaces on "
    261              "Wayland");
    262    return NULL;
    263 }
    264 
    265 /**
    266  * Called via eglDestroySurface(), drv->API.DestroySurface().
    267  */
    268 static EGLBoolean
    269 dri2_wl_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
    270 {
    271    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
    272    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
    273 
    274    (void) drv;
    275 
    276    dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
    277 
    278    for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
    279       if (dri2_surf->color_buffers[i].wl_buffer)
    280          wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
    281       if (dri2_surf->color_buffers[i].dri_image)
    282          dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
    283       if (dri2_surf->color_buffers[i].linear_copy)
    284          dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy);
    285       if (dri2_surf->color_buffers[i].data)
    286          munmap(dri2_surf->color_buffers[i].data,
    287                 dri2_surf->color_buffers[i].data_size);
    288    }
    289 
    290    if (dri2_dpy->dri2)
    291       dri2_egl_surface_free_local_buffers(dri2_surf);
    292 
    293    if (dri2_surf->throttle_callback)
    294       wl_callback_destroy(dri2_surf->throttle_callback);
    295 
    296    if (dri2_surf->wl_win) {
    297       dri2_surf->wl_win->private = NULL;
    298       dri2_surf->wl_win->resize_callback = NULL;
    299       dri2_surf->wl_win->destroy_window_callback = NULL;
    300    }
    301 
    302    wl_proxy_wrapper_destroy(dri2_surf->wl_surface_wrapper);
    303    wl_proxy_wrapper_destroy(dri2_surf->wl_dpy_wrapper);
    304    if (dri2_surf->wl_drm_wrapper)
    305       wl_proxy_wrapper_destroy(dri2_surf->wl_drm_wrapper);
    306    wl_event_queue_destroy(dri2_surf->wl_queue);
    307 
    308    dri2_fini_surface(surf);
    309    free(surf);
    310 
    311    return EGL_TRUE;
    312 }
    313 
    314 static void
    315 dri2_wl_release_buffers(struct dri2_egl_surface *dri2_surf)
    316 {
    317    struct dri2_egl_display *dri2_dpy =
    318       dri2_egl_display(dri2_surf->base.Resource.Display);
    319 
    320    for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
    321       if (dri2_surf->color_buffers[i].wl_buffer &&
    322           !dri2_surf->color_buffers[i].locked)
    323          wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
    324       if (dri2_surf->color_buffers[i].dri_image)
    325          dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
    326       if (dri2_surf->color_buffers[i].linear_copy)
    327          dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy);
    328       if (dri2_surf->color_buffers[i].data)
    329          munmap(dri2_surf->color_buffers[i].data,
    330                 dri2_surf->color_buffers[i].data_size);
    331 
    332       dri2_surf->color_buffers[i].wl_buffer = NULL;
    333       dri2_surf->color_buffers[i].dri_image = NULL;
    334       dri2_surf->color_buffers[i].linear_copy = NULL;
    335       dri2_surf->color_buffers[i].data = NULL;
    336       dri2_surf->color_buffers[i].locked = false;
    337    }
    338 
    339    if (dri2_dpy->dri2)
    340       dri2_egl_surface_free_local_buffers(dri2_surf);
    341 }
    342 
    343 static int
    344 get_back_bo(struct dri2_egl_surface *dri2_surf)
    345 {
    346    struct dri2_egl_display *dri2_dpy =
    347       dri2_egl_display(dri2_surf->base.Resource.Display);
    348    int use_flags;
    349    unsigned int dri_image_format;
    350    uint64_t *modifiers;
    351    int num_modifiers;
    352 
    353    /* currently supports five WL DRM formats,
    354     * WL_DRM_FORMAT_ARGB2101010, WL_DRM_FORMAT_XRGB2101010,
    355     * WL_DRM_FORMAT_ARGB8888, WL_DRM_FORMAT_XRGB8888,
    356     * and WL_DRM_FORMAT_RGB565
    357     */
    358    switch (dri2_surf->format) {
    359    case WL_DRM_FORMAT_ARGB2101010:
    360       dri_image_format = __DRI_IMAGE_FORMAT_ARGB2101010;
    361       modifiers = u_vector_tail(&dri2_dpy->wl_modifiers.argb2101010);
    362       num_modifiers = u_vector_length(&dri2_dpy->wl_modifiers.argb2101010);
    363       break;
    364    case WL_DRM_FORMAT_XRGB2101010:
    365       dri_image_format = __DRI_IMAGE_FORMAT_XRGB2101010;
    366       modifiers = u_vector_tail(&dri2_dpy->wl_modifiers.xrgb2101010);
    367       num_modifiers = u_vector_length(&dri2_dpy->wl_modifiers.xrgb2101010);
    368       break;
    369    case WL_DRM_FORMAT_ARGB8888:
    370       dri_image_format = __DRI_IMAGE_FORMAT_ARGB8888;
    371       modifiers = u_vector_tail(&dri2_dpy->wl_modifiers.argb8888);
    372       num_modifiers = u_vector_length(&dri2_dpy->wl_modifiers.argb8888);
    373       break;
    374    case WL_DRM_FORMAT_XRGB8888:
    375       dri_image_format = __DRI_IMAGE_FORMAT_XRGB8888;
    376       modifiers = u_vector_tail(&dri2_dpy->wl_modifiers.xrgb8888);
    377       num_modifiers = u_vector_length(&dri2_dpy->wl_modifiers.xrgb8888);
    378       break;
    379    case WL_DRM_FORMAT_RGB565:
    380       dri_image_format = __DRI_IMAGE_FORMAT_RGB565;
    381       modifiers = u_vector_tail(&dri2_dpy->wl_modifiers.rgb565);
    382       num_modifiers = u_vector_length(&dri2_dpy->wl_modifiers.rgb565);
    383       break;
    384    default:
    385       /* format is not supported */
    386       return -1;
    387    }
    388 
    389    /* There might be a buffer release already queued that wasn't processed */
    390    wl_display_dispatch_queue_pending(dri2_dpy->wl_dpy, dri2_surf->wl_queue);
    391 
    392    while (dri2_surf->back == NULL) {
    393       for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
    394          /* Get an unlocked buffer, preferrably one with a dri_buffer
    395           * already allocated. */
    396          if (dri2_surf->color_buffers[i].locked)
    397             continue;
    398          if (dri2_surf->back == NULL)
    399             dri2_surf->back = &dri2_surf->color_buffers[i];
    400          else if (dri2_surf->back->dri_image == NULL)
    401             dri2_surf->back = &dri2_surf->color_buffers[i];
    402       }
    403 
    404       if (dri2_surf->back)
    405          break;
    406 
    407       /* If we don't have a buffer, then block on the server to release one for
    408        * us, and try again. wl_display_dispatch_queue will process any pending
    409        * events, however not all servers flush on issuing a buffer release
    410        * event. So, we spam the server with roundtrips as they always cause a
    411        * client flush.
    412        */
    413       if (wl_display_roundtrip_queue(dri2_dpy->wl_dpy,
    414                                      dri2_surf->wl_queue) < 0)
    415           return -1;
    416    }
    417 
    418    if (dri2_surf->back == NULL)
    419       return -1;
    420 
    421    use_flags = __DRI_IMAGE_USE_SHARE | __DRI_IMAGE_USE_BACKBUFFER;
    422 
    423    if (dri2_dpy->is_different_gpu &&
    424        dri2_surf->back->linear_copy == NULL) {
    425       /* The LINEAR modifier should be a perfect alias of the LINEAR use
    426        * flag; try the new interface first before the old, then fall back. */
    427       if (dri2_dpy->image->base.version >= 15 &&
    428            dri2_dpy->image->createImageWithModifiers) {
    429          uint64_t linear_mod = DRM_FORMAT_MOD_LINEAR;
    430 
    431          dri2_surf->back->linear_copy =
    432             dri2_dpy->image->createImageWithModifiers(dri2_dpy->dri_screen,
    433                                                       dri2_surf->base.Width,
    434                                                       dri2_surf->base.Height,
    435                                                       dri_image_format,
    436                                                       &linear_mod,
    437                                                       1,
    438                                                       NULL);
    439       } else {
    440          dri2_surf->back->linear_copy =
    441             dri2_dpy->image->createImage(dri2_dpy->dri_screen,
    442                                          dri2_surf->base.Width,
    443                                          dri2_surf->base.Height,
    444                                          dri_image_format,
    445                                          use_flags |
    446                                          __DRI_IMAGE_USE_LINEAR,
    447                                          NULL);
    448       }
    449       if (dri2_surf->back->linear_copy == NULL)
    450           return -1;
    451    }
    452 
    453    if (dri2_surf->back->dri_image == NULL) {
    454       /* If our DRIImage implementation does not support
    455        * createImageWithModifiers, then fall back to the old createImage,
    456        * and hope it allocates an image which is acceptable to the winsys.
    457         */
    458       if (num_modifiers && dri2_dpy->image->base.version >= 15 &&
    459           dri2_dpy->image->createImageWithModifiers) {
    460          dri2_surf->back->dri_image =
    461            dri2_dpy->image->createImageWithModifiers(dri2_dpy->dri_screen,
    462                                                      dri2_surf->base.Width,
    463                                                      dri2_surf->base.Height,
    464                                                      dri_image_format,
    465                                                      modifiers,
    466                                                      num_modifiers,
    467                                                      NULL);
    468       } else {
    469          dri2_surf->back->dri_image =
    470             dri2_dpy->image->createImage(dri2_dpy->dri_screen,
    471                                          dri2_surf->base.Width,
    472                                          dri2_surf->base.Height,
    473                                          dri_image_format,
    474                                          dri2_dpy->is_different_gpu ?
    475                                               0 : use_flags,
    476                                          NULL);
    477       }
    478 
    479       dri2_surf->back->age = 0;
    480    }
    481    if (dri2_surf->back->dri_image == NULL)
    482       return -1;
    483 
    484    dri2_surf->back->locked = true;
    485 
    486    return 0;
    487 }
    488 
    489 
    490 static void
    491 back_bo_to_dri_buffer(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer)
    492 {
    493    struct dri2_egl_display *dri2_dpy =
    494       dri2_egl_display(dri2_surf->base.Resource.Display);
    495    __DRIimage *image;
    496    int name, pitch;
    497 
    498    image = dri2_surf->back->dri_image;
    499 
    500    dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name);
    501    dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch);
    502 
    503    buffer->attachment = __DRI_BUFFER_BACK_LEFT;
    504    buffer->name = name;
    505    buffer->pitch = pitch;
    506    buffer->cpp = 4;
    507    buffer->flags = 0;
    508 }
    509 
    510 static int
    511 update_buffers(struct dri2_egl_surface *dri2_surf)
    512 {
    513    struct dri2_egl_display *dri2_dpy =
    514       dri2_egl_display(dri2_surf->base.Resource.Display);
    515 
    516    if (dri2_surf->base.Width != dri2_surf->wl_win->width ||
    517        dri2_surf->base.Height != dri2_surf->wl_win->height) {
    518 
    519       dri2_wl_release_buffers(dri2_surf);
    520 
    521       dri2_surf->base.Width  = dri2_surf->wl_win->width;
    522       dri2_surf->base.Height = dri2_surf->wl_win->height;
    523       dri2_surf->dx = dri2_surf->wl_win->dx;
    524       dri2_surf->dy = dri2_surf->wl_win->dy;
    525    }
    526 
    527    if (get_back_bo(dri2_surf) < 0) {
    528       _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer");
    529       return -1;
    530    }
    531 
    532    /* If we have an extra unlocked buffer at this point, we had to do triple
    533     * buffering for a while, but now can go back to just double buffering.
    534     * That means we can free any unlocked buffer now. */
    535    for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
    536       if (!dri2_surf->color_buffers[i].locked &&
    537           dri2_surf->color_buffers[i].wl_buffer) {
    538          wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
    539          dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
    540          if (dri2_dpy->is_different_gpu)
    541             dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy);
    542          dri2_surf->color_buffers[i].wl_buffer = NULL;
    543          dri2_surf->color_buffers[i].dri_image = NULL;
    544          dri2_surf->color_buffers[i].linear_copy = NULL;
    545       }
    546    }
    547 
    548    return 0;
    549 }
    550 
    551 static __DRIbuffer *
    552 dri2_wl_get_buffers_with_format(__DRIdrawable * driDrawable,
    553                                 int *width, int *height,
    554                                 unsigned int *attachments, int count,
    555                                 int *out_count, void *loaderPrivate)
    556 {
    557    struct dri2_egl_surface *dri2_surf = loaderPrivate;
    558    int i, j;
    559 
    560    if (update_buffers(dri2_surf) < 0)
    561       return NULL;
    562 
    563    for (i = 0, j = 0; i < 2 * count; i += 2, j++) {
    564       __DRIbuffer *local;
    565 
    566       switch (attachments[i]) {
    567       case __DRI_BUFFER_BACK_LEFT:
    568          back_bo_to_dri_buffer(dri2_surf, &dri2_surf->buffers[j]);
    569          break;
    570       default:
    571          local = dri2_egl_surface_alloc_local_buffer(dri2_surf, attachments[i],
    572                                                      attachments[i + 1]);
    573 
    574          if (!local) {
    575             _eglError(EGL_BAD_ALLOC, "failed to allocate local buffer");
    576             return NULL;
    577          }
    578          dri2_surf->buffers[j] = *local;
    579          break;
    580       }
    581    }
    582 
    583    *out_count = j;
    584    if (j == 0)
    585       return NULL;
    586 
    587    *width = dri2_surf->base.Width;
    588    *height = dri2_surf->base.Height;
    589 
    590    return dri2_surf->buffers;
    591 }
    592 
    593 static __DRIbuffer *
    594 dri2_wl_get_buffers(__DRIdrawable * driDrawable,
    595                     int *width, int *height,
    596                     unsigned int *attachments, int count,
    597                     int *out_count, void *loaderPrivate)
    598 {
    599    struct dri2_egl_surface *dri2_surf = loaderPrivate;
    600    unsigned int *attachments_with_format;
    601    __DRIbuffer *buffer;
    602    unsigned int bpp;
    603 
    604    switch (dri2_surf->format) {
    605    case WL_DRM_FORMAT_ARGB2101010:
    606    case WL_DRM_FORMAT_XRGB2101010:
    607    case WL_DRM_FORMAT_ARGB8888:
    608    case WL_DRM_FORMAT_XRGB8888:
    609       bpp = 32;
    610       break;
    611    case WL_DRM_FORMAT_RGB565:
    612       bpp = 16;
    613       break;
    614    default:
    615       /* format is not supported */
    616       return NULL;
    617    }
    618 
    619    attachments_with_format = calloc(count, 2 * sizeof(unsigned int));
    620    if (!attachments_with_format) {
    621       *out_count = 0;
    622       return NULL;
    623    }
    624 
    625    for (int i = 0; i < count; ++i) {
    626       attachments_with_format[2*i] = attachments[i];
    627       attachments_with_format[2*i + 1] = bpp;
    628    }
    629 
    630    buffer =
    631       dri2_wl_get_buffers_with_format(driDrawable,
    632                                       width, height,
    633                                       attachments_with_format, count,
    634                                       out_count, loaderPrivate);
    635 
    636    free(attachments_with_format);
    637 
    638    return buffer;
    639 }
    640 
    641 static int
    642 image_get_buffers(__DRIdrawable *driDrawable,
    643                   unsigned int format,
    644                   uint32_t *stamp,
    645                   void *loaderPrivate,
    646                   uint32_t buffer_mask,
    647                   struct __DRIimageList *buffers)
    648 {
    649    struct dri2_egl_surface *dri2_surf = loaderPrivate;
    650 
    651    if (update_buffers(dri2_surf) < 0)
    652       return 0;
    653 
    654    buffers->image_mask = __DRI_IMAGE_BUFFER_BACK;
    655    buffers->back = dri2_surf->back->dri_image;
    656 
    657    return 1;
    658 }
    659 
    660 static void
    661 dri2_wl_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
    662 {
    663    (void) driDrawable;
    664    (void) loaderPrivate;
    665 }
    666 
    667 static const __DRIdri2LoaderExtension dri2_loader_extension = {
    668    .base = { __DRI_DRI2_LOADER, 3 },
    669 
    670    .getBuffers           = dri2_wl_get_buffers,
    671    .flushFrontBuffer     = dri2_wl_flush_front_buffer,
    672    .getBuffersWithFormat = dri2_wl_get_buffers_with_format,
    673 };
    674 
    675 static const __DRIimageLoaderExtension image_loader_extension = {
    676    .base = { __DRI_IMAGE_LOADER, 1 },
    677 
    678    .getBuffers          = image_get_buffers,
    679    .flushFrontBuffer    = dri2_wl_flush_front_buffer,
    680 };
    681 
    682 static void
    683 wayland_throttle_callback(void *data,
    684                           struct wl_callback *callback,
    685                           uint32_t time)
    686 {
    687    struct dri2_egl_surface *dri2_surf = data;
    688 
    689    dri2_surf->throttle_callback = NULL;
    690    wl_callback_destroy(callback);
    691 }
    692 
    693 static const struct wl_callback_listener throttle_listener = {
    694    .done = wayland_throttle_callback
    695 };
    696 
    697 static EGLBoolean
    698 get_fourcc(struct dri2_egl_display *dri2_dpy,
    699            __DRIimage *image, int *fourcc)
    700 {
    701    EGLBoolean query;
    702    int dri_format;
    703 
    704    query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FOURCC,
    705                                        fourcc);
    706    if (query)
    707       return true;
    708 
    709    query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT,
    710                                        &dri_format);
    711    if (!query)
    712       return false;
    713 
    714    switch (dri_format) {
    715    case __DRI_IMAGE_FORMAT_ARGB8888:
    716       *fourcc = __DRI_IMAGE_FOURCC_ARGB8888;
    717       return true;
    718    case __DRI_IMAGE_FORMAT_XRGB8888:
    719       *fourcc = __DRI_IMAGE_FOURCC_XRGB8888;
    720       return true;
    721    default:
    722       return false;
    723    }
    724 }
    725 
    726 static struct wl_buffer *
    727 create_wl_buffer(struct dri2_egl_display *dri2_dpy,
    728                  struct dri2_egl_surface *dri2_surf,
    729                  __DRIimage *image)
    730 {
    731    struct wl_buffer *ret;
    732    EGLBoolean query;
    733    int width, height, fourcc, num_planes;
    734    uint64_t modifier = DRM_FORMAT_MOD_INVALID;
    735 
    736    query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_WIDTH, &width);
    737    query &= dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_HEIGHT,
    738                                         &height);
    739    query &= get_fourcc(dri2_dpy, image, &fourcc);
    740    if (!query)
    741       return NULL;
    742 
    743    query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NUM_PLANES,
    744                                        &num_planes);
    745    if (!query)
    746       num_planes = 1;
    747 
    748    if (dri2_dpy->image->base.version >= 15) {
    749       int mod_hi, mod_lo;
    750 
    751       query = dri2_dpy->image->queryImage(image,
    752                                           __DRI_IMAGE_ATTRIB_MODIFIER_UPPER,
    753                                           &mod_hi);
    754       query &= dri2_dpy->image->queryImage(image,
    755                                            __DRI_IMAGE_ATTRIB_MODIFIER_LOWER,
    756                                            &mod_lo);
    757       if (query) {
    758          modifier = (uint64_t) mod_hi << 32;
    759          modifier |= (uint64_t) (mod_lo & 0xffffffff);
    760       }
    761    }
    762 
    763    if (dri2_dpy->wl_dmabuf && modifier != DRM_FORMAT_MOD_INVALID) {
    764       struct zwp_linux_buffer_params_v1 *params;
    765       int i;
    766 
    767       /* We don't need a wrapper for wl_dmabuf objects, because we have to
    768        * create the intermediate params object; we can set the queue on this,
    769        * and the wl_buffer inherits it race-free. */
    770       params = zwp_linux_dmabuf_v1_create_params(dri2_dpy->wl_dmabuf);
    771       if (dri2_surf)
    772          wl_proxy_set_queue((struct wl_proxy *) params, dri2_surf->wl_queue);
    773 
    774       for (i = 0; i < num_planes; i++) {
    775          __DRIimage *p_image;
    776          int stride, offset;
    777          int fd = -1;
    778 
    779          if (i == 0)
    780             p_image = image;
    781          else
    782             p_image = dri2_dpy->image->fromPlanar(image, i, NULL);
    783          if (!p_image) {
    784             zwp_linux_buffer_params_v1_destroy(params);
    785             return NULL;
    786          }
    787 
    788          query = dri2_dpy->image->queryImage(p_image,
    789                                              __DRI_IMAGE_ATTRIB_FD,
    790                                              &fd);
    791          query &= dri2_dpy->image->queryImage(p_image,
    792                                               __DRI_IMAGE_ATTRIB_STRIDE,
    793                                               &stride);
    794          query &= dri2_dpy->image->queryImage(p_image,
    795                                               __DRI_IMAGE_ATTRIB_OFFSET,
    796                                               &offset);
    797          if (image != p_image)
    798             dri2_dpy->image->destroyImage(p_image);
    799 
    800          if (!query) {
    801             if (fd >= 0)
    802                close(fd);
    803             zwp_linux_buffer_params_v1_destroy(params);
    804             return NULL;
    805          }
    806 
    807          zwp_linux_buffer_params_v1_add(params, fd, i, offset, stride,
    808                                         modifier >> 32, modifier & 0xffffffff);
    809          close(fd);
    810       }
    811 
    812       ret = zwp_linux_buffer_params_v1_create_immed(params, width, height,
    813                                                     fourcc, 0);
    814       zwp_linux_buffer_params_v1_destroy(params);
    815    } else if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) {
    816       struct wl_drm *wl_drm =
    817          dri2_surf ? dri2_surf->wl_drm_wrapper : dri2_dpy->wl_drm;
    818       int fd, stride;
    819 
    820       if (num_planes > 1)
    821          return NULL;
    822 
    823       dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &fd);
    824       dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
    825       ret = wl_drm_create_prime_buffer(wl_drm, fd, width, height, fourcc, 0,
    826                                        stride, 0, 0, 0, 0);
    827       close(fd);
    828    } else {
    829       struct wl_drm *wl_drm =
    830          dri2_surf ? dri2_surf->wl_drm_wrapper : dri2_dpy->wl_drm;
    831       int name, stride;
    832 
    833       if (num_planes > 1)
    834          return NULL;
    835 
    836       dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name);
    837       dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
    838       ret = wl_drm_create_buffer(wl_drm, name, width, height, stride, fourcc);
    839    }
    840 
    841    return ret;
    842 }
    843 
    844 static EGLBoolean
    845 try_damage_buffer(struct dri2_egl_surface *dri2_surf,
    846                   const EGLint *rects,
    847                   EGLint n_rects)
    848 {
    849    if (wl_proxy_get_version((struct wl_proxy *) dri2_surf->wl_surface_wrapper)
    850        < WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION)
    851       return EGL_FALSE;
    852 
    853    for (int i = 0; i < n_rects; i++) {
    854       const int *rect = &rects[i * 4];
    855 
    856       wl_surface_damage_buffer(dri2_surf->wl_surface_wrapper,
    857                                rect[0],
    858                                dri2_surf->base.Height - rect[1] - rect[3],
    859                                rect[2], rect[3]);
    860    }
    861    return EGL_TRUE;
    862 }
    863 /**
    864  * Called via eglSwapBuffers(), drv->API.SwapBuffers().
    865  */
    866 static EGLBoolean
    867 dri2_wl_swap_buffers_with_damage(_EGLDriver *drv,
    868                                  _EGLDisplay *disp,
    869                                  _EGLSurface *draw,
    870                                  const EGLint *rects,
    871                                  EGLint n_rects)
    872 {
    873    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
    874    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
    875 
    876    while (dri2_surf->throttle_callback != NULL)
    877       if (wl_display_dispatch_queue(dri2_dpy->wl_dpy,
    878                                     dri2_surf->wl_queue) == -1)
    879          return -1;
    880 
    881    for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
    882       if (dri2_surf->color_buffers[i].age > 0)
    883          dri2_surf->color_buffers[i].age++;
    884 
    885    /* Make sure we have a back buffer in case we're swapping without ever
    886     * rendering. */
    887    if (get_back_bo(dri2_surf) < 0)
    888       return _eglError(EGL_BAD_ALLOC, "dri2_swap_buffers");
    889 
    890    if (draw->SwapInterval > 0) {
    891       dri2_surf->throttle_callback =
    892          wl_surface_frame(dri2_surf->wl_surface_wrapper);
    893       wl_callback_add_listener(dri2_surf->throttle_callback,
    894                                &throttle_listener, dri2_surf);
    895    }
    896 
    897    dri2_surf->back->age = 1;
    898    dri2_surf->current = dri2_surf->back;
    899    dri2_surf->back = NULL;
    900 
    901    if (!dri2_surf->current->wl_buffer) {
    902       __DRIimage *image;
    903 
    904       if (dri2_dpy->is_different_gpu)
    905          image = dri2_surf->current->linear_copy;
    906       else
    907          image = dri2_surf->current->dri_image;
    908 
    909       dri2_surf->current->wl_buffer =
    910          create_wl_buffer(dri2_dpy, dri2_surf, image);
    911 
    912       wl_buffer_add_listener(dri2_surf->current->wl_buffer,
    913                              &wl_buffer_listener, dri2_surf);
    914    }
    915 
    916    wl_surface_attach(dri2_surf->wl_surface_wrapper,
    917                      dri2_surf->current->wl_buffer,
    918                      dri2_surf->dx, dri2_surf->dy);
    919 
    920    dri2_surf->wl_win->attached_width  = dri2_surf->base.Width;
    921    dri2_surf->wl_win->attached_height = dri2_surf->base.Height;
    922    /* reset resize growing parameters */
    923    dri2_surf->dx = 0;
    924    dri2_surf->dy = 0;
    925 
    926    /* If the compositor doesn't support damage_buffer, we deliberately
    927     * ignore the damage region and post maximum damage, due to
    928     * https://bugs.freedesktop.org/78190 */
    929    if (!n_rects || !try_damage_buffer(dri2_surf, rects, n_rects))
    930       wl_surface_damage(dri2_surf->wl_surface_wrapper,
    931                         0, 0, INT32_MAX, INT32_MAX);
    932 
    933    if (dri2_dpy->is_different_gpu) {
    934       _EGLContext *ctx = _eglGetCurrentContext();
    935       struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
    936       dri2_dpy->image->blitImage(dri2_ctx->dri_context,
    937                                  dri2_surf->current->linear_copy,
    938                                  dri2_surf->current->dri_image,
    939                                  0, 0, dri2_surf->base.Width,
    940                                  dri2_surf->base.Height,
    941                                  0, 0, dri2_surf->base.Width,
    942                                  dri2_surf->base.Height, 0);
    943    }
    944 
    945    dri2_flush_drawable_for_swapbuffers(disp, draw);
    946    dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);
    947 
    948    wl_surface_commit(dri2_surf->wl_surface_wrapper);
    949 
    950    /* If we're not waiting for a frame callback then we'll at least throttle
    951     * to a sync callback so that we always give a chance for the compositor to
    952     * handle the commit and send a release event before checking for a free
    953     * buffer */
    954    if (dri2_surf->throttle_callback == NULL) {
    955       dri2_surf->throttle_callback = wl_display_sync(dri2_surf->wl_dpy_wrapper);
    956       wl_callback_add_listener(dri2_surf->throttle_callback,
    957                                &throttle_listener, dri2_surf);
    958    }
    959 
    960    wl_display_flush(dri2_dpy->wl_dpy);
    961 
    962    return EGL_TRUE;
    963 }
    964 
    965 static EGLint
    966 dri2_wl_query_buffer_age(_EGLDriver *drv,
    967                          _EGLDisplay *disp, _EGLSurface *surface)
    968 {
    969    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);
    970 
    971    if (get_back_bo(dri2_surf) < 0) {
    972       _eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age");
    973       return -1;
    974    }
    975 
    976    return dri2_surf->back->age;
    977 }
    978 
    979 static EGLBoolean
    980 dri2_wl_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
    981 {
    982    return dri2_wl_swap_buffers_with_damage(drv, disp, draw, NULL, 0);
    983 }
    984 
    985 static struct wl_buffer *
    986 dri2_wl_create_wayland_buffer_from_image(_EGLDriver *drv,
    987                                           _EGLDisplay *disp,
    988                                           _EGLImage *img)
    989 {
    990    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
    991    struct dri2_egl_image *dri2_img = dri2_egl_image(img);
    992    __DRIimage *image = dri2_img->dri_image;
    993    struct wl_buffer *buffer;
    994    int format;
    995 
    996    dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &format);
    997    switch (format) {
    998    case __DRI_IMAGE_FORMAT_ARGB2101010:
    999       if (!(dri2_dpy->formats & HAS_ARGB2101010))
   1000          goto bad_format;
   1001       break;
   1002    case __DRI_IMAGE_FORMAT_XRGB2101010:
   1003       if (!(dri2_dpy->formats & HAS_XRGB2101010))
   1004          goto bad_format;
   1005       break;
   1006    case __DRI_IMAGE_FORMAT_ARGB8888:
   1007       if (!(dri2_dpy->formats & HAS_ARGB8888))
   1008          goto bad_format;
   1009       break;
   1010    case __DRI_IMAGE_FORMAT_XRGB8888:
   1011       if (!(dri2_dpy->formats & HAS_XRGB8888))
   1012          goto bad_format;
   1013       break;
   1014    default:
   1015       goto bad_format;
   1016    }
   1017 
   1018    buffer = create_wl_buffer(dri2_dpy, NULL, image);
   1019 
   1020    /* The buffer object will have been created with our internal event queue
   1021     * because it is using wl_dmabuf/wl_drm as a proxy factory. We want the
   1022     * buffer to be used by the application so we'll reset it to the display's
   1023     * default event queue. This isn't actually racy, as the only event the
   1024     * buffer can get is a buffer release, which doesn't happen with an explicit
   1025     * attach. */
   1026    if (buffer)
   1027       wl_proxy_set_queue((struct wl_proxy *) buffer, NULL);
   1028 
   1029    return buffer;
   1030 
   1031 bad_format:
   1032    _eglError(EGL_BAD_MATCH, "unsupported image format");
   1033    return NULL;
   1034 }
   1035 
   1036 static int
   1037 dri2_wl_authenticate(_EGLDisplay *disp, uint32_t id)
   1038 {
   1039    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
   1040    int ret = 0;
   1041 
   1042    if (dri2_dpy->is_render_node) {
   1043       _eglLog(_EGL_WARNING, "wayland-egl: client asks server to "
   1044                             "authenticate for render-nodes");
   1045       return 0;
   1046    }
   1047    dri2_dpy->authenticated = false;
   1048 
   1049    wl_drm_authenticate(dri2_dpy->wl_drm, id);
   1050    if (roundtrip(dri2_dpy) < 0)
   1051       ret = -1;
   1052 
   1053    if (!dri2_dpy->authenticated)
   1054       ret = -1;
   1055 
   1056    /* reset authenticated */
   1057    dri2_dpy->authenticated = true;
   1058 
   1059    return ret;
   1060 }
   1061 
   1062 static void
   1063 drm_handle_device(void *data, struct wl_drm *drm, const char *device)
   1064 {
   1065    struct dri2_egl_display *dri2_dpy = data;
   1066    drm_magic_t magic;
   1067 
   1068    dri2_dpy->device_name = strdup(device);
   1069    if (!dri2_dpy->device_name)
   1070       return;
   1071 
   1072    dri2_dpy->fd = loader_open_device(dri2_dpy->device_name);
   1073    if (dri2_dpy->fd == -1) {
   1074       _eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)",
   1075               dri2_dpy->device_name, strerror(errno));
   1076       return;
   1077    }
   1078 
   1079    if (drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER) {
   1080       dri2_dpy->authenticated = true;
   1081    } else {
   1082       drmGetMagic(dri2_dpy->fd, &magic);
   1083       wl_drm_authenticate(dri2_dpy->wl_drm, magic);
   1084    }
   1085 }
   1086 
   1087 static void
   1088 drm_handle_format(void *data, struct wl_drm *drm, uint32_t format)
   1089 {
   1090    struct dri2_egl_display *dri2_dpy = data;
   1091 
   1092    switch (format) {
   1093    case WL_DRM_FORMAT_ARGB2101010:
   1094       dri2_dpy->formats |= HAS_ARGB2101010;
   1095       break;
   1096    case WL_DRM_FORMAT_XRGB2101010:
   1097       dri2_dpy->formats |= HAS_XRGB2101010;
   1098       break;
   1099    case WL_DRM_FORMAT_ARGB8888:
   1100       dri2_dpy->formats |= HAS_ARGB8888;
   1101       break;
   1102    case WL_DRM_FORMAT_XRGB8888:
   1103       dri2_dpy->formats |= HAS_XRGB8888;
   1104       break;
   1105    case WL_DRM_FORMAT_RGB565:
   1106       dri2_dpy->formats |= HAS_RGB565;
   1107       break;
   1108    }
   1109 }
   1110 
   1111 static void
   1112 drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t value)
   1113 {
   1114    struct dri2_egl_display *dri2_dpy = data;
   1115 
   1116    dri2_dpy->capabilities = value;
   1117 }
   1118 
   1119 static void
   1120 drm_handle_authenticated(void *data, struct wl_drm *drm)
   1121 {
   1122    struct dri2_egl_display *dri2_dpy = data;
   1123 
   1124    dri2_dpy->authenticated = true;
   1125 }
   1126 
   1127 static const struct wl_drm_listener drm_listener = {
   1128    .device = drm_handle_device,
   1129    .format = drm_handle_format,
   1130    .authenticated = drm_handle_authenticated,
   1131    .capabilities = drm_handle_capabilities
   1132 };
   1133 
   1134 static void
   1135 dmabuf_ignore_format(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
   1136                      uint32_t format)
   1137 {
   1138    /* formats are implicitly advertised by the 'modifier' event, so ignore */
   1139 }
   1140 
   1141 static void
   1142 dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
   1143                        uint32_t format, uint32_t modifier_hi,
   1144                        uint32_t modifier_lo)
   1145 {
   1146    struct dri2_egl_display *dri2_dpy = data;
   1147    uint64_t *mod = NULL;
   1148 
   1149    if (modifier_hi == (DRM_FORMAT_MOD_INVALID >> 32) &&
   1150        modifier_lo == (DRM_FORMAT_MOD_INVALID & 0xffffffff))
   1151       return;
   1152 
   1153    switch (format) {
   1154    case WL_DRM_FORMAT_ARGB2101010:
   1155       mod = u_vector_add(&dri2_dpy->wl_modifiers.argb2101010);
   1156       dri2_dpy->formats |= HAS_ARGB2101010;
   1157       break;
   1158    case WL_DRM_FORMAT_XRGB2101010:
   1159       mod = u_vector_add(&dri2_dpy->wl_modifiers.xrgb2101010);
   1160       dri2_dpy->formats |= HAS_XRGB2101010;
   1161       break;
   1162    case WL_DRM_FORMAT_ARGB8888:
   1163       mod = u_vector_add(&dri2_dpy->wl_modifiers.argb8888);
   1164       dri2_dpy->formats |= HAS_ARGB8888;
   1165       break;
   1166    case WL_DRM_FORMAT_XRGB8888:
   1167       mod = u_vector_add(&dri2_dpy->wl_modifiers.xrgb8888);
   1168       dri2_dpy->formats |= HAS_XRGB8888;
   1169       break;
   1170    case WL_DRM_FORMAT_RGB565:
   1171       mod = u_vector_add(&dri2_dpy->wl_modifiers.rgb565);
   1172       dri2_dpy->formats |= HAS_RGB565;
   1173       break;
   1174    default:
   1175       break;
   1176    }
   1177 
   1178    if (!mod)
   1179       return;
   1180 
   1181    *mod = (uint64_t) modifier_hi << 32;
   1182    *mod |= (uint64_t) (modifier_lo & 0xffffffff);
   1183 }
   1184 
   1185 static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = {
   1186    .format = dmabuf_ignore_format,
   1187    .modifier = dmabuf_handle_modifier,
   1188 };
   1189 
   1190 static void
   1191 registry_handle_global_drm(void *data, struct wl_registry *registry,
   1192                            uint32_t name, const char *interface,
   1193                            uint32_t version)
   1194 {
   1195    struct dri2_egl_display *dri2_dpy = data;
   1196 
   1197    if (strcmp(interface, "wl_drm") == 0) {
   1198       dri2_dpy->wl_drm =
   1199          wl_registry_bind(registry, name, &wl_drm_interface, MIN2(version, 2));
   1200       wl_drm_add_listener(dri2_dpy->wl_drm, &drm_listener, dri2_dpy);
   1201    } else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0 && version >= 3) {
   1202       dri2_dpy->wl_dmabuf =
   1203          wl_registry_bind(registry, name, &zwp_linux_dmabuf_v1_interface,
   1204                           MIN2(version, 3));
   1205       zwp_linux_dmabuf_v1_add_listener(dri2_dpy->wl_dmabuf, &dmabuf_listener,
   1206                                        dri2_dpy);
   1207    }
   1208 }
   1209 
   1210 static void
   1211 registry_handle_global_remove(void *data, struct wl_registry *registry,
   1212                               uint32_t name)
   1213 {
   1214 }
   1215 
   1216 static const struct wl_registry_listener registry_listener_drm = {
   1217    .global = registry_handle_global_drm,
   1218    .global_remove = registry_handle_global_remove
   1219 };
   1220 
   1221 static void
   1222 dri2_wl_setup_swap_interval(_EGLDisplay *disp)
   1223 {
   1224    /* We can't use values greater than 1 on Wayland because we are using the
   1225     * frame callback to synchronise the frame and the only way we be sure to
   1226     * get a frame callback is to attach a new buffer. Therefore we can't just
   1227     * sit drawing nothing to wait until the next n frame callbacks */
   1228 
   1229    dri2_setup_swap_interval(disp, 1);
   1230 }
   1231 
   1232 static const struct dri2_egl_display_vtbl dri2_wl_display_vtbl = {
   1233    .authenticate = dri2_wl_authenticate,
   1234    .create_window_surface = dri2_wl_create_window_surface,
   1235    .create_pixmap_surface = dri2_wl_create_pixmap_surface,
   1236    .create_pbuffer_surface = dri2_fallback_create_pbuffer_surface,
   1237    .destroy_surface = dri2_wl_destroy_surface,
   1238    .create_image = dri2_create_image_khr,
   1239    .swap_buffers = dri2_wl_swap_buffers,
   1240    .swap_buffers_with_damage = dri2_wl_swap_buffers_with_damage,
   1241    .swap_buffers_region = dri2_fallback_swap_buffers_region,
   1242    .set_damage_region = dri2_fallback_set_damage_region,
   1243    .post_sub_buffer = dri2_fallback_post_sub_buffer,
   1244    .copy_buffers = dri2_fallback_copy_buffers,
   1245    .query_buffer_age = dri2_wl_query_buffer_age,
   1246    .create_wayland_buffer_from_image = dri2_wl_create_wayland_buffer_from_image,
   1247    .get_sync_values = dri2_fallback_get_sync_values,
   1248    .get_dri_drawable = dri2_surface_get_dri_drawable,
   1249 };
   1250 
   1251 static const __DRIextension *dri2_loader_extensions[] = {
   1252    &dri2_loader_extension.base,
   1253    &image_loader_extension.base,
   1254    &image_lookup_extension.base,
   1255    &use_invalidate.base,
   1256    NULL,
   1257 };
   1258 
   1259 static const __DRIextension *image_loader_extensions[] = {
   1260    &image_loader_extension.base,
   1261    &image_lookup_extension.base,
   1262    &use_invalidate.base,
   1263    NULL,
   1264 };
   1265 
   1266 static EGLBoolean
   1267 dri2_wl_add_configs_for_visuals(_EGLDriver *drv, _EGLDisplay *disp)
   1268 {
   1269    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
   1270    static const struct {
   1271       const char *format_name;
   1272       int has_format;
   1273       unsigned int rgba_masks[4];
   1274    } visuals[] = {
   1275       { "XRGB2101010", HAS_XRGB2101010, { 0x3ff00000, 0xffc00, 0x3ff, 0 } },
   1276       { "ARGB2101010", HAS_ARGB2101010, { 0x3ff00000, 0xffc00, 0x3ff, 0xc0000000 } },
   1277       { "XRGB8888", HAS_XRGB8888, { 0xff0000, 0xff00, 0x00ff, 0 } },
   1278       { "ARGB8888", HAS_ARGB8888, { 0xff0000, 0xff00, 0x00ff, 0xff000000 } },
   1279       { "RGB565",   HAS_RGB565,   { 0x00f800, 0x07e0, 0x001f, 0 } },
   1280    };
   1281    unsigned int format_count[ARRAY_SIZE(visuals)] = { 0 };
   1282    unsigned int count = 0;
   1283 
   1284    for (unsigned i = 0; dri2_dpy->driver_configs[i]; i++) {
   1285       for (unsigned j = 0; j < ARRAY_SIZE(visuals); j++) {
   1286          struct dri2_egl_config *dri2_conf;
   1287 
   1288          if (!(dri2_dpy->formats & visuals[j].has_format))
   1289             continue;
   1290 
   1291          dri2_conf = dri2_add_config(disp, dri2_dpy->driver_configs[i],
   1292                count + 1, EGL_WINDOW_BIT, NULL, visuals[j].rgba_masks);
   1293          if (dri2_conf) {
   1294             if (dri2_conf->base.ConfigID == count + 1)
   1295                count++;
   1296             format_count[j]++;
   1297          }
   1298       }
   1299    }
   1300 
   1301    for (unsigned i = 0; i < ARRAY_SIZE(format_count); i++) {
   1302       if (!format_count[i]) {
   1303          _eglLog(_EGL_DEBUG, "No DRI config supports native format %s",
   1304                  visuals[i].format_name);
   1305       }
   1306    }
   1307 
   1308    return (count != 0);
   1309 }
   1310 
   1311 static EGLBoolean
   1312 dri2_initialize_wayland_drm(_EGLDriver *drv, _EGLDisplay *disp)
   1313 {
   1314    struct dri2_egl_display *dri2_dpy;
   1315 
   1316    loader_set_logger(_eglLog);
   1317 
   1318    dri2_dpy = calloc(1, sizeof *dri2_dpy);
   1319    if (!dri2_dpy)
   1320       return _eglError(EGL_BAD_ALLOC, "eglInitialize");
   1321 
   1322    dri2_dpy->fd = -1;
   1323    disp->DriverData = (void *) dri2_dpy;
   1324    if (disp->PlatformDisplay == NULL) {
   1325       dri2_dpy->wl_dpy = wl_display_connect(NULL);
   1326       if (dri2_dpy->wl_dpy == NULL)
   1327          goto cleanup;
   1328       dri2_dpy->own_device = true;
   1329    } else {
   1330       dri2_dpy->wl_dpy = disp->PlatformDisplay;
   1331    }
   1332 
   1333    if (!u_vector_init(&dri2_dpy->wl_modifiers.xrgb2101010, sizeof(uint64_t), 32) ||
   1334        !u_vector_init(&dri2_dpy->wl_modifiers.argb2101010, sizeof(uint64_t), 32) ||
   1335        !u_vector_init(&dri2_dpy->wl_modifiers.xrgb8888, sizeof(uint64_t), 32) ||
   1336        !u_vector_init(&dri2_dpy->wl_modifiers.argb8888, sizeof(uint64_t), 32) ||
   1337        !u_vector_init(&dri2_dpy->wl_modifiers.rgb565, sizeof(uint64_t), 32)) {
   1338       goto cleanup;
   1339    }
   1340 
   1341    dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
   1342 
   1343    dri2_dpy->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy);
   1344    if (dri2_dpy->wl_dpy_wrapper == NULL)
   1345       goto cleanup;
   1346 
   1347    wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_dpy_wrapper,
   1348                       dri2_dpy->wl_queue);
   1349 
   1350    if (dri2_dpy->own_device)
   1351       wl_display_dispatch_pending(dri2_dpy->wl_dpy);
   1352 
   1353    dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy_wrapper);
   1354    wl_registry_add_listener(dri2_dpy->wl_registry,
   1355                             &registry_listener_drm, dri2_dpy);
   1356    if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_drm == NULL)
   1357       goto cleanup;
   1358 
   1359    if (roundtrip(dri2_dpy) < 0 || dri2_dpy->fd == -1)
   1360       goto cleanup;
   1361 
   1362    if (roundtrip(dri2_dpy) < 0 || !dri2_dpy->authenticated)
   1363       goto cleanup;
   1364 
   1365    dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd,
   1366                                                &dri2_dpy->is_different_gpu);
   1367    if (dri2_dpy->is_different_gpu) {
   1368       free(dri2_dpy->device_name);
   1369       dri2_dpy->device_name = loader_get_device_name_for_fd(dri2_dpy->fd);
   1370       if (!dri2_dpy->device_name) {
   1371          _eglError(EGL_BAD_ALLOC, "wayland-egl: failed to get device name "
   1372                                   "for requested GPU");
   1373          goto cleanup;
   1374       }
   1375    }
   1376 
   1377    /* we have to do the check now, because loader_get_user_preferred_fd
   1378     * will return a render-node when the requested gpu is different
   1379     * to the server, but also if the client asks for the same gpu than
   1380     * the server by requesting its pci-id */
   1381    dri2_dpy->is_render_node = drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER;
   1382 
   1383    dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd);
   1384    if (dri2_dpy->driver_name == NULL) {
   1385       _eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name");
   1386       goto cleanup;
   1387    }
   1388 
   1389    /* render nodes cannot use Gem names, and thus do not support
   1390     * the __DRI_DRI2_LOADER extension */
   1391    if (!dri2_dpy->is_render_node) {
   1392       dri2_dpy->loader_extensions = dri2_loader_extensions;
   1393       if (!dri2_load_driver(disp)) {
   1394          _eglError(EGL_BAD_ALLOC, "DRI2: failed to load driver");
   1395          goto cleanup;
   1396       }
   1397    } else {
   1398       dri2_dpy->loader_extensions = image_loader_extensions;
   1399       if (!dri2_load_driver_dri3(disp)) {
   1400          _eglError(EGL_BAD_ALLOC, "DRI3: failed to load driver");
   1401          goto cleanup;
   1402       }
   1403    }
   1404 
   1405    if (!dri2_create_screen(disp))
   1406       goto cleanup;
   1407 
   1408    if (!dri2_setup_extensions(disp))
   1409       goto cleanup;
   1410 
   1411    dri2_setup_screen(disp);
   1412 
   1413    dri2_wl_setup_swap_interval(disp);
   1414 
   1415    /* To use Prime, we must have _DRI_IMAGE v7 at least.
   1416     * createImageFromFds support indicates that Prime export/import
   1417     * is supported by the driver. Fall back to
   1418     * gem names if we don't have Prime support. */
   1419 
   1420    if (dri2_dpy->image->base.version < 7 ||
   1421        dri2_dpy->image->createImageFromFds == NULL)
   1422       dri2_dpy->capabilities &= ~WL_DRM_CAPABILITY_PRIME;
   1423 
   1424    /* We cannot use Gem names with render-nodes, only prime fds (dma-buf).
   1425     * The server needs to accept them */
   1426    if (dri2_dpy->is_render_node &&
   1427        !(dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME)) {
   1428       _eglLog(_EGL_WARNING, "wayland-egl: display is not render-node capable");
   1429       goto cleanup;
   1430    }
   1431 
   1432    if (dri2_dpy->is_different_gpu &&
   1433        (dri2_dpy->image->base.version < 9 ||
   1434         dri2_dpy->image->blitImage == NULL)) {
   1435       _eglLog(_EGL_WARNING, "wayland-egl: Different GPU selected, but the "
   1436                             "Image extension in the driver is not "
   1437                             "compatible. Version 9 or later and blitImage() "
   1438                             "are required");
   1439       goto cleanup;
   1440    }
   1441 
   1442    if (!dri2_wl_add_configs_for_visuals(drv, disp)) {
   1443       _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to add configs");
   1444       goto cleanup;
   1445    }
   1446 
   1447    dri2_set_WL_bind_wayland_display(drv, disp);
   1448    /* When cannot convert EGLImage to wl_buffer when on a different gpu,
   1449     * because the buffer of the EGLImage has likely a tiling mode the server
   1450     * gpu won't support. These is no way to check for now. Thus do not support the
   1451     * extension */
   1452    if (!dri2_dpy->is_different_gpu)
   1453       disp->Extensions.WL_create_wayland_buffer_from_image = EGL_TRUE;
   1454 
   1455    disp->Extensions.EXT_buffer_age = EGL_TRUE;
   1456 
   1457    disp->Extensions.EXT_swap_buffers_with_damage = EGL_TRUE;
   1458 
   1459    /* Fill vtbl last to prevent accidentally calling virtual function during
   1460     * initialization.
   1461     */
   1462    dri2_dpy->vtbl = &dri2_wl_display_vtbl;
   1463 
   1464    return EGL_TRUE;
   1465 
   1466  cleanup:
   1467    dri2_display_destroy(disp);
   1468    return EGL_FALSE;
   1469 }
   1470 
   1471 static int
   1472 dri2_wl_swrast_get_stride_for_format(int format, int w)
   1473 {
   1474    if (format == WL_SHM_FORMAT_RGB565)
   1475       return 2 * w;
   1476    else /* ARGB8888 || XRGB8888 || ARGB2101010 || XRGB2101010 */
   1477       return 4 * w;
   1478 }
   1479 
   1480 /*
   1481  * Taken from weston shared/os-compatibility.c
   1482  */
   1483 
   1484 #ifndef HAVE_MKOSTEMP
   1485 
   1486 static int
   1487 set_cloexec_or_close(int fd)
   1488 {
   1489    long flags;
   1490 
   1491    if (fd == -1)
   1492       return -1;
   1493 
   1494    flags = fcntl(fd, F_GETFD);
   1495    if (flags == -1)
   1496       goto err;
   1497 
   1498    if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
   1499       goto err;
   1500 
   1501    return fd;
   1502 
   1503 err:
   1504    close(fd);
   1505    return -1;
   1506 }
   1507 
   1508 #endif
   1509 
   1510 /*
   1511  * Taken from weston shared/os-compatibility.c
   1512  */
   1513 
   1514 static int
   1515 create_tmpfile_cloexec(char *tmpname)
   1516 {
   1517    int fd;
   1518 
   1519 #ifdef HAVE_MKOSTEMP
   1520    fd = mkostemp(tmpname, O_CLOEXEC);
   1521    if (fd >= 0)
   1522       unlink(tmpname);
   1523 #else
   1524    fd = mkstemp(tmpname);
   1525    if (fd >= 0) {
   1526       fd = set_cloexec_or_close(fd);
   1527       unlink(tmpname);
   1528    }
   1529 #endif
   1530 
   1531    return fd;
   1532 }
   1533 
   1534 /*
   1535  * Taken from weston shared/os-compatibility.c
   1536  *
   1537  * Create a new, unique, anonymous file of the given size, and
   1538  * return the file descriptor for it. The file descriptor is set
   1539  * CLOEXEC. The file is immediately suitable for mmap()'ing
   1540  * the given size at offset zero.
   1541  *
   1542  * The file should not have a permanent backing store like a disk,
   1543  * but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
   1544  *
   1545  * The file name is deleted from the file system.
   1546  *
   1547  * The file is suitable for buffer sharing between processes by
   1548  * transmitting the file descriptor over Unix sockets using the
   1549  * SCM_RIGHTS methods.
   1550  *
   1551  * If the C library implements posix_fallocate(), it is used to
   1552  * guarantee that disk space is available for the file at the
   1553  * given size. If disk space is insufficent, errno is set to ENOSPC.
   1554  * If posix_fallocate() is not supported, program may receive
   1555  * SIGBUS on accessing mmap()'ed file contents instead.
   1556  */
   1557 static int
   1558 os_create_anonymous_file(off_t size)
   1559 {
   1560    static const char templ[] = "/mesa-shared-XXXXXX";
   1561    const char *path;
   1562    char *name;
   1563    int fd;
   1564    int ret;
   1565 
   1566    path = getenv("XDG_RUNTIME_DIR");
   1567    if (!path) {
   1568       errno = ENOENT;
   1569       return -1;
   1570    }
   1571 
   1572    name = malloc(strlen(path) + sizeof(templ));
   1573    if (!name)
   1574       return -1;
   1575 
   1576    strcpy(name, path);
   1577    strcat(name, templ);
   1578 
   1579    fd = create_tmpfile_cloexec(name);
   1580 
   1581    free(name);
   1582 
   1583    if (fd < 0)
   1584       return -1;
   1585 
   1586    ret = ftruncate(fd, size);
   1587    if (ret < 0) {
   1588       close(fd);
   1589       return -1;
   1590    }
   1591 
   1592    return fd;
   1593 }
   1594 
   1595 
   1596 static EGLBoolean
   1597 dri2_wl_swrast_allocate_buffer(struct dri2_egl_surface *dri2_surf,
   1598                                int format, int w, int h,
   1599                                void **data, int *size,
   1600                                struct wl_buffer **buffer)
   1601 {
   1602    struct dri2_egl_display *dri2_dpy =
   1603       dri2_egl_display(dri2_surf->base.Resource.Display);
   1604    struct wl_shm_pool *pool;
   1605    int fd, stride, size_map;
   1606    void *data_map;
   1607 
   1608    stride = dri2_wl_swrast_get_stride_for_format(format, w);
   1609    size_map = h * stride;
   1610 
   1611    /* Create a sharable buffer */
   1612    fd = os_create_anonymous_file(size_map);
   1613    if (fd < 0)
   1614       return EGL_FALSE;
   1615 
   1616    data_map = mmap(NULL, size_map, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
   1617    if (data_map == MAP_FAILED) {
   1618       close(fd);
   1619       return EGL_FALSE;
   1620    }
   1621 
   1622    /* Share it in a wl_buffer */
   1623    pool = wl_shm_create_pool(dri2_dpy->wl_shm, fd, size_map);
   1624    wl_proxy_set_queue((struct wl_proxy *)pool, dri2_surf->wl_queue);
   1625    *buffer = wl_shm_pool_create_buffer(pool, 0, w, h, stride, format);
   1626    wl_shm_pool_destroy(pool);
   1627    close(fd);
   1628 
   1629    *data = data_map;
   1630    *size = size_map;
   1631    return EGL_TRUE;
   1632 }
   1633 
   1634 static int
   1635 swrast_update_buffers(struct dri2_egl_surface *dri2_surf)
   1636 {
   1637    struct dri2_egl_display *dri2_dpy =
   1638       dri2_egl_display(dri2_surf->base.Resource.Display);
   1639 
   1640    /* we need to do the following operations only once per frame */
   1641    if (dri2_surf->back)
   1642       return 0;
   1643 
   1644    if (dri2_surf->base.Width != dri2_surf->wl_win->width ||
   1645        dri2_surf->base.Height != dri2_surf->wl_win->height) {
   1646 
   1647       dri2_wl_release_buffers(dri2_surf);
   1648 
   1649       dri2_surf->base.Width  = dri2_surf->wl_win->width;
   1650       dri2_surf->base.Height = dri2_surf->wl_win->height;
   1651       dri2_surf->dx = dri2_surf->wl_win->dx;
   1652       dri2_surf->dy = dri2_surf->wl_win->dy;
   1653       dri2_surf->current = NULL;
   1654    }
   1655 
   1656    /* find back buffer */
   1657 
   1658    /* There might be a buffer release already queued that wasn't processed */
   1659    wl_display_dispatch_queue_pending(dri2_dpy->wl_dpy, dri2_surf->wl_queue);
   1660 
   1661    /* try get free buffer already created */
   1662    for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
   1663       if (!dri2_surf->color_buffers[i].locked &&
   1664           dri2_surf->color_buffers[i].wl_buffer) {
   1665           dri2_surf->back = &dri2_surf->color_buffers[i];
   1666           break;
   1667       }
   1668    }
   1669 
   1670    /* else choose any another free location */
   1671    if (!dri2_surf->back) {
   1672       for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
   1673          if (!dri2_surf->color_buffers[i].locked) {
   1674              dri2_surf->back = &dri2_surf->color_buffers[i];
   1675              if (!dri2_wl_swrast_allocate_buffer(dri2_surf,
   1676                                                  dri2_surf->format,
   1677                                                  dri2_surf->base.Width,
   1678                                                  dri2_surf->base.Height,
   1679                                                  &dri2_surf->back->data,
   1680                                                  &dri2_surf->back->data_size,
   1681                                                  &dri2_surf->back->wl_buffer)) {
   1682                 _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer");
   1683                  return -1;
   1684              }
   1685              wl_buffer_add_listener(dri2_surf->back->wl_buffer,
   1686                                     &wl_buffer_listener, dri2_surf);
   1687              break;
   1688          }
   1689       }
   1690    }
   1691 
   1692    if (!dri2_surf->back) {
   1693       _eglError(EGL_BAD_ALLOC, "failed to find free buffer");
   1694       return -1;
   1695    }
   1696 
   1697    dri2_surf->back->locked = true;
   1698 
   1699    /* If we have an extra unlocked buffer at this point, we had to do triple
   1700     * buffering for a while, but now can go back to just double buffering.
   1701     * That means we can free any unlocked buffer now. */
   1702    for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
   1703       if (!dri2_surf->color_buffers[i].locked &&
   1704           dri2_surf->color_buffers[i].wl_buffer) {
   1705          wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
   1706          munmap(dri2_surf->color_buffers[i].data,
   1707                 dri2_surf->color_buffers[i].data_size);
   1708          dri2_surf->color_buffers[i].wl_buffer = NULL;
   1709          dri2_surf->color_buffers[i].data = NULL;
   1710       }
   1711    }
   1712 
   1713    return 0;
   1714 }
   1715 
   1716 static void*
   1717 dri2_wl_swrast_get_frontbuffer_data(struct dri2_egl_surface *dri2_surf)
   1718 {
   1719    /* if there has been a resize: */
   1720    if (!dri2_surf->current)
   1721       return NULL;
   1722 
   1723    return dri2_surf->current->data;
   1724 }
   1725 
   1726 static void*
   1727 dri2_wl_swrast_get_backbuffer_data(struct dri2_egl_surface *dri2_surf)
   1728 {
   1729    assert(dri2_surf->back);
   1730    return dri2_surf->back->data;
   1731 }
   1732 
   1733 static void
   1734 dri2_wl_swrast_commit_backbuffer(struct dri2_egl_surface *dri2_surf)
   1735 {
   1736    struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);
   1737 
   1738    while (dri2_surf->throttle_callback != NULL)
   1739       if (wl_display_dispatch_queue(dri2_dpy->wl_dpy,
   1740                                     dri2_surf->wl_queue) == -1)
   1741          return;
   1742 
   1743    if (dri2_surf->base.SwapInterval > 0) {
   1744       dri2_surf->throttle_callback =
   1745          wl_surface_frame(dri2_surf->wl_surface_wrapper);
   1746       wl_callback_add_listener(dri2_surf->throttle_callback,
   1747                                &throttle_listener, dri2_surf);
   1748    }
   1749 
   1750    dri2_surf->current = dri2_surf->back;
   1751    dri2_surf->back = NULL;
   1752 
   1753    wl_surface_attach(dri2_surf->wl_surface_wrapper,
   1754                      dri2_surf->current->wl_buffer,
   1755                      dri2_surf->dx, dri2_surf->dy);
   1756 
   1757    dri2_surf->wl_win->attached_width  = dri2_surf->base.Width;
   1758    dri2_surf->wl_win->attached_height = dri2_surf->base.Height;
   1759    /* reset resize growing parameters */
   1760    dri2_surf->dx = 0;
   1761    dri2_surf->dy = 0;
   1762 
   1763    wl_surface_damage(dri2_surf->wl_surface_wrapper,
   1764                      0, 0, INT32_MAX, INT32_MAX);
   1765    wl_surface_commit(dri2_surf->wl_surface_wrapper);
   1766 
   1767    /* If we're not waiting for a frame callback then we'll at least throttle
   1768     * to a sync callback so that we always give a chance for the compositor to
   1769     * handle the commit and send a release event before checking for a free
   1770     * buffer */
   1771    if (dri2_surf->throttle_callback == NULL) {
   1772       dri2_surf->throttle_callback = wl_display_sync(dri2_surf->wl_dpy_wrapper);
   1773       wl_callback_add_listener(dri2_surf->throttle_callback,
   1774                                &throttle_listener, dri2_surf);
   1775    }
   1776 
   1777    wl_display_flush(dri2_dpy->wl_dpy);
   1778 }
   1779 
   1780 static void
   1781 dri2_wl_swrast_get_drawable_info(__DRIdrawable * draw,
   1782                                  int *x, int *y, int *w, int *h,
   1783                                  void *loaderPrivate)
   1784 {
   1785    struct dri2_egl_surface *dri2_surf = loaderPrivate;
   1786 
   1787    (void) swrast_update_buffers(dri2_surf);
   1788    *x = 0;
   1789    *y = 0;
   1790    *w = dri2_surf->base.Width;
   1791    *h = dri2_surf->base.Height;
   1792 }
   1793 
   1794 static void
   1795 dri2_wl_swrast_get_image(__DRIdrawable * read,
   1796                          int x, int y, int w, int h,
   1797                          char *data, void *loaderPrivate)
   1798 {
   1799    struct dri2_egl_surface *dri2_surf = loaderPrivate;
   1800    int copy_width = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w);
   1801    int x_offset = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, x);
   1802    int src_stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, dri2_surf->base.Width);
   1803    int dst_stride = copy_width;
   1804    char *src, *dst;
   1805 
   1806    src = dri2_wl_swrast_get_frontbuffer_data(dri2_surf);
   1807    if (!src) {
   1808       memset(data, 0, copy_width * h);
   1809       return;
   1810    }
   1811 
   1812    assert(data != src);
   1813    assert(copy_width <= src_stride);
   1814 
   1815    src += x_offset;
   1816    src += y * src_stride;
   1817    dst = data;
   1818 
   1819    if (copy_width > src_stride-x_offset)
   1820       copy_width = src_stride-x_offset;
   1821    if (h > dri2_surf->base.Height-y)
   1822       h = dri2_surf->base.Height-y;
   1823 
   1824    for (; h>0; h--) {
   1825       memcpy(dst, src, copy_width);
   1826       src += src_stride;
   1827       dst += dst_stride;
   1828    }
   1829 }
   1830 
   1831 static void
   1832 dri2_wl_swrast_put_image2(__DRIdrawable * draw, int op,
   1833                          int x, int y, int w, int h, int stride,
   1834                          char *data, void *loaderPrivate)
   1835 {
   1836    struct dri2_egl_surface *dri2_surf = loaderPrivate;
   1837    int copy_width = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w);
   1838    int dst_stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, dri2_surf->base.Width);
   1839    int x_offset = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, x);
   1840    char *src, *dst;
   1841 
   1842    assert(copy_width <= stride);
   1843 
   1844    (void) swrast_update_buffers(dri2_surf);
   1845    dst = dri2_wl_swrast_get_backbuffer_data(dri2_surf);
   1846 
   1847    /* partial copy, copy old content */
   1848    if (copy_width < dst_stride)
   1849       dri2_wl_swrast_get_image(draw, 0, 0,
   1850                                dri2_surf->base.Width, dri2_surf->base.Height,
   1851                                dst, loaderPrivate);
   1852 
   1853    dst += x_offset;
   1854    dst += y * dst_stride;
   1855 
   1856    src = data;
   1857 
   1858    /* drivers expect we do these checks (and some rely on it) */
   1859    if (copy_width > dst_stride-x_offset)
   1860       copy_width = dst_stride-x_offset;
   1861    if (h > dri2_surf->base.Height-y)
   1862       h = dri2_surf->base.Height-y;
   1863 
   1864    for (; h>0; h--) {
   1865       memcpy(dst, src, copy_width);
   1866       src += stride;
   1867       dst += dst_stride;
   1868    }
   1869    dri2_wl_swrast_commit_backbuffer(dri2_surf);
   1870 }
   1871 
   1872 static void
   1873 dri2_wl_swrast_put_image(__DRIdrawable * draw, int op,
   1874                          int x, int y, int w, int h,
   1875                          char *data, void *loaderPrivate)
   1876 {
   1877    struct dri2_egl_surface *dri2_surf = loaderPrivate;
   1878    int stride;
   1879 
   1880    stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w);
   1881    dri2_wl_swrast_put_image2(draw, op, x, y, w, h,
   1882                              stride, data, loaderPrivate);
   1883 }
   1884 
   1885 static EGLBoolean
   1886 dri2_wl_swrast_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
   1887 {
   1888    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
   1889    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
   1890 
   1891    dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable);
   1892    return EGL_TRUE;
   1893 }
   1894 
   1895 static void
   1896 shm_handle_format(void *data, struct wl_shm *shm, uint32_t format)
   1897 {
   1898    struct dri2_egl_display *dri2_dpy = data;
   1899 
   1900    switch (format) {
   1901    case WL_SHM_FORMAT_ARGB2101010:
   1902       dri2_dpy->formats |= HAS_ARGB2101010;
   1903       break;
   1904    case WL_SHM_FORMAT_XRGB2101010:
   1905       dri2_dpy->formats |= HAS_XRGB2101010;
   1906       break;
   1907    case WL_SHM_FORMAT_ARGB8888:
   1908       dri2_dpy->formats |= HAS_ARGB8888;
   1909       break;
   1910    case WL_SHM_FORMAT_XRGB8888:
   1911       dri2_dpy->formats |= HAS_XRGB8888;
   1912       break;
   1913    case WL_SHM_FORMAT_RGB565:
   1914       dri2_dpy->formats |= HAS_RGB565;
   1915       break;
   1916    }
   1917 }
   1918 
   1919 static const struct wl_shm_listener shm_listener = {
   1920    .format = shm_handle_format
   1921 };
   1922 
   1923 static void
   1924 registry_handle_global_swrast(void *data, struct wl_registry *registry,
   1925                               uint32_t name, const char *interface,
   1926                               uint32_t version)
   1927 {
   1928    struct dri2_egl_display *dri2_dpy = data;
   1929 
   1930    if (strcmp(interface, "wl_shm") == 0) {
   1931       dri2_dpy->wl_shm =
   1932          wl_registry_bind(registry, name, &wl_shm_interface, 1);
   1933       wl_shm_add_listener(dri2_dpy->wl_shm, &shm_listener, dri2_dpy);
   1934    }
   1935 }
   1936 
   1937 static const struct wl_registry_listener registry_listener_swrast = {
   1938    .global = registry_handle_global_swrast,
   1939    .global_remove = registry_handle_global_remove
   1940 };
   1941 
   1942 static const struct dri2_egl_display_vtbl dri2_wl_swrast_display_vtbl = {
   1943    .authenticate = NULL,
   1944    .create_window_surface = dri2_wl_create_window_surface,
   1945    .create_pixmap_surface = dri2_wl_create_pixmap_surface,
   1946    .create_pbuffer_surface = dri2_fallback_create_pbuffer_surface,
   1947    .destroy_surface = dri2_wl_destroy_surface,
   1948    .create_image = dri2_create_image_khr,
   1949    .swap_buffers = dri2_wl_swrast_swap_buffers,
   1950    .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage,
   1951    .swap_buffers_region = dri2_fallback_swap_buffers_region,
   1952    .post_sub_buffer = dri2_fallback_post_sub_buffer,
   1953    .copy_buffers = dri2_fallback_copy_buffers,
   1954    .query_buffer_age = dri2_fallback_query_buffer_age,
   1955    .create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image,
   1956    .get_sync_values = dri2_fallback_get_sync_values,
   1957    .get_dri_drawable = dri2_surface_get_dri_drawable,
   1958 };
   1959 
   1960 static const __DRIswrastLoaderExtension swrast_loader_extension = {
   1961    .base = { __DRI_SWRAST_LOADER, 2 },
   1962 
   1963    .getDrawableInfo = dri2_wl_swrast_get_drawable_info,
   1964    .putImage        = dri2_wl_swrast_put_image,
   1965    .getImage        = dri2_wl_swrast_get_image,
   1966    .putImage2       = dri2_wl_swrast_put_image2,
   1967 };
   1968 
   1969 static const __DRIextension *swrast_loader_extensions[] = {
   1970    &swrast_loader_extension.base,
   1971    &image_lookup_extension.base,
   1972    NULL,
   1973 };
   1974 
   1975 static EGLBoolean
   1976 dri2_initialize_wayland_swrast(_EGLDriver *drv, _EGLDisplay *disp)
   1977 {
   1978    struct dri2_egl_display *dri2_dpy;
   1979 
   1980    loader_set_logger(_eglLog);
   1981 
   1982    dri2_dpy = calloc(1, sizeof *dri2_dpy);
   1983    if (!dri2_dpy)
   1984       return _eglError(EGL_BAD_ALLOC, "eglInitialize");
   1985 
   1986    dri2_dpy->fd = -1;
   1987    disp->DriverData = (void *) dri2_dpy;
   1988    if (disp->PlatformDisplay == NULL) {
   1989       dri2_dpy->wl_dpy = wl_display_connect(NULL);
   1990       if (dri2_dpy->wl_dpy == NULL)
   1991          goto cleanup;
   1992       dri2_dpy->own_device = true;
   1993    } else {
   1994       dri2_dpy->wl_dpy = disp->PlatformDisplay;
   1995    }
   1996 
   1997    dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
   1998 
   1999    dri2_dpy->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy);
   2000    if (dri2_dpy->wl_dpy_wrapper == NULL)
   2001       goto cleanup;
   2002 
   2003    wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_dpy_wrapper,
   2004                       dri2_dpy->wl_queue);
   2005 
   2006    if (dri2_dpy->own_device)
   2007       wl_display_dispatch_pending(dri2_dpy->wl_dpy);
   2008 
   2009    dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy_wrapper);
   2010    wl_registry_add_listener(dri2_dpy->wl_registry,
   2011                             &registry_listener_swrast, dri2_dpy);
   2012 
   2013    if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_shm == NULL)
   2014       goto cleanup;
   2015 
   2016    if (roundtrip(dri2_dpy) < 0 || dri2_dpy->formats == 0)
   2017       goto cleanup;
   2018 
   2019    dri2_dpy->driver_name = strdup("swrast");
   2020    if (!dri2_load_driver_swrast(disp))
   2021       goto cleanup;
   2022 
   2023    dri2_dpy->loader_extensions = swrast_loader_extensions;
   2024 
   2025    if (!dri2_create_screen(disp))
   2026       goto cleanup;
   2027 
   2028    if (!dri2_setup_extensions(disp))
   2029       goto cleanup;
   2030 
   2031    dri2_setup_screen(disp);
   2032 
   2033    dri2_wl_setup_swap_interval(disp);
   2034 
   2035    if (!dri2_wl_add_configs_for_visuals(drv, disp)) {
   2036       _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to add configs");
   2037       goto cleanup;
   2038    }
   2039 
   2040    /* Fill vtbl last to prevent accidentally calling virtual function during
   2041     * initialization.
   2042     */
   2043    dri2_dpy->vtbl = &dri2_wl_swrast_display_vtbl;
   2044 
   2045    return EGL_TRUE;
   2046 
   2047  cleanup:
   2048    dri2_display_destroy(disp);
   2049    return EGL_FALSE;
   2050 }
   2051 
   2052 EGLBoolean
   2053 dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp)
   2054 {
   2055    EGLBoolean initialized = EGL_FALSE;
   2056 
   2057    if (!disp->Options.ForceSoftware)
   2058       initialized = dri2_initialize_wayland_drm(drv, disp);
   2059 
   2060    if (!initialized)
   2061       initialized = dri2_initialize_wayland_swrast(drv, disp);
   2062 
   2063    return initialized;
   2064 
   2065 }
   2066 
   2067 void
   2068 dri2_teardown_wayland(struct dri2_egl_display *dri2_dpy)
   2069 {
   2070    if (dri2_dpy->wl_drm)
   2071       wl_drm_destroy(dri2_dpy->wl_drm);
   2072    if (dri2_dpy->wl_dmabuf)
   2073       zwp_linux_dmabuf_v1_destroy(dri2_dpy->wl_dmabuf);
   2074    if (dri2_dpy->wl_shm)
   2075       wl_shm_destroy(dri2_dpy->wl_shm);
   2076    if (dri2_dpy->wl_registry)
   2077       wl_registry_destroy(dri2_dpy->wl_registry);
   2078    if (dri2_dpy->wl_queue)
   2079       wl_event_queue_destroy(dri2_dpy->wl_queue);
   2080    if (dri2_dpy->wl_dpy_wrapper)
   2081       wl_proxy_wrapper_destroy(dri2_dpy->wl_dpy_wrapper);
   2082    u_vector_finish(&dri2_dpy->wl_modifiers.argb2101010);
   2083    u_vector_finish(&dri2_dpy->wl_modifiers.xrgb2101010);
   2084    u_vector_finish(&dri2_dpy->wl_modifiers.argb8888);
   2085    u_vector_finish(&dri2_dpy->wl_modifiers.xrgb8888);
   2086    u_vector_finish(&dri2_dpy->wl_modifiers.rgb565);
   2087    if (dri2_dpy->own_device)
   2088       wl_display_disconnect(dri2_dpy->wl_dpy);
   2089 }
   2090