1 /*
2 * Copyright © 2011-2014 Intel Corporation
3 * Copyright © 2017 Red Hat Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person
6 * obtaining a copy of this software and associated documentation
7 * files (the "Software"), to deal in the Software without
8 * restriction, including without limitation the rights to use, copy,
9 * modify, merge, publish, distribute, sublicense, and/or sell copies
10 * of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including
14 * the next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
25 *
26 * Authors:
27 * Lyude Paul <lyude@redhat.com>
28 *
29 */
30
31 #include <xwayland-config.h>
32
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <sys/stat.h>
36 #include <xf86drm.h>
37 #include <drm_fourcc.h>
38
39 #define MESA_EGL_NO_X11_HEADERS
40 #define EGL_NO_X11
41 #include <gbm.h>
42 #include <glamor_egl.h>
43
44 #include <glamor.h>
45 #include <glamor_context.h>
46 #include <dri3.h>
47 #include "drm-client-protocol.h"
48
49 #include "xwayland-glamor.h"
50 #include "xwayland-pixmap.h"
51 #include "xwayland-screen.h"
52
53 #include "linux-dmabuf-unstable-v1-client-protocol.h"
54
55 struct xwl_gbm_private {
56 char *device_name;
57 struct gbm_device *gbm;
58 struct wl_drm *drm;
59 struct zwp_linux_dmabuf_v1 *dmabuf;
60 int drm_fd;
61 int fd_render_node;
62 Bool drm_authenticated;
63 uint32_t capabilities;
64 int dmabuf_capable;
65 };
66
67 struct xwl_pixmap {
68 struct wl_buffer *buffer;
69 EGLImage image;
70 unsigned int texture;
71 struct gbm_bo *bo;
72 };
73
74 static DevPrivateKeyRec xwl_gbm_private_key;
75 static DevPrivateKeyRec xwl_auth_state_private_key;
76
77 static inline struct xwl_gbm_private *
xwl_gbm_get(struct xwl_screen * xwl_screen)78 xwl_gbm_get(struct xwl_screen *xwl_screen)
79 {
80 return dixLookupPrivate(&xwl_screen->screen->devPrivates,
81 &xwl_gbm_private_key);
82 }
83
84 static uint32_t
gbm_format_for_depth(int depth)85 gbm_format_for_depth(int depth)
86 {
87 switch (depth) {
88 case 16:
89 return GBM_FORMAT_RGB565;
90 case 24:
91 return GBM_FORMAT_XRGB8888;
92 case 30:
93 return GBM_FORMAT_ARGB2101010;
94 default:
95 ErrorF("unexpected depth: %d\n", depth);
96 case 32:
97 return GBM_FORMAT_ARGB8888;
98 }
99 }
100
101 static uint32_t
wl_drm_format_for_depth(int depth)102 wl_drm_format_for_depth(int depth)
103 {
104 switch (depth) {
105 case 15:
106 return WL_DRM_FORMAT_XRGB1555;
107 case 16:
108 return WL_DRM_FORMAT_RGB565;
109 case 24:
110 return WL_DRM_FORMAT_XRGB8888;
111 case 30:
112 return WL_DRM_FORMAT_ARGB2101010;
113 default:
114 ErrorF("unexpected depth: %d\n", depth);
115 case 32:
116 return WL_DRM_FORMAT_ARGB8888;
117 }
118 }
119
120 static char
is_device_path_render_node(const char * device_path)121 is_device_path_render_node (const char *device_path)
122 {
123 char is_render_node;
124 int fd;
125
126 fd = open(device_path, O_RDWR | O_CLOEXEC);
127 if (fd < 0)
128 return 0;
129
130 is_render_node = (drmGetNodeTypeFromFd(fd) == DRM_NODE_RENDER);
131 close(fd);
132
133 return is_render_node;
134 }
135
136 static PixmapPtr
xwl_glamor_gbm_create_pixmap_for_bo(ScreenPtr screen,struct gbm_bo * bo,int depth)137 xwl_glamor_gbm_create_pixmap_for_bo(ScreenPtr screen, struct gbm_bo *bo,
138 int depth)
139 {
140 PixmapPtr pixmap;
141 struct xwl_pixmap *xwl_pixmap;
142 struct xwl_screen *xwl_screen = xwl_screen_get(screen);
143
144 xwl_pixmap = calloc(1, sizeof(*xwl_pixmap));
145 if (xwl_pixmap == NULL)
146 return NULL;
147
148 pixmap = glamor_create_pixmap(screen,
149 gbm_bo_get_width(bo),
150 gbm_bo_get_height(bo),
151 depth,
152 GLAMOR_CREATE_PIXMAP_NO_TEXTURE);
153 if (!pixmap) {
154 free(xwl_pixmap);
155 return NULL;
156 }
157
158 xwl_glamor_egl_make_current(xwl_screen);
159 xwl_pixmap->bo = bo;
160 xwl_pixmap->buffer = NULL;
161 xwl_pixmap->image = eglCreateImageKHR(xwl_screen->egl_display,
162 xwl_screen->egl_context,
163 EGL_NATIVE_PIXMAP_KHR,
164 xwl_pixmap->bo, NULL);
165 if (xwl_pixmap->image == EGL_NO_IMAGE_KHR)
166 goto error;
167
168 glGenTextures(1, &xwl_pixmap->texture);
169 glBindTexture(GL_TEXTURE_2D, xwl_pixmap->texture);
170 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
171 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
172
173 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, xwl_pixmap->image);
174 if (eglGetError() != EGL_SUCCESS)
175 goto error;
176
177 glBindTexture(GL_TEXTURE_2D, 0);
178
179 if (!glamor_set_pixmap_texture(pixmap, xwl_pixmap->texture))
180 goto error;
181
182 glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM);
183 xwl_pixmap_set_private(pixmap, xwl_pixmap);
184
185 return pixmap;
186
187 error:
188 if (xwl_pixmap->image != EGL_NO_IMAGE_KHR)
189 eglDestroyImageKHR(xwl_screen->egl_display, xwl_pixmap->image);
190 if (pixmap)
191 glamor_destroy_pixmap(pixmap);
192 free(xwl_pixmap);
193
194 return NULL;
195 }
196
197 static PixmapPtr
xwl_glamor_gbm_create_pixmap(ScreenPtr screen,int width,int height,int depth,unsigned int hint)198 xwl_glamor_gbm_create_pixmap(ScreenPtr screen,
199 int width, int height, int depth,
200 unsigned int hint)
201 {
202 struct xwl_screen *xwl_screen = xwl_screen_get(screen);
203 struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
204 struct gbm_bo *bo;
205 PixmapPtr pixmap = NULL;
206
207 if (width > 0 && height > 0 && depth >= 15 &&
208 (hint == CREATE_PIXMAP_USAGE_BACKING_PIXMAP ||
209 hint == CREATE_PIXMAP_USAGE_SHARED ||
210 (xwl_screen->rootless && hint == 0))) {
211 uint32_t format = gbm_format_for_depth(depth);
212
213 #ifdef GBM_BO_WITH_MODIFIERS
214 if (xwl_gbm->dmabuf_capable) {
215 uint32_t num_modifiers;
216 uint64_t *modifiers = NULL;
217
218 glamor_get_modifiers(screen, format, &num_modifiers, &modifiers);
219 bo = gbm_bo_create_with_modifiers(xwl_gbm->gbm, width, height,
220 format, modifiers, num_modifiers);
221 free(modifiers);
222 }
223 else
224 #endif
225 {
226 bo = gbm_bo_create(xwl_gbm->gbm, width, height, format,
227 GBM_BO_USE_RENDERING);
228 }
229
230 if (bo) {
231 pixmap = xwl_glamor_gbm_create_pixmap_for_bo(screen, bo, depth);
232
233 if (!pixmap) {
234 gbm_bo_destroy(bo);
235 }
236 else if (xwl_screen->rootless && hint == CREATE_PIXMAP_USAGE_BACKING_PIXMAP) {
237 glamor_clear_pixmap(pixmap);
238 }
239 }
240 }
241
242 if (!pixmap)
243 pixmap = glamor_create_pixmap(screen, width, height, depth, hint);
244
245 return pixmap;
246 }
247
248 static Bool
xwl_glamor_gbm_destroy_pixmap(PixmapPtr pixmap)249 xwl_glamor_gbm_destroy_pixmap(PixmapPtr pixmap)
250 {
251 struct xwl_screen *xwl_screen = xwl_screen_get(pixmap->drawable.pScreen);
252 struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
253
254 if (xwl_pixmap && pixmap->refcnt == 1) {
255 xwl_pixmap_del_buffer_release_cb(pixmap);
256 if (xwl_pixmap->buffer)
257 wl_buffer_destroy(xwl_pixmap->buffer);
258
259 eglDestroyImageKHR(xwl_screen->egl_display, xwl_pixmap->image);
260 if (xwl_pixmap->bo)
261 gbm_bo_destroy(xwl_pixmap->bo);
262 free(xwl_pixmap);
263 }
264
265 return glamor_destroy_pixmap(pixmap);
266 }
267
268 static const struct wl_buffer_listener xwl_glamor_gbm_buffer_listener = {
269 xwl_pixmap_buffer_release_cb,
270 };
271
272 static struct wl_buffer *
xwl_glamor_gbm_get_wl_buffer_for_pixmap(PixmapPtr pixmap,Bool * created)273 xwl_glamor_gbm_get_wl_buffer_for_pixmap(PixmapPtr pixmap,
274 Bool *created)
275 {
276 struct xwl_screen *xwl_screen = xwl_screen_get(pixmap->drawable.pScreen);
277 struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
278 struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
279 unsigned short width = pixmap->drawable.width;
280 unsigned short height = pixmap->drawable.height;
281 uint32_t format;
282 struct xwl_format *xwl_format = NULL;
283 Bool modifier_supported = FALSE;
284 int prime_fd;
285 int num_planes;
286 uint32_t strides[4];
287 uint32_t offsets[4];
288 uint64_t modifier;
289 int i;
290
291 if (xwl_pixmap == NULL)
292 return NULL;
293
294 if (xwl_pixmap->buffer) {
295 /* Buffer already exists. Return it and inform caller if interested. */
296 if (created)
297 *created = FALSE;
298 return xwl_pixmap->buffer;
299 }
300
301 /* Buffer does not exist yet. Create now and inform caller if interested. */
302 if (created)
303 *created = TRUE;
304
305 if (!xwl_pixmap->bo)
306 return NULL;
307
308 format = wl_drm_format_for_depth(pixmap->drawable.depth);
309
310 prime_fd = gbm_bo_get_fd(xwl_pixmap->bo);
311 if (prime_fd == -1)
312 return NULL;
313
314 #ifdef GBM_BO_WITH_MODIFIERS
315 num_planes = gbm_bo_get_plane_count(xwl_pixmap->bo);
316 modifier = gbm_bo_get_modifier(xwl_pixmap->bo);
317 for (i = 0; i < num_planes; i++) {
318 strides[i] = gbm_bo_get_stride_for_plane(xwl_pixmap->bo, i);
319 offsets[i] = gbm_bo_get_offset(xwl_pixmap->bo, i);
320 }
321 #else
322 num_planes = 1;
323 modifier = DRM_FORMAT_MOD_INVALID;
324 strides[0] = gbm_bo_get_stride(xwl_pixmap->bo);
325 offsets[0] = 0;
326 #endif
327
328 for (i = 0; i < xwl_screen->num_formats; i++) {
329 if (xwl_screen->formats[i].format == format) {
330 xwl_format = &xwl_screen->formats[i];
331 break;
332 }
333 }
334
335 if (xwl_format) {
336 for (i = 0; i < xwl_format->num_modifiers; i++) {
337 if (xwl_format->modifiers[i] == modifier) {
338 modifier_supported = TRUE;
339 break;
340 }
341 }
342 }
343
344 if (xwl_gbm->dmabuf && modifier_supported) {
345 struct zwp_linux_buffer_params_v1 *params;
346
347 params = zwp_linux_dmabuf_v1_create_params(xwl_gbm->dmabuf);
348 for (i = 0; i < num_planes; i++) {
349 zwp_linux_buffer_params_v1_add(params, prime_fd, i,
350 offsets[i], strides[i],
351 modifier >> 32, modifier & 0xffffffff);
352 }
353
354 xwl_pixmap->buffer =
355 zwp_linux_buffer_params_v1_create_immed(params, width, height,
356 format, 0);
357 zwp_linux_buffer_params_v1_destroy(params);
358 } else if (num_planes == 1) {
359 xwl_pixmap->buffer =
360 wl_drm_create_prime_buffer(xwl_gbm->drm, prime_fd, width, height,
361 format,
362 0, gbm_bo_get_stride(xwl_pixmap->bo),
363 0, 0,
364 0, 0);
365 }
366
367 close(prime_fd);
368
369 /* Add our listener now */
370 wl_buffer_add_listener(xwl_pixmap->buffer,
371 &xwl_glamor_gbm_buffer_listener, pixmap);
372
373 return xwl_pixmap->buffer;
374 }
375
376 static void
xwl_glamor_gbm_cleanup(struct xwl_screen * xwl_screen)377 xwl_glamor_gbm_cleanup(struct xwl_screen *xwl_screen)
378 {
379 struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
380
381 if (xwl_gbm->device_name)
382 free(xwl_gbm->device_name);
383 if (xwl_gbm->drm_fd)
384 close(xwl_gbm->drm_fd);
385 if (xwl_gbm->drm)
386 wl_drm_destroy(xwl_gbm->drm);
387 if (xwl_gbm->gbm)
388 gbm_device_destroy(xwl_gbm->gbm);
389
390 free(xwl_gbm);
391 }
392
393 struct xwl_auth_state {
394 int fd;
395 ClientPtr client;
396 struct wl_callback *callback;
397 };
398
399 static void
free_xwl_auth_state(ClientPtr pClient,struct xwl_auth_state * state)400 free_xwl_auth_state(ClientPtr pClient, struct xwl_auth_state *state)
401 {
402 dixSetPrivate(&pClient->devPrivates, &xwl_auth_state_private_key, NULL);
403 if (state) {
404 wl_callback_destroy(state->callback);
405 free(state);
406 }
407 }
408
409 static void
xwl_auth_state_client_callback(CallbackListPtr * pcbl,void * unused,void * data)410 xwl_auth_state_client_callback(CallbackListPtr *pcbl, void *unused, void *data)
411 {
412 NewClientInfoRec *clientinfo = (NewClientInfoRec *) data;
413 ClientPtr pClient = clientinfo->client;
414 struct xwl_auth_state *state;
415
416 switch (pClient->clientState) {
417 case ClientStateGone:
418 case ClientStateRetained:
419 state = dixLookupPrivate(&pClient->devPrivates,
420 &xwl_auth_state_private_key);
421 free_xwl_auth_state(pClient, state);
422 break;
423 default:
424 break;
425 }
426 }
427
428 static void
sync_callback(void * data,struct wl_callback * callback,uint32_t serial)429 sync_callback(void *data, struct wl_callback *callback, uint32_t serial)
430 {
431 struct xwl_auth_state *state = data;
432 ClientPtr client = state->client;
433
434 /* if the client is gone, the callback is cancelled so it's safe to
435 * assume the client is still in ClientStateRunning at this point...
436 */
437 dri3_send_open_reply(client, state->fd);
438 AttendClient(client);
439 free_xwl_auth_state(client, state);
440 }
441
442 static const struct wl_callback_listener sync_listener = {
443 sync_callback
444 };
445
446 static int
xwl_dri3_open_client(ClientPtr client,ScreenPtr screen,RRProviderPtr provider,int * pfd)447 xwl_dri3_open_client(ClientPtr client,
448 ScreenPtr screen,
449 RRProviderPtr provider,
450 int *pfd)
451 {
452 struct xwl_screen *xwl_screen = xwl_screen_get(screen);
453 struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
454 struct xwl_auth_state *state;
455 drm_magic_t magic;
456 int fd;
457
458 fd = open(xwl_gbm->device_name, O_RDWR | O_CLOEXEC);
459 if (fd < 0)
460 return BadAlloc;
461 if (xwl_gbm->fd_render_node) {
462 *pfd = fd;
463 return Success;
464 }
465
466 state = malloc(sizeof *state);
467 if (state == NULL) {
468 close(fd);
469 return BadAlloc;
470 }
471
472 state->client = client;
473 state->fd = fd;
474
475 if (drmGetMagic(state->fd, &magic) < 0) {
476 close(state->fd);
477 free(state);
478 return BadMatch;
479 }
480
481 wl_drm_authenticate(xwl_gbm->drm, magic);
482 state->callback = wl_display_sync(xwl_screen->display);
483 wl_callback_add_listener(state->callback, &sync_listener, state);
484 dixSetPrivate(&client->devPrivates, &xwl_auth_state_private_key, state);
485
486 IgnoreClient(client);
487
488 return Success;
489 }
490
491 _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)492 glamor_pixmap_from_fds(ScreenPtr screen, CARD8 num_fds, const int *fds,
493 CARD16 width, CARD16 height,
494 const CARD32 *strides, const CARD32 *offsets,
495 CARD8 depth, CARD8 bpp, uint64_t modifier)
496 {
497 struct xwl_screen *xwl_screen = xwl_screen_get(screen);
498 struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
499 struct gbm_bo *bo = NULL;
500 PixmapPtr pixmap;
501 int i;
502
503 if (width == 0 || height == 0 || num_fds == 0 ||
504 depth < 15 || bpp != BitsPerPixel(depth) ||
505 strides[0] < width * bpp / 8)
506 goto error;
507
508 if (xwl_gbm->dmabuf_capable && modifier != DRM_FORMAT_MOD_INVALID) {
509 #ifdef GBM_BO_WITH_MODIFIERS
510 struct gbm_import_fd_modifier_data data;
511
512 data.width = width;
513 data.height = height;
514 data.num_fds = num_fds;
515 data.format = gbm_format_for_depth(depth);
516 data.modifier = modifier;
517 for (i = 0; i < num_fds; i++) {
518 data.fds[i] = fds[i];
519 data.strides[i] = strides[i];
520 data.offsets[i] = offsets[i];
521 }
522 bo = gbm_bo_import(xwl_gbm->gbm, GBM_BO_IMPORT_FD_MODIFIER, &data,
523 GBM_BO_USE_RENDERING);
524 #endif
525 } else if (num_fds == 1) {
526 struct gbm_import_fd_data data;
527
528 data.fd = fds[0];
529 data.width = width;
530 data.height = height;
531 data.stride = strides[0];
532 data.format = gbm_format_for_depth(depth);
533 bo = gbm_bo_import(xwl_gbm->gbm, GBM_BO_IMPORT_FD, &data,
534 GBM_BO_USE_RENDERING);
535 } else {
536 goto error;
537 }
538
539 if (bo == NULL)
540 goto error;
541
542 pixmap = xwl_glamor_gbm_create_pixmap_for_bo(screen, bo, depth);
543 if (pixmap == NULL) {
544 gbm_bo_destroy(bo);
545 goto error;
546 }
547
548 return pixmap;
549
550 error:
551 return NULL;
552 }
553
554 _X_EXPORT int
glamor_egl_fds_from_pixmap(ScreenPtr screen,PixmapPtr pixmap,int * fds,uint32_t * strides,uint32_t * offsets,uint64_t * modifier)555 glamor_egl_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds,
556 uint32_t *strides, uint32_t *offsets,
557 uint64_t *modifier)
558 {
559 struct xwl_pixmap *xwl_pixmap;
560 #ifdef GBM_BO_WITH_MODIFIERS
561 uint32_t num_fds;
562 int i;
563 #endif
564
565 xwl_pixmap = xwl_pixmap_get(pixmap);
566
567 if (xwl_pixmap == NULL)
568 return 0;
569
570 if (!xwl_pixmap->bo)
571 return 0;
572
573 #ifdef GBM_BO_WITH_MODIFIERS
574 num_fds = gbm_bo_get_plane_count(xwl_pixmap->bo);
575 *modifier = gbm_bo_get_modifier(xwl_pixmap->bo);
576
577 for (i = 0; i < num_fds; i++) {
578 fds[i] = gbm_bo_get_fd(xwl_pixmap->bo);
579 strides[i] = gbm_bo_get_stride_for_plane(xwl_pixmap->bo, i);
580 offsets[i] = gbm_bo_get_offset(xwl_pixmap->bo, i);
581 }
582
583 return num_fds;
584 #else
585 *modifier = DRM_FORMAT_MOD_INVALID;
586 fds[0] = gbm_bo_get_fd(xwl_pixmap->bo);
587 strides[0] = gbm_bo_get_stride(xwl_pixmap->bo);
588 offsets[0] = 0;
589 return 1;
590 #endif
591 }
592
593 /* Not actually used, just defined here so there's something for
594 * _glamor_egl_fds_from_pixmap() to link against
595 */
596 _X_EXPORT int
glamor_egl_fd_from_pixmap(ScreenPtr screen,PixmapPtr pixmap,CARD16 * stride,CARD32 * size)597 glamor_egl_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap,
598 CARD16 *stride, CARD32 *size)
599 {
600 return -1;
601 }
602
603 _X_EXPORT Bool
glamor_get_formats(ScreenPtr screen,CARD32 * num_formats,CARD32 ** formats)604 glamor_get_formats(ScreenPtr screen,
605 CARD32 *num_formats, CARD32 **formats)
606 {
607 struct xwl_screen *xwl_screen = xwl_screen_get(screen);
608 struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
609 int i;
610
611 /* Explicitly zero the count as the caller may ignore the return value */
612 *num_formats = 0;
613
614 if (!xwl_gbm->dmabuf_capable || !xwl_gbm->dmabuf)
615 return FALSE;
616
617 if (xwl_screen->num_formats == 0)
618 return TRUE;
619
620 *formats = calloc(xwl_screen->num_formats, sizeof(CARD32));
621 if (*formats == NULL)
622 return FALSE;
623
624 for (i = 0; i < xwl_screen->num_formats; i++)
625 (*formats)[i] = xwl_screen->formats[i].format;
626 *num_formats = xwl_screen->num_formats;
627
628 return TRUE;
629 }
630
631 _X_EXPORT Bool
glamor_get_modifiers(ScreenPtr screen,uint32_t format,uint32_t * num_modifiers,uint64_t ** modifiers)632 glamor_get_modifiers(ScreenPtr screen, uint32_t format,
633 uint32_t *num_modifiers, uint64_t **modifiers)
634 {
635 struct xwl_screen *xwl_screen = xwl_screen_get(screen);
636 struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
637 struct xwl_format *xwl_format = NULL;
638 int i;
639
640 /* Explicitly zero the count as the caller may ignore the return value */
641 *num_modifiers = 0;
642
643 if (!xwl_gbm->dmabuf_capable || !xwl_gbm->dmabuf)
644 return FALSE;
645
646 if (xwl_screen->num_formats == 0)
647 return TRUE;
648
649 for (i = 0; i < xwl_screen->num_formats; i++) {
650 if (xwl_screen->formats[i].format == format) {
651 xwl_format = &xwl_screen->formats[i];
652 break;
653 }
654 }
655
656 if (!xwl_format ||
657 (xwl_format->num_modifiers == 1 &&
658 xwl_format->modifiers[0] == DRM_FORMAT_MOD_INVALID))
659 return FALSE;
660
661 *modifiers = calloc(xwl_format->num_modifiers, sizeof(uint64_t));
662 if (*modifiers == NULL)
663 return FALSE;
664
665 for (i = 0; i < xwl_format->num_modifiers; i++)
666 (*modifiers)[i] = xwl_format->modifiers[i];
667 *num_modifiers = xwl_format->num_modifiers;
668
669 return TRUE;
670 }
671
672 static const dri3_screen_info_rec xwl_dri3_info = {
673 .version = 2,
674 .open = NULL,
675 .pixmap_from_fds = glamor_pixmap_from_fds,
676 .fds_from_pixmap = glamor_fds_from_pixmap,
677 .open_client = xwl_dri3_open_client,
678 .get_formats = glamor_get_formats,
679 .get_modifiers = glamor_get_modifiers,
680 .get_drawable_modifiers = glamor_get_drawable_modifiers,
681 };
682
683 static const char *
get_render_node_path_for_device(const drmDevicePtr drm_device,const char * device_path)684 get_render_node_path_for_device(const drmDevicePtr drm_device,
685 const char *device_path)
686 {
687 char *render_node_path = NULL;
688 char device_found = 0;
689 int i;
690
691 for (i = 0; i < DRM_NODE_MAX; i++) {
692 if ((drm_device->available_nodes & (1 << i)) == 0)
693 continue;
694
695 if (!strcmp (device_path, drm_device->nodes[i]))
696 device_found = 1;
697
698 if (is_device_path_render_node(drm_device->nodes[i]))
699 render_node_path = drm_device->nodes[i];
700
701 if (device_found && render_node_path)
702 return render_node_path;
703 }
704
705 return NULL;
706 }
707
708 static char *
get_render_node_path(const char * device_path)709 get_render_node_path(const char *device_path)
710 {
711 drmDevicePtr *devices = NULL;
712 char *render_node_path = NULL;
713 int i, n_devices, max_devices;
714
715 max_devices = drmGetDevices2(0, NULL, 0);
716 if (max_devices <= 0)
717 goto out;
718
719 devices = calloc(max_devices, sizeof(drmDevicePtr));
720 if (!devices)
721 goto out;
722
723 n_devices = drmGetDevices2(0, devices, max_devices);
724 if (n_devices < 0)
725 goto out;
726
727 for (i = 0; i < n_devices; i++) {
728 const char *node_path = get_render_node_path_for_device(devices[i],
729 device_path);
730 if (node_path) {
731 render_node_path = strdup(node_path);
732 break;
733 }
734 }
735
736 out:
737 free(devices);
738 return render_node_path;
739 }
740
741 static void
xwl_drm_handle_device(void * data,struct wl_drm * drm,const char * device)742 xwl_drm_handle_device(void *data, struct wl_drm *drm, const char *device)
743 {
744 struct xwl_screen *xwl_screen = data;
745 struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
746 drm_magic_t magic;
747 char *render_node_path = NULL;
748
749 if (!is_device_path_render_node(device))
750 render_node_path = get_render_node_path(device);
751
752 if (render_node_path)
753 xwl_gbm->device_name = render_node_path;
754 else
755 xwl_gbm->device_name = strdup(device);
756
757 if (!xwl_gbm->device_name) {
758 xwl_glamor_gbm_cleanup(xwl_screen);
759 return;
760 }
761
762 xwl_gbm->drm_fd = open(xwl_gbm->device_name, O_RDWR | O_CLOEXEC);
763 if (xwl_gbm->drm_fd == -1) {
764 ErrorF("wayland-egl: could not open %s (%s)\n",
765 xwl_gbm->device_name, strerror(errno));
766 xwl_glamor_gbm_cleanup(xwl_screen);
767 return;
768 }
769
770 if (drmGetNodeTypeFromFd(xwl_gbm->drm_fd) == DRM_NODE_RENDER) {
771 xwl_gbm->fd_render_node = 1;
772 xwl_screen->expecting_event--;
773 } else {
774 drmGetMagic(xwl_gbm->drm_fd, &magic);
775 wl_drm_authenticate(xwl_gbm->drm, magic);
776 }
777 }
778
779 static void
xwl_drm_handle_format(void * data,struct wl_drm * drm,uint32_t format)780 xwl_drm_handle_format(void *data, struct wl_drm *drm, uint32_t format)
781 {
782 }
783
784 static void
xwl_drm_handle_authenticated(void * data,struct wl_drm * drm)785 xwl_drm_handle_authenticated(void *data, struct wl_drm *drm)
786 {
787 struct xwl_screen *xwl_screen = data;
788 struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
789
790 xwl_gbm->drm_authenticated = TRUE;
791 xwl_screen->expecting_event--;
792 }
793
794 static void
xwl_drm_handle_capabilities(void * data,struct wl_drm * drm,uint32_t value)795 xwl_drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t value)
796 {
797 xwl_gbm_get(data)->capabilities = value;
798 }
799
800 static const struct wl_drm_listener xwl_drm_listener = {
801 xwl_drm_handle_device,
802 xwl_drm_handle_format,
803 xwl_drm_handle_authenticated,
804 xwl_drm_handle_capabilities
805 };
806
807 static void
xwl_dmabuf_handle_format(void * data,struct zwp_linux_dmabuf_v1 * dmabuf,uint32_t format)808 xwl_dmabuf_handle_format(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
809 uint32_t format)
810 {
811 }
812
813 static void
xwl_dmabuf_handle_modifier(void * data,struct zwp_linux_dmabuf_v1 * dmabuf,uint32_t format,uint32_t modifier_hi,uint32_t modifier_lo)814 xwl_dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
815 uint32_t format, uint32_t modifier_hi,
816 uint32_t modifier_lo)
817 {
818 struct xwl_screen *xwl_screen = data;
819 struct xwl_format *xwl_format = NULL;
820 int i;
821
822 for (i = 0; i < xwl_screen->num_formats; i++) {
823 if (xwl_screen->formats[i].format == format) {
824 xwl_format = &xwl_screen->formats[i];
825 break;
826 }
827 }
828
829 if (xwl_format == NULL) {
830 xwl_screen->num_formats++;
831 xwl_screen->formats = realloc(xwl_screen->formats,
832 xwl_screen->num_formats * sizeof(*xwl_format));
833 if (!xwl_screen->formats)
834 return;
835 xwl_format = &xwl_screen->formats[xwl_screen->num_formats - 1];
836 xwl_format->format = format;
837 xwl_format->num_modifiers = 0;
838 xwl_format->modifiers = NULL;
839 }
840
841 xwl_format->num_modifiers++;
842 xwl_format->modifiers = realloc(xwl_format->modifiers,
843 xwl_format->num_modifiers * sizeof(uint64_t));
844 if (!xwl_format->modifiers)
845 return;
846 xwl_format->modifiers[xwl_format->num_modifiers - 1] = (uint64_t) modifier_lo;
847 xwl_format->modifiers[xwl_format->num_modifiers - 1] |= (uint64_t) modifier_hi << 32;
848 }
849
850 static const struct zwp_linux_dmabuf_v1_listener xwl_dmabuf_listener = {
851 .format = xwl_dmabuf_handle_format,
852 .modifier = xwl_dmabuf_handle_modifier
853 };
854
855 Bool
xwl_screen_set_drm_interface(struct xwl_screen * xwl_screen,uint32_t id,uint32_t version)856 xwl_screen_set_drm_interface(struct xwl_screen *xwl_screen,
857 uint32_t id, uint32_t version)
858 {
859 struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
860
861 if (version < 2)
862 return FALSE;
863
864 xwl_gbm->drm =
865 wl_registry_bind(xwl_screen->registry, id, &wl_drm_interface, 2);
866 wl_drm_add_listener(xwl_gbm->drm, &xwl_drm_listener, xwl_screen);
867 xwl_screen->expecting_event++;
868
869 return TRUE;
870 }
871
872 Bool
xwl_screen_set_dmabuf_interface(struct xwl_screen * xwl_screen,uint32_t id,uint32_t version)873 xwl_screen_set_dmabuf_interface(struct xwl_screen *xwl_screen,
874 uint32_t id, uint32_t version)
875 {
876 struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
877
878 if (version < 3)
879 return FALSE;
880
881 xwl_gbm->dmabuf =
882 wl_registry_bind(xwl_screen->registry, id, &zwp_linux_dmabuf_v1_interface, 3);
883 zwp_linux_dmabuf_v1_add_listener(xwl_gbm->dmabuf, &xwl_dmabuf_listener, xwl_screen);
884
885 return TRUE;
886 }
887
888 static Bool
xwl_glamor_gbm_init_wl_registry(struct xwl_screen * xwl_screen,struct wl_registry * wl_registry,uint32_t id,const char * name,uint32_t version)889 xwl_glamor_gbm_init_wl_registry(struct xwl_screen *xwl_screen,
890 struct wl_registry *wl_registry,
891 uint32_t id, const char *name,
892 uint32_t version)
893 {
894 if (strcmp(name, "wl_drm") == 0) {
895 xwl_screen_set_drm_interface(xwl_screen, id, version);
896 return TRUE;
897 } else if (strcmp(name, "zwp_linux_dmabuf_v1") == 0) {
898 xwl_screen_set_dmabuf_interface(xwl_screen, id, version);
899 return TRUE;
900 }
901
902 /* no match */
903 return FALSE;
904 }
905
906 static Bool
xwl_glamor_gbm_has_egl_extension(void)907 xwl_glamor_gbm_has_egl_extension(void)
908 {
909 return (epoxy_has_egl_extension(NULL, "EGL_MESA_platform_gbm") ||
910 epoxy_has_egl_extension(NULL, "EGL_KHR_platform_gbm"));
911 }
912
913 static Bool
xwl_glamor_gbm_has_wl_interfaces(struct xwl_screen * xwl_screen)914 xwl_glamor_gbm_has_wl_interfaces(struct xwl_screen *xwl_screen)
915 {
916 struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
917
918 if (xwl_gbm->drm == NULL) {
919 ErrorF("glamor: 'wl_drm' not supported\n");
920 return FALSE;
921 }
922
923 return TRUE;
924 }
925
926 static Bool
xwl_glamor_gbm_init_egl(struct xwl_screen * xwl_screen)927 xwl_glamor_gbm_init_egl(struct xwl_screen *xwl_screen)
928 {
929 struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
930 EGLint major, minor;
931 Bool egl_initialized = FALSE;
932 static const EGLint config_attribs_core[] = {
933 EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR,
934 EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR,
935 EGL_CONTEXT_MAJOR_VERSION_KHR,
936 GLAMOR_GL_CORE_VER_MAJOR,
937 EGL_CONTEXT_MINOR_VERSION_KHR,
938 GLAMOR_GL_CORE_VER_MINOR,
939 EGL_NONE
940 };
941 const GLubyte *renderer;
942
943 if (!xwl_gbm->fd_render_node && !xwl_gbm->drm_authenticated) {
944 ErrorF("Failed to get wl_drm, disabling Glamor and DRI3\n");
945 return FALSE;
946 }
947
948 xwl_gbm->gbm = gbm_create_device(xwl_gbm->drm_fd);
949 if (!xwl_gbm->gbm) {
950 ErrorF("couldn't create gbm device\n");
951 goto error;
952 }
953
954 xwl_screen->egl_display = glamor_egl_get_display(EGL_PLATFORM_GBM_MESA,
955 xwl_gbm->gbm);
956 if (xwl_screen->egl_display == EGL_NO_DISPLAY) {
957 ErrorF("glamor_egl_get_display() failed\n");
958 goto error;
959 }
960
961 egl_initialized = eglInitialize(xwl_screen->egl_display, &major, &minor);
962 if (!egl_initialized) {
963 ErrorF("eglInitialize() failed\n");
964 goto error;
965 }
966
967 eglBindAPI(EGL_OPENGL_API);
968
969 xwl_screen->egl_context = eglCreateContext(
970 xwl_screen->egl_display, NULL, EGL_NO_CONTEXT, config_attribs_core);
971 if (xwl_screen->egl_context == EGL_NO_CONTEXT) {
972 xwl_screen->egl_context = eglCreateContext(
973 xwl_screen->egl_display, NULL, EGL_NO_CONTEXT, NULL);
974 }
975
976 if (xwl_screen->egl_context == EGL_NO_CONTEXT) {
977 ErrorF("Failed to create EGL context with GL\n");
978 goto error;
979 }
980
981 if (!eglMakeCurrent(xwl_screen->egl_display,
982 EGL_NO_SURFACE, EGL_NO_SURFACE,
983 xwl_screen->egl_context)) {
984 ErrorF("Failed to make EGL context current with GL\n");
985 goto error;
986 }
987
988 /* glamor needs either big-GL 2.1 or GLES2 */
989 if (epoxy_gl_version() < 21) {
990 const EGLint gles_attribs[] = {
991 EGL_CONTEXT_CLIENT_VERSION,
992 2,
993 EGL_NONE,
994 };
995
996 /* Recreate the context with GLES2 instead */
997 eglMakeCurrent(xwl_screen->egl_display,EGL_NO_SURFACE,
998 EGL_NO_SURFACE, EGL_NO_CONTEXT);
999 eglDestroyContext(xwl_screen->egl_display, xwl_screen->egl_context);
1000
1001 eglBindAPI(EGL_OPENGL_ES_API);
1002 xwl_screen->egl_context = eglCreateContext(xwl_screen->egl_display,
1003 NULL, EGL_NO_CONTEXT,
1004 gles_attribs);
1005
1006 if (xwl_screen->egl_context == EGL_NO_CONTEXT) {
1007 ErrorF("Failed to create EGL context with GLES2\n");
1008 goto error;
1009 }
1010
1011 if (!eglMakeCurrent(xwl_screen->egl_display,
1012 EGL_NO_SURFACE, EGL_NO_SURFACE,
1013 xwl_screen->egl_context)) {
1014 ErrorF("Failed to make EGL context current with GLES2\n");
1015 goto error;
1016 }
1017 }
1018
1019 renderer = glGetString(GL_RENDERER);
1020 if (!renderer) {
1021 ErrorF("glGetString() returned NULL, your GL is broken\n");
1022 goto error;
1023 }
1024 if (strstr((const char *)renderer, "llvmpipe")) {
1025 ErrorF("Refusing to try glamor on llvmpipe\n");
1026 goto error;
1027 }
1028
1029 if (!epoxy_has_gl_extension("GL_OES_EGL_image")) {
1030 ErrorF("GL_OES_EGL_image not available\n");
1031 goto error;
1032 }
1033
1034 if (epoxy_has_egl_extension(xwl_screen->egl_display,
1035 "EXT_image_dma_buf_import") &&
1036 epoxy_has_egl_extension(xwl_screen->egl_display,
1037 "EXT_image_dma_buf_import_modifiers"))
1038 xwl_gbm->dmabuf_capable = TRUE;
1039
1040 return TRUE;
1041 error:
1042 if (xwl_screen->egl_context != EGL_NO_CONTEXT) {
1043 eglDestroyContext(xwl_screen->egl_display, xwl_screen->egl_context);
1044 xwl_screen->egl_context = EGL_NO_CONTEXT;
1045 }
1046
1047 if (xwl_screen->egl_display != EGL_NO_DISPLAY) {
1048 eglTerminate(xwl_screen->egl_display);
1049 xwl_screen->egl_display = EGL_NO_DISPLAY;
1050 }
1051
1052 xwl_glamor_gbm_cleanup(xwl_screen);
1053 return FALSE;
1054 }
1055
1056 static Bool
xwl_glamor_gbm_init_screen(struct xwl_screen * xwl_screen)1057 xwl_glamor_gbm_init_screen(struct xwl_screen *xwl_screen)
1058 {
1059 struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen);
1060
1061 if (!dri3_screen_init(xwl_screen->screen, &xwl_dri3_info)) {
1062 ErrorF("Failed to initialize dri3\n");
1063 goto error;
1064 }
1065
1066 if (xwl_gbm->fd_render_node)
1067 goto skip_drm_auth;
1068
1069 if (!dixRegisterPrivateKey(&xwl_auth_state_private_key, PRIVATE_CLIENT,
1070 0)) {
1071 ErrorF("Failed to register private key\n");
1072 goto error;
1073 }
1074
1075 if (!AddCallback(&ClientStateCallback, xwl_auth_state_client_callback,
1076 NULL)) {
1077 ErrorF("Failed to add client state callback\n");
1078 goto error;
1079 }
1080
1081 skip_drm_auth:
1082 xwl_screen->screen->CreatePixmap = xwl_glamor_gbm_create_pixmap;
1083 xwl_screen->screen->DestroyPixmap = xwl_glamor_gbm_destroy_pixmap;
1084
1085 return TRUE;
1086 error:
1087 xwl_glamor_gbm_cleanup(xwl_screen);
1088 return FALSE;
1089 }
1090
1091 void
xwl_glamor_init_gbm(struct xwl_screen * xwl_screen)1092 xwl_glamor_init_gbm(struct xwl_screen *xwl_screen)
1093 {
1094 struct xwl_gbm_private *xwl_gbm;
1095
1096 xwl_screen->gbm_backend.is_available = FALSE;
1097
1098 if (!xwl_glamor_gbm_has_egl_extension())
1099 return;
1100
1101 if (!dixRegisterPrivateKey(&xwl_gbm_private_key, PRIVATE_SCREEN, 0))
1102 return;
1103
1104 xwl_gbm = calloc(sizeof(*xwl_gbm), 1);
1105 if (!xwl_gbm) {
1106 ErrorF("glamor: Not enough memory to setup GBM, disabling\n");
1107 return;
1108 }
1109
1110 dixSetPrivate(&xwl_screen->screen->devPrivates, &xwl_gbm_private_key,
1111 xwl_gbm);
1112
1113 xwl_screen->gbm_backend.init_wl_registry = xwl_glamor_gbm_init_wl_registry;
1114 xwl_screen->gbm_backend.has_wl_interfaces = xwl_glamor_gbm_has_wl_interfaces;
1115 xwl_screen->gbm_backend.init_egl = xwl_glamor_gbm_init_egl;
1116 xwl_screen->gbm_backend.init_screen = xwl_glamor_gbm_init_screen;
1117 xwl_screen->gbm_backend.get_wl_buffer_for_pixmap = xwl_glamor_gbm_get_wl_buffer_for_pixmap;
1118 xwl_screen->gbm_backend.is_available = TRUE;
1119 xwl_screen->gbm_backend.backend_flags = XWL_EGL_BACKEND_HAS_PRESENT_FLIP |
1120 XWL_EGL_BACKEND_NEEDS_BUFFER_FLUSH |
1121 XWL_EGL_BACKEND_NEEDS_N_BUFFERING;
1122 }
1123