xref: /OK3568_Linux_fs/external/xserver/hw/xwayland/xwayland-glamor-gbm.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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