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