"Fossies" - the Fresh Open Source Software Archive

Member "xorg-server-1.20.8/hw/xwayland/xwayland-glamor-gbm.c" (29 Mar 2020, 30876 Bytes) of package /linux/misc/xorg-server-1.20.8.tar.bz2:


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

    1 /*
    2  * Copyright © 2011-2014 Intel Corporation
    3  * Copyright © 2017 Red Hat Inc.
    4  *
    5  * Permission is hereby granted, free of charge, to any person
    6  * obtaining a copy of this software and associated documentation
    7  * files (the "Software"), to deal in the Software without
    8  * restriction, including without limitation the rights to use, copy,
    9  * modify, merge, publish, distribute, sublicense, and/or sell copies
   10  * of the Software, and to permit persons to whom the Software is
   11  * furnished to do so, subject to the following conditions:
   12  *
   13  * The above copyright notice and this permission notice (including
   14  * the next paragraph) shall be included in all copies or substantial
   15  * portions of the Software.
   16  *
   17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
   20  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
   21  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
   22  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   24  * DEALINGS IN THE SOFTWARE.
   25  *
   26  * Authors:
   27  *    Lyude Paul <lyude@redhat.com>
   28  *
   29  */
   30 
   31 #include "xwayland.h"
   32 
   33 #include <fcntl.h>
   34 #include <sys/stat.h>
   35 #include <xf86drm.h>
   36 #include <drm_fourcc.h>
   37 
   38 #define MESA_EGL_NO_X11_HEADERS
   39 #define EGL_NO_X11
   40 #include <gbm.h>
   41 #include <glamor_egl.h>
   42 
   43 #include <glamor.h>
   44 #include <glamor_context.h>
   45 #include <dri3.h>
   46 #include "drm-client-protocol.h"
   47 
   48 struct xwl_gbm_private {
   49     char *device_name;
   50     struct gbm_device *gbm;
   51     struct wl_drm *drm;
   52     struct zwp_linux_dmabuf_v1 *dmabuf;
   53     int drm_fd;
   54     int fd_render_node;
   55     Bool drm_authenticated;
   56     uint32_t capabilities;
   57     int dmabuf_capable;
   58 };
   59 
   60 struct xwl_pixmap {
   61     struct wl_buffer *buffer;
   62     EGLImage image;
   63     unsigned int texture;
   64     struct gbm_bo *bo;
   65 };
   66 
   67 static DevPrivateKeyRec xwl_gbm_private_key;
   68 static DevPrivateKeyRec xwl_auth_state_private_key;
   69 
   70 static inline struct xwl_gbm_private *
   71 xwl_gbm_get(struct xwl_screen *xwl_screen)
   72 {
   73     return dixLookupPrivate(&xwl_screen->screen->devPrivates,
   74                             &xwl_gbm_private_key);
   75 }
   76 
   77 static uint32_t
   78 gbm_format_for_depth(int depth)
   79 {
   80     switch (depth) {
   81     case 16:
   82         return GBM_FORMAT_RGB565;
   83     case 24:
   84         return GBM_FORMAT_XRGB8888;
   85     case 30:
   86         return GBM_FORMAT_ARGB2101010;
   87     default:
   88         ErrorF("unexpected depth: %d\n", depth);
   89     case 32:
   90         return GBM_FORMAT_ARGB8888;
   91     }
   92 }
   93 
   94 static uint32_t
   95 wl_drm_format_for_depth(int depth)
   96 {
   97     switch (depth) {
   98     case 15:
   99         return WL_DRM_FORMAT_XRGB1555;
  100     case 16:
  101         return WL_DRM_FORMAT_RGB565;
  102     case 24:
  103         return WL_DRM_FORMAT_XRGB8888;
  104     case 30:
  105         return WL_DRM_FORMAT_ARGB2101010;
  106     default:
  107         ErrorF("unexpected depth: %d\n", depth);
  108     case 32:
  109         return WL_DRM_FORMAT_ARGB8888;
  110     }
  111 }
  112 
  113 static char
  114 is_fd_render_node(int fd)
  115 {
  116     struct stat render;
  117 
  118     if (fstat(fd, &render))
  119         return 0;
  120     if (!S_ISCHR(render.st_mode))
  121         return 0;
  122     if (render.st_rdev & 0x80)
  123         return 1;
  124 
  125     return 0;
  126 }
  127 
  128 static char
  129 is_device_path_render_node (const char *device_path)
  130 {
  131     char is_render_node;
  132     int fd;
  133 
  134     fd = open(device_path, O_RDWR | O_CLOEXEC);
  135     if (fd < 0)
  136         return 0;
  137 
  138     is_render_node = is_fd_render_node(fd);
  139     close(fd);
  140 
  141     return is_render_node;
  142 }
  143 
  144 static PixmapPtr
  145 xwl_glamor_gbm_create_pixmap_for_bo(ScreenPtr screen, struct gbm_bo *bo,
  146                                     int depth)
  147 {
  148     PixmapPtr pixmap;
  149     struct xwl_pixmap *xwl_pixmap;
  150     struct xwl_screen *xwl_screen = xwl_screen_get(screen);
  151 
  152     xwl_pixmap = malloc(sizeof *xwl_pixmap);
  153     if (xwl_pixmap == NULL)
  154         return NULL;
  155 
  156     pixmap = glamor_create_pixmap(screen,
  157                                   gbm_bo_get_width(bo),
  158                                   gbm_bo_get_height(bo),
  159                                   depth,
  160                                   GLAMOR_CREATE_PIXMAP_NO_TEXTURE);
  161     if (!pixmap) {
  162         free(xwl_pixmap);
  163         return NULL;
  164     }
  165 
  166     xwl_glamor_egl_make_current(xwl_screen);
  167     xwl_pixmap->bo = bo;
  168     xwl_pixmap->buffer = NULL;
  169     xwl_pixmap->image = eglCreateImageKHR(xwl_screen->egl_display,
  170                                           xwl_screen->egl_context,
  171                                           EGL_NATIVE_PIXMAP_KHR,
  172                                           xwl_pixmap->bo, NULL);
  173     if (xwl_pixmap->image == EGL_NO_IMAGE_KHR)
  174       goto error;
  175 
  176     glGenTextures(1, &xwl_pixmap->texture);
  177     glBindTexture(GL_TEXTURE_2D, xwl_pixmap->texture);
  178     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  179     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  180 
  181     glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, xwl_pixmap->image);
  182     if (eglGetError() != EGL_SUCCESS)
  183       goto error;
  184 
  185     glBindTexture(GL_TEXTURE_2D, 0);
  186 
  187     glamor_set_pixmap_texture(pixmap, xwl_pixmap->texture);
  188     /* `set_pixmap_texture()` may fail silently if the FBO creation failed,
  189      * so we check again the texture to be sure it worked.
  190      */
  191     if (!glamor_get_pixmap_texture(pixmap))
  192       goto error;
  193 
  194     glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM);
  195     xwl_pixmap_set_private(pixmap, xwl_pixmap);
  196 
  197     return pixmap;
  198 
  199 error:
  200     if (xwl_pixmap->image != EGL_NO_IMAGE_KHR)
  201       eglDestroyImageKHR(xwl_screen->egl_display, xwl_pixmap->image);
  202     if (pixmap)
  203       glamor_destroy_pixmap(pixmap);
  204     free(xwl_pixmap);
  205 
  206     return NULL;
  207 }
  208 
  209 static PixmapPtr
  210 xwl_glamor_gbm_create_pixmap(ScreenPtr screen,
  211                              int width, int height, int depth,
  212                              unsigned int hint)
  213 {
  214     struct xwl_screen *xwl_screen = xwl_screen_get(screen);
  215     struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
  216     struct gbm_bo *bo;
  217     PixmapPtr pixmap = NULL;
  218 
  219     if (width > 0 && height > 0 && depth >= 15 &&
  220         (hint == 0 ||
  221          hint == CREATE_PIXMAP_USAGE_BACKING_PIXMAP ||
  222          hint == CREATE_PIXMAP_USAGE_SHARED)) {
  223         uint32_t format = gbm_format_for_depth(depth);
  224 
  225 #ifdef GBM_BO_WITH_MODIFIERS
  226         if (xwl_gbm->dmabuf_capable) {
  227             uint32_t num_modifiers;
  228             uint64_t *modifiers = NULL;
  229 
  230             glamor_get_modifiers(screen, format, &num_modifiers, &modifiers);
  231             bo = gbm_bo_create_with_modifiers(xwl_gbm->gbm, width, height,
  232                                               format, modifiers, num_modifiers);
  233             free(modifiers);
  234         }
  235         else
  236 #endif
  237         {
  238             bo = gbm_bo_create(xwl_gbm->gbm, width, height, format,
  239                                GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
  240         }
  241 
  242         if (bo) {
  243             pixmap = xwl_glamor_gbm_create_pixmap_for_bo(screen, bo, depth);
  244 
  245             if (!pixmap) {
  246                 gbm_bo_destroy(bo);
  247             }
  248             else if (xwl_screen->rootless && hint == CREATE_PIXMAP_USAGE_BACKING_PIXMAP) {
  249                 glamor_clear_pixmap(pixmap);
  250             }
  251         }
  252     }
  253 
  254     if (!pixmap)
  255         pixmap = glamor_create_pixmap(screen, width, height, depth, hint);
  256 
  257     return pixmap;
  258 }
  259 
  260 static Bool
  261 xwl_glamor_gbm_destroy_pixmap(PixmapPtr pixmap)
  262 {
  263     struct xwl_screen *xwl_screen = xwl_screen_get(pixmap->drawable.pScreen);
  264     struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
  265 
  266     if (xwl_pixmap && pixmap->refcnt == 1) {
  267         if (xwl_pixmap->buffer)
  268             wl_buffer_destroy(xwl_pixmap->buffer);
  269 
  270         eglDestroyImageKHR(xwl_screen->egl_display, xwl_pixmap->image);
  271         if (xwl_pixmap->bo)
  272            gbm_bo_destroy(xwl_pixmap->bo);
  273         free(xwl_pixmap);
  274     }
  275 
  276     return glamor_destroy_pixmap(pixmap);
  277 }
  278 
  279 static struct wl_buffer *
  280 xwl_glamor_gbm_get_wl_buffer_for_pixmap(PixmapPtr pixmap,
  281                                         Bool *created)
  282 {
  283     struct xwl_screen *xwl_screen = xwl_screen_get(pixmap->drawable.pScreen);
  284     struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
  285     struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
  286     unsigned short width = pixmap->drawable.width;
  287     unsigned short height = pixmap->drawable.height;
  288     int prime_fd;
  289     int num_planes;
  290     uint32_t strides[4];
  291     uint32_t offsets[4];
  292     uint64_t modifier;
  293     int i;
  294 
  295     if (xwl_pixmap == NULL)
  296        return NULL;
  297 
  298     if (xwl_pixmap->buffer) {
  299         /* Buffer already exists. Return it and inform caller if interested. */
  300         if (created)
  301             *created = FALSE;
  302         return xwl_pixmap->buffer;
  303     }
  304 
  305     /* Buffer does not exist yet. Create now and inform caller if interested. */
  306     if (created)
  307         *created = TRUE;
  308 
  309     if (!xwl_pixmap->bo)
  310        return NULL;
  311 
  312     prime_fd = gbm_bo_get_fd(xwl_pixmap->bo);
  313     if (prime_fd == -1)
  314         return NULL;
  315 
  316 #ifdef GBM_BO_WITH_MODIFIERS
  317     num_planes = gbm_bo_get_plane_count(xwl_pixmap->bo);
  318     modifier = gbm_bo_get_modifier(xwl_pixmap->bo);
  319     for (i = 0; i < num_planes; i++) {
  320         strides[i] = gbm_bo_get_stride_for_plane(xwl_pixmap->bo, i);
  321         offsets[i] = gbm_bo_get_offset(xwl_pixmap->bo, i);
  322     }
  323 #else
  324     num_planes = 1;
  325     modifier = DRM_FORMAT_MOD_INVALID;
  326     strides[0] = gbm_bo_get_stride(xwl_pixmap->bo);
  327     offsets[0] = 0;
  328 #endif
  329 
  330     if (xwl_gbm->dmabuf && modifier != DRM_FORMAT_MOD_INVALID) {
  331         struct zwp_linux_buffer_params_v1 *params;
  332 
  333         params = zwp_linux_dmabuf_v1_create_params(xwl_gbm->dmabuf);
  334         for (i = 0; i < num_planes; i++) {
  335             zwp_linux_buffer_params_v1_add(params, prime_fd, i,
  336                                            offsets[i], strides[i],
  337                                            modifier >> 32, modifier & 0xffffffff);
  338         }
  339 
  340         xwl_pixmap->buffer =
  341            zwp_linux_buffer_params_v1_create_immed(params, width, height,
  342                                                    wl_drm_format_for_depth(pixmap->drawable.depth),
  343                                                    0);
  344         zwp_linux_buffer_params_v1_destroy(params);
  345     } else if (num_planes == 1) {
  346         xwl_pixmap->buffer =
  347             wl_drm_create_prime_buffer(xwl_gbm->drm, prime_fd, width, height,
  348                                        wl_drm_format_for_depth(pixmap->drawable.depth),
  349                                        0, gbm_bo_get_stride(xwl_pixmap->bo),
  350                                        0, 0,
  351                                        0, 0);
  352     }
  353 
  354     close(prime_fd);
  355     return xwl_pixmap->buffer;
  356 }
  357 
  358 static void
  359 xwl_glamor_gbm_cleanup(struct xwl_screen *xwl_screen)
  360 {
  361     struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
  362 
  363     if (xwl_gbm->device_name)
  364         free(xwl_gbm->device_name);
  365     if (xwl_gbm->drm_fd)
  366         close(xwl_gbm->drm_fd);
  367     if (xwl_gbm->drm)
  368         wl_drm_destroy(xwl_gbm->drm);
  369     if (xwl_gbm->gbm)
  370         gbm_device_destroy(xwl_gbm->gbm);
  371 
  372     free(xwl_gbm);
  373 }
  374 
  375 struct xwl_auth_state {
  376     int fd;
  377     ClientPtr client;
  378     struct wl_callback *callback;
  379 };
  380 
  381 static void
  382 free_xwl_auth_state(ClientPtr pClient, struct xwl_auth_state *state)
  383 {
  384     dixSetPrivate(&pClient->devPrivates, &xwl_auth_state_private_key, NULL);
  385     if (state) {
  386         wl_callback_destroy(state->callback);
  387         free(state);
  388     }
  389 }
  390 
  391 static void
  392 xwl_auth_state_client_callback(CallbackListPtr *pcbl, void *unused, void *data)
  393 {
  394     NewClientInfoRec *clientinfo = (NewClientInfoRec *) data;
  395     ClientPtr pClient = clientinfo->client;
  396     struct xwl_auth_state *state;
  397 
  398     switch (pClient->clientState) {
  399     case ClientStateGone:
  400     case ClientStateRetained:
  401         state = dixLookupPrivate(&pClient->devPrivates,
  402                                  &xwl_auth_state_private_key);
  403         free_xwl_auth_state(pClient, state);
  404         break;
  405     default:
  406         break;
  407     }
  408 }
  409 
  410 static void
  411 sync_callback(void *data, struct wl_callback *callback, uint32_t serial)
  412 {
  413     struct xwl_auth_state *state = data;
  414     ClientPtr client = state->client;
  415 
  416     /* if the client is gone, the callback is cancelled so it's safe to
  417      * assume the client is still in ClientStateRunning at this point...
  418      */
  419     dri3_send_open_reply(client, state->fd);
  420     AttendClient(client);
  421     free_xwl_auth_state(client, state);
  422 }
  423 
  424 static const struct wl_callback_listener sync_listener = {
  425    sync_callback
  426 };
  427 
  428 static int
  429 xwl_dri3_open_client(ClientPtr client,
  430                      ScreenPtr screen,
  431                      RRProviderPtr provider,
  432                      int *pfd)
  433 {
  434     struct xwl_screen *xwl_screen = xwl_screen_get(screen);
  435     struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
  436     struct xwl_auth_state *state;
  437     drm_magic_t magic;
  438     int fd;
  439 
  440     fd = open(xwl_gbm->device_name, O_RDWR | O_CLOEXEC);
  441     if (fd < 0)
  442         return BadAlloc;
  443     if (xwl_gbm->fd_render_node) {
  444         *pfd = fd;
  445         return Success;
  446     }
  447 
  448     state = malloc(sizeof *state);
  449     if (state == NULL) {
  450         close(fd);
  451         return BadAlloc;
  452     }
  453 
  454     state->client = client;
  455     state->fd = fd;
  456 
  457     if (drmGetMagic(state->fd, &magic) < 0) {
  458         close(state->fd);
  459         free(state);
  460         return BadMatch;
  461     }
  462 
  463     wl_drm_authenticate(xwl_gbm->drm, magic);
  464     state->callback = wl_display_sync(xwl_screen->display);
  465     wl_callback_add_listener(state->callback, &sync_listener, state);
  466     dixSetPrivate(&client->devPrivates, &xwl_auth_state_private_key, state);
  467 
  468     IgnoreClient(client);
  469 
  470     return Success;
  471 }
  472 
  473 _X_EXPORT PixmapPtr
  474 glamor_pixmap_from_fds(ScreenPtr screen, CARD8 num_fds, const int *fds,
  475                        CARD16 width, CARD16 height,
  476                        const CARD32 *strides, const CARD32 *offsets,
  477                        CARD8 depth, CARD8 bpp, uint64_t modifier)
  478 {
  479     struct xwl_screen *xwl_screen = xwl_screen_get(screen);
  480     struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
  481     struct gbm_bo *bo = NULL;
  482     PixmapPtr pixmap;
  483     int i;
  484 
  485     if (width == 0 || height == 0 || num_fds == 0 ||
  486         depth < 15 || bpp != BitsPerPixel(depth) ||
  487         strides[0] < width * bpp / 8)
  488        goto error;
  489 
  490     if (xwl_gbm->dmabuf_capable && modifier != DRM_FORMAT_MOD_INVALID) {
  491 #ifdef GBM_BO_WITH_MODIFIERS
  492        struct gbm_import_fd_modifier_data data;
  493 
  494        data.width = width;
  495        data.height = height;
  496        data.num_fds = num_fds;
  497        data.format = gbm_format_for_depth(depth);
  498        data.modifier = modifier;
  499        for (i = 0; i < num_fds; i++) {
  500           data.fds[i] = fds[i];
  501           data.strides[i] = strides[i];
  502           data.offsets[i] = offsets[i];
  503        }
  504        bo = gbm_bo_import(xwl_gbm->gbm, GBM_BO_IMPORT_FD_MODIFIER, &data, 0);
  505 #endif
  506     } else if (num_fds == 1) {
  507        struct gbm_import_fd_data data;
  508 
  509        data.fd = fds[0];
  510        data.width = width;
  511        data.height = height;
  512        data.stride = strides[0];
  513        data.format = gbm_format_for_depth(depth);
  514        bo = gbm_bo_import(xwl_gbm->gbm, GBM_BO_IMPORT_FD, &data,
  515              GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
  516     } else {
  517        goto error;
  518     }
  519 
  520     if (bo == NULL)
  521        goto error;
  522 
  523     pixmap = xwl_glamor_gbm_create_pixmap_for_bo(screen, bo, depth);
  524     if (pixmap == NULL) {
  525        gbm_bo_destroy(bo);
  526        goto error;
  527     }
  528 
  529     return pixmap;
  530 
  531 error:
  532     return NULL;
  533 }
  534 
  535 _X_EXPORT int
  536 glamor_egl_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds,
  537                            uint32_t *strides, uint32_t *offsets,
  538                            uint64_t *modifier)
  539 {
  540     struct xwl_pixmap *xwl_pixmap;
  541 #ifdef GBM_BO_WITH_MODIFIERS
  542     uint32_t num_fds;
  543     int i;
  544 #endif
  545 
  546     xwl_pixmap = xwl_pixmap_get(pixmap);
  547 
  548     if (xwl_pixmap == NULL)
  549        return 0;
  550 
  551     if (!xwl_pixmap->bo)
  552        return 0;
  553 
  554 #ifdef GBM_BO_WITH_MODIFIERS
  555     num_fds = gbm_bo_get_plane_count(xwl_pixmap->bo);
  556     *modifier = gbm_bo_get_modifier(xwl_pixmap->bo);
  557 
  558     for (i = 0; i < num_fds; i++) {
  559         fds[i] = gbm_bo_get_fd(xwl_pixmap->bo);
  560         strides[i] = gbm_bo_get_stride_for_plane(xwl_pixmap->bo, i);
  561         offsets[i] = gbm_bo_get_offset(xwl_pixmap->bo, i);
  562     }
  563 
  564     return num_fds;
  565 #else
  566     *modifier = DRM_FORMAT_MOD_INVALID;
  567     fds[0] = gbm_bo_get_fd(xwl_pixmap->bo);
  568     strides[0] = gbm_bo_get_stride(xwl_pixmap->bo);
  569     offsets[0] = 0;
  570     return 1;
  571 #endif
  572 }
  573 
  574 /* Not actually used, just defined here so there's something for
  575  * _glamor_egl_fds_from_pixmap() to link against
  576  */
  577 _X_EXPORT int
  578 glamor_egl_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap,
  579                           CARD16 *stride, CARD32 *size)
  580 {
  581     return -1;
  582 }
  583 
  584 _X_EXPORT Bool
  585 glamor_get_formats(ScreenPtr screen,
  586                    CARD32 *num_formats, CARD32 **formats)
  587 {
  588     struct xwl_screen *xwl_screen = xwl_screen_get(screen);
  589     struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
  590     int i;
  591 
  592     /* Explicitly zero the count as the caller may ignore the return value */
  593     *num_formats = 0;
  594 
  595     if (!xwl_gbm->dmabuf_capable || !xwl_gbm->dmabuf)
  596         return FALSE;
  597 
  598     if (xwl_screen->num_formats == 0)
  599        return TRUE;
  600 
  601     *formats = calloc(xwl_screen->num_formats, sizeof(CARD32));
  602     if (*formats == NULL)
  603         return FALSE;
  604 
  605     for (i = 0; i < xwl_screen->num_formats; i++)
  606        (*formats)[i] = xwl_screen->formats[i].format;
  607     *num_formats = xwl_screen->num_formats;
  608 
  609     return TRUE;
  610 }
  611 
  612 _X_EXPORT Bool
  613 glamor_get_modifiers(ScreenPtr screen, uint32_t format,
  614                      uint32_t *num_modifiers, uint64_t **modifiers)
  615 {
  616     struct xwl_screen *xwl_screen = xwl_screen_get(screen);
  617     struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
  618     struct xwl_format *xwl_format = NULL;
  619     int i;
  620 
  621     /* Explicitly zero the count as the caller may ignore the return value */
  622     *num_modifiers = 0;
  623 
  624     if (!xwl_gbm->dmabuf_capable || !xwl_gbm->dmabuf)
  625         return FALSE;
  626 
  627     if (xwl_screen->num_formats == 0)
  628        return TRUE;
  629 
  630     for (i = 0; i < xwl_screen->num_formats; i++) {
  631        if (xwl_screen->formats[i].format == format) {
  632           xwl_format = &xwl_screen->formats[i];
  633           break;
  634        }
  635     }
  636 
  637     if (!xwl_format)
  638         return FALSE;
  639 
  640     *modifiers = calloc(xwl_format->num_modifiers, sizeof(uint64_t));
  641     if (*modifiers == NULL)
  642         return FALSE;
  643 
  644     for (i = 0; i < xwl_format->num_modifiers; i++)
  645        (*modifiers)[i] = xwl_format->modifiers[i];
  646     *num_modifiers = xwl_format->num_modifiers;
  647 
  648     return TRUE;
  649 }
  650 
  651 static const dri3_screen_info_rec xwl_dri3_info = {
  652     .version = 2,
  653     .open = NULL,
  654     .pixmap_from_fds = glamor_pixmap_from_fds,
  655     .fds_from_pixmap = glamor_fds_from_pixmap,
  656     .open_client = xwl_dri3_open_client,
  657     .get_formats = glamor_get_formats,
  658     .get_modifiers = glamor_get_modifiers,
  659     .get_drawable_modifiers = glamor_get_drawable_modifiers,
  660 };
  661 
  662 static const char *
  663 get_render_node_path_for_device(const drmDevicePtr drm_device,
  664                                 const char *device_path)
  665 {
  666     char *render_node_path = NULL;
  667     char device_found = 0;
  668     int i;
  669 
  670     for (i = 0; i < DRM_NODE_MAX; i++) {
  671         if ((drm_device->available_nodes & (1 << i)) == 0)
  672            continue;
  673 
  674         if (!strcmp (device_path, drm_device->nodes[i]))
  675             device_found = 1;
  676 
  677         if (is_device_path_render_node(drm_device->nodes[i]))
  678             render_node_path = drm_device->nodes[i];
  679 
  680         if (device_found && render_node_path)
  681             return render_node_path;
  682     }
  683 
  684     return NULL;
  685 }
  686 
  687 static char *
  688 get_render_node_path(const char *device_path)
  689 {
  690     drmDevicePtr *devices = NULL;
  691     char *render_node_path = NULL;
  692     int i, n_devices, max_devices;
  693 
  694     max_devices = drmGetDevices2(0, NULL, 0);
  695     if (max_devices <= 0)
  696         goto out;
  697 
  698     devices = calloc(max_devices, sizeof(drmDevicePtr));
  699     if (!devices)
  700         goto out;
  701 
  702     n_devices = drmGetDevices2(0, devices, max_devices);
  703     if (n_devices < 0)
  704         goto out;
  705 
  706     for (i = 0; i < n_devices; i++) {
  707        const char *node_path = get_render_node_path_for_device(devices[i],
  708                                                                device_path);
  709        if (node_path) {
  710            render_node_path = strdup(node_path);
  711            break;
  712        }
  713     }
  714 
  715 out:
  716     free(devices);
  717     return render_node_path;
  718 }
  719 
  720 static void
  721 xwl_drm_handle_device(void *data, struct wl_drm *drm, const char *device)
  722 {
  723    struct xwl_screen *xwl_screen = data;
  724    struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
  725    drm_magic_t magic;
  726    char *render_node_path = NULL;
  727 
  728    if (!is_device_path_render_node(device))
  729        render_node_path = get_render_node_path(device);
  730 
  731    if (render_node_path)
  732        xwl_gbm->device_name = render_node_path;
  733    else
  734        xwl_gbm->device_name = strdup(device);
  735 
  736    if (!xwl_gbm->device_name) {
  737        xwl_glamor_gbm_cleanup(xwl_screen);
  738        return;
  739    }
  740 
  741    xwl_gbm->drm_fd = open(xwl_gbm->device_name, O_RDWR | O_CLOEXEC);
  742    if (xwl_gbm->drm_fd == -1) {
  743        ErrorF("wayland-egl: could not open %s (%s)\n",
  744               xwl_gbm->device_name, strerror(errno));
  745        xwl_glamor_gbm_cleanup(xwl_screen);
  746        return;
  747    }
  748 
  749    if (is_fd_render_node(xwl_gbm->drm_fd)) {
  750        xwl_gbm->fd_render_node = 1;
  751        xwl_screen->expecting_event--;
  752    } else {
  753        drmGetMagic(xwl_gbm->drm_fd, &magic);
  754        wl_drm_authenticate(xwl_gbm->drm, magic);
  755    }
  756 }
  757 
  758 static void
  759 xwl_drm_handle_format(void *data, struct wl_drm *drm, uint32_t format)
  760 {
  761 }
  762 
  763 static void
  764 xwl_drm_handle_authenticated(void *data, struct wl_drm *drm)
  765 {
  766     struct xwl_screen *xwl_screen = data;
  767     struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
  768 
  769     xwl_gbm->drm_authenticated = TRUE;
  770     xwl_screen->expecting_event--;
  771 }
  772 
  773 static void
  774 xwl_drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t value)
  775 {
  776     xwl_gbm_get(data)->capabilities = value;
  777 }
  778 
  779 static const struct wl_drm_listener xwl_drm_listener = {
  780     xwl_drm_handle_device,
  781     xwl_drm_handle_format,
  782     xwl_drm_handle_authenticated,
  783     xwl_drm_handle_capabilities
  784 };
  785 
  786 static void
  787 xwl_dmabuf_handle_format(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
  788                          uint32_t format)
  789 {
  790 }
  791 
  792 static void
  793 xwl_dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
  794                            uint32_t format, uint32_t modifier_hi,
  795                            uint32_t modifier_lo)
  796 {
  797    struct xwl_screen *xwl_screen = data;
  798     struct xwl_format *xwl_format = NULL;
  799     int i;
  800 
  801     if (modifier_hi == (DRM_FORMAT_MOD_INVALID >> 32) &&
  802         modifier_lo == (DRM_FORMAT_MOD_INVALID & 0xffffffff))
  803         return;
  804 
  805     for (i = 0; i < xwl_screen->num_formats; i++) {
  806         if (xwl_screen->formats[i].format == format) {
  807             xwl_format = &xwl_screen->formats[i];
  808             break;
  809         }
  810     }
  811 
  812     if (xwl_format == NULL) {
  813        xwl_screen->num_formats++;
  814        xwl_screen->formats = realloc(xwl_screen->formats,
  815                                      xwl_screen->num_formats * sizeof(*xwl_format));
  816        if (!xwl_screen->formats)
  817           return;
  818        xwl_format = &xwl_screen->formats[xwl_screen->num_formats - 1];
  819        xwl_format->format = format;
  820        xwl_format->num_modifiers = 0;
  821        xwl_format->modifiers = NULL;
  822     }
  823 
  824     xwl_format->num_modifiers++;
  825     xwl_format->modifiers = realloc(xwl_format->modifiers,
  826                                     xwl_format->num_modifiers * sizeof(uint64_t));
  827     if (!xwl_format->modifiers)
  828        return;
  829     xwl_format->modifiers[xwl_format->num_modifiers - 1]  = (uint64_t) modifier_lo;
  830     xwl_format->modifiers[xwl_format->num_modifiers - 1] |= (uint64_t) modifier_hi << 32;
  831 }
  832 
  833 static const struct zwp_linux_dmabuf_v1_listener xwl_dmabuf_listener = {
  834     .format   = xwl_dmabuf_handle_format,
  835     .modifier = xwl_dmabuf_handle_modifier
  836 };
  837 
  838 Bool
  839 xwl_screen_set_drm_interface(struct xwl_screen *xwl_screen,
  840                              uint32_t id, uint32_t version)
  841 {
  842     struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
  843 
  844     if (version < 2)
  845         return FALSE;
  846 
  847     xwl_gbm->drm =
  848         wl_registry_bind(xwl_screen->registry, id, &wl_drm_interface, 2);
  849     wl_drm_add_listener(xwl_gbm->drm, &xwl_drm_listener, xwl_screen);
  850     xwl_screen->expecting_event++;
  851 
  852     return TRUE;
  853 }
  854 
  855 Bool
  856 xwl_screen_set_dmabuf_interface(struct xwl_screen *xwl_screen,
  857                                 uint32_t id, uint32_t version)
  858 {
  859     struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
  860 
  861     if (version < 3)
  862         return FALSE;
  863 
  864     xwl_gbm->dmabuf =
  865         wl_registry_bind(xwl_screen->registry, id, &zwp_linux_dmabuf_v1_interface, 3);
  866     zwp_linux_dmabuf_v1_add_listener(xwl_gbm->dmabuf, &xwl_dmabuf_listener, xwl_screen);
  867 
  868     return TRUE;
  869 }
  870 
  871 static Bool
  872 xwl_glamor_gbm_init_wl_registry(struct xwl_screen *xwl_screen,
  873                                 struct wl_registry *wl_registry,
  874                                 uint32_t id, const char *name,
  875                                 uint32_t version)
  876 {
  877     if (strcmp(name, "wl_drm") == 0) {
  878         xwl_screen_set_drm_interface(xwl_screen, id, version);
  879         return TRUE;
  880     } else if (strcmp(name, "zwp_linux_dmabuf_v1") == 0) {
  881         xwl_screen_set_dmabuf_interface(xwl_screen, id, version);
  882         return TRUE;
  883     }
  884 
  885     /* no match */
  886     return FALSE;
  887 }
  888 
  889 static Bool
  890 xwl_glamor_gbm_has_egl_extension(void)
  891 {
  892     return (epoxy_has_egl_extension(NULL, "EGL_MESA_platform_gbm") ||
  893             epoxy_has_egl_extension(NULL, "EGL_KHR_platform_gbm"));
  894 }
  895 
  896 static Bool
  897 xwl_glamor_gbm_has_wl_interfaces(struct xwl_screen *xwl_screen)
  898 {
  899     struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
  900 
  901     if (xwl_gbm->drm == NULL) {
  902         ErrorF("glamor: 'wl_drm' not supported\n");
  903         return FALSE;
  904     }
  905 
  906     return TRUE;
  907 }
  908 
  909 static Bool
  910 xwl_glamor_gbm_init_egl(struct xwl_screen *xwl_screen)
  911 {
  912     struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
  913     EGLint major, minor;
  914     Bool egl_initialized = FALSE;
  915     static const EGLint config_attribs_core[] = {
  916         EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR,
  917         EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR,
  918         EGL_CONTEXT_MAJOR_VERSION_KHR,
  919         GLAMOR_GL_CORE_VER_MAJOR,
  920         EGL_CONTEXT_MINOR_VERSION_KHR,
  921         GLAMOR_GL_CORE_VER_MINOR,
  922         EGL_NONE
  923     };
  924     const GLubyte *renderer;
  925 
  926     if (!xwl_gbm->fd_render_node && !xwl_gbm->drm_authenticated) {
  927         ErrorF("Failed to get wl_drm, disabling Glamor and DRI3\n");
  928     return FALSE;
  929     }
  930 
  931     xwl_gbm->gbm = gbm_create_device(xwl_gbm->drm_fd);
  932     if (!xwl_gbm->gbm) {
  933         ErrorF("couldn't create gbm device\n");
  934         goto error;
  935     }
  936 
  937     xwl_screen->egl_display = glamor_egl_get_display(EGL_PLATFORM_GBM_MESA,
  938                                                      xwl_gbm->gbm);
  939     if (xwl_screen->egl_display == EGL_NO_DISPLAY) {
  940         ErrorF("glamor_egl_get_display() failed\n");
  941         goto error;
  942     }
  943 
  944     egl_initialized = eglInitialize(xwl_screen->egl_display, &major, &minor);
  945     if (!egl_initialized) {
  946         ErrorF("eglInitialize() failed\n");
  947         goto error;
  948     }
  949 
  950     eglBindAPI(EGL_OPENGL_API);
  951 
  952     xwl_screen->egl_context = eglCreateContext(
  953         xwl_screen->egl_display, NULL, EGL_NO_CONTEXT, config_attribs_core);
  954     if (xwl_screen->egl_context == EGL_NO_CONTEXT) {
  955         xwl_screen->egl_context = eglCreateContext(
  956             xwl_screen->egl_display, NULL, EGL_NO_CONTEXT, NULL);
  957     }
  958 
  959     if (xwl_screen->egl_context == EGL_NO_CONTEXT) {
  960         ErrorF("Failed to create EGL context\n");
  961         goto error;
  962     }
  963 
  964     if (!eglMakeCurrent(xwl_screen->egl_display,
  965                         EGL_NO_SURFACE, EGL_NO_SURFACE,
  966                         xwl_screen->egl_context)) {
  967         ErrorF("Failed to make EGL context current\n");
  968         goto error;
  969     }
  970 
  971     renderer = glGetString(GL_RENDERER);
  972     if (!renderer) {
  973         ErrorF("glGetString() returned NULL, your GL is broken\n");
  974         goto error;
  975     }
  976     if (strstr((const char *)renderer, "llvmpipe")) {
  977         ErrorF("Refusing to try glamor on llvmpipe\n");
  978         goto error;
  979     }
  980 
  981     if (!epoxy_has_gl_extension("GL_OES_EGL_image")) {
  982         ErrorF("GL_OES_EGL_image not available\n");
  983         goto error;
  984     }
  985 
  986     if (epoxy_has_egl_extension(xwl_screen->egl_display,
  987                                 "EXT_image_dma_buf_import") &&
  988         epoxy_has_egl_extension(xwl_screen->egl_display,
  989                                 "EXT_image_dma_buf_import_modifiers"))
  990        xwl_gbm->dmabuf_capable = TRUE;
  991 
  992     return TRUE;
  993 error:
  994     if (xwl_screen->egl_context != EGL_NO_CONTEXT) {
  995         eglDestroyContext(xwl_screen->egl_display, xwl_screen->egl_context);
  996         xwl_screen->egl_context = EGL_NO_CONTEXT;
  997     }
  998 
  999     if (xwl_screen->egl_display != EGL_NO_DISPLAY) {
 1000         eglTerminate(xwl_screen->egl_display);
 1001         xwl_screen->egl_display = EGL_NO_DISPLAY;
 1002     }
 1003 
 1004     xwl_glamor_gbm_cleanup(xwl_screen);
 1005     return FALSE;
 1006 }
 1007 
 1008 static Bool
 1009 xwl_glamor_gbm_init_screen(struct xwl_screen *xwl_screen)
 1010 {
 1011     struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
 1012 
 1013     if (!dri3_screen_init(xwl_screen->screen, &xwl_dri3_info)) {
 1014         ErrorF("Failed to initialize dri3\n");
 1015         goto error;
 1016     }
 1017 
 1018     if (xwl_gbm->fd_render_node)
 1019         goto skip_drm_auth;
 1020 
 1021     if (!dixRegisterPrivateKey(&xwl_auth_state_private_key, PRIVATE_CLIENT,
 1022                                0)) {
 1023         ErrorF("Failed to register private key\n");
 1024         goto error;
 1025     }
 1026 
 1027     if (!AddCallback(&ClientStateCallback, xwl_auth_state_client_callback,
 1028                      NULL)) {
 1029         ErrorF("Failed to add client state callback\n");
 1030         goto error;
 1031     }
 1032 
 1033 skip_drm_auth:
 1034     xwl_screen->screen->CreatePixmap = xwl_glamor_gbm_create_pixmap;
 1035     xwl_screen->screen->DestroyPixmap = xwl_glamor_gbm_destroy_pixmap;
 1036 
 1037     return TRUE;
 1038 error:
 1039     xwl_glamor_gbm_cleanup(xwl_screen);
 1040     return FALSE;
 1041 }
 1042 
 1043 void
 1044 xwl_glamor_init_gbm(struct xwl_screen *xwl_screen)
 1045 {
 1046     struct xwl_gbm_private *xwl_gbm;
 1047 
 1048     xwl_screen->gbm_backend.is_available = FALSE;
 1049 
 1050     if (!xwl_glamor_gbm_has_egl_extension())
 1051         return;
 1052 
 1053     if (!dixRegisterPrivateKey(&xwl_gbm_private_key, PRIVATE_SCREEN, 0))
 1054         return;
 1055 
 1056     xwl_gbm = calloc(sizeof(*xwl_gbm), 1);
 1057     if (!xwl_gbm) {
 1058         ErrorF("glamor: Not enough memory to setup GBM, disabling\n");
 1059         return;
 1060     }
 1061 
 1062     dixSetPrivate(&xwl_screen->screen->devPrivates, &xwl_gbm_private_key,
 1063                   xwl_gbm);
 1064 
 1065     xwl_screen->gbm_backend.init_wl_registry = xwl_glamor_gbm_init_wl_registry;
 1066     xwl_screen->gbm_backend.has_wl_interfaces = xwl_glamor_gbm_has_wl_interfaces;
 1067     xwl_screen->gbm_backend.init_egl = xwl_glamor_gbm_init_egl;
 1068     xwl_screen->gbm_backend.init_screen = xwl_glamor_gbm_init_screen;
 1069     xwl_screen->gbm_backend.get_wl_buffer_for_pixmap = xwl_glamor_gbm_get_wl_buffer_for_pixmap;
 1070     xwl_screen->gbm_backend.is_available = TRUE;
 1071 }