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