glamor_egl.c revision 5a7dfde8
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
51struct 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
67int xf86GlamorEGLPrivateIndex = -1;
68
69
70static struct glamor_egl_screen_private *
71glamor_egl_get_screen_private(ScrnInfoPtr scrn)
72{
73    return (struct glamor_egl_screen_private *)
74        scrn->privates[xf86GlamorEGLPrivateIndex].ptr;
75}
76
77static void
78glamor_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
96static int
97glamor_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
118static Bool
119glamor_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
138struct gbm_device *
139glamor_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
146Bool
147glamor_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
162static void
163glamor_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
182Bool
183glamor_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
217Bool
218glamor_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                              glamor_egl->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
252static void
253glamor_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
262static Bool
263glamor_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    if (pixmap->drawable.bitsPerPixel != 32) {
284        xf86DrvMsg(scrn->scrnIndex, X_ERROR,
285                   "Failed to make %dbpp pixmap exportable\n",
286                   pixmap->drawable.bitsPerPixel);
287        return FALSE;
288    }
289
290    if (pixmap->drawable.depth == 30)
291	format = GBM_FORMAT_ARGB2101010;
292    else
293        format = GBM_FORMAT_ARGB8888;
294
295#ifdef GBM_BO_WITH_MODIFIERS
296    if (modifiers_ok && glamor_egl->dmabuf_capable) {
297        uint32_t num_modifiers;
298        uint64_t *modifiers = NULL;
299
300        glamor_get_modifiers(screen, format, &num_modifiers, &modifiers);
301
302        bo = gbm_bo_create_with_modifiers(glamor_egl->gbm, width, height,
303                                          format, modifiers, num_modifiers);
304        if (bo)
305            used_modifiers = TRUE;
306        free(modifiers);
307    }
308#endif
309
310    if (!bo)
311    {
312        bo = gbm_bo_create(glamor_egl->gbm, width, height, format,
313#ifdef GLAMOR_HAS_GBM_LINEAR
314                (pixmap->usage_hint == CREATE_PIXMAP_USAGE_SHARED ?
315                 GBM_BO_USE_LINEAR : 0) |
316#endif
317                GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT);
318    }
319
320    if (!bo) {
321        xf86DrvMsg(scrn->scrnIndex, X_ERROR,
322                   "Failed to make %dx%dx%dbpp GBM bo\n",
323                   width, height, pixmap->drawable.bitsPerPixel);
324        return FALSE;
325    }
326
327    exported = screen->CreatePixmap(screen, 0, 0, pixmap->drawable.depth, 0);
328    screen->ModifyPixmapHeader(exported, width, height, 0, 0,
329                               gbm_bo_get_stride(bo), NULL);
330    if (!glamor_egl_create_textured_pixmap_from_gbm_bo(exported, bo,
331                                                       used_modifiers)) {
332        xf86DrvMsg(scrn->scrnIndex, X_ERROR,
333                   "Failed to make %dx%dx%dbpp pixmap from GBM bo\n",
334                   width, height, pixmap->drawable.bitsPerPixel);
335        screen->DestroyPixmap(exported);
336        gbm_bo_destroy(bo);
337        return FALSE;
338    }
339    gbm_bo_destroy(bo);
340
341    scratch_gc = GetScratchGC(pixmap->drawable.depth, screen);
342    ValidateGC(&pixmap->drawable, scratch_gc);
343    scratch_gc->ops->CopyArea(&pixmap->drawable, &exported->drawable,
344                              scratch_gc,
345                              0, 0, width, height, 0, 0);
346    FreeScratchGC(scratch_gc);
347
348    /* Now, swap the tex/gbm/EGLImage/etc. of the exported pixmap into
349     * the original pixmap struct.
350     */
351    glamor_egl_exchange_buffers(pixmap, exported);
352
353    /* Swap the devKind into the original pixmap, reflecting the bo's stride */
354    screen->ModifyPixmapHeader(pixmap, 0, 0, 0, 0, exported->devKind, NULL);
355
356    screen->DestroyPixmap(exported);
357
358    return TRUE;
359}
360
361static struct gbm_bo *
362glamor_gbm_bo_from_pixmap_internal(ScreenPtr screen, PixmapPtr pixmap)
363{
364    struct glamor_egl_screen_private *glamor_egl =
365        glamor_egl_get_screen_private(xf86ScreenToScrn(screen));
366    struct glamor_pixmap_private *pixmap_priv =
367        glamor_get_pixmap_private(pixmap);
368
369    if (!pixmap_priv->image)
370        return NULL;
371
372    return gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_EGL_IMAGE,
373                         pixmap_priv->image, 0);
374}
375
376struct gbm_bo *
377glamor_gbm_bo_from_pixmap(ScreenPtr screen, PixmapPtr pixmap)
378{
379    if (!glamor_make_pixmap_exportable(pixmap, TRUE))
380        return NULL;
381
382    return glamor_gbm_bo_from_pixmap_internal(screen, pixmap);
383}
384
385int
386glamor_egl_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds,
387                           uint32_t *strides, uint32_t *offsets,
388                           uint64_t *modifier)
389{
390#ifdef GLAMOR_HAS_GBM
391    struct gbm_bo *bo;
392    int num_fds;
393#ifdef GBM_BO_WITH_MODIFIERS
394    int i;
395#endif
396
397    if (!glamor_make_pixmap_exportable(pixmap, TRUE))
398        return 0;
399
400    bo = glamor_gbm_bo_from_pixmap_internal(screen, pixmap);
401    if (!bo)
402        return 0;
403
404#ifdef GBM_BO_WITH_MODIFIERS
405    num_fds = gbm_bo_get_plane_count(bo);
406    for (i = 0; i < num_fds; i++) {
407        fds[i] = gbm_bo_get_fd(bo);
408        strides[i] = gbm_bo_get_stride_for_plane(bo, i);
409        offsets[i] = gbm_bo_get_offset(bo, i);
410    }
411    *modifier = gbm_bo_get_modifier(bo);
412#else
413    num_fds = 1;
414    fds[0] = gbm_bo_get_fd(bo);
415    strides[0] = gbm_bo_get_stride(bo);
416    offsets[0] = 0;
417    *modifier = DRM_FORMAT_MOD_INVALID;
418#endif
419
420    gbm_bo_destroy(bo);
421    return num_fds;
422#else
423    return 0;
424#endif
425}
426
427_X_EXPORT int
428glamor_egl_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap,
429                          CARD16 *stride, CARD32 *size)
430{
431#ifdef GLAMOR_HAS_GBM
432    struct gbm_bo *bo;
433    int fd;
434
435    if (!glamor_make_pixmap_exportable(pixmap, FALSE))
436        return -1;
437
438    bo = glamor_gbm_bo_from_pixmap_internal(screen, pixmap);
439    if (!bo)
440        return -1;
441
442    fd = gbm_bo_get_fd(bo);
443    *stride = gbm_bo_get_stride(bo);
444    *size = *stride * gbm_bo_get_height(bo);
445    gbm_bo_destroy(bo);
446
447    return fd;
448#else
449    return -1;
450#endif
451}
452
453int
454glamor_egl_fd_name_from_pixmap(ScreenPtr screen,
455                               PixmapPtr pixmap,
456                               CARD16 *stride, CARD32 *size)
457{
458    struct glamor_egl_screen_private *glamor_egl;
459    struct gbm_bo *bo;
460    int fd = -1;
461
462    glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen));
463
464    if (!glamor_make_pixmap_exportable(pixmap, FALSE))
465        goto failure;
466
467    bo = glamor_gbm_bo_from_pixmap_internal(screen, pixmap);
468    if (!bo)
469        goto failure;
470
471    pixmap->devKind = gbm_bo_get_stride(bo);
472
473    glamor_get_name_from_bo(glamor_egl->fd, bo, &fd);
474    *stride = pixmap->devKind;
475    *size = pixmap->devKind * gbm_bo_get_height(bo);
476
477    gbm_bo_destroy(bo);
478 failure:
479    return fd;
480}
481
482_X_EXPORT Bool
483glamor_back_pixmap_from_fd(PixmapPtr pixmap,
484                           int fd,
485                           CARD16 width,
486                           CARD16 height,
487                           CARD16 stride, CARD8 depth, CARD8 bpp)
488{
489    ScreenPtr screen = pixmap->drawable.pScreen;
490    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
491    struct glamor_egl_screen_private *glamor_egl;
492    struct gbm_bo *bo;
493    struct gbm_import_fd_data import_data = { 0 };
494    Bool ret;
495
496    glamor_egl = glamor_egl_get_screen_private(scrn);
497
498    if (bpp != 32 || !(depth == 24 || depth == 32 || depth == 30) || width == 0 || height == 0)
499        return FALSE;
500
501    import_data.fd = fd;
502    import_data.width = width;
503    import_data.height = height;
504    import_data.stride = stride;
505    if (depth == 30)
506        import_data.format = GBM_FORMAT_ARGB2101010;
507    else
508        import_data.format = GBM_FORMAT_ARGB8888;
509    bo = gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_FD, &import_data, 0);
510    if (!bo)
511        return FALSE;
512
513    screen->ModifyPixmapHeader(pixmap, width, height, 0, 0, stride, NULL);
514
515    ret = glamor_egl_create_textured_pixmap_from_gbm_bo(pixmap, bo, FALSE);
516    gbm_bo_destroy(bo);
517    return ret;
518}
519
520static uint32_t
521gbm_format_for_depth(CARD8 depth)
522{
523    switch (depth) {
524    case 16:
525        return GBM_FORMAT_RGB565;
526    case 24:
527        return GBM_FORMAT_XRGB8888;
528    case 30:
529        return GBM_FORMAT_ARGB2101010;
530    default:
531        ErrorF("unexpected depth: %d\n", depth);
532    case 32:
533        return GBM_FORMAT_ARGB8888;
534    }
535}
536
537_X_EXPORT PixmapPtr
538glamor_pixmap_from_fds(ScreenPtr screen,
539                       CARD8 num_fds, const int *fds,
540                       CARD16 width, CARD16 height,
541                       const CARD32 *strides, const CARD32 *offsets,
542                       CARD8 depth, CARD8 bpp,
543                       uint64_t modifier)
544{
545    PixmapPtr pixmap;
546    struct glamor_egl_screen_private *glamor_egl;
547    Bool ret = FALSE;
548    int i;
549
550    glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen));
551
552    pixmap = screen->CreatePixmap(screen, 0, 0, depth, 0);
553
554#ifdef GBM_BO_WITH_MODIFIERS
555    if (glamor_egl->dmabuf_capable && modifier != DRM_FORMAT_MOD_INVALID) {
556        struct gbm_import_fd_modifier_data import_data = { 0 };
557        struct gbm_bo *bo;
558
559        import_data.width = width;
560        import_data.height = height;
561        import_data.num_fds = num_fds;
562        import_data.modifier = modifier;
563        for (i = 0; i < num_fds; i++) {
564            import_data.fds[i] = fds[i];
565            import_data.strides[i] = strides[i];
566            import_data.offsets[i] = offsets[i];
567        }
568        import_data.format = gbm_format_for_depth(depth);
569        bo = gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_FD_MODIFIER, &import_data, 0);
570        if (bo) {
571            screen->ModifyPixmapHeader(pixmap, width, height, 0, 0, strides[0], NULL);
572            ret = glamor_egl_create_textured_pixmap_from_gbm_bo(pixmap, bo, TRUE);
573            gbm_bo_destroy(bo);
574        }
575    } else
576#endif
577    {
578        if (num_fds == 1) {
579            ret = glamor_back_pixmap_from_fd(pixmap, fds[0], width, height,
580                                             strides[0], depth, bpp);
581        }
582    }
583
584    if (ret == FALSE) {
585        screen->DestroyPixmap(pixmap);
586        return NULL;
587    }
588    return pixmap;
589}
590
591_X_EXPORT PixmapPtr
592glamor_pixmap_from_fd(ScreenPtr screen,
593                      int fd,
594                      CARD16 width,
595                      CARD16 height,
596                      CARD16 stride, CARD8 depth, CARD8 bpp)
597{
598    PixmapPtr pixmap;
599    Bool ret;
600
601    pixmap = screen->CreatePixmap(screen, 0, 0, depth, 0);
602
603    ret = glamor_back_pixmap_from_fd(pixmap, fd, width, height,
604                                     stride, depth, bpp);
605
606    if (ret == FALSE) {
607        screen->DestroyPixmap(pixmap);
608        return NULL;
609    }
610    return pixmap;
611}
612
613_X_EXPORT Bool
614glamor_get_formats(ScreenPtr screen,
615                   CARD32 *num_formats, CARD32 **formats)
616{
617#ifdef GLAMOR_HAS_EGL_QUERY_DMABUF
618    struct glamor_egl_screen_private *glamor_egl;
619    EGLint num;
620
621    /* Explicitly zero the count as the caller may ignore the return value */
622    *num_formats = 0;
623
624    glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen));
625
626    if (!glamor_egl->dmabuf_capable)
627        return TRUE;
628
629    if (!eglQueryDmaBufFormatsEXT(glamor_egl->display, 0, NULL, &num))
630        return FALSE;
631
632    if (num == 0)
633        return TRUE;
634
635    *formats = calloc(num, sizeof(CARD32));
636    if (*formats == NULL)
637        return FALSE;
638
639    if (!eglQueryDmaBufFormatsEXT(glamor_egl->display, num,
640                                  (EGLint *) *formats, &num)) {
641        free(*formats);
642        return FALSE;
643    }
644
645    *num_formats = num;
646    return TRUE;
647#else
648    *num_formats = 0;
649    return TRUE;
650#endif
651}
652
653_X_EXPORT Bool
654glamor_get_modifiers(ScreenPtr screen, uint32_t format,
655                     uint32_t *num_modifiers, uint64_t **modifiers)
656{
657#ifdef GLAMOR_HAS_EGL_QUERY_DMABUF
658    struct glamor_egl_screen_private *glamor_egl;
659    EGLint num;
660
661    /* Explicitly zero the count as the caller may ignore the return value */
662    *num_modifiers = 0;
663
664    glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen));
665
666    if (!glamor_egl->dmabuf_capable)
667        return FALSE;
668
669    if (!eglQueryDmaBufModifiersEXT(glamor_egl->display, format, 0, NULL,
670                                    NULL, &num))
671        return FALSE;
672
673    if (num == 0)
674        return TRUE;
675
676    *modifiers = calloc(num, sizeof(uint64_t));
677    if (*modifiers == NULL)
678        return FALSE;
679
680    if (!eglQueryDmaBufModifiersEXT(glamor_egl->display, format, num,
681                                    (EGLuint64KHR *) *modifiers, NULL, &num)) {
682        free(*modifiers);
683        return FALSE;
684    }
685
686    *num_modifiers = num;
687    return TRUE;
688#else
689    *num_modifiers = 0;
690    return TRUE;
691#endif
692}
693
694_X_EXPORT const char *
695glamor_egl_get_driver_name(ScreenPtr screen)
696{
697#ifdef GLAMOR_HAS_EGL_QUERY_DRIVER
698    struct glamor_egl_screen_private *glamor_egl;
699
700    glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen));
701
702    if (epoxy_has_egl_extension(glamor_egl->display, "EGL_MESA_query_driver"))
703        return eglGetDisplayDriverName(glamor_egl->display);
704#endif
705
706    return NULL;
707}
708
709
710static Bool
711glamor_egl_destroy_pixmap(PixmapPtr pixmap)
712{
713    ScreenPtr screen = pixmap->drawable.pScreen;
714    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
715    struct glamor_egl_screen_private *glamor_egl =
716        glamor_egl_get_screen_private(scrn);
717    Bool ret;
718
719    if (pixmap->refcnt == 1) {
720        struct glamor_pixmap_private *pixmap_priv =
721            glamor_get_pixmap_private(pixmap);
722
723        if (pixmap_priv->image)
724            eglDestroyImageKHR(glamor_egl->display, pixmap_priv->image);
725    }
726
727    screen->DestroyPixmap = glamor_egl->saved_destroy_pixmap;
728    ret = screen->DestroyPixmap(pixmap);
729    glamor_egl->saved_destroy_pixmap = screen->DestroyPixmap;
730    screen->DestroyPixmap = glamor_egl_destroy_pixmap;
731
732    return ret;
733}
734
735_X_EXPORT void
736glamor_egl_exchange_buffers(PixmapPtr front, PixmapPtr back)
737{
738    EGLImageKHR temp_img;
739    Bool temp_mod;
740    struct glamor_pixmap_private *front_priv =
741        glamor_get_pixmap_private(front);
742    struct glamor_pixmap_private *back_priv =
743        glamor_get_pixmap_private(back);
744
745    glamor_pixmap_exchange_fbos(front, back);
746
747    temp_img = back_priv->image;
748    temp_mod = back_priv->used_modifiers;
749    back_priv->image = front_priv->image;
750    back_priv->used_modifiers = front_priv->used_modifiers;
751    front_priv->image = temp_img;
752    front_priv->used_modifiers = temp_mod;
753
754    glamor_set_pixmap_type(front, GLAMOR_TEXTURE_DRM);
755    glamor_set_pixmap_type(back, GLAMOR_TEXTURE_DRM);
756}
757
758static Bool
759glamor_egl_close_screen(ScreenPtr screen)
760{
761    ScrnInfoPtr scrn;
762    struct glamor_egl_screen_private *glamor_egl;
763    struct glamor_pixmap_private *pixmap_priv;
764    PixmapPtr screen_pixmap;
765
766    scrn = xf86ScreenToScrn(screen);
767    glamor_egl = glamor_egl_get_screen_private(scrn);
768    screen_pixmap = screen->GetScreenPixmap(screen);
769    pixmap_priv = glamor_get_pixmap_private(screen_pixmap);
770
771    eglDestroyImageKHR(glamor_egl->display, pixmap_priv->image);
772    pixmap_priv->image = NULL;
773
774    screen->CloseScreen = glamor_egl->saved_close_screen;
775
776    return screen->CloseScreen(screen);
777}
778
779#ifdef DRI3
780static int
781glamor_dri3_open_client(ClientPtr client,
782                        ScreenPtr screen,
783                        RRProviderPtr provider,
784                        int *fdp)
785{
786    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
787    struct glamor_egl_screen_private *glamor_egl =
788        glamor_egl_get_screen_private(scrn);
789    int fd;
790    drm_magic_t magic;
791
792    fd = open(glamor_egl->device_path, O_RDWR|O_CLOEXEC);
793    if (fd < 0)
794        return BadAlloc;
795
796    /* Before FD passing in the X protocol with DRI3 (and increased
797     * security of rendering with per-process address spaces on the
798     * GPU), the kernel had to come up with a way to have the server
799     * decide which clients got to access the GPU, which was done by
800     * each client getting a unique (magic) number from the kernel,
801     * passing it to the server, and the server then telling the
802     * kernel which clients were authenticated for using the device.
803     *
804     * Now that we have FD passing, the server can just set up the
805     * authentication on its own and hand the prepared FD off to the
806     * client.
807     */
808    if (drmGetMagic(fd, &magic) < 0) {
809        if (errno == EACCES) {
810            /* Assume that we're on a render node, and the fd is
811             * already as authenticated as it should be.
812             */
813            *fdp = fd;
814            return Success;
815        } else {
816            close(fd);
817            return BadMatch;
818        }
819    }
820
821    if (drmAuthMagic(glamor_egl->fd, magic) < 0) {
822        close(fd);
823        return BadMatch;
824    }
825
826    *fdp = fd;
827    return Success;
828}
829
830static const dri3_screen_info_rec glamor_dri3_info = {
831    .version = 2,
832    .open_client = glamor_dri3_open_client,
833    .pixmap_from_fds = glamor_pixmap_from_fds,
834    .fd_from_pixmap = glamor_egl_fd_from_pixmap,
835    .fds_from_pixmap = glamor_egl_fds_from_pixmap,
836    .get_formats = glamor_get_formats,
837    .get_modifiers = glamor_get_modifiers,
838    .get_drawable_modifiers = glamor_get_drawable_modifiers,
839};
840#endif /* DRI3 */
841
842void
843glamor_egl_screen_init(ScreenPtr screen, struct glamor_context *glamor_ctx)
844{
845    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
846    struct glamor_egl_screen_private *glamor_egl =
847        glamor_egl_get_screen_private(scrn);
848#ifdef DRI3
849    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
850#endif
851
852    glamor_egl->saved_close_screen = screen->CloseScreen;
853    screen->CloseScreen = glamor_egl_close_screen;
854
855    glamor_egl->saved_destroy_pixmap = screen->DestroyPixmap;
856    screen->DestroyPixmap = glamor_egl_destroy_pixmap;
857
858    glamor_ctx->ctx = glamor_egl->context;
859    glamor_ctx->display = glamor_egl->display;
860
861    glamor_ctx->make_current = glamor_egl_make_current;
862
863#ifdef DRI3
864    /* Tell the core that we have the interfaces for import/export
865     * of pixmaps.
866     */
867    glamor_enable_dri3(screen);
868
869    /* If the driver wants to do its own auth dance (e.g. Xwayland
870     * on pre-3.15 kernels that don't have render nodes and thus
871     * has the wayland compositor as a master), then it needs us
872     * to stay out of the way and let it init DRI3 on its own.
873     */
874    if (!(glamor_priv->flags & GLAMOR_NO_DRI3)) {
875        /* To do DRI3 device FD generation, we need to open a new fd
876         * to the same device we were handed in originally.
877         */
878        glamor_egl->device_path = drmGetDeviceNameFromFd2(glamor_egl->fd);
879
880        if (!dri3_screen_init(screen, &glamor_dri3_info)) {
881            xf86DrvMsg(scrn->scrnIndex, X_ERROR,
882                       "Failed to initialize DRI3.\n");
883        }
884    }
885#endif
886}
887
888static void glamor_egl_cleanup(struct glamor_egl_screen_private *glamor_egl)
889{
890    if (glamor_egl->display != EGL_NO_DISPLAY) {
891        eglMakeCurrent(glamor_egl->display,
892                       EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
893        /*
894         * Force the next glamor_make_current call to update the context
895         * (on hot unplug another GPU may still be using glamor)
896         */
897        lastGLContext = NULL;
898        eglTerminate(glamor_egl->display);
899    }
900    if (glamor_egl->gbm)
901        gbm_device_destroy(glamor_egl->gbm);
902    free(glamor_egl->device_path);
903    free(glamor_egl);
904}
905
906static void
907glamor_egl_free_screen(ScrnInfoPtr scrn)
908{
909    struct glamor_egl_screen_private *glamor_egl;
910
911    glamor_egl = glamor_egl_get_screen_private(scrn);
912    if (glamor_egl != NULL) {
913        scrn->FreeScreen = glamor_egl->saved_free_screen;
914        glamor_egl_cleanup(glamor_egl);
915        scrn->FreeScreen(scrn);
916    }
917}
918
919Bool
920glamor_egl_init(ScrnInfoPtr scrn, int fd)
921{
922    struct glamor_egl_screen_private *glamor_egl;
923    const GLubyte *renderer;
924
925    glamor_egl = calloc(sizeof(*glamor_egl), 1);
926    if (glamor_egl == NULL)
927        return FALSE;
928    if (xf86GlamorEGLPrivateIndex == -1)
929        xf86GlamorEGLPrivateIndex = xf86AllocateScrnInfoPrivateIndex();
930
931    scrn->privates[xf86GlamorEGLPrivateIndex].ptr = glamor_egl;
932    glamor_egl->fd = fd;
933    glamor_egl->gbm = gbm_create_device(glamor_egl->fd);
934    if (glamor_egl->gbm == NULL) {
935        ErrorF("couldn't get display device\n");
936        goto error;
937    }
938
939    glamor_egl->display = glamor_egl_get_display(EGL_PLATFORM_GBM_MESA,
940                                                 glamor_egl->gbm);
941    if (!glamor_egl->display) {
942        xf86DrvMsg(scrn->scrnIndex, X_ERROR, "eglGetDisplay() failed\n");
943        goto error;
944    }
945
946    if (!eglInitialize(glamor_egl->display, NULL, NULL)) {
947        xf86DrvMsg(scrn->scrnIndex, X_ERROR, "eglInitialize() failed\n");
948        glamor_egl->display = EGL_NO_DISPLAY;
949        goto error;
950    }
951
952#define GLAMOR_CHECK_EGL_EXTENSION(EXT)  \
953	if (!epoxy_has_egl_extension(glamor_egl->display, "EGL_" #EXT)) {  \
954		ErrorF("EGL_" #EXT " required.\n");  \
955		goto error;  \
956	}
957
958#define GLAMOR_CHECK_EGL_EXTENSIONS(EXT1, EXT2)	 \
959	if (!epoxy_has_egl_extension(glamor_egl->display, "EGL_" #EXT1) &&  \
960	    !epoxy_has_egl_extension(glamor_egl->display, "EGL_" #EXT2)) {  \
961		ErrorF("EGL_" #EXT1 " or EGL_" #EXT2 " required.\n");  \
962		goto error;  \
963	}
964
965    GLAMOR_CHECK_EGL_EXTENSION(KHR_surfaceless_context);
966
967    if (eglBindAPI(EGL_OPENGL_API)) {
968        static const EGLint config_attribs_core[] = {
969            EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR,
970            EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR,
971            EGL_CONTEXT_MAJOR_VERSION_KHR,
972            GLAMOR_GL_CORE_VER_MAJOR,
973            EGL_CONTEXT_MINOR_VERSION_KHR,
974            GLAMOR_GL_CORE_VER_MINOR,
975            EGL_NONE
976        };
977        static const EGLint config_attribs[] = {
978            EGL_NONE
979        };
980
981        glamor_egl->context = eglCreateContext(glamor_egl->display,
982                                               NULL, EGL_NO_CONTEXT,
983                                               config_attribs_core);
984
985        if (glamor_egl->context == EGL_NO_CONTEXT)
986            glamor_egl->context = eglCreateContext(glamor_egl->display,
987                                                   NULL, EGL_NO_CONTEXT,
988                                                   config_attribs);
989    }
990
991    if (glamor_egl->context == EGL_NO_CONTEXT) {
992        static const EGLint config_attribs[] = {
993            EGL_CONTEXT_CLIENT_VERSION, 2,
994            EGL_NONE
995        };
996        if (!eglBindAPI(EGL_OPENGL_ES_API)) {
997            xf86DrvMsg(scrn->scrnIndex, X_ERROR,
998                       "glamor: Failed to bind either GL or GLES APIs.\n");
999            goto error;
1000        }
1001
1002        glamor_egl->context = eglCreateContext(glamor_egl->display,
1003                                               NULL, EGL_NO_CONTEXT,
1004                                               config_attribs);
1005    }
1006    if (glamor_egl->context == EGL_NO_CONTEXT) {
1007        xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1008                   "glamor: Failed to create GL or GLES2 contexts\n");
1009        goto error;
1010    }
1011
1012    if (!eglMakeCurrent(glamor_egl->display,
1013                        EGL_NO_SURFACE, EGL_NO_SURFACE, glamor_egl->context)) {
1014        xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1015                   "Failed to make EGL context current\n");
1016        goto error;
1017    }
1018
1019    renderer = glGetString(GL_RENDERER);
1020    if (!renderer) {
1021        xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1022                   "glGetString() returned NULL, your GL is broken\n");
1023        goto error;
1024    }
1025    if (strstr((const char *)renderer, "llvmpipe")) {
1026        xf86DrvMsg(scrn->scrnIndex, X_INFO,
1027                   "Refusing to try glamor on llvmpipe\n");
1028        goto error;
1029    }
1030
1031    /*
1032     * Force the next glamor_make_current call to set the right context
1033     * (in case of multiple GPUs using glamor)
1034     */
1035    lastGLContext = NULL;
1036
1037    if (!epoxy_has_gl_extension("GL_OES_EGL_image")) {
1038        xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1039                   "glamor acceleration requires GL_OES_EGL_image\n");
1040        goto error;
1041    }
1042
1043    xf86DrvMsg(scrn->scrnIndex, X_INFO, "glamor X acceleration enabled on %s\n",
1044               renderer);
1045
1046#ifdef GBM_BO_WITH_MODIFIERS
1047    if (epoxy_has_egl_extension(glamor_egl->display,
1048                                "EGL_EXT_image_dma_buf_import") &&
1049        epoxy_has_egl_extension(glamor_egl->display,
1050                                "EGL_EXT_image_dma_buf_import_modifiers")) {
1051       if (xf86Info.debug != NULL)
1052           glamor_egl->dmabuf_capable = !!strstr(xf86Info.debug,
1053                                                "dmabuf_capable");
1054        else
1055            glamor_egl->dmabuf_capable = FALSE;
1056    }
1057#endif
1058
1059    glamor_egl->saved_free_screen = scrn->FreeScreen;
1060    scrn->FreeScreen = glamor_egl_free_screen;
1061    return TRUE;
1062
1063error:
1064    glamor_egl_cleanup(glamor_egl);
1065    return FALSE;
1066}
1067
1068/** Stub to retain compatibility with pre-server-1.16 ABI. */
1069Bool
1070glamor_egl_init_textured_pixmap(ScreenPtr screen)
1071{
1072    return TRUE;
1073}
1074