tizen 2.4 release
[framework/uifw/xorg/server/xorg-server.git] / glamor / glamor_egl.c
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 <xorg-server.h>
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include <sys/ioctl.h>
37 #include <errno.h>
38 #include <xf86.h>
39 #include <xf86drm.h>
40 #define EGL_DISPLAY_NO_X_MESA
41
42 #ifdef GLAMOR_HAS_GBM
43 #include <gbm.h>
44 #include <drm_fourcc.h>
45 #endif
46
47 #define MESA_EGL_NO_X11_HEADERS
48 #include <epoxy/gl.h>
49 #include <epoxy/egl.h>
50
51 #include "glamor.h"
52 #include "glamor_priv.h"
53 #include "dri3.h"
54
55 static const char glamor_name[] = "glamor";
56
57 static void
58 glamor_identify(int flags)
59 {
60     xf86Msg(X_INFO, "%s: OpenGL accelerated X.org driver based.\n",
61             glamor_name);
62 }
63
64 struct glamor_egl_screen_private {
65     EGLDisplay display;
66     EGLContext context;
67     EGLint major, minor;
68     char *device_path;
69
70     CreateScreenResourcesProcPtr CreateScreenResources;
71     CloseScreenProcPtr CloseScreen;
72     int fd;
73     EGLImageKHR front_image;
74     PixmapPtr *back_pixmap;
75     int cpp;
76 #ifdef GLAMOR_HAS_GBM
77     struct gbm_device *gbm;
78 #endif
79     int has_gem;
80     int gl_context_depth;
81     int dri3_capable;
82
83     CloseScreenProcPtr saved_close_screen;
84     xf86FreeScreenProc *saved_free_screen;
85 };
86
87 int xf86GlamorEGLPrivateIndex = -1;
88
89
90 static struct glamor_egl_screen_private *
91 glamor_egl_get_screen_private(ScrnInfoPtr scrn)
92 {
93     return (struct glamor_egl_screen_private *)
94         scrn->privates[xf86GlamorEGLPrivateIndex].ptr;
95 }
96
97 static void
98 glamor_egl_make_current(struct glamor_context *glamor_ctx)
99 {
100     /* There's only a single global dispatch table in Mesa.  EGL, GLX,
101      * and AIGLX's direct dispatch table manipulation don't talk to
102      * each other.  We need to set the context to NULL first to avoid
103      * EGL's no-op context change fast path when switching back to
104      * EGL.
105      */
106     eglMakeCurrent(glamor_ctx->display, EGL_NO_SURFACE,
107                    EGL_NO_SURFACE, EGL_NO_CONTEXT);
108
109     if (!eglMakeCurrent(glamor_ctx->display,
110                         EGL_NO_SURFACE, EGL_NO_SURFACE,
111                         glamor_ctx->ctx)) {
112         FatalError("Failed to make EGL context current\n");
113     }
114 }
115
116 static EGLImageKHR
117 _glamor_egl_create_image(struct glamor_egl_screen_private *glamor_egl,
118                          int width, int height, int stride, int name, int depth)
119 {
120     EGLImageKHR image;
121
122     EGLint attribs[] = {
123         EGL_WIDTH, 0,
124         EGL_HEIGHT, 0,
125         EGL_DRM_BUFFER_STRIDE_MESA, 0,
126         EGL_DRM_BUFFER_FORMAT_MESA,
127         EGL_DRM_BUFFER_FORMAT_ARGB32_MESA,
128         EGL_DRM_BUFFER_USE_MESA,
129         EGL_DRM_BUFFER_USE_SHARE_MESA | EGL_DRM_BUFFER_USE_SCANOUT_MESA,
130         EGL_NONE
131     };
132     attribs[1] = width;
133     attribs[3] = height;
134     attribs[5] = stride;
135     if (depth != 32 && depth != 24)
136         return EGL_NO_IMAGE_KHR;
137     image = eglCreateImageKHR(glamor_egl->display,
138                               glamor_egl->context,
139                               EGL_DRM_BUFFER_MESA,
140                               (void *) (uintptr_t) name,
141                               attribs);
142     if (image == EGL_NO_IMAGE_KHR)
143         return EGL_NO_IMAGE_KHR;
144
145     return image;
146 }
147
148 static int
149 glamor_get_flink_name(int fd, int handle, int *name)
150 {
151     struct drm_gem_flink flink;
152
153     flink.handle = handle;
154     if (ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink) < 0)
155         return FALSE;
156     *name = flink.name;
157     return TRUE;
158 }
159
160 static Bool
161 glamor_create_texture_from_image(ScreenPtr screen,
162                                  EGLImageKHR image, GLuint * texture)
163 {
164     struct glamor_screen_private *glamor_priv =
165         glamor_get_screen_private(screen);
166
167     glamor_make_current(glamor_priv);
168
169     glGenTextures(1, texture);
170     glBindTexture(GL_TEXTURE_2D, *texture);
171     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
172     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
173
174     glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
175     glBindTexture(GL_TEXTURE_2D, 0);
176
177     return TRUE;
178 }
179
180 unsigned int
181 glamor_egl_create_argb8888_based_texture(ScreenPtr screen, int w, int h)
182 {
183     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
184     struct glamor_egl_screen_private *glamor_egl;
185     EGLImageKHR image;
186     GLuint texture;
187
188 #ifdef GLAMOR_HAS_GBM
189     struct gbm_bo *bo;
190     EGLNativePixmapType native_pixmap;
191
192     glamor_egl = glamor_egl_get_screen_private(scrn);
193     bo = gbm_bo_create(glamor_egl->gbm, w, h, GBM_FORMAT_ARGB8888,
194                        GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT);
195     if (!bo)
196         return 0;
197
198     /* If the following assignment raises an error or a warning
199      * then that means EGLNativePixmapType is not struct gbm_bo *
200      * on your platform: This code won't work and you should not
201      * compile with dri3 support enabled */
202     native_pixmap = bo;
203
204     image = eglCreateImageKHR(glamor_egl->display,
205                               EGL_NO_CONTEXT,
206                               EGL_NATIVE_PIXMAP_KHR,
207                               native_pixmap, NULL);
208     gbm_bo_destroy(bo);
209     if (image == EGL_NO_IMAGE_KHR)
210         return 0;
211     glamor_create_texture_from_image(screen, image, &texture);
212     eglDestroyImageKHR(glamor_egl->display, image);
213
214     return texture;
215 #else
216     return 0;                   /* this path should never happen */
217 #endif
218 }
219
220 Bool
221 glamor_egl_create_textured_screen(ScreenPtr screen, int handle, int stride)
222 {
223     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
224     struct glamor_pixmap_private *pixmap_priv;
225     struct glamor_egl_screen_private *glamor_egl;
226     PixmapPtr screen_pixmap;
227
228     glamor_egl = glamor_egl_get_screen_private(scrn);
229     screen_pixmap = screen->GetScreenPixmap(screen);
230     pixmap_priv = glamor_get_pixmap_private(screen_pixmap);
231
232     if (!glamor_egl_create_textured_pixmap(screen_pixmap, handle, stride)) {
233         xf86DrvMsg(scrn->scrnIndex, X_ERROR,
234                    "Failed to create textured screen.");
235         return FALSE;
236     }
237
238     glamor_egl->front_image = pixmap_priv->base.image;
239     glamor_set_screen_pixmap(screen_pixmap, glamor_egl->back_pixmap);
240     return TRUE;
241 }
242
243 Bool
244 glamor_egl_create_textured_screen_ext(ScreenPtr screen,
245                                       int handle,
246                                       int stride, PixmapPtr *back_pixmap)
247 {
248     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
249     struct glamor_egl_screen_private *glamor_egl;
250
251     glamor_egl = glamor_egl_get_screen_private(scrn);
252
253     glamor_egl->back_pixmap = back_pixmap;
254     if (!glamor_egl_create_textured_screen(screen, handle, stride))
255         return FALSE;
256     return TRUE;
257 }
258
259 static Bool
260 glamor_egl_check_has_gem(int fd)
261 {
262     struct drm_gem_flink flink;
263
264     flink.handle = 0;
265
266     ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink);
267     if (errno == ENOENT || errno == EINVAL)
268         return TRUE;
269     return FALSE;
270 }
271
272 Bool
273 glamor_egl_create_textured_pixmap(PixmapPtr pixmap, int handle, int stride)
274 {
275     ScreenPtr screen = pixmap->drawable.pScreen;
276     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
277     struct glamor_screen_private *glamor_priv =
278         glamor_get_screen_private(screen);
279     struct glamor_pixmap_private *pixmap_priv =
280         glamor_get_pixmap_private(pixmap);
281     struct glamor_egl_screen_private *glamor_egl;
282     EGLImageKHR image;
283     GLuint texture;
284     int name;
285     Bool ret = FALSE;
286
287     glamor_egl = glamor_egl_get_screen_private(scrn);
288
289     glamor_make_current(glamor_priv);
290     if (glamor_egl->has_gem) {
291         if (!glamor_get_flink_name(glamor_egl->fd, handle, &name)) {
292             xf86DrvMsg(scrn->scrnIndex, X_ERROR,
293                        "Couldn't flink pixmap handle\n");
294             glamor_set_pixmap_type(pixmap, GLAMOR_DRM_ONLY);
295             assert(0);
296             return FALSE;
297         }
298     }
299     else
300         name = handle;
301
302     image = _glamor_egl_create_image(glamor_egl,
303                                      pixmap->drawable.width,
304                                      pixmap->drawable.height,
305                                      ((stride * 8 +
306                                        7) / pixmap->drawable.bitsPerPixel),
307                                      name, pixmap->drawable.depth);
308     if (image == EGL_NO_IMAGE_KHR) {
309         glamor_set_pixmap_type(pixmap, GLAMOR_DRM_ONLY);
310         goto done;
311     }
312     glamor_create_texture_from_image(screen, image, &texture);
313     glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM);
314     glamor_set_pixmap_texture(pixmap, texture);
315     pixmap_priv->base.image = image;
316     ret = TRUE;
317
318  done:
319     return ret;
320 }
321
322 Bool
323 glamor_egl_create_textured_pixmap_from_gbm_bo(PixmapPtr pixmap, void *bo)
324 {
325     ScreenPtr screen = pixmap->drawable.pScreen;
326     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
327     struct glamor_screen_private *glamor_priv =
328         glamor_get_screen_private(screen);
329     struct glamor_pixmap_private *pixmap_priv =
330         glamor_get_pixmap_private(pixmap);
331     struct glamor_egl_screen_private *glamor_egl;
332     EGLImageKHR image;
333     GLuint texture;
334     Bool ret = FALSE;
335
336     glamor_egl = glamor_egl_get_screen_private(scrn);
337
338     glamor_make_current(glamor_priv);
339
340     image = eglCreateImageKHR(glamor_egl->display,
341                               glamor_egl->context,
342                               EGL_NATIVE_PIXMAP_KHR, bo, NULL);
343     if (image == EGL_NO_IMAGE_KHR) {
344         glamor_set_pixmap_type(pixmap, GLAMOR_DRM_ONLY);
345         goto done;
346     }
347     glamor_create_texture_from_image(screen, image, &texture);
348     glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM);
349     glamor_set_pixmap_texture(pixmap, texture);
350     pixmap_priv->base.image = image;
351     ret = TRUE;
352
353  done:
354     return ret;
355 }
356
357 #ifdef GLAMOR_HAS_GBM
358 int glamor_get_fd_from_bo(int gbm_fd, struct gbm_bo *bo, int *fd);
359 void glamor_get_name_from_bo(int gbm_fd, struct gbm_bo *bo, int *name);
360 int
361 glamor_get_fd_from_bo(int gbm_fd, struct gbm_bo *bo, int *fd)
362 {
363     union gbm_bo_handle handle;
364     struct drm_prime_handle args;
365
366     handle = gbm_bo_get_handle(bo);
367     args.handle = handle.u32;
368     args.flags = DRM_CLOEXEC;
369     if (ioctl(gbm_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args))
370         return FALSE;
371     *fd = args.fd;
372     return TRUE;
373 }
374
375 void
376 glamor_get_name_from_bo(int gbm_fd, struct gbm_bo *bo, int *name)
377 {
378     union gbm_bo_handle handle;
379
380     handle = gbm_bo_get_handle(bo);
381     if (!glamor_get_flink_name(gbm_fd, handle.u32, name))
382         *name = -1;
383 }
384 #endif
385
386 int
387 glamor_egl_dri3_fd_name_from_tex(ScreenPtr screen,
388                                  PixmapPtr pixmap,
389                                  unsigned int tex,
390                                  Bool want_name, CARD16 *stride, CARD32 *size)
391 {
392 #ifdef GLAMOR_HAS_GBM
393     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
394     struct glamor_pixmap_private *pixmap_priv =
395         glamor_get_pixmap_private(pixmap);
396     struct glamor_screen_private *glamor_priv =
397         glamor_get_screen_private(screen);
398     struct glamor_egl_screen_private *glamor_egl;
399     EGLImageKHR image;
400     struct gbm_bo *bo;
401     int fd = -1;
402
403     EGLint attribs[] = {
404         EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
405         EGL_GL_TEXTURE_LEVEL_KHR, 0,
406         EGL_NONE
407     };
408
409     glamor_egl = glamor_egl_get_screen_private(scrn);
410
411     glamor_make_current(glamor_priv);
412
413     image = pixmap_priv->base.image;
414     if (!image) {
415         image = eglCreateImageKHR(glamor_egl->display,
416                                   glamor_egl->context,
417                                   EGL_GL_TEXTURE_2D_KHR,
418                                   (EGLClientBuffer) (uintptr_t)
419                                   tex, attribs);
420         if (image == EGL_NO_IMAGE_KHR)
421             goto failure;
422
423         pixmap_priv->base.image = image;
424         glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM);
425     }
426
427     bo = gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_EGL_IMAGE, image, 0);
428     if (!bo)
429         goto failure;
430
431     pixmap->devKind = gbm_bo_get_stride(bo);
432
433     if (want_name) {
434         if (glamor_egl->has_gem)
435             glamor_get_name_from_bo(glamor_egl->fd, bo, &fd);
436     }
437     else {
438         if (glamor_get_fd_from_bo(glamor_egl->fd, bo, &fd)) {
439         }
440     }
441     *stride = pixmap->devKind;
442     *size = pixmap->devKind * gbm_bo_get_height(bo);
443
444     gbm_bo_destroy(bo);
445  failure:
446     return fd;
447 #else
448     return -1;
449 #endif
450 }
451
452 _X_EXPORT PixmapPtr
453 glamor_pixmap_from_fd(ScreenPtr screen,
454                       int fd,
455                       CARD16 width,
456                       CARD16 height,
457                       CARD16 stride, CARD8 depth, CARD8 bpp)
458 {
459 #ifdef GLAMOR_HAS_GBM
460     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
461     struct glamor_egl_screen_private *glamor_egl;
462     struct gbm_bo *bo;
463     EGLImageKHR image;
464     PixmapPtr pixmap;
465     Bool ret = FALSE;
466
467     EGLint attribs[] = {
468         EGL_WIDTH, 0,
469         EGL_HEIGHT, 0,
470         EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_ARGB8888,
471         EGL_DMA_BUF_PLANE0_FD_EXT, 0,
472         EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
473         EGL_DMA_BUF_PLANE0_PITCH_EXT, 0,
474         EGL_NONE
475     };
476
477     glamor_egl = glamor_egl_get_screen_private(scrn);
478
479     if (!glamor_egl->dri3_capable)
480         return NULL;
481
482     if (bpp != 32 || !(depth == 24 || depth == 32) || width == 0 || height == 0)
483         return NULL;
484
485     attribs[1] = width;
486     attribs[3] = height;
487     attribs[7] = fd;
488     attribs[11] = stride;
489     image = eglCreateImageKHR(glamor_egl->display,
490                               EGL_NO_CONTEXT,
491                               EGL_LINUX_DMA_BUF_EXT,
492                               NULL, attribs);
493
494     if (image == EGL_NO_IMAGE_KHR)
495         return NULL;
496
497     /* EGL_EXT_image_dma_buf_import can impose restrictions on the
498      * usage of the image. Use gbm_bo to bypass the limitations. */
499
500     bo = gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_EGL_IMAGE, image, 0);
501     eglDestroyImageKHR(glamor_egl->display, image);
502
503     if (!bo)
504         return NULL;
505
506     pixmap = screen->CreatePixmap(screen, 0, 0, depth, 0);
507     screen->ModifyPixmapHeader(pixmap, width, height, 0, 0, stride, NULL);
508
509     ret = glamor_egl_create_textured_pixmap_from_gbm_bo(pixmap, bo);
510     gbm_bo_destroy(bo);
511
512     if (ret)
513         return pixmap;
514     else {
515         screen->DestroyPixmap(pixmap);
516         return NULL;
517     }
518 #else
519     return NULL;
520 #endif
521 }
522
523 static void
524 _glamor_egl_destroy_pixmap_image(PixmapPtr pixmap)
525 {
526     ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
527     struct glamor_egl_screen_private *glamor_egl =
528         glamor_egl_get_screen_private(scrn);
529     struct glamor_pixmap_private *pixmap_priv =
530         glamor_get_pixmap_private(pixmap);
531
532     if (pixmap_priv->base.image) {
533         /* Before destroy an image which was attached to
534          * a texture. we must call glFlush to make sure the
535          * operation on that texture has been done.*/
536         glamor_block_handler(pixmap->drawable.pScreen);
537         eglDestroyImageKHR(glamor_egl->display, pixmap_priv->base.image);
538         pixmap_priv->base.image = NULL;
539     }
540 }
541
542 _X_EXPORT void
543 glamor_egl_exchange_buffers(PixmapPtr front, PixmapPtr back)
544 {
545     ScrnInfoPtr scrn = xf86ScreenToScrn(front->drawable.pScreen);
546     struct glamor_egl_screen_private *glamor_egl =
547         glamor_egl_get_screen_private(scrn);
548     EGLImageKHR temp;
549     struct glamor_pixmap_private *front_priv =
550         glamor_get_pixmap_private(front);
551     struct glamor_pixmap_private *back_priv =
552         glamor_get_pixmap_private(back);
553
554     glamor_pixmap_exchange_fbos(front, back);
555
556     temp = back_priv->base.image;
557     back_priv->base.image = front_priv->base.image;
558     front_priv->base.image = temp;
559
560     glamor_set_pixmap_type(front, GLAMOR_TEXTURE_DRM);
561     glamor_set_pixmap_type(back, GLAMOR_TEXTURE_DRM);
562     glamor_egl->front_image = front_priv->base.image;
563
564 }
565
566 void
567 glamor_egl_destroy_textured_pixmap(PixmapPtr pixmap)
568 {
569     if (pixmap->refcnt == 1)
570         _glamor_egl_destroy_pixmap_image(pixmap);
571     glamor_destroy_textured_pixmap(pixmap);
572 }
573
574 static Bool
575 glamor_egl_close_screen(ScreenPtr screen)
576 {
577     ScrnInfoPtr scrn;
578     struct glamor_egl_screen_private *glamor_egl;
579     struct glamor_pixmap_private *pixmap_priv;
580     PixmapPtr screen_pixmap;
581
582     scrn = xf86ScreenToScrn(screen);
583     glamor_egl = glamor_egl_get_screen_private(scrn);
584     screen_pixmap = screen->GetScreenPixmap(screen);
585     pixmap_priv = glamor_get_pixmap_private(screen_pixmap);
586
587     eglDestroyImageKHR(glamor_egl->display, glamor_egl->front_image);
588     pixmap_priv->base.image = NULL;
589     glamor_egl->front_image = NULL;
590
591     if (glamor_egl->back_pixmap && *glamor_egl->back_pixmap) {
592         pixmap_priv = glamor_get_pixmap_private(*glamor_egl->back_pixmap);
593         if (pixmap_priv->base.image) {
594             eglDestroyImageKHR(glamor_egl->display, pixmap_priv->base.image);
595             pixmap_priv->base.image = NULL;
596         }
597     }
598
599     screen->CloseScreen = glamor_egl->saved_close_screen;
600
601     return screen->CloseScreen(screen);
602 }
603
604 static int
605 glamor_dri3_open_client(ClientPtr client,
606                         ScreenPtr screen,
607                         RRProviderPtr provider,
608                         int *fdp)
609 {
610     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
611     struct glamor_egl_screen_private *glamor_egl =
612         glamor_egl_get_screen_private(scrn);
613     int fd;
614     drm_magic_t magic;
615
616     fd = open(glamor_egl->device_path, O_RDWR|O_CLOEXEC);
617     if (fd < 0)
618         return BadAlloc;
619
620     /* Before FD passing in the X protocol with DRI3 (and increased
621      * security of rendering with per-process address spaces on the
622      * GPU), the kernel had to come up with a way to have the server
623      * decide which clients got to access the GPU, which was done by
624      * each client getting a unique (magic) number from the kernel,
625      * passing it to the server, and the server then telling the
626      * kernel which clients were authenticated for using the device.
627      *
628      * Now that we have FD passing, the server can just set up the
629      * authentication on its own and hand the prepared FD off to the
630      * client.
631      */
632     if (drmGetMagic(fd, &magic) < 0) {
633         if (errno == EACCES) {
634             /* Assume that we're on a render node, and the fd is
635              * already as authenticated as it should be.
636              */
637             *fdp = fd;
638             return Success;
639         } else {
640             close(fd);
641             return BadMatch;
642         }
643     }
644
645     if (drmAuthMagic(glamor_egl->fd, magic) < 0) {
646         close(fd);
647         return BadMatch;
648     }
649
650     *fdp = fd;
651     return Success;
652 }
653
654 static dri3_screen_info_rec glamor_dri3_info = {
655     .version = 1,
656     .open_client = glamor_dri3_open_client,
657     .pixmap_from_fd = glamor_pixmap_from_fd,
658     .fd_from_pixmap = glamor_fd_from_pixmap,
659 };
660
661 void
662 glamor_egl_screen_init(ScreenPtr screen, struct glamor_context *glamor_ctx)
663 {
664     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
665     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
666     struct glamor_egl_screen_private *glamor_egl =
667         glamor_egl_get_screen_private(scrn);
668
669     glamor_egl->saved_close_screen = screen->CloseScreen;
670     screen->CloseScreen = glamor_egl_close_screen;
671
672     glamor_ctx->ctx = glamor_egl->context;
673     glamor_ctx->display = glamor_egl->display;
674
675     glamor_ctx->make_current = glamor_egl_make_current;
676
677     if (glamor_egl->dri3_capable) {
678         /* Tell the core that we have the interfaces for import/export
679          * of pixmaps.
680          */
681         glamor_enable_dri3(screen);
682
683         /* If the driver wants to do its own auth dance (e.g. Xwayland
684          * on pre-3.15 kernels that don't have render nodes and thus
685          * has the wayland compositor as a master), then it needs us
686          * to stay out of the way and let it init DRI3 on its own.
687          */
688         if (!(glamor_priv->flags & GLAMOR_NO_DRI3)) {
689             /* To do DRI3 device FD generation, we need to open a new fd
690              * to the same device we were handed in originally.
691              */
692             glamor_egl->device_path = drmGetDeviceNameFromFd(glamor_egl->fd);
693
694             if (!dri3_screen_init(screen, &glamor_dri3_info)) {
695                 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
696                            "Failed to initialize DRI3.\n");
697             }
698         }
699     }
700 }
701
702 static void
703 glamor_egl_free_screen(ScrnInfoPtr scrn)
704 {
705     struct glamor_egl_screen_private *glamor_egl;
706
707     glamor_egl = glamor_egl_get_screen_private(scrn);
708     if (glamor_egl != NULL) {
709
710         eglMakeCurrent(glamor_egl->display,
711                        EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
712 #ifdef GLAMOR_HAS_GBM
713         if (glamor_egl->gbm)
714             gbm_device_destroy(glamor_egl->gbm);
715 #endif
716         free(glamor_egl->device_path);
717
718         scrn->FreeScreen = glamor_egl->saved_free_screen;
719         free(glamor_egl);
720         scrn->FreeScreen(scrn);
721     }
722 }
723
724 Bool
725 glamor_egl_init(ScrnInfoPtr scrn, int fd)
726 {
727     struct glamor_egl_screen_private *glamor_egl;
728     const char *version;
729
730     EGLint config_attribs[] = {
731 #ifdef GLAMOR_GLES2
732         EGL_CONTEXT_CLIENT_VERSION, 2,
733 #endif
734         EGL_NONE
735     };
736
737     glamor_identify(0);
738     glamor_egl = calloc(sizeof(*glamor_egl), 1);
739     if (glamor_egl == NULL)
740         return FALSE;
741     if (xf86GlamorEGLPrivateIndex == -1)
742         xf86GlamorEGLPrivateIndex = xf86AllocateScrnInfoPrivateIndex();
743
744     scrn->privates[xf86GlamorEGLPrivateIndex].ptr = glamor_egl;
745     glamor_egl->fd = fd;
746 #ifdef GLAMOR_HAS_GBM
747     glamor_egl->gbm = gbm_create_device(glamor_egl->fd);
748     if (glamor_egl->gbm == NULL) {
749         ErrorF("couldn't get display device\n");
750         return FALSE;
751     }
752     glamor_egl->display = eglGetDisplay(glamor_egl->gbm);
753 #else
754     glamor_egl->display = eglGetDisplay((EGLNativeDisplayType) (intptr_t) fd);
755 #endif
756
757     glamor_egl->has_gem = glamor_egl_check_has_gem(fd);
758
759 #ifndef GLAMOR_GLES2
760     eglBindAPI(EGL_OPENGL_API);
761 #else
762     eglBindAPI(EGL_OPENGL_ES_API);
763 #endif
764     if (!eglInitialize
765         (glamor_egl->display, &glamor_egl->major, &glamor_egl->minor)) {
766         xf86DrvMsg(scrn->scrnIndex, X_ERROR, "eglInitialize() failed\n");
767         return FALSE;
768     }
769
770     version = eglQueryString(glamor_egl->display, EGL_VERSION);
771     xf86Msg(X_INFO, "%s: EGL version %s:\n", glamor_name, version);
772
773 #define GLAMOR_CHECK_EGL_EXTENSION(EXT)  \
774         if (!epoxy_has_egl_extension(glamor_egl->display, "EGL_" #EXT)) {  \
775                 ErrorF("EGL_" #EXT " required.\n");  \
776                 return FALSE;  \
777         }
778
779 #define GLAMOR_CHECK_EGL_EXTENSIONS(EXT1, EXT2)  \
780         if (!epoxy_has_egl_extension(glamor_egl->display, "EGL_" #EXT1) &&  \
781             !epoxy_has_egl_extension(glamor_egl->display, "EGL_" #EXT2)) {  \
782                 ErrorF("EGL_" #EXT1 " or EGL_" #EXT2 " required.\n");  \
783                 return FALSE;  \
784         }
785
786     GLAMOR_CHECK_EGL_EXTENSION(MESA_drm_image);
787     GLAMOR_CHECK_EGL_EXTENSION(KHR_gl_renderbuffer_image);
788 #ifdef GLAMOR_GLES2
789     GLAMOR_CHECK_EGL_EXTENSIONS(KHR_surfaceless_context, KHR_surfaceless_gles2);
790 #else
791     GLAMOR_CHECK_EGL_EXTENSIONS(KHR_surfaceless_context,
792                                 KHR_surfaceless_opengl);
793 #endif
794
795 #ifdef GLAMOR_HAS_GBM
796     if (epoxy_has_egl_extension(glamor_egl->display,
797                                 "EGL_KHR_gl_texture_2D_image") &&
798         epoxy_has_egl_extension(glamor_egl->display,
799                                 "EGL_EXT_image_dma_buf_import"))
800         glamor_egl->dri3_capable = TRUE;
801 #endif
802
803     glamor_egl->context = eglCreateContext(glamor_egl->display,
804                                            NULL, EGL_NO_CONTEXT,
805                                            config_attribs);
806     if (glamor_egl->context == EGL_NO_CONTEXT) {
807         xf86DrvMsg(scrn->scrnIndex, X_ERROR, "Failed to create EGL context\n");
808         return FALSE;
809     }
810
811     if (!eglMakeCurrent(glamor_egl->display,
812                         EGL_NO_SURFACE, EGL_NO_SURFACE, glamor_egl->context)) {
813         xf86DrvMsg(scrn->scrnIndex, X_ERROR,
814                    "Failed to make EGL context current\n");
815         return FALSE;
816     }
817     glamor_egl->saved_free_screen = scrn->FreeScreen;
818     scrn->FreeScreen = glamor_egl_free_screen;
819 #ifdef GLAMOR_GLES2
820     xf86DrvMsg(scrn->scrnIndex, X_INFO, "Using GLES2.\n");
821     xf86DrvMsg(scrn->scrnIndex, X_WARNING,
822                "Glamor is using GLES2 but GLX needs GL. "
823                "Indirect GLX may not work correctly.\n");
824 #endif
825     return TRUE;
826 }
827
828 /** Stub to retain compatibility with pre-server-1.16 ABI. */
829 Bool
830 glamor_egl_init_textured_pixmap(ScreenPtr screen)
831 {
832     return TRUE;
833 }