Home | History | Annotate | Line # | Download | only in glamor
      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 (at) 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 #ifndef GBM_BO_FD_FOR_PLANE
    407     int32_t first_handle;
    408 #endif
    409     int i;
    410 #endif
    411 
    412     if (!glamor_make_pixmap_exportable(pixmap, TRUE))
    413         return 0;
    414 
    415     bo = glamor_gbm_bo_from_pixmap_internal(screen, pixmap);
    416     if (!bo)
    417         return 0;
    418 
    419 #ifdef GBM_BO_WITH_MODIFIERS
    420     num_fds = gbm_bo_get_plane_count(bo);
    421     for (i = 0; i < num_fds; i++) {
    422 #ifdef GBM_BO_FD_FOR_PLANE
    423         fds[i] = gbm_bo_get_fd_for_plane(bo, i);
    424 #else
    425         union gbm_bo_handle plane_handle = gbm_bo_get_handle_for_plane(bo, i);
    426 
    427         if (i == 0)
    428             first_handle = plane_handle.s32;
    429 
    430         /* If all planes point to the same object as the first plane, i.e. they
    431          * all have the same handle, we can fall back to the non-planar
    432          * gbm_bo_get_fd without losing information. If they point to different
    433          * objects we are out of luck and need to give up.
    434          */
    435 	if (first_handle == plane_handle.s32)
    436             fds[i] = gbm_bo_get_fd(bo);
    437         else
    438             fds[i] = -1;
    439 #endif
    440         if (fds[i] == -1) {
    441             while (--i >= 0)
    442                 close(fds[i]);
    443             return 0;
    444         }
    445         strides[i] = gbm_bo_get_stride_for_plane(bo, i);
    446         offsets[i] = gbm_bo_get_offset(bo, i);
    447     }
    448     *modifier = gbm_bo_get_modifier(bo);
    449 #else
    450     num_fds = 1;
    451     fds[0] = gbm_bo_get_fd(bo);
    452     if (fds[0] == -1)
    453         return 0;
    454     strides[0] = gbm_bo_get_stride(bo);
    455     offsets[0] = 0;
    456     *modifier = DRM_FORMAT_MOD_INVALID;
    457 #endif
    458 
    459     gbm_bo_destroy(bo);
    460     return num_fds;
    461 #else
    462     return 0;
    463 #endif
    464 }
    465 
    466 _X_EXPORT int
    467 glamor_egl_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap,
    468                           CARD16 *stride, CARD32 *size)
    469 {
    470 #ifdef GLAMOR_HAS_GBM
    471     struct gbm_bo *bo;
    472     int fd;
    473 
    474     if (!glamor_make_pixmap_exportable(pixmap, FALSE))
    475         return -1;
    476 
    477     bo = glamor_gbm_bo_from_pixmap_internal(screen, pixmap);
    478     if (!bo)
    479         return -1;
    480 
    481     fd = gbm_bo_get_fd(bo);
    482     *stride = gbm_bo_get_stride(bo);
    483     *size = *stride * gbm_bo_get_height(bo);
    484     gbm_bo_destroy(bo);
    485 
    486     return fd;
    487 #else
    488     return -1;
    489 #endif
    490 }
    491 
    492 int
    493 glamor_egl_fd_name_from_pixmap(ScreenPtr screen,
    494                                PixmapPtr pixmap,
    495                                CARD16 *stride, CARD32 *size)
    496 {
    497     struct glamor_egl_screen_private *glamor_egl;
    498     struct gbm_bo *bo;
    499     int fd = -1;
    500 
    501     glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen));
    502 
    503     if (!glamor_make_pixmap_exportable(pixmap, FALSE))
    504         goto failure;
    505 
    506     bo = glamor_gbm_bo_from_pixmap_internal(screen, pixmap);
    507     if (!bo)
    508         goto failure;
    509 
    510     pixmap->devKind = gbm_bo_get_stride(bo);
    511 
    512     glamor_get_name_from_bo(glamor_egl->fd, bo, &fd);
    513     *stride = pixmap->devKind;
    514     *size = pixmap->devKind * gbm_bo_get_height(bo);
    515 
    516     gbm_bo_destroy(bo);
    517  failure:
    518     return fd;
    519 }
    520 
    521 static bool
    522 gbm_format_for_depth(CARD8 depth, uint32_t *format)
    523 {
    524     switch (depth) {
    525     case 15:
    526         *format = GBM_FORMAT_ARGB1555;
    527         return true;
    528     case 16:
    529         *format = GBM_FORMAT_RGB565;
    530         return true;
    531     case 24:
    532         *format = GBM_FORMAT_XRGB8888;
    533         return true;
    534     case 30:
    535         *format = GBM_FORMAT_ARGB2101010;
    536         return true;
    537     case 32:
    538         *format = GBM_FORMAT_ARGB8888;
    539         return true;
    540     default:
    541         ErrorF("unexpected depth: %d\n", depth);
    542         return false;
    543     }
    544 }
    545 
    546 _X_EXPORT Bool
    547 glamor_back_pixmap_from_fd(PixmapPtr pixmap,
    548                            int fd,
    549                            CARD16 width,
    550                            CARD16 height,
    551                            CARD16 stride, CARD8 depth, CARD8 bpp)
    552 {
    553     ScreenPtr screen = pixmap->drawable.pScreen;
    554     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    555     struct glamor_egl_screen_private *glamor_egl;
    556     struct gbm_bo *bo;
    557     struct gbm_import_fd_data import_data = { 0 };
    558     Bool ret;
    559 
    560     glamor_egl = glamor_egl_get_screen_private(scrn);
    561 
    562     if (!gbm_format_for_depth(depth, &import_data.format) ||
    563         width == 0 || height == 0)
    564         return FALSE;
    565 
    566     import_data.fd = fd;
    567     import_data.width = width;
    568     import_data.height = height;
    569     import_data.stride = stride;
    570     bo = gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_FD, &import_data, 0);
    571     if (!bo)
    572         return FALSE;
    573 
    574     screen->ModifyPixmapHeader(pixmap, width, height, 0, 0, stride, NULL);
    575 
    576     ret = glamor_egl_create_textured_pixmap_from_gbm_bo(pixmap, bo, FALSE);
    577     gbm_bo_destroy(bo);
    578     return ret;
    579 }
    580 
    581 _X_EXPORT PixmapPtr
    582 glamor_pixmap_from_fds(ScreenPtr screen,
    583                        CARD8 num_fds, const int *fds,
    584                        CARD16 width, CARD16 height,
    585                        const CARD32 *strides, const CARD32 *offsets,
    586                        CARD8 depth, CARD8 bpp,
    587                        uint64_t modifier)
    588 {
    589     PixmapPtr pixmap;
    590     struct glamor_egl_screen_private *glamor_egl;
    591     Bool ret = FALSE;
    592     int i;
    593 
    594     glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen));
    595 
    596     pixmap = screen->CreatePixmap(screen, 0, 0, depth, 0);
    597 
    598 #ifdef GBM_BO_WITH_MODIFIERS
    599     if (glamor_egl->dmabuf_capable && modifier != DRM_FORMAT_MOD_INVALID) {
    600         struct gbm_import_fd_modifier_data import_data = { 0 };
    601         struct gbm_bo *bo;
    602 
    603         if (!gbm_format_for_depth(depth, &import_data.format) ||
    604             width == 0 || height == 0)
    605             goto error;
    606 
    607         import_data.width = width;
    608         import_data.height = height;
    609         import_data.num_fds = num_fds;
    610         import_data.modifier = modifier;
    611         for (i = 0; i < num_fds; i++) {
    612             import_data.fds[i] = fds[i];
    613             import_data.strides[i] = strides[i];
    614             import_data.offsets[i] = offsets[i];
    615         }
    616         bo = gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_FD_MODIFIER, &import_data, 0);
    617         if (bo) {
    618             screen->ModifyPixmapHeader(pixmap, width, height, 0, 0, strides[0], NULL);
    619             ret = glamor_egl_create_textured_pixmap_from_gbm_bo(pixmap, bo, TRUE);
    620             gbm_bo_destroy(bo);
    621         }
    622     } else
    623 #endif
    624     {
    625         if (num_fds == 1) {
    626             ret = glamor_back_pixmap_from_fd(pixmap, fds[0], width, height,
    627                                              strides[0], depth, bpp);
    628         }
    629     }
    630 
    631 error:
    632     if (ret == FALSE) {
    633         screen->DestroyPixmap(pixmap);
    634         return NULL;
    635     }
    636     return pixmap;
    637 }
    638 
    639 _X_EXPORT PixmapPtr
    640 glamor_pixmap_from_fd(ScreenPtr screen,
    641                       int fd,
    642                       CARD16 width,
    643                       CARD16 height,
    644                       CARD16 stride, CARD8 depth, CARD8 bpp)
    645 {
    646     PixmapPtr pixmap;
    647     Bool ret;
    648 
    649     pixmap = screen->CreatePixmap(screen, 0, 0, depth, 0);
    650 
    651     ret = glamor_back_pixmap_from_fd(pixmap, fd, width, height,
    652                                      stride, depth, bpp);
    653 
    654     if (ret == FALSE) {
    655         screen->DestroyPixmap(pixmap);
    656         return NULL;
    657     }
    658     return pixmap;
    659 }
    660 
    661 _X_EXPORT Bool
    662 glamor_get_formats(ScreenPtr screen,
    663                    CARD32 *num_formats, CARD32 **formats)
    664 {
    665 #ifdef GLAMOR_HAS_EGL_QUERY_DMABUF
    666     struct glamor_egl_screen_private *glamor_egl;
    667     EGLint num;
    668 
    669     /* Explicitly zero the count as the caller may ignore the return value */
    670     *num_formats = 0;
    671 
    672     glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen));
    673 
    674     if (!glamor_egl->dmabuf_capable)
    675         return TRUE;
    676 
    677     if (!eglQueryDmaBufFormatsEXT(glamor_egl->display, 0, NULL, &num))
    678         return FALSE;
    679 
    680     if (num == 0)
    681         return TRUE;
    682 
    683     *formats = calloc(num, sizeof(CARD32));
    684     if (*formats == NULL)
    685         return FALSE;
    686 
    687     if (!eglQueryDmaBufFormatsEXT(glamor_egl->display, num,
    688                                   (EGLint *) *formats, &num)) {
    689         free(*formats);
    690         return FALSE;
    691     }
    692 
    693     *num_formats = num;
    694     return TRUE;
    695 #else
    696     *num_formats = 0;
    697     return TRUE;
    698 #endif
    699 }
    700 
    701 _X_EXPORT Bool
    702 glamor_get_modifiers(ScreenPtr screen, uint32_t format,
    703                      uint32_t *num_modifiers, uint64_t **modifiers)
    704 {
    705 #ifdef GLAMOR_HAS_EGL_QUERY_DMABUF
    706     struct glamor_egl_screen_private *glamor_egl;
    707     EGLint num;
    708 
    709     /* Explicitly zero the count as the caller may ignore the return value */
    710     *num_modifiers = 0;
    711 
    712     glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen));
    713 
    714     if (!glamor_egl->dmabuf_capable)
    715         return FALSE;
    716 
    717     if (!eglQueryDmaBufModifiersEXT(glamor_egl->display, format, 0, NULL,
    718                                     NULL, &num))
    719         return FALSE;
    720 
    721     if (num == 0)
    722         return TRUE;
    723 
    724     *modifiers = calloc(num, sizeof(uint64_t));
    725     if (*modifiers == NULL)
    726         return FALSE;
    727 
    728     if (!eglQueryDmaBufModifiersEXT(glamor_egl->display, format, num,
    729                                     (EGLuint64KHR *) *modifiers, NULL, &num)) {
    730         free(*modifiers);
    731         *modifiers = NULL;
    732         return FALSE;
    733     }
    734 
    735     *num_modifiers = num;
    736     return TRUE;
    737 #else
    738     *num_modifiers = 0;
    739     return TRUE;
    740 #endif
    741 }
    742 
    743 _X_EXPORT const char *
    744 glamor_egl_get_driver_name(ScreenPtr screen)
    745 {
    746 #ifdef GLAMOR_HAS_EGL_QUERY_DRIVER
    747     struct glamor_egl_screen_private *glamor_egl;
    748 
    749     glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen));
    750 
    751     if (epoxy_has_egl_extension(glamor_egl->display, "EGL_MESA_query_driver"))
    752         return eglGetDisplayDriverName(glamor_egl->display);
    753 #endif
    754 
    755     return NULL;
    756 }
    757 
    758 
    759 static Bool
    760 glamor_egl_destroy_pixmap(PixmapPtr pixmap)
    761 {
    762     ScreenPtr screen = pixmap->drawable.pScreen;
    763     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    764     struct glamor_egl_screen_private *glamor_egl =
    765         glamor_egl_get_screen_private(scrn);
    766     Bool ret;
    767 
    768     if (pixmap->refcnt == 1) {
    769         struct glamor_pixmap_private *pixmap_priv =
    770             glamor_get_pixmap_private(pixmap);
    771 
    772         if (pixmap_priv->image)
    773             eglDestroyImageKHR(glamor_egl->display, pixmap_priv->image);
    774     }
    775 
    776     screen->DestroyPixmap = glamor_egl->saved_destroy_pixmap;
    777     ret = screen->DestroyPixmap(pixmap);
    778     glamor_egl->saved_destroy_pixmap = screen->DestroyPixmap;
    779     screen->DestroyPixmap = glamor_egl_destroy_pixmap;
    780 
    781     return ret;
    782 }
    783 
    784 _X_EXPORT void
    785 glamor_egl_exchange_buffers(PixmapPtr front, PixmapPtr back)
    786 {
    787     EGLImageKHR temp_img;
    788     Bool temp_mod;
    789     struct glamor_pixmap_private *front_priv =
    790         glamor_get_pixmap_private(front);
    791     struct glamor_pixmap_private *back_priv =
    792         glamor_get_pixmap_private(back);
    793 
    794     glamor_pixmap_exchange_fbos(front, back);
    795 
    796     temp_img = back_priv->image;
    797     temp_mod = back_priv->used_modifiers;
    798     back_priv->image = front_priv->image;
    799     back_priv->used_modifiers = front_priv->used_modifiers;
    800     front_priv->image = temp_img;
    801     front_priv->used_modifiers = temp_mod;
    802 
    803     glamor_set_pixmap_type(front, GLAMOR_TEXTURE_DRM);
    804     glamor_set_pixmap_type(back, GLAMOR_TEXTURE_DRM);
    805 }
    806 
    807 static Bool
    808 glamor_egl_close_screen(ScreenPtr screen)
    809 {
    810     ScrnInfoPtr scrn;
    811     struct glamor_egl_screen_private *glamor_egl;
    812     struct glamor_pixmap_private *pixmap_priv;
    813     PixmapPtr screen_pixmap;
    814 
    815     scrn = xf86ScreenToScrn(screen);
    816     glamor_egl = glamor_egl_get_screen_private(scrn);
    817     screen_pixmap = screen->GetScreenPixmap(screen);
    818     pixmap_priv = glamor_get_pixmap_private(screen_pixmap);
    819 
    820     eglDestroyImageKHR(glamor_egl->display, pixmap_priv->image);
    821     pixmap_priv->image = NULL;
    822 
    823     screen->CloseScreen = glamor_egl->saved_close_screen;
    824 
    825     return screen->CloseScreen(screen);
    826 }
    827 
    828 #ifdef DRI3
    829 static int
    830 glamor_dri3_open_client(ClientPtr client,
    831                         ScreenPtr screen,
    832                         RRProviderPtr provider,
    833                         int *fdp)
    834 {
    835     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    836     struct glamor_egl_screen_private *glamor_egl =
    837         glamor_egl_get_screen_private(scrn);
    838     int fd;
    839     drm_magic_t magic;
    840 
    841     fd = open(glamor_egl->device_path, O_RDWR|O_CLOEXEC);
    842     if (fd < 0)
    843         return BadAlloc;
    844 
    845     /* Before FD passing in the X protocol with DRI3 (and increased
    846      * security of rendering with per-process address spaces on the
    847      * GPU), the kernel had to come up with a way to have the server
    848      * decide which clients got to access the GPU, which was done by
    849      * each client getting a unique (magic) number from the kernel,
    850      * passing it to the server, and the server then telling the
    851      * kernel which clients were authenticated for using the device.
    852      *
    853      * Now that we have FD passing, the server can just set up the
    854      * authentication on its own and hand the prepared FD off to the
    855      * client.
    856      */
    857     if (drmGetMagic(fd, &magic) < 0) {
    858         if (errno == EACCES) {
    859             /* Assume that we're on a render node, and the fd is
    860              * already as authenticated as it should be.
    861              */
    862             *fdp = fd;
    863             return Success;
    864         } else {
    865             close(fd);
    866             return BadMatch;
    867         }
    868     }
    869 
    870     if (drmAuthMagic(glamor_egl->fd, magic) < 0) {
    871         close(fd);
    872         return BadMatch;
    873     }
    874 
    875     *fdp = fd;
    876     return Success;
    877 }
    878 
    879 static const dri3_screen_info_rec glamor_dri3_info = {
    880     .version = 2,
    881     .open_client = glamor_dri3_open_client,
    882     .pixmap_from_fds = glamor_pixmap_from_fds,
    883     .fd_from_pixmap = glamor_egl_fd_from_pixmap,
    884     .fds_from_pixmap = glamor_egl_fds_from_pixmap,
    885     .get_formats = glamor_get_formats,
    886     .get_modifiers = glamor_get_modifiers,
    887     .get_drawable_modifiers = glamor_get_drawable_modifiers,
    888 };
    889 #endif /* DRI3 */
    890 
    891 void
    892 glamor_egl_screen_init(ScreenPtr screen, struct glamor_context *glamor_ctx)
    893 {
    894     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
    895     struct glamor_egl_screen_private *glamor_egl =
    896         glamor_egl_get_screen_private(scrn);
    897 #ifdef DRI3
    898     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
    899 #endif
    900 
    901     glamor_egl->saved_close_screen = screen->CloseScreen;
    902     screen->CloseScreen = glamor_egl_close_screen;
    903 
    904     glamor_egl->saved_destroy_pixmap = screen->DestroyPixmap;
    905     screen->DestroyPixmap = glamor_egl_destroy_pixmap;
    906 
    907     glamor_ctx->ctx = glamor_egl->context;
    908     glamor_ctx->display = glamor_egl->display;
    909 
    910     glamor_ctx->make_current = glamor_egl_make_current;
    911 
    912 #ifdef DRI3
    913     /* Tell the core that we have the interfaces for import/export
    914      * of pixmaps.
    915      */
    916     glamor_enable_dri3(screen);
    917 
    918     /* If the driver wants to do its own auth dance (e.g. Xwayland
    919      * on pre-3.15 kernels that don't have render nodes and thus
    920      * has the wayland compositor as a master), then it needs us
    921      * to stay out of the way and let it init DRI3 on its own.
    922      */
    923     if (!(glamor_priv->flags & GLAMOR_NO_DRI3)) {
    924         /* To do DRI3 device FD generation, we need to open a new fd
    925          * to the same device we were handed in originally.
    926          */
    927         glamor_egl->device_path = drmGetDeviceNameFromFd2(glamor_egl->fd);
    928 
    929         if (!dri3_screen_init(screen, &glamor_dri3_info)) {
    930             xf86DrvMsg(scrn->scrnIndex, X_ERROR,
    931                        "Failed to initialize DRI3.\n");
    932         }
    933     }
    934 #endif
    935 }
    936 
    937 static void glamor_egl_cleanup(struct glamor_egl_screen_private *glamor_egl)
    938 {
    939     if (glamor_egl->display != EGL_NO_DISPLAY) {
    940         eglMakeCurrent(glamor_egl->display,
    941                        EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    942         /*
    943          * Force the next glamor_make_current call to update the context
    944          * (on hot unplug another GPU may still be using glamor)
    945          */
    946         lastGLContext = NULL;
    947         eglTerminate(glamor_egl->display);
    948     }
    949     if (glamor_egl->gbm)
    950         gbm_device_destroy(glamor_egl->gbm);
    951     free(glamor_egl->device_path);
    952     free(glamor_egl);
    953 }
    954 
    955 static void
    956 glamor_egl_free_screen(ScrnInfoPtr scrn)
    957 {
    958     struct glamor_egl_screen_private *glamor_egl;
    959 
    960     glamor_egl = glamor_egl_get_screen_private(scrn);
    961     if (glamor_egl != NULL) {
    962         scrn->FreeScreen = glamor_egl->saved_free_screen;
    963         glamor_egl_cleanup(glamor_egl);
    964         scrn->FreeScreen(scrn);
    965     }
    966 }
    967 
    968 static Bool
    969 glamor_egl_try_big_gl_api(ScrnInfoPtr scrn)
    970 {
    971     struct glamor_egl_screen_private *glamor_egl =
    972         glamor_egl_get_screen_private(scrn);
    973 
    974     if (eglBindAPI(EGL_OPENGL_API)) {
    975         static const EGLint config_attribs_core[] = {
    976             EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR,
    977             EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR,
    978             EGL_CONTEXT_MAJOR_VERSION_KHR,
    979             GLAMOR_GL_CORE_VER_MAJOR,
    980             EGL_CONTEXT_MINOR_VERSION_KHR,
    981             GLAMOR_GL_CORE_VER_MINOR,
    982             EGL_NONE
    983         };
    984         static const EGLint config_attribs[] = {
    985             EGL_NONE
    986         };
    987 
    988         glamor_egl->context = eglCreateContext(glamor_egl->display,
    989                                                EGL_NO_CONFIG_KHR, EGL_NO_CONTEXT,
    990                                                config_attribs_core);
    991 
    992         if (glamor_egl->context == EGL_NO_CONTEXT)
    993             glamor_egl->context = eglCreateContext(glamor_egl->display,
    994                                                    EGL_NO_CONFIG_KHR,
    995                                                    EGL_NO_CONTEXT,
    996                                                    config_attribs);
    997     }
    998 
    999     if (glamor_egl->context != EGL_NO_CONTEXT) {
   1000         if (!eglMakeCurrent(glamor_egl->display,
   1001                             EGL_NO_SURFACE, EGL_NO_SURFACE, glamor_egl->context)) {
   1002             xf86DrvMsg(scrn->scrnIndex, X_ERROR,
   1003                        "Failed to make GL context current\n");
   1004             return FALSE;
   1005         }
   1006 
   1007         if (epoxy_gl_version() < 21) {
   1008             xf86DrvMsg(scrn->scrnIndex, X_INFO,
   1009                        "glamor: Ignoring GL < 2.1, falling back to GLES.\n");
   1010             eglDestroyContext(glamor_egl->display, glamor_egl->context);
   1011             glamor_egl->context = EGL_NO_CONTEXT;
   1012         }
   1013         xf86DrvMsg(scrn->scrnIndex, X_INFO,
   1014             "glamor: Using OpenGL %d.%d context.\n",
   1015             epoxy_gl_version() / 10,
   1016             epoxy_gl_version() % 10);
   1017     }
   1018     return TRUE;
   1019 }
   1020 
   1021 static Bool
   1022 glamor_egl_try_gles_api(ScrnInfoPtr scrn)
   1023 {
   1024     struct glamor_egl_screen_private *glamor_egl =
   1025         glamor_egl_get_screen_private(scrn);
   1026 
   1027     static const EGLint config_attribs[] = {
   1028         EGL_CONTEXT_CLIENT_VERSION, 2,
   1029         EGL_NONE
   1030     };
   1031     if (!eglBindAPI(EGL_OPENGL_ES_API)) {
   1032         xf86DrvMsg(scrn->scrnIndex, X_ERROR,
   1033                     "glamor: Failed to bind GLES API.\n");
   1034         return FALSE;
   1035     }
   1036 
   1037     glamor_egl->context = eglCreateContext(glamor_egl->display,
   1038                                             EGL_NO_CONFIG_KHR, EGL_NO_CONTEXT,
   1039                                             config_attribs);
   1040 
   1041     if (glamor_egl->context != EGL_NO_CONTEXT) {
   1042         if (!eglMakeCurrent(glamor_egl->display,
   1043                             EGL_NO_SURFACE, EGL_NO_SURFACE, glamor_egl->context)) {
   1044             xf86DrvMsg(scrn->scrnIndex, X_ERROR,
   1045                        "Failed to make GLES context current\n");
   1046             return FALSE;
   1047         }
   1048         xf86DrvMsg(scrn->scrnIndex, X_INFO,
   1049                 "glamor: Using OpenGL ES %d.%d context.\n",
   1050                 epoxy_gl_version() / 10,
   1051                 epoxy_gl_version() % 10);
   1052     }
   1053     return TRUE;
   1054 }
   1055 
   1056 enum {
   1057     GLAMOREGLOPT_RENDERING_API,
   1058 };
   1059 
   1060 static const OptionInfoRec GlamorEGLOptions[] = {
   1061     { GLAMOREGLOPT_RENDERING_API, "RenderingAPI", OPTV_STRING, {0}, FALSE },
   1062     { -1, NULL, OPTV_NONE, {0}, FALSE },
   1063 };
   1064 
   1065 Bool
   1066 glamor_egl_init(ScrnInfoPtr scrn, int fd)
   1067 {
   1068     struct glamor_egl_screen_private *glamor_egl;
   1069     const GLubyte *renderer;
   1070     OptionInfoPtr options;
   1071     const char *api = NULL;
   1072     Bool es_allowed = TRUE;
   1073     Bool force_es = FALSE;
   1074 
   1075     glamor_egl = calloc(sizeof(*glamor_egl), 1);
   1076     if (glamor_egl == NULL)
   1077         return FALSE;
   1078     if (xf86GlamorEGLPrivateIndex == -1)
   1079         xf86GlamorEGLPrivateIndex = xf86AllocateScrnInfoPrivateIndex();
   1080 
   1081     options = xnfalloc(sizeof(GlamorEGLOptions));
   1082     memcpy(options, GlamorEGLOptions, sizeof(GlamorEGLOptions));
   1083     xf86ProcessOptions(scrn->scrnIndex, scrn->options, options);
   1084     api = xf86GetOptValString(options, GLAMOREGLOPT_RENDERING_API);
   1085     if (api && !strncasecmp(api, "es", 2))
   1086         force_es = TRUE;
   1087     else if (api && !strncasecmp(api, "gl", 2))
   1088         es_allowed = FALSE;
   1089     free(options);
   1090 
   1091     scrn->privates[xf86GlamorEGLPrivateIndex].ptr = glamor_egl;
   1092     glamor_egl->fd = fd;
   1093     glamor_egl->gbm = gbm_create_device(glamor_egl->fd);
   1094     if (glamor_egl->gbm == NULL) {
   1095         ErrorF("couldn't get display device\n");
   1096         goto error;
   1097     }
   1098 
   1099     glamor_egl->display = glamor_egl_get_display(EGL_PLATFORM_GBM_MESA,
   1100                                                  glamor_egl->gbm);
   1101     if (!glamor_egl->display) {
   1102         xf86DrvMsg(scrn->scrnIndex, X_ERROR, "eglGetDisplay() failed\n");
   1103         goto error;
   1104     }
   1105 
   1106     if (!eglInitialize(glamor_egl->display, NULL, NULL)) {
   1107         xf86DrvMsg(scrn->scrnIndex, X_ERROR, "eglInitialize() failed\n");
   1108         glamor_egl->display = EGL_NO_DISPLAY;
   1109         goto error;
   1110     }
   1111 
   1112 #define GLAMOR_CHECK_EGL_EXTENSION(EXT)  \
   1113 	if (!epoxy_has_egl_extension(glamor_egl->display, "EGL_" #EXT)) {  \
   1114 		ErrorF("EGL_" #EXT " required.\n");  \
   1115 		goto error;  \
   1116 	}
   1117 
   1118 #define GLAMOR_CHECK_EGL_EXTENSIONS(EXT1, EXT2)	 \
   1119 	if (!epoxy_has_egl_extension(glamor_egl->display, "EGL_" #EXT1) &&  \
   1120 	    !epoxy_has_egl_extension(glamor_egl->display, "EGL_" #EXT2)) {  \
   1121 		ErrorF("EGL_" #EXT1 " or EGL_" #EXT2 " required.\n");  \
   1122 		goto error;  \
   1123 	}
   1124 
   1125     GLAMOR_CHECK_EGL_EXTENSION(KHR_surfaceless_context);
   1126 
   1127     if (!force_es) {
   1128         if(!glamor_egl_try_big_gl_api(scrn))
   1129             goto error;
   1130     }
   1131 
   1132     if (glamor_egl->context == EGL_NO_CONTEXT && es_allowed) {
   1133         if(!glamor_egl_try_gles_api(scrn))
   1134             goto error;
   1135     }
   1136 
   1137     if (glamor_egl->context == EGL_NO_CONTEXT) {
   1138         xf86DrvMsg(scrn->scrnIndex, X_ERROR,
   1139                     "glamor: Failed to create GL or GLES2 contexts\n");
   1140         goto error;
   1141     }
   1142 
   1143     renderer = glGetString(GL_RENDERER);
   1144     if (!renderer) {
   1145         xf86DrvMsg(scrn->scrnIndex, X_ERROR,
   1146                    "glGetString() returned NULL, your GL is broken\n");
   1147         goto error;
   1148     }
   1149     if (strstr((const char *)renderer, "llvmpipe")) {
   1150         if (scrn->confScreen->num_gpu_devices)
   1151             xf86DrvMsg(scrn->scrnIndex, X_INFO,
   1152                        "Allowing glamor on llvmpipe for PRIME\n");
   1153         else {
   1154             xf86DrvMsg(scrn->scrnIndex, X_INFO,
   1155                        "Refusing to try glamor on llvmpipe\n");
   1156             goto error;
   1157         }
   1158     }
   1159 
   1160     /*
   1161      * Force the next glamor_make_current call to set the right context
   1162      * (in case of multiple GPUs using glamor)
   1163      */
   1164     lastGLContext = NULL;
   1165 
   1166     if (!epoxy_has_gl_extension("GL_OES_EGL_image")) {
   1167         xf86DrvMsg(scrn->scrnIndex, X_ERROR,
   1168                    "glamor acceleration requires GL_OES_EGL_image\n");
   1169         goto error;
   1170     }
   1171 
   1172     xf86DrvMsg(scrn->scrnIndex, X_INFO, "glamor X acceleration enabled on %s\n",
   1173                renderer);
   1174 
   1175 #ifdef GBM_BO_WITH_MODIFIERS
   1176     if (epoxy_has_egl_extension(glamor_egl->display,
   1177                                 "EGL_EXT_image_dma_buf_import") &&
   1178         epoxy_has_egl_extension(glamor_egl->display,
   1179                                 "EGL_EXT_image_dma_buf_import_modifiers")) {
   1180         if (xf86Info.debug != NULL)
   1181             glamor_egl->dmabuf_capable = !!strstr(xf86Info.debug,
   1182                                                   "dmabuf_capable");
   1183         else
   1184             glamor_egl->dmabuf_capable = FALSE;
   1185     }
   1186 #endif
   1187 
   1188     glamor_egl->saved_free_screen = scrn->FreeScreen;
   1189     scrn->FreeScreen = glamor_egl_free_screen;
   1190     return TRUE;
   1191 
   1192 error:
   1193     glamor_egl_cleanup(glamor_egl);
   1194     return FALSE;
   1195 }
   1196 
   1197 /** Stub to retain compatibility with pre-server-1.16 ABI. */
   1198 Bool
   1199 glamor_egl_init_textured_pixmap(ScreenPtr screen)
   1200 {
   1201     return TRUE;
   1202 }
   1203