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