1 /*
2  * Copyright © 2010 Intel Corporation.
3  *
4  * Permission is hereby granted, free of charge, to any person
5  * obtaining a copy of this software and associated documentation
6  * files (the "Software"), to deal in the Software without
7  * restriction, including without limitation the rights to use, copy,
8  * modify, merge, publish, distribute, sublicense, and/or sell copies
9  * of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including
13  * the next paragraph) shall be included in all copies or substantial
14  * portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23  * DEALINGS IN THE SOFTWARE.
24  *
25  * Authors:
26  *    Zhigang Gong <zhigang.gong@linux.intel.com>
27  *
28  */
29 
30 #include "dix-config.h"
31 
32 #define GLAMOR_FOR_XORG
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include <sys/ioctl.h>
36 #include <errno.h>
37 #include <xf86.h>
38 #include <xf86Priv.h>
39 #include <xf86drm.h>
40 #define EGL_DISPLAY_NO_X_MESA
41 
42 #include <gbm.h>
43 #include <drm_fourcc.h>
44 
45 #include "glamor_egl.h"
46 
47 #include "glamor.h"
48 #include "glamor_priv.h"
49 #include "dri3.h"
50 
51 struct glamor_egl_screen_private {
52     EGLDisplay display;
53     EGLContext context;
54     char *device_path;
55 
56     CreateScreenResourcesProcPtr CreateScreenResources;
57     CloseScreenProcPtr CloseScreen;
58     int fd;
59     struct gbm_device *gbm;
60     int dmabuf_capable;
61 
62     CloseScreenProcPtr saved_close_screen;
63     DestroyPixmapProcPtr saved_destroy_pixmap;
64     xf86FreeScreenProc *saved_free_screen;
65 };
66 
67 int xf86GlamorEGLPrivateIndex = -1;
68 
69 
70 static struct glamor_egl_screen_private *
glamor_egl_get_screen_private(ScrnInfoPtr scrn)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
glamor_egl_make_current(struct glamor_context * glamor_ctx)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
glamor_get_flink_name(int fd,int handle,int * name)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
glamor_create_texture_from_image(ScreenPtr screen,EGLImageKHR image,GLuint * texture)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 *
glamor_egl_get_gbm_device(ScreenPtr screen)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
glamor_egl_create_textured_screen(ScreenPtr screen,int handle,int stride)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
glamor_egl_set_pixmap_image(PixmapPtr pixmap,EGLImageKHR image,Bool used_modifiers)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
glamor_egl_create_textured_pixmap(PixmapPtr pixmap,int handle,int stride)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
glamor_egl_create_textured_pixmap_from_gbm_bo(PixmapPtr pixmap,struct gbm_bo * bo,Bool used_modifiers)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                               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 
252 static void
glamor_get_name_from_bo(int gbm_fd,struct gbm_bo * bo,int * name)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
glamor_make_pixmap_exportable(PixmapPtr pixmap,Bool modifiers_ok)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     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 
361 static struct gbm_bo *
glamor_gbm_bo_from_pixmap_internal(ScreenPtr screen,PixmapPtr pixmap)362 glamor_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 
376 struct gbm_bo *
glamor_gbm_bo_from_pixmap(ScreenPtr screen,PixmapPtr pixmap)377 glamor_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 
385 int
glamor_egl_fds_from_pixmap(ScreenPtr screen,PixmapPtr pixmap,int * fds,uint32_t * strides,uint32_t * offsets,uint64_t * modifier)386 glamor_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
glamor_egl_fd_from_pixmap(ScreenPtr screen,PixmapPtr pixmap,CARD16 * stride,CARD32 * size)428 glamor_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 
453 int
glamor_egl_fd_name_from_pixmap(ScreenPtr screen,PixmapPtr pixmap,CARD16 * stride,CARD32 * size)454 glamor_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
glamor_back_pixmap_from_fd(PixmapPtr pixmap,int fd,CARD16 width,CARD16 height,CARD16 stride,CARD8 depth,CARD8 bpp)483 glamor_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 
520 static uint32_t
gbm_format_for_depth(CARD8 depth)521 gbm_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
glamor_pixmap_from_fds(ScreenPtr screen,CARD8 num_fds,const int * fds,CARD16 width,CARD16 height,const CARD32 * strides,const CARD32 * offsets,CARD8 depth,CARD8 bpp,uint64_t modifier)538 glamor_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
glamor_pixmap_from_fd(ScreenPtr screen,int fd,CARD16 width,CARD16 height,CARD16 stride,CARD8 depth,CARD8 bpp)592 glamor_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
glamor_get_formats(ScreenPtr screen,CARD32 * num_formats,CARD32 ** formats)614 glamor_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
glamor_get_modifiers(ScreenPtr screen,uint32_t format,uint32_t * num_modifiers,uint64_t ** modifiers)654 glamor_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 *
glamor_egl_get_driver_name(ScreenPtr screen)695 glamor_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 
710 static Bool
glamor_egl_destroy_pixmap(PixmapPtr pixmap)711 glamor_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
glamor_egl_exchange_buffers(PixmapPtr front,PixmapPtr back)736 glamor_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 
758 static Bool
glamor_egl_close_screen(ScreenPtr screen)759 glamor_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
780 static int
glamor_dri3_open_client(ClientPtr client,ScreenPtr screen,RRProviderPtr provider,int * fdp)781 glamor_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 
830 static 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 
842 void
glamor_egl_screen_init(ScreenPtr screen,struct glamor_context * glamor_ctx)843 glamor_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 
glamor_egl_cleanup(struct glamor_egl_screen_private * glamor_egl)888 static 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 
906 static void
glamor_egl_free_screen(ScrnInfoPtr scrn)907 glamor_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 
919 Bool
glamor_egl_init(ScrnInfoPtr scrn,int fd)920 glamor_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 
1063 error:
1064     glamor_egl_cleanup(glamor_egl);
1065     return FALSE;
1066 }
1067 
1068 /** Stub to retain compatibility with pre-server-1.16 ABI. */
1069 Bool
glamor_egl_init_textured_pixmap(ScreenPtr screen)1070 glamor_egl_init_textured_pixmap(ScreenPtr screen)
1071 {
1072     return TRUE;
1073 }
1074