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