xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

glamor_egl.c (33833B)


      1 /*
      2  * Copyright © 2010 Intel Corporation.
      3  *
      4  * Permission is hereby granted, free of charge, to any person
      5  * obtaining a copy of this software and associated documentation
      6  * files (the "Software"), to deal in the Software without
      7  * restriction, including without limitation the rights to use, copy,
      8  * modify, merge, publish, distribute, sublicense, and/or sell copies
      9  * of the Software, and to permit persons to whom the Software is
     10  * furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice and this permission notice (including
     13  * the next paragraph) shall be included in all copies or substantial
     14  * portions of the 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  *    Zhigang Gong <zhigang.gong@linux.intel.com>
     27  *
     28  */
     29 
     30 #include "dix-config.h"
     31 
     32 #define GLAMOR_FOR_XORG
     33 #include <unistd.h>
     34 #include <fcntl.h>
     35 #include <sys/ioctl.h>
     36 #include <errno.h>
     37 #include <xf86.h>
     38 #include <xf86Priv.h>
     39 #include <xf86drm.h>
     40 #define EGL_DISPLAY_NO_X_MESA
     41 
     42 #include <gbm.h>
     43 #include <drm_fourcc.h>
     44 
     45 #include "glamor_egl.h"
     46 
     47 #include "glamor.h"
     48 #include "glamor_priv.h"
     49 #include "dri3.h"
     50 
     51 struct glamor_egl_screen_private {
     52     EGLDisplay display;
     53     EGLContext context;
     54     char *device_path;
     55 
     56     CreateScreenResourcesProcPtr CreateScreenResources;
     57     CloseScreenProcPtr CloseScreen;
     58     int fd;
     59     struct gbm_device *gbm;
     60     int dmabuf_capable;
     61 
     62     CloseScreenProcPtr saved_close_screen;
     63     DestroyPixmapProcPtr saved_destroy_pixmap;
     64     xf86FreeScreenProc *saved_free_screen;
     65 };
     66 
     67 int xf86GlamorEGLPrivateIndex = -1;
     68 
     69 
     70 static struct glamor_egl_screen_private *
     71 glamor_egl_get_screen_private(ScrnInfoPtr scrn)
     72 {
     73     return (struct glamor_egl_screen_private *)
     74         scrn->privates[xf86GlamorEGLPrivateIndex].ptr;
     75 }
     76 
     77 static void
     78 glamor_egl_make_current(struct glamor_context *glamor_ctx)
     79 {
     80     /* There's only a single global dispatch table in Mesa.  EGL, GLX,
     81      * and AIGLX's direct dispatch table manipulation don't talk to
     82      * each other.  We need to set the context to NULL first to avoid
     83      * EGL's no-op context change fast path when switching back to
     84      * EGL.
     85      */
     86     eglMakeCurrent(glamor_ctx->display, EGL_NO_SURFACE,
     87                    EGL_NO_SURFACE, EGL_NO_CONTEXT);
     88 
     89     if (!eglMakeCurrent(glamor_ctx->display,
     90                         EGL_NO_SURFACE, EGL_NO_SURFACE,
     91                         glamor_ctx->ctx)) {
     92         FatalError("Failed to make EGL context current\n");
     93     }
     94 }
     95 
     96 static int
     97 glamor_get_flink_name(int fd, int handle, int *name)
     98 {
     99     struct drm_gem_flink flink;
    100 
    101     flink.handle = handle;
    102     if (ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) {
    103 
    104 	/*
    105 	 * Assume non-GEM kernels have names identical to the handle
    106 	 */
    107 	if (errno == ENODEV) {
    108 	    *name = handle;
    109 	    return TRUE;
    110 	} else {
    111 	    return FALSE;
    112 	}
    113     }
    114     *name = flink.name;
    115     return TRUE;
    116 }
    117 
    118 static Bool
    119 glamor_create_texture_from_image(ScreenPtr screen,
    120                                  EGLImageKHR image, GLuint * texture)
    121 {
    122     struct glamor_screen_private *glamor_priv =
    123         glamor_get_screen_private(screen);
    124 
    125     glamor_make_current(glamor_priv);
    126 
    127     glGenTextures(1, texture);
    128     glBindTexture(GL_TEXTURE_2D, *texture);
    129     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    130     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    131 
    132     glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
    133     glBindTexture(GL_TEXTURE_2D, 0);
    134 
    135     return TRUE;
    136 }
    137 
    138 struct gbm_device *
    139 glamor_egl_get_gbm_device(ScreenPtr screen)
    140 {
    141     struct glamor_egl_screen_private *glamor_egl =
    142         glamor_egl_get_screen_private(xf86ScreenToScrn(screen));
    143     return glamor_egl->gbm;
    144 }
    145 
    146 Bool
    147 glamor_egl_create_textured_screen(ScreenPtr screen, int handle, int stride)
    148 {
    149     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    150     PixmapPtr screen_pixmap;
    151 
    152     screen_pixmap = screen->GetScreenPixmap(screen);
    153 
    154     if (!glamor_egl_create_textured_pixmap(screen_pixmap, handle, stride)) {
    155         xf86DrvMsg(scrn->scrnIndex, X_ERROR,
    156                    "Failed to create textured screen.");
    157         return FALSE;
    158     }
    159     return TRUE;
    160 }
    161 
    162 static void
    163 glamor_egl_set_pixmap_image(PixmapPtr pixmap, EGLImageKHR image,
    164                             Bool used_modifiers)
    165 {
    166     struct glamor_pixmap_private *pixmap_priv =
    167         glamor_get_pixmap_private(pixmap);
    168     EGLImageKHR old;
    169 
    170     old = pixmap_priv->image;
    171     if (old) {
    172         ScreenPtr                               screen = pixmap->drawable.pScreen;
    173         ScrnInfoPtr                             scrn = xf86ScreenToScrn(screen);
    174         struct glamor_egl_screen_private        *glamor_egl = glamor_egl_get_screen_private(scrn);
    175 
    176         eglDestroyImageKHR(glamor_egl->display, old);
    177     }
    178     pixmap_priv->image = image;
    179     pixmap_priv->used_modifiers = used_modifiers;
    180 }
    181 
    182 Bool
    183 glamor_egl_create_textured_pixmap(PixmapPtr pixmap, int handle, int stride)
    184 {
    185     ScreenPtr screen = pixmap->drawable.pScreen;
    186     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    187     struct glamor_egl_screen_private *glamor_egl =
    188         glamor_egl_get_screen_private(scrn);
    189     int ret, fd;
    190 
    191     /* GBM doesn't have an import path from handles, so we make a
    192      * dma-buf fd from it and then go through that.
    193      */
    194     ret = drmPrimeHandleToFD(glamor_egl->fd, handle, O_CLOEXEC, &fd);
    195     if (ret) {
    196         xf86DrvMsg(scrn->scrnIndex, X_ERROR,
    197                    "Failed to make prime FD for handle: %d\n", errno);
    198         return FALSE;
    199     }
    200 
    201     if (!glamor_back_pixmap_from_fd(pixmap, fd,
    202                                     pixmap->drawable.width,
    203                                     pixmap->drawable.height,
    204                                     stride,
    205                                     pixmap->drawable.depth,
    206                                     pixmap->drawable.bitsPerPixel)) {
    207         xf86DrvMsg(scrn->scrnIndex, X_ERROR,
    208                    "Failed to make import prime FD as pixmap: %d\n", errno);
    209         close(fd);
    210         return FALSE;
    211     }
    212 
    213     close(fd);
    214     return TRUE;
    215 }
    216 
    217 Bool
    218 glamor_egl_create_textured_pixmap_from_gbm_bo(PixmapPtr pixmap,
    219                                               struct gbm_bo *bo,
    220                                               Bool used_modifiers)
    221 {
    222     ScreenPtr screen = pixmap->drawable.pScreen;
    223     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    224     struct glamor_screen_private *glamor_priv =
    225         glamor_get_screen_private(screen);
    226     struct glamor_egl_screen_private *glamor_egl;
    227     EGLImageKHR image;
    228     GLuint texture;
    229     Bool ret = FALSE;
    230 
    231     glamor_egl = glamor_egl_get_screen_private(scrn);
    232 
    233     glamor_make_current(glamor_priv);
    234 
    235     image = eglCreateImageKHR(glamor_egl->display,
    236                               EGL_NO_CONTEXT,
    237                               EGL_NATIVE_PIXMAP_KHR, bo, NULL);
    238     if (image == EGL_NO_IMAGE_KHR) {
    239         glamor_set_pixmap_type(pixmap, GLAMOR_DRM_ONLY);
    240         goto done;
    241     }
    242     glamor_create_texture_from_image(screen, image, &texture);
    243     glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM);
    244     glamor_set_pixmap_texture(pixmap, texture);
    245     glamor_egl_set_pixmap_image(pixmap, image, used_modifiers);
    246     ret = TRUE;
    247 
    248  done:
    249     return ret;
    250 }
    251 
    252 static void
    253 glamor_get_name_from_bo(int gbm_fd, struct gbm_bo *bo, int *name)
    254 {
    255     union gbm_bo_handle handle;
    256 
    257     handle = gbm_bo_get_handle(bo);
    258     if (!glamor_get_flink_name(gbm_fd, handle.u32, name))
    259         *name = -1;
    260 }
    261 
    262 static Bool
    263 glamor_make_pixmap_exportable(PixmapPtr pixmap, Bool modifiers_ok)
    264 {
    265     ScreenPtr screen = pixmap->drawable.pScreen;
    266     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    267     struct glamor_egl_screen_private *glamor_egl =
    268         glamor_egl_get_screen_private(scrn);
    269     struct glamor_pixmap_private *pixmap_priv =
    270         glamor_get_pixmap_private(pixmap);
    271     unsigned width = pixmap->drawable.width;
    272     unsigned height = pixmap->drawable.height;
    273     uint32_t format;
    274     struct gbm_bo *bo = NULL;
    275     Bool used_modifiers = FALSE;
    276     PixmapPtr exported;
    277     GCPtr scratch_gc;
    278 
    279     if (pixmap_priv->image &&
    280         (modifiers_ok || !pixmap_priv->used_modifiers))
    281         return TRUE;
    282 
    283     switch (pixmap->drawable.depth) {
    284     case 30:
    285         format = GBM_FORMAT_ARGB2101010;
    286         break;
    287     case 32:
    288     case 24:
    289         format = GBM_FORMAT_ARGB8888;
    290         break;
    291     case 16:
    292         format = GBM_FORMAT_RGB565;
    293         break;
    294     case 15:
    295         format = GBM_FORMAT_ARGB1555;
    296         break;
    297     case 8:
    298         format = GBM_FORMAT_R8;
    299         break;
    300     default:
    301         xf86DrvMsg(scrn->scrnIndex, X_ERROR,
    302                    "Failed to make %d depth, %dbpp pixmap exportable\n",
    303                    pixmap->drawable.depth, pixmap->drawable.bitsPerPixel);
    304         return FALSE;
    305     }
    306 
    307 #ifdef GBM_BO_WITH_MODIFIERS
    308     if (modifiers_ok && glamor_egl->dmabuf_capable) {
    309         uint32_t num_modifiers;
    310         uint64_t *modifiers = NULL;
    311 
    312         glamor_get_modifiers(screen, format, &num_modifiers, &modifiers);
    313 
    314         bo = gbm_bo_create_with_modifiers(glamor_egl->gbm, width, height,
    315                                           format, modifiers, num_modifiers);
    316         if (bo)
    317             used_modifiers = TRUE;
    318         free(modifiers);
    319     }
    320 #endif
    321 
    322     if (!bo)
    323     {
    324         bo = gbm_bo_create(glamor_egl->gbm, width, height, format,
    325 #ifdef GLAMOR_HAS_GBM_LINEAR
    326                 (pixmap->usage_hint == CREATE_PIXMAP_USAGE_SHARED ?
    327                  GBM_BO_USE_LINEAR : 0) |
    328 #endif
    329                 GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT);
    330     }
    331 
    332     if (!bo) {
    333         xf86DrvMsg(scrn->scrnIndex, X_ERROR,
    334                    "Failed to make %dx%dx%dbpp GBM bo\n",
    335                    width, height, pixmap->drawable.bitsPerPixel);
    336         return FALSE;
    337     }
    338 
    339     exported = screen->CreatePixmap(screen, 0, 0, pixmap->drawable.depth, 0);
    340     screen->ModifyPixmapHeader(exported, width, height, 0, 0,
    341                                gbm_bo_get_stride(bo), NULL);
    342     if (!glamor_egl_create_textured_pixmap_from_gbm_bo(exported, bo,
    343                                                        used_modifiers)) {
    344         xf86DrvMsg(scrn->scrnIndex, X_ERROR,
    345                    "Failed to make %dx%dx%dbpp pixmap from GBM bo\n",
    346                    width, height, pixmap->drawable.bitsPerPixel);
    347         screen->DestroyPixmap(exported);
    348         gbm_bo_destroy(bo);
    349         return FALSE;
    350     }
    351     gbm_bo_destroy(bo);
    352 
    353     scratch_gc = GetScratchGC(pixmap->drawable.depth, screen);
    354     ValidateGC(&pixmap->drawable, scratch_gc);
    355     scratch_gc->ops->CopyArea(&pixmap->drawable, &exported->drawable,
    356                               scratch_gc,
    357                               0, 0, width, height, 0, 0);
    358     FreeScratchGC(scratch_gc);
    359 
    360     /* Now, swap the tex/gbm/EGLImage/etc. of the exported pixmap into
    361      * the original pixmap struct.
    362      */
    363     glamor_egl_exchange_buffers(pixmap, exported);
    364 
    365     /* Swap the devKind into the original pixmap, reflecting the bo's stride */
    366     screen->ModifyPixmapHeader(pixmap, 0, 0, 0, 0, exported->devKind, NULL);
    367 
    368     screen->DestroyPixmap(exported);
    369 
    370     return TRUE;
    371 }
    372 
    373 static struct gbm_bo *
    374 glamor_gbm_bo_from_pixmap_internal(ScreenPtr screen, PixmapPtr pixmap)
    375 {
    376     struct glamor_egl_screen_private *glamor_egl =
    377         glamor_egl_get_screen_private(xf86ScreenToScrn(screen));
    378     struct glamor_pixmap_private *pixmap_priv =
    379         glamor_get_pixmap_private(pixmap);
    380 
    381     if (!pixmap_priv->image)
    382         return NULL;
    383 
    384     return gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_EGL_IMAGE,
    385                          pixmap_priv->image, 0);
    386 }
    387 
    388 struct gbm_bo *
    389 glamor_gbm_bo_from_pixmap(ScreenPtr screen, PixmapPtr pixmap)
    390 {
    391     if (!glamor_make_pixmap_exportable(pixmap, TRUE))
    392         return NULL;
    393 
    394     return glamor_gbm_bo_from_pixmap_internal(screen, pixmap);
    395 }
    396 
    397 int
    398 glamor_egl_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds,
    399                            uint32_t *strides, uint32_t *offsets,
    400                            uint64_t *modifier)
    401 {
    402 #ifdef GLAMOR_HAS_GBM
    403     struct gbm_bo *bo;
    404     int num_fds;
    405 #ifdef GBM_BO_WITH_MODIFIERS
    406     int i;
    407 #endif
    408 
    409     if (!glamor_make_pixmap_exportable(pixmap, TRUE))
    410         return 0;
    411 
    412     bo = glamor_gbm_bo_from_pixmap_internal(screen, pixmap);
    413     if (!bo)
    414         return 0;
    415 
    416 #ifdef GBM_BO_WITH_MODIFIERS
    417     num_fds = gbm_bo_get_plane_count(bo);
    418     for (i = 0; i < num_fds; i++) {
    419         fds[i] = gbm_bo_get_fd(bo);
    420         strides[i] = gbm_bo_get_stride_for_plane(bo, i);
    421         offsets[i] = gbm_bo_get_offset(bo, i);
    422     }
    423     *modifier = gbm_bo_get_modifier(bo);
    424 #else
    425     num_fds = 1;
    426     fds[0] = gbm_bo_get_fd(bo);
    427     strides[0] = gbm_bo_get_stride(bo);
    428     offsets[0] = 0;
    429     *modifier = DRM_FORMAT_MOD_INVALID;
    430 #endif
    431 
    432     gbm_bo_destroy(bo);
    433     return num_fds;
    434 #else
    435     return 0;
    436 #endif
    437 }
    438 
    439 _X_EXPORT int
    440 glamor_egl_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap,
    441                           CARD16 *stride, CARD32 *size)
    442 {
    443 #ifdef GLAMOR_HAS_GBM
    444     struct gbm_bo *bo;
    445     int fd;
    446 
    447     if (!glamor_make_pixmap_exportable(pixmap, FALSE))
    448         return -1;
    449 
    450     bo = glamor_gbm_bo_from_pixmap_internal(screen, pixmap);
    451     if (!bo)
    452         return -1;
    453 
    454     fd = gbm_bo_get_fd(bo);
    455     *stride = gbm_bo_get_stride(bo);
    456     *size = *stride * gbm_bo_get_height(bo);
    457     gbm_bo_destroy(bo);
    458 
    459     return fd;
    460 #else
    461     return -1;
    462 #endif
    463 }
    464 
    465 int
    466 glamor_egl_fd_name_from_pixmap(ScreenPtr screen,
    467                                PixmapPtr pixmap,
    468                                CARD16 *stride, CARD32 *size)
    469 {
    470     struct glamor_egl_screen_private *glamor_egl;
    471     struct gbm_bo *bo;
    472     int fd = -1;
    473 
    474     glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen));
    475 
    476     if (!glamor_make_pixmap_exportable(pixmap, FALSE))
    477         goto failure;
    478 
    479     bo = glamor_gbm_bo_from_pixmap_internal(screen, pixmap);
    480     if (!bo)
    481         goto failure;
    482 
    483     pixmap->devKind = gbm_bo_get_stride(bo);
    484 
    485     glamor_get_name_from_bo(glamor_egl->fd, bo, &fd);
    486     *stride = pixmap->devKind;
    487     *size = pixmap->devKind * gbm_bo_get_height(bo);
    488 
    489     gbm_bo_destroy(bo);
    490  failure:
    491     return fd;
    492 }
    493 
    494 _X_EXPORT Bool
    495 glamor_back_pixmap_from_fd(PixmapPtr pixmap,
    496                            int fd,
    497                            CARD16 width,
    498                            CARD16 height,
    499                            CARD16 stride, CARD8 depth, CARD8 bpp)
    500 {
    501     ScreenPtr screen = pixmap->drawable.pScreen;
    502     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    503     struct glamor_egl_screen_private *glamor_egl;
    504     struct gbm_bo *bo;
    505     struct gbm_import_fd_data import_data = { 0 };
    506     Bool ret;
    507 
    508     glamor_egl = glamor_egl_get_screen_private(scrn);
    509 
    510     if (bpp != 32 || !(depth == 24 || depth == 32 || depth == 30) || width == 0 || height == 0)
    511         return FALSE;
    512 
    513     import_data.fd = fd;
    514     import_data.width = width;
    515     import_data.height = height;
    516     import_data.stride = stride;
    517     if (depth == 30)
    518         import_data.format = GBM_FORMAT_ARGB2101010;
    519     else
    520         import_data.format = GBM_FORMAT_ARGB8888;
    521     bo = gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_FD, &import_data, 0);
    522     if (!bo)
    523         return FALSE;
    524 
    525     screen->ModifyPixmapHeader(pixmap, width, height, 0, 0, stride, NULL);
    526 
    527     ret = glamor_egl_create_textured_pixmap_from_gbm_bo(pixmap, bo, FALSE);
    528     gbm_bo_destroy(bo);
    529     return ret;
    530 }
    531 
    532 static uint32_t
    533 gbm_format_for_depth(CARD8 depth)
    534 {
    535     switch (depth) {
    536     case 16:
    537         return GBM_FORMAT_RGB565;
    538     case 24:
    539         return GBM_FORMAT_XRGB8888;
    540     case 30:
    541         return GBM_FORMAT_ARGB2101010;
    542     default:
    543         ErrorF("unexpected depth: %d\n", depth);
    544     case 32:
    545         return GBM_FORMAT_ARGB8888;
    546     }
    547 }
    548 
    549 _X_EXPORT PixmapPtr
    550 glamor_pixmap_from_fds(ScreenPtr screen,
    551                        CARD8 num_fds, const int *fds,
    552                        CARD16 width, CARD16 height,
    553                        const CARD32 *strides, const CARD32 *offsets,
    554                        CARD8 depth, CARD8 bpp,
    555                        uint64_t modifier)
    556 {
    557     PixmapPtr pixmap;
    558     struct glamor_egl_screen_private *glamor_egl;
    559     Bool ret = FALSE;
    560     int i;
    561 
    562     glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen));
    563 
    564     pixmap = screen->CreatePixmap(screen, 0, 0, depth, 0);
    565 
    566 #ifdef GBM_BO_WITH_MODIFIERS
    567     if (glamor_egl->dmabuf_capable && modifier != DRM_FORMAT_MOD_INVALID) {
    568         struct gbm_import_fd_modifier_data import_data = { 0 };
    569         struct gbm_bo *bo;
    570 
    571         import_data.width = width;
    572         import_data.height = height;
    573         import_data.num_fds = num_fds;
    574         import_data.modifier = modifier;
    575         for (i = 0; i < num_fds; i++) {
    576             import_data.fds[i] = fds[i];
    577             import_data.strides[i] = strides[i];
    578             import_data.offsets[i] = offsets[i];
    579         }
    580         import_data.format = gbm_format_for_depth(depth);
    581         bo = gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_FD_MODIFIER, &import_data, 0);
    582         if (bo) {
    583             screen->ModifyPixmapHeader(pixmap, width, height, 0, 0, strides[0], NULL);
    584             ret = glamor_egl_create_textured_pixmap_from_gbm_bo(pixmap, bo, TRUE);
    585             gbm_bo_destroy(bo);
    586         }
    587     } else
    588 #endif
    589     {
    590         if (num_fds == 1) {
    591             ret = glamor_back_pixmap_from_fd(pixmap, fds[0], width, height,
    592                                              strides[0], depth, bpp);
    593         }
    594     }
    595 
    596     if (ret == FALSE) {
    597         screen->DestroyPixmap(pixmap);
    598         return NULL;
    599     }
    600     return pixmap;
    601 }
    602 
    603 _X_EXPORT PixmapPtr
    604 glamor_pixmap_from_fd(ScreenPtr screen,
    605                       int fd,
    606                       CARD16 width,
    607                       CARD16 height,
    608                       CARD16 stride, CARD8 depth, CARD8 bpp)
    609 {
    610     PixmapPtr pixmap;
    611     Bool ret;
    612 
    613     pixmap = screen->CreatePixmap(screen, 0, 0, depth, 0);
    614 
    615     ret = glamor_back_pixmap_from_fd(pixmap, fd, width, height,
    616                                      stride, depth, bpp);
    617 
    618     if (ret == FALSE) {
    619         screen->DestroyPixmap(pixmap);
    620         return NULL;
    621     }
    622     return pixmap;
    623 }
    624 
    625 _X_EXPORT Bool
    626 glamor_get_formats(ScreenPtr screen,
    627                    CARD32 *num_formats, CARD32 **formats)
    628 {
    629 #ifdef GLAMOR_HAS_EGL_QUERY_DMABUF
    630     struct glamor_egl_screen_private *glamor_egl;
    631     EGLint num;
    632 
    633     /* Explicitly zero the count as the caller may ignore the return value */
    634     *num_formats = 0;
    635 
    636     glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen));
    637 
    638     if (!glamor_egl->dmabuf_capable)
    639         return TRUE;
    640 
    641     if (!eglQueryDmaBufFormatsEXT(glamor_egl->display, 0, NULL, &num))
    642         return FALSE;
    643 
    644     if (num == 0)
    645         return TRUE;
    646 
    647     *formats = calloc(num, sizeof(CARD32));
    648     if (*formats == NULL)
    649         return FALSE;
    650 
    651     if (!eglQueryDmaBufFormatsEXT(glamor_egl->display, num,
    652                                   (EGLint *) *formats, &num)) {
    653         free(*formats);
    654         return FALSE;
    655     }
    656 
    657     *num_formats = num;
    658     return TRUE;
    659 #else
    660     *num_formats = 0;
    661     return TRUE;
    662 #endif
    663 }
    664 
    665 _X_EXPORT Bool
    666 glamor_get_modifiers(ScreenPtr screen, uint32_t format,
    667                      uint32_t *num_modifiers, uint64_t **modifiers)
    668 {
    669 #ifdef GLAMOR_HAS_EGL_QUERY_DMABUF
    670     struct glamor_egl_screen_private *glamor_egl;
    671     EGLint num;
    672 
    673     /* Explicitly zero the count as the caller may ignore the return value */
    674     *num_modifiers = 0;
    675 
    676     glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen));
    677 
    678     if (!glamor_egl->dmabuf_capable)
    679         return FALSE;
    680 
    681     if (!eglQueryDmaBufModifiersEXT(glamor_egl->display, format, 0, NULL,
    682                                     NULL, &num))
    683         return FALSE;
    684 
    685     if (num == 0)
    686         return TRUE;
    687 
    688     *modifiers = calloc(num, sizeof(uint64_t));
    689     if (*modifiers == NULL)
    690         return FALSE;
    691 
    692     if (!eglQueryDmaBufModifiersEXT(glamor_egl->display, format, num,
    693                                     (EGLuint64KHR *) *modifiers, NULL, &num)) {
    694         free(*modifiers);
    695         return FALSE;
    696     }
    697 
    698     *num_modifiers = num;
    699     return TRUE;
    700 #else
    701     *num_modifiers = 0;
    702     return TRUE;
    703 #endif
    704 }
    705 
    706 _X_EXPORT const char *
    707 glamor_egl_get_driver_name(ScreenPtr screen)
    708 {
    709 #ifdef GLAMOR_HAS_EGL_QUERY_DRIVER
    710     struct glamor_egl_screen_private *glamor_egl;
    711 
    712     glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen));
    713 
    714     if (epoxy_has_egl_extension(glamor_egl->display, "EGL_MESA_query_driver"))
    715         return eglGetDisplayDriverName(glamor_egl->display);
    716 #endif
    717 
    718     return NULL;
    719 }
    720 
    721 
    722 static Bool
    723 glamor_egl_destroy_pixmap(PixmapPtr pixmap)
    724 {
    725     ScreenPtr screen = pixmap->drawable.pScreen;
    726     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    727     struct glamor_egl_screen_private *glamor_egl =
    728         glamor_egl_get_screen_private(scrn);
    729     Bool ret;
    730 
    731     if (pixmap->refcnt == 1) {
    732         struct glamor_pixmap_private *pixmap_priv =
    733             glamor_get_pixmap_private(pixmap);
    734 
    735         if (pixmap_priv->image)
    736             eglDestroyImageKHR(glamor_egl->display, pixmap_priv->image);
    737     }
    738 
    739     screen->DestroyPixmap = glamor_egl->saved_destroy_pixmap;
    740     ret = screen->DestroyPixmap(pixmap);
    741     glamor_egl->saved_destroy_pixmap = screen->DestroyPixmap;
    742     screen->DestroyPixmap = glamor_egl_destroy_pixmap;
    743 
    744     return ret;
    745 }
    746 
    747 _X_EXPORT void
    748 glamor_egl_exchange_buffers(PixmapPtr front, PixmapPtr back)
    749 {
    750     EGLImageKHR temp_img;
    751     Bool temp_mod;
    752     struct glamor_pixmap_private *front_priv =
    753         glamor_get_pixmap_private(front);
    754     struct glamor_pixmap_private *back_priv =
    755         glamor_get_pixmap_private(back);
    756 
    757     glamor_pixmap_exchange_fbos(front, back);
    758 
    759     temp_img = back_priv->image;
    760     temp_mod = back_priv->used_modifiers;
    761     back_priv->image = front_priv->image;
    762     back_priv->used_modifiers = front_priv->used_modifiers;
    763     front_priv->image = temp_img;
    764     front_priv->used_modifiers = temp_mod;
    765 
    766     glamor_set_pixmap_type(front, GLAMOR_TEXTURE_DRM);
    767     glamor_set_pixmap_type(back, GLAMOR_TEXTURE_DRM);
    768 }
    769 
    770 static Bool
    771 glamor_egl_close_screen(ScreenPtr screen)
    772 {
    773     ScrnInfoPtr scrn;
    774     struct glamor_egl_screen_private *glamor_egl;
    775     struct glamor_pixmap_private *pixmap_priv;
    776     PixmapPtr screen_pixmap;
    777 
    778     scrn = xf86ScreenToScrn(screen);
    779     glamor_egl = glamor_egl_get_screen_private(scrn);
    780     screen_pixmap = screen->GetScreenPixmap(screen);
    781     pixmap_priv = glamor_get_pixmap_private(screen_pixmap);
    782 
    783     eglDestroyImageKHR(glamor_egl->display, pixmap_priv->image);
    784     pixmap_priv->image = NULL;
    785 
    786     screen->CloseScreen = glamor_egl->saved_close_screen;
    787 
    788     return screen->CloseScreen(screen);
    789 }
    790 
    791 #ifdef DRI3
    792 static int
    793 glamor_dri3_open_client(ClientPtr client,
    794                         ScreenPtr screen,
    795                         RRProviderPtr provider,
    796                         int *fdp)
    797 {
    798     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    799     struct glamor_egl_screen_private *glamor_egl =
    800         glamor_egl_get_screen_private(scrn);
    801     int fd;
    802     drm_magic_t magic;
    803 
    804     fd = open(glamor_egl->device_path, O_RDWR|O_CLOEXEC);
    805     if (fd < 0)
    806         return BadAlloc;
    807 
    808     /* Before FD passing in the X protocol with DRI3 (and increased
    809      * security of rendering with per-process address spaces on the
    810      * GPU), the kernel had to come up with a way to have the server
    811      * decide which clients got to access the GPU, which was done by
    812      * each client getting a unique (magic) number from the kernel,
    813      * passing it to the server, and the server then telling the
    814      * kernel which clients were authenticated for using the device.
    815      *
    816      * Now that we have FD passing, the server can just set up the
    817      * authentication on its own and hand the prepared FD off to the
    818      * client.
    819      */
    820     if (drmGetMagic(fd, &magic) < 0) {
    821         if (errno == EACCES) {
    822             /* Assume that we're on a render node, and the fd is
    823              * already as authenticated as it should be.
    824              */
    825             *fdp = fd;
    826             return Success;
    827         } else {
    828             close(fd);
    829             return BadMatch;
    830         }
    831     }
    832 
    833     if (drmAuthMagic(glamor_egl->fd, magic) < 0) {
    834         close(fd);
    835         return BadMatch;
    836     }
    837 
    838     *fdp = fd;
    839     return Success;
    840 }
    841 
    842 static const dri3_screen_info_rec glamor_dri3_info = {
    843     .version = 2,
    844     .open_client = glamor_dri3_open_client,
    845     .pixmap_from_fds = glamor_pixmap_from_fds,
    846     .fd_from_pixmap = glamor_egl_fd_from_pixmap,
    847     .fds_from_pixmap = glamor_egl_fds_from_pixmap,
    848     .get_formats = glamor_get_formats,
    849     .get_modifiers = glamor_get_modifiers,
    850     .get_drawable_modifiers = glamor_get_drawable_modifiers,
    851 };
    852 #endif /* DRI3 */
    853 
    854 void
    855 glamor_egl_screen_init(ScreenPtr screen, struct glamor_context *glamor_ctx)
    856 {
    857     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    858     struct glamor_egl_screen_private *glamor_egl =
    859         glamor_egl_get_screen_private(scrn);
    860 #ifdef DRI3
    861     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
    862 #endif
    863 
    864     glamor_egl->saved_close_screen = screen->CloseScreen;
    865     screen->CloseScreen = glamor_egl_close_screen;
    866 
    867     glamor_egl->saved_destroy_pixmap = screen->DestroyPixmap;
    868     screen->DestroyPixmap = glamor_egl_destroy_pixmap;
    869 
    870     glamor_ctx->ctx = glamor_egl->context;
    871     glamor_ctx->display = glamor_egl->display;
    872 
    873     glamor_ctx->make_current = glamor_egl_make_current;
    874 
    875 #ifdef DRI3
    876     /* Tell the core that we have the interfaces for import/export
    877      * of pixmaps.
    878      */
    879     glamor_enable_dri3(screen);
    880 
    881     /* If the driver wants to do its own auth dance (e.g. Xwayland
    882      * on pre-3.15 kernels that don't have render nodes and thus
    883      * has the wayland compositor as a master), then it needs us
    884      * to stay out of the way and let it init DRI3 on its own.
    885      */
    886     if (!(glamor_priv->flags & GLAMOR_NO_DRI3)) {
    887         /* To do DRI3 device FD generation, we need to open a new fd
    888          * to the same device we were handed in originally.
    889          */
    890         glamor_egl->device_path = drmGetDeviceNameFromFd2(glamor_egl->fd);
    891 
    892         if (!dri3_screen_init(screen, &glamor_dri3_info)) {
    893             xf86DrvMsg(scrn->scrnIndex, X_ERROR,
    894                        "Failed to initialize DRI3.\n");
    895         }
    896     }
    897 #endif
    898 }
    899 
    900 static void glamor_egl_cleanup(struct glamor_egl_screen_private *glamor_egl)
    901 {
    902     if (glamor_egl->display != EGL_NO_DISPLAY) {
    903         eglMakeCurrent(glamor_egl->display,
    904                        EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    905         /*
    906          * Force the next glamor_make_current call to update the context
    907          * (on hot unplug another GPU may still be using glamor)
    908          */
    909         lastGLContext = NULL;
    910         eglTerminate(glamor_egl->display);
    911     }
    912     if (glamor_egl->gbm)
    913         gbm_device_destroy(glamor_egl->gbm);
    914     free(glamor_egl->device_path);
    915     free(glamor_egl);
    916 }
    917 
    918 static void
    919 glamor_egl_free_screen(ScrnInfoPtr scrn)
    920 {
    921     struct glamor_egl_screen_private *glamor_egl;
    922 
    923     glamor_egl = glamor_egl_get_screen_private(scrn);
    924     if (glamor_egl != NULL) {
    925         scrn->FreeScreen = glamor_egl->saved_free_screen;
    926         glamor_egl_cleanup(glamor_egl);
    927         scrn->FreeScreen(scrn);
    928     }
    929 }
    930 
    931 Bool
    932 glamor_egl_init(ScrnInfoPtr scrn, int fd)
    933 {
    934     struct glamor_egl_screen_private *glamor_egl;
    935     const GLubyte *renderer;
    936     EGLConfig egl_config;
    937     int n;
    938 
    939     glamor_egl = calloc(sizeof(*glamor_egl), 1);
    940     if (glamor_egl == NULL)
    941         return FALSE;
    942     if (xf86GlamorEGLPrivateIndex == -1)
    943         xf86GlamorEGLPrivateIndex = xf86AllocateScrnInfoPrivateIndex();
    944 
    945     scrn->privates[xf86GlamorEGLPrivateIndex].ptr = glamor_egl;
    946     glamor_egl->fd = fd;
    947     glamor_egl->gbm = gbm_create_device(glamor_egl->fd);
    948     if (glamor_egl->gbm == NULL) {
    949         ErrorF("couldn't get display device\n");
    950         goto error;
    951     }
    952 
    953     glamor_egl->display = glamor_egl_get_display(EGL_PLATFORM_GBM_MESA,
    954                                                  glamor_egl->gbm);
    955     if (!glamor_egl->display) {
    956         xf86DrvMsg(scrn->scrnIndex, X_ERROR, "eglGetDisplay() failed\n");
    957         goto error;
    958     }
    959 
    960     if (!eglInitialize(glamor_egl->display, NULL, NULL)) {
    961         xf86DrvMsg(scrn->scrnIndex, X_ERROR, "eglInitialize() failed\n");
    962         glamor_egl->display = EGL_NO_DISPLAY;
    963         goto error;
    964     }
    965 
    966 #define GLAMOR_CHECK_EGL_EXTENSION(EXT)  \
    967 	if (!epoxy_has_egl_extension(glamor_egl->display, "EGL_" #EXT)) {  \
    968 		ErrorF("EGL_" #EXT " required.\n");  \
    969 		goto error;  \
    970 	}
    971 
    972 #define GLAMOR_CHECK_EGL_EXTENSIONS(EXT1, EXT2)	 \
    973 	if (!epoxy_has_egl_extension(glamor_egl->display, "EGL_" #EXT1) &&  \
    974 	    !epoxy_has_egl_extension(glamor_egl->display, "EGL_" #EXT2)) {  \
    975 		ErrorF("EGL_" #EXT1 " or EGL_" #EXT2 " required.\n");  \
    976 		goto error;  \
    977 	}
    978 
    979     GLAMOR_CHECK_EGL_EXTENSION(KHR_surfaceless_context);
    980 
    981     if (eglBindAPI(EGL_OPENGL_API)) {
    982         static const EGLint config_attribs_core[] = {
    983             EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR,
    984             EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR,
    985             EGL_CONTEXT_MAJOR_VERSION_KHR,
    986             GLAMOR_GL_CORE_VER_MAJOR,
    987             EGL_CONTEXT_MINOR_VERSION_KHR,
    988             GLAMOR_GL_CORE_VER_MINOR,
    989             EGL_NONE
    990         };
    991         static const EGLint config_attribs[] = {
    992             EGL_NONE
    993         };
    994 
    995         glamor_egl->context = eglCreateContext(glamor_egl->display,
    996                                                NULL, EGL_NO_CONTEXT,
    997                                                config_attribs_core);
    998 
    999         if (glamor_egl->context == EGL_NO_CONTEXT)
   1000             glamor_egl->context = eglCreateContext(glamor_egl->display,
   1001                                                    NULL, EGL_NO_CONTEXT,
   1002                                                    config_attribs);
   1003     }
   1004 
   1005     if (glamor_egl->context != EGL_NO_CONTEXT) {
   1006         if (!eglMakeCurrent(glamor_egl->display,
   1007                             EGL_NO_SURFACE, EGL_NO_SURFACE, glamor_egl->context)) {
   1008             xf86DrvMsg(scrn->scrnIndex, X_ERROR,
   1009                        "Failed to make GL context current\n");
   1010             goto error;
   1011         }
   1012 
   1013         if (epoxy_gl_version() < 21) {
   1014             xf86DrvMsg(scrn->scrnIndex, X_INFO,
   1015                        "glamor: Ignoring GL < 2.1, falling back to GLES.\n");
   1016             eglDestroyContext(glamor_egl->display, glamor_egl->context);
   1017             glamor_egl->context = EGL_NO_CONTEXT;
   1018         }
   1019     }
   1020 
   1021     if (glamor_egl->context == EGL_NO_CONTEXT) {
   1022         static const EGLint config_attribs[] = {
   1023             EGL_CONTEXT_CLIENT_VERSION, 2,
   1024             EGL_NONE
   1025         };
   1026         if (!eglBindAPI(EGL_OPENGL_ES_API)) {
   1027             xf86DrvMsg(scrn->scrnIndex, X_ERROR,
   1028                        "glamor: Failed to bind either GL or GLES APIs.\n");
   1029             goto error;
   1030         }
   1031 
   1032         if (!eglChooseConfig(glamor_egl->display, NULL, &egl_config, 1, &n)) {
   1033             xf86DrvMsg(scrn->scrnIndex, X_ERROR,
   1034                        "glamor: No acceptable EGL configs found\n");
   1035             goto error;
   1036         }
   1037 
   1038         glamor_egl->context = eglCreateContext(glamor_egl->display,
   1039                                                egl_config, EGL_NO_CONTEXT,
   1040                                                config_attribs);
   1041 
   1042         if (glamor_egl->context == EGL_NO_CONTEXT) {
   1043             xf86DrvMsg(scrn->scrnIndex, X_ERROR,
   1044                        "glamor: Failed to create GL or GLES2 contexts\n");
   1045             goto error;
   1046         }
   1047 
   1048         if (!eglMakeCurrent(glamor_egl->display,
   1049                             EGL_NO_SURFACE, EGL_NO_SURFACE, glamor_egl->context)) {
   1050             xf86DrvMsg(scrn->scrnIndex, X_ERROR,
   1051                        "Failed to make GLES2 context current\n");
   1052             goto error;
   1053         }
   1054     }
   1055 
   1056     renderer = glGetString(GL_RENDERER);
   1057     if (!renderer) {
   1058         xf86DrvMsg(scrn->scrnIndex, X_ERROR,
   1059                    "glGetString() returned NULL, your GL is broken\n");
   1060         goto error;
   1061     }
   1062     if (strstr((const char *)renderer, "llvmpipe")) {
   1063         if (scrn->confScreen->num_gpu_devices)
   1064             xf86DrvMsg(scrn->scrnIndex, X_INFO,
   1065                        "Allowing glamor on llvmpipe for PRIME\n");
   1066         else {
   1067             xf86DrvMsg(scrn->scrnIndex, X_INFO,
   1068                        "Refusing to try glamor on llvmpipe\n");
   1069             goto error;
   1070         }
   1071     }
   1072 
   1073     /*
   1074      * Force the next glamor_make_current call to set the right context
   1075      * (in case of multiple GPUs using glamor)
   1076      */
   1077     lastGLContext = NULL;
   1078 
   1079     if (!epoxy_has_gl_extension("GL_OES_EGL_image")) {
   1080         xf86DrvMsg(scrn->scrnIndex, X_ERROR,
   1081                    "glamor acceleration requires GL_OES_EGL_image\n");
   1082         goto error;
   1083     }
   1084 
   1085     xf86DrvMsg(scrn->scrnIndex, X_INFO, "glamor X acceleration enabled on %s\n",
   1086                renderer);
   1087 
   1088 #ifdef GBM_BO_WITH_MODIFIERS
   1089     if (epoxy_has_egl_extension(glamor_egl->display,
   1090                                 "EGL_EXT_image_dma_buf_import") &&
   1091         epoxy_has_egl_extension(glamor_egl->display,
   1092                                 "EGL_EXT_image_dma_buf_import_modifiers")) {
   1093         if (xf86Info.debug != NULL)
   1094             glamor_egl->dmabuf_capable = !!strstr(xf86Info.debug,
   1095                                                   "dmabuf_capable");
   1096         else
   1097             glamor_egl->dmabuf_capable = FALSE;
   1098     }
   1099 #endif
   1100 
   1101     glamor_egl->saved_free_screen = scrn->FreeScreen;
   1102     scrn->FreeScreen = glamor_egl_free_screen;
   1103     return TRUE;
   1104 
   1105 error:
   1106     glamor_egl_cleanup(glamor_egl);
   1107     return FALSE;
   1108 }
   1109 
   1110 /** Stub to retain compatibility with pre-server-1.16 ABI. */
   1111 Bool
   1112 glamor_egl_init_textured_pixmap(ScreenPtr screen)
   1113 {
   1114     return TRUE;
   1115 }