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