• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2011-2012 Intel Corporation
3  * Copyright © 2012 Collabora, Ltd.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23  * DEALINGS IN THE SOFTWARE.
24  *
25  * Authors:
26  *    Kristian Høgsberg <krh@bitplanet.net>
27  *    Benjamin Franzke <benjaminfranzke@googlemail.com>
28  */
29 
30 #include <stdint.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <limits.h>
34 #include <dlfcn.h>
35 #include <errno.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38 #include <xf86drm.h>
39 #include <drm_fourcc.h>
40 #include <sys/mman.h>
41 
42 #include "egl_dri2.h"
43 #include "egl_dri2_fallbacks.h"
44 #include "loader.h"
45 #include "util/u_vector.h"
46 #include "eglglobals.h"
47 
48 #include <wayland-client.h>
49 #include "wayland-drm-client-protocol.h"
50 #include "linux-dmabuf-unstable-v1-client-protocol.h"
51 
52 #ifndef DRM_FORMAT_MOD_INVALID
53 #define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
54 #endif
55 
56 #ifndef DRM_FORMAT_MOD_LINEAR
57 #define DRM_FORMAT_MOD_LINEAR 0
58 #endif
59 
60 enum wl_drm_format_flags {
61    HAS_ARGB8888 = 1,
62    HAS_XRGB8888 = 2,
63    HAS_RGB565 = 4,
64    HAS_ARGB2101010 = 8,
65    HAS_XRGB2101010 = 16,
66 };
67 
68 static int
roundtrip(struct dri2_egl_display * dri2_dpy)69 roundtrip(struct dri2_egl_display *dri2_dpy)
70 {
71    return wl_display_roundtrip_queue(dri2_dpy->wl_dpy, dri2_dpy->wl_queue);
72 }
73 
74 static void
wl_buffer_release(void * data,struct wl_buffer * buffer)75 wl_buffer_release(void *data, struct wl_buffer *buffer)
76 {
77    struct dri2_egl_surface *dri2_surf = data;
78    int i;
79 
80    for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); ++i)
81       if (dri2_surf->color_buffers[i].wl_buffer == buffer)
82          break;
83 
84    if (i == ARRAY_SIZE(dri2_surf->color_buffers)) {
85       wl_buffer_destroy(buffer);
86       return;
87    }
88 
89    dri2_surf->color_buffers[i].locked = false;
90 }
91 
92 static const struct wl_buffer_listener wl_buffer_listener = {
93    .release = wl_buffer_release
94 };
95 
96 static void
resize_callback(struct wl_egl_window * wl_win,void * data)97 resize_callback(struct wl_egl_window *wl_win, void *data)
98 {
99    struct dri2_egl_surface *dri2_surf = data;
100    struct dri2_egl_display *dri2_dpy =
101       dri2_egl_display(dri2_surf->base.Resource.Display);
102 
103    dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);
104 }
105 
106 static void
destroy_window_callback(void * data)107 destroy_window_callback(void *data)
108 {
109    struct dri2_egl_surface *dri2_surf = data;
110    dri2_surf->wl_win = NULL;
111 }
112 
113 static struct wl_surface *
get_wl_surface_proxy(struct wl_egl_window * window)114 get_wl_surface_proxy(struct wl_egl_window *window)
115 {
116     /* Version 3 of wl_egl_window introduced a version field at the same
117      * location where a pointer to wl_surface was stored. Thus, if
118      * window->version is dereferencable, we've been given an older version of
119      * wl_egl_window, and window->version points to wl_surface */
120    if (_eglPointerIsDereferencable((void *)(window->version))) {
121       return wl_proxy_create_wrapper((void *)(window->version));
122    }
123    return wl_proxy_create_wrapper(window->surface);
124 }
125 
126 /**
127  * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
128  */
129 static _EGLSurface *
dri2_wl_create_window_surface(_EGLDriver * drv,_EGLDisplay * disp,_EGLConfig * conf,void * native_window,const EGLint * attrib_list)130 dri2_wl_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
131                               _EGLConfig *conf, void *native_window,
132                               const EGLint *attrib_list)
133 {
134    __DRIcreateNewDrawableFunc createNewDrawable;
135    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
136    struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
137    struct wl_egl_window *window = native_window;
138    struct dri2_egl_surface *dri2_surf;
139    const __DRIconfig *config;
140 
141    dri2_surf = calloc(1, sizeof *dri2_surf);
142    if (!dri2_surf) {
143       _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
144       return NULL;
145    }
146 
147    if (!dri2_init_surface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf, attrib_list, false))
148       goto cleanup_surf;
149 
150    if (dri2_dpy->wl_dmabuf || dri2_dpy->wl_drm) {
151       if (conf->RedSize == 5)
152          dri2_surf->format = WL_DRM_FORMAT_RGB565;
153       else if (conf->RedSize == 8 && conf->AlphaSize == 0)
154          dri2_surf->format = WL_DRM_FORMAT_XRGB8888;
155       else if (conf->RedSize == 8)
156          dri2_surf->format = WL_DRM_FORMAT_ARGB8888;
157       else if (conf->RedSize == 10 && conf->AlphaSize == 0)
158          dri2_surf->format = WL_DRM_FORMAT_XRGB2101010;
159       else if (conf->RedSize == 10)
160          dri2_surf->format = WL_DRM_FORMAT_ARGB2101010;
161    } else {
162       assert(dri2_dpy->wl_shm);
163       if (conf->RedSize == 5)
164          dri2_surf->format = WL_SHM_FORMAT_RGB565;
165       else if (conf->RedSize == 8 && conf->AlphaSize == 0)
166          dri2_surf->format = WL_SHM_FORMAT_XRGB8888;
167       else if (conf->RedSize == 8)
168          dri2_surf->format = WL_SHM_FORMAT_ARGB8888;
169       else if (conf->RedSize == 10 && conf->AlphaSize == 0)
170          dri2_surf->format = WL_SHM_FORMAT_XRGB2101010;
171       else if (conf->RedSize == 10)
172          dri2_surf->format = WL_SHM_FORMAT_ARGB2101010;
173    }
174 
175    dri2_surf->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
176    if (!dri2_surf->wl_queue) {
177       _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
178       goto cleanup_surf;
179    }
180 
181    if (dri2_dpy->wl_drm) {
182       dri2_surf->wl_drm_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_drm);
183       if (!dri2_surf->wl_drm_wrapper) {
184          _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
185          goto cleanup_queue;
186       }
187       wl_proxy_set_queue((struct wl_proxy *)dri2_surf->wl_drm_wrapper,
188                          dri2_surf->wl_queue);
189    }
190 
191    dri2_surf->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy);
192    if (!dri2_surf->wl_dpy_wrapper) {
193       _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
194       goto cleanup_drm;
195    }
196    wl_proxy_set_queue((struct wl_proxy *)dri2_surf->wl_dpy_wrapper,
197                       dri2_surf->wl_queue);
198 
199    dri2_surf->wl_surface_wrapper = get_wl_surface_proxy(window);
200    if (!dri2_surf->wl_surface_wrapper) {
201       _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
202       goto cleanup_dpy_wrapper;
203    }
204    wl_proxy_set_queue((struct wl_proxy *)dri2_surf->wl_surface_wrapper,
205                       dri2_surf->wl_queue);
206 
207    dri2_surf->wl_win = window;
208    dri2_surf->wl_win->private = dri2_surf;
209    dri2_surf->wl_win->destroy_window_callback = destroy_window_callback;
210    if (dri2_dpy->flush)
211       dri2_surf->wl_win->resize_callback = resize_callback;
212 
213    config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT,
214                                 dri2_surf->base.GLColorspace);
215 
216    if (dri2_dpy->image_driver)
217       createNewDrawable = dri2_dpy->image_driver->createNewDrawable;
218    else if (dri2_dpy->dri2)
219       createNewDrawable = dri2_dpy->dri2->createNewDrawable;
220    else
221       createNewDrawable = dri2_dpy->swrast->createNewDrawable;
222 
223    dri2_surf->dri_drawable = (*createNewDrawable)(dri2_dpy->dri_screen, config,
224                                                   dri2_surf);
225     if (dri2_surf->dri_drawable == NULL) {
226       _eglError(EGL_BAD_ALLOC, "createNewDrawable");
227        goto cleanup_surf_wrapper;
228     }
229 
230    dri2_surf->base.SwapInterval = dri2_dpy->default_swap_interval;
231 
232    return &dri2_surf->base;
233 
234  cleanup_surf_wrapper:
235    wl_proxy_wrapper_destroy(dri2_surf->wl_surface_wrapper);
236  cleanup_dpy_wrapper:
237    wl_proxy_wrapper_destroy(dri2_surf->wl_dpy_wrapper);
238  cleanup_drm:
239    if (dri2_surf->wl_drm_wrapper)
240       wl_proxy_wrapper_destroy(dri2_surf->wl_drm_wrapper);
241  cleanup_queue:
242    wl_event_queue_destroy(dri2_surf->wl_queue);
243  cleanup_surf:
244    free(dri2_surf);
245 
246    return NULL;
247 }
248 
249 static _EGLSurface *
dri2_wl_create_pixmap_surface(_EGLDriver * drv,_EGLDisplay * disp,_EGLConfig * conf,void * native_window,const EGLint * attrib_list)250 dri2_wl_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,
251                               _EGLConfig *conf, void *native_window,
252                               const EGLint *attrib_list)
253 {
254    /* From the EGL_EXT_platform_wayland spec, version 3:
255     *
256     *   It is not valid to call eglCreatePlatformPixmapSurfaceEXT with a <dpy>
257     *   that belongs to Wayland. Any such call fails and generates
258     *   EGL_BAD_PARAMETER.
259     */
260    _eglError(EGL_BAD_PARAMETER, "cannot create EGL pixmap surfaces on "
261              "Wayland");
262    return NULL;
263 }
264 
265 /**
266  * Called via eglDestroySurface(), drv->API.DestroySurface().
267  */
268 static EGLBoolean
dri2_wl_destroy_surface(_EGLDriver * drv,_EGLDisplay * disp,_EGLSurface * surf)269 dri2_wl_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
270 {
271    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
272    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
273 
274    (void) drv;
275 
276    dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
277 
278    for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
279       if (dri2_surf->color_buffers[i].wl_buffer)
280          wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
281       if (dri2_surf->color_buffers[i].dri_image)
282          dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
283       if (dri2_surf->color_buffers[i].linear_copy)
284          dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy);
285       if (dri2_surf->color_buffers[i].data)
286          munmap(dri2_surf->color_buffers[i].data,
287                 dri2_surf->color_buffers[i].data_size);
288    }
289 
290    if (dri2_dpy->dri2)
291       dri2_egl_surface_free_local_buffers(dri2_surf);
292 
293    if (dri2_surf->throttle_callback)
294       wl_callback_destroy(dri2_surf->throttle_callback);
295 
296    if (dri2_surf->wl_win) {
297       dri2_surf->wl_win->private = NULL;
298       dri2_surf->wl_win->resize_callback = NULL;
299       dri2_surf->wl_win->destroy_window_callback = NULL;
300    }
301 
302    wl_proxy_wrapper_destroy(dri2_surf->wl_surface_wrapper);
303    wl_proxy_wrapper_destroy(dri2_surf->wl_dpy_wrapper);
304    if (dri2_surf->wl_drm_wrapper)
305       wl_proxy_wrapper_destroy(dri2_surf->wl_drm_wrapper);
306    wl_event_queue_destroy(dri2_surf->wl_queue);
307 
308    dri2_fini_surface(surf);
309    free(surf);
310 
311    return EGL_TRUE;
312 }
313 
314 static void
dri2_wl_release_buffers(struct dri2_egl_surface * dri2_surf)315 dri2_wl_release_buffers(struct dri2_egl_surface *dri2_surf)
316 {
317    struct dri2_egl_display *dri2_dpy =
318       dri2_egl_display(dri2_surf->base.Resource.Display);
319 
320    for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
321       if (dri2_surf->color_buffers[i].wl_buffer &&
322           !dri2_surf->color_buffers[i].locked)
323          wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
324       if (dri2_surf->color_buffers[i].dri_image)
325          dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
326       if (dri2_surf->color_buffers[i].linear_copy)
327          dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy);
328       if (dri2_surf->color_buffers[i].data)
329          munmap(dri2_surf->color_buffers[i].data,
330                 dri2_surf->color_buffers[i].data_size);
331 
332       dri2_surf->color_buffers[i].wl_buffer = NULL;
333       dri2_surf->color_buffers[i].dri_image = NULL;
334       dri2_surf->color_buffers[i].linear_copy = NULL;
335       dri2_surf->color_buffers[i].data = NULL;
336       dri2_surf->color_buffers[i].locked = false;
337    }
338 
339    if (dri2_dpy->dri2)
340       dri2_egl_surface_free_local_buffers(dri2_surf);
341 }
342 
343 static int
get_back_bo(struct dri2_egl_surface * dri2_surf)344 get_back_bo(struct dri2_egl_surface *dri2_surf)
345 {
346    struct dri2_egl_display *dri2_dpy =
347       dri2_egl_display(dri2_surf->base.Resource.Display);
348    int use_flags;
349    unsigned int dri_image_format;
350    uint64_t *modifiers;
351    int num_modifiers;
352 
353    /* currently supports five WL DRM formats,
354     * WL_DRM_FORMAT_ARGB2101010, WL_DRM_FORMAT_XRGB2101010,
355     * WL_DRM_FORMAT_ARGB8888, WL_DRM_FORMAT_XRGB8888,
356     * and WL_DRM_FORMAT_RGB565
357     */
358    switch (dri2_surf->format) {
359    case WL_DRM_FORMAT_ARGB2101010:
360       dri_image_format = __DRI_IMAGE_FORMAT_ARGB2101010;
361       modifiers = u_vector_tail(&dri2_dpy->wl_modifiers.argb2101010);
362       num_modifiers = u_vector_length(&dri2_dpy->wl_modifiers.argb2101010);
363       break;
364    case WL_DRM_FORMAT_XRGB2101010:
365       dri_image_format = __DRI_IMAGE_FORMAT_XRGB2101010;
366       modifiers = u_vector_tail(&dri2_dpy->wl_modifiers.xrgb2101010);
367       num_modifiers = u_vector_length(&dri2_dpy->wl_modifiers.xrgb2101010);
368       break;
369    case WL_DRM_FORMAT_ARGB8888:
370       dri_image_format = __DRI_IMAGE_FORMAT_ARGB8888;
371       modifiers = u_vector_tail(&dri2_dpy->wl_modifiers.argb8888);
372       num_modifiers = u_vector_length(&dri2_dpy->wl_modifiers.argb8888);
373       break;
374    case WL_DRM_FORMAT_XRGB8888:
375       dri_image_format = __DRI_IMAGE_FORMAT_XRGB8888;
376       modifiers = u_vector_tail(&dri2_dpy->wl_modifiers.xrgb8888);
377       num_modifiers = u_vector_length(&dri2_dpy->wl_modifiers.xrgb8888);
378       break;
379    case WL_DRM_FORMAT_RGB565:
380       dri_image_format = __DRI_IMAGE_FORMAT_RGB565;
381       modifiers = u_vector_tail(&dri2_dpy->wl_modifiers.rgb565);
382       num_modifiers = u_vector_length(&dri2_dpy->wl_modifiers.rgb565);
383       break;
384    default:
385       /* format is not supported */
386       return -1;
387    }
388 
389    /* There might be a buffer release already queued that wasn't processed */
390    wl_display_dispatch_queue_pending(dri2_dpy->wl_dpy, dri2_surf->wl_queue);
391 
392    while (dri2_surf->back == NULL) {
393       for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
394          /* Get an unlocked buffer, preferrably one with a dri_buffer
395           * already allocated. */
396          if (dri2_surf->color_buffers[i].locked)
397             continue;
398          if (dri2_surf->back == NULL)
399             dri2_surf->back = &dri2_surf->color_buffers[i];
400          else if (dri2_surf->back->dri_image == NULL)
401             dri2_surf->back = &dri2_surf->color_buffers[i];
402       }
403 
404       if (dri2_surf->back)
405          break;
406 
407       /* If we don't have a buffer, then block on the server to release one for
408        * us, and try again. wl_display_dispatch_queue will process any pending
409        * events, however not all servers flush on issuing a buffer release
410        * event. So, we spam the server with roundtrips as they always cause a
411        * client flush.
412        */
413       if (wl_display_roundtrip_queue(dri2_dpy->wl_dpy,
414                                      dri2_surf->wl_queue) < 0)
415           return -1;
416    }
417 
418    if (dri2_surf->back == NULL)
419       return -1;
420 
421    use_flags = __DRI_IMAGE_USE_SHARE | __DRI_IMAGE_USE_BACKBUFFER;
422 
423    if (dri2_dpy->is_different_gpu &&
424        dri2_surf->back->linear_copy == NULL) {
425       /* The LINEAR modifier should be a perfect alias of the LINEAR use
426        * flag; try the new interface first before the old, then fall back. */
427       if (dri2_dpy->image->base.version >= 15 &&
428            dri2_dpy->image->createImageWithModifiers) {
429          uint64_t linear_mod = DRM_FORMAT_MOD_LINEAR;
430 
431          dri2_surf->back->linear_copy =
432             dri2_dpy->image->createImageWithModifiers(dri2_dpy->dri_screen,
433                                                       dri2_surf->base.Width,
434                                                       dri2_surf->base.Height,
435                                                       dri_image_format,
436                                                       &linear_mod,
437                                                       1,
438                                                       NULL);
439       } else {
440          dri2_surf->back->linear_copy =
441             dri2_dpy->image->createImage(dri2_dpy->dri_screen,
442                                          dri2_surf->base.Width,
443                                          dri2_surf->base.Height,
444                                          dri_image_format,
445                                          use_flags |
446                                          __DRI_IMAGE_USE_LINEAR,
447                                          NULL);
448       }
449       if (dri2_surf->back->linear_copy == NULL)
450           return -1;
451    }
452 
453    if (dri2_surf->back->dri_image == NULL) {
454       /* If our DRIImage implementation does not support
455        * createImageWithModifiers, then fall back to the old createImage,
456        * and hope it allocates an image which is acceptable to the winsys.
457         */
458       if (num_modifiers && dri2_dpy->image->base.version >= 15 &&
459           dri2_dpy->image->createImageWithModifiers) {
460          dri2_surf->back->dri_image =
461            dri2_dpy->image->createImageWithModifiers(dri2_dpy->dri_screen,
462                                                      dri2_surf->base.Width,
463                                                      dri2_surf->base.Height,
464                                                      dri_image_format,
465                                                      modifiers,
466                                                      num_modifiers,
467                                                      NULL);
468       } else {
469          dri2_surf->back->dri_image =
470             dri2_dpy->image->createImage(dri2_dpy->dri_screen,
471                                          dri2_surf->base.Width,
472                                          dri2_surf->base.Height,
473                                          dri_image_format,
474                                          dri2_dpy->is_different_gpu ?
475                                               0 : use_flags,
476                                          NULL);
477       }
478 
479       dri2_surf->back->age = 0;
480    }
481    if (dri2_surf->back->dri_image == NULL)
482       return -1;
483 
484    dri2_surf->back->locked = true;
485 
486    return 0;
487 }
488 
489 
490 static void
back_bo_to_dri_buffer(struct dri2_egl_surface * dri2_surf,__DRIbuffer * buffer)491 back_bo_to_dri_buffer(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer)
492 {
493    struct dri2_egl_display *dri2_dpy =
494       dri2_egl_display(dri2_surf->base.Resource.Display);
495    __DRIimage *image;
496    int name, pitch;
497 
498    image = dri2_surf->back->dri_image;
499 
500    dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name);
501    dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch);
502 
503    buffer->attachment = __DRI_BUFFER_BACK_LEFT;
504    buffer->name = name;
505    buffer->pitch = pitch;
506    buffer->cpp = 4;
507    buffer->flags = 0;
508 }
509 
510 static int
update_buffers(struct dri2_egl_surface * dri2_surf)511 update_buffers(struct dri2_egl_surface *dri2_surf)
512 {
513    struct dri2_egl_display *dri2_dpy =
514       dri2_egl_display(dri2_surf->base.Resource.Display);
515 
516    if (dri2_surf->base.Width != dri2_surf->wl_win->width ||
517        dri2_surf->base.Height != dri2_surf->wl_win->height) {
518 
519       dri2_wl_release_buffers(dri2_surf);
520 
521       dri2_surf->base.Width  = dri2_surf->wl_win->width;
522       dri2_surf->base.Height = dri2_surf->wl_win->height;
523       dri2_surf->dx = dri2_surf->wl_win->dx;
524       dri2_surf->dy = dri2_surf->wl_win->dy;
525    }
526 
527    if (get_back_bo(dri2_surf) < 0) {
528       _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer");
529       return -1;
530    }
531 
532    /* If we have an extra unlocked buffer at this point, we had to do triple
533     * buffering for a while, but now can go back to just double buffering.
534     * That means we can free any unlocked buffer now. */
535    for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
536       if (!dri2_surf->color_buffers[i].locked &&
537           dri2_surf->color_buffers[i].wl_buffer) {
538          wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
539          dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
540          if (dri2_dpy->is_different_gpu)
541             dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy);
542          dri2_surf->color_buffers[i].wl_buffer = NULL;
543          dri2_surf->color_buffers[i].dri_image = NULL;
544          dri2_surf->color_buffers[i].linear_copy = NULL;
545       }
546    }
547 
548    return 0;
549 }
550 
551 static __DRIbuffer *
dri2_wl_get_buffers_with_format(__DRIdrawable * driDrawable,int * width,int * height,unsigned int * attachments,int count,int * out_count,void * loaderPrivate)552 dri2_wl_get_buffers_with_format(__DRIdrawable * driDrawable,
553                                 int *width, int *height,
554                                 unsigned int *attachments, int count,
555                                 int *out_count, void *loaderPrivate)
556 {
557    struct dri2_egl_surface *dri2_surf = loaderPrivate;
558    int i, j;
559 
560    if (update_buffers(dri2_surf) < 0)
561       return NULL;
562 
563    for (i = 0, j = 0; i < 2 * count; i += 2, j++) {
564       __DRIbuffer *local;
565 
566       switch (attachments[i]) {
567       case __DRI_BUFFER_BACK_LEFT:
568          back_bo_to_dri_buffer(dri2_surf, &dri2_surf->buffers[j]);
569          break;
570       default:
571          local = dri2_egl_surface_alloc_local_buffer(dri2_surf, attachments[i],
572                                                      attachments[i + 1]);
573 
574          if (!local) {
575             _eglError(EGL_BAD_ALLOC, "failed to allocate local buffer");
576             return NULL;
577          }
578          dri2_surf->buffers[j] = *local;
579          break;
580       }
581    }
582 
583    *out_count = j;
584    if (j == 0)
585       return NULL;
586 
587    *width = dri2_surf->base.Width;
588    *height = dri2_surf->base.Height;
589 
590    return dri2_surf->buffers;
591 }
592 
593 static __DRIbuffer *
dri2_wl_get_buffers(__DRIdrawable * driDrawable,int * width,int * height,unsigned int * attachments,int count,int * out_count,void * loaderPrivate)594 dri2_wl_get_buffers(__DRIdrawable * driDrawable,
595                     int *width, int *height,
596                     unsigned int *attachments, int count,
597                     int *out_count, void *loaderPrivate)
598 {
599    struct dri2_egl_surface *dri2_surf = loaderPrivate;
600    unsigned int *attachments_with_format;
601    __DRIbuffer *buffer;
602    unsigned int bpp;
603 
604    switch (dri2_surf->format) {
605    case WL_DRM_FORMAT_ARGB2101010:
606    case WL_DRM_FORMAT_XRGB2101010:
607    case WL_DRM_FORMAT_ARGB8888:
608    case WL_DRM_FORMAT_XRGB8888:
609       bpp = 32;
610       break;
611    case WL_DRM_FORMAT_RGB565:
612       bpp = 16;
613       break;
614    default:
615       /* format is not supported */
616       return NULL;
617    }
618 
619    attachments_with_format = calloc(count, 2 * sizeof(unsigned int));
620    if (!attachments_with_format) {
621       *out_count = 0;
622       return NULL;
623    }
624 
625    for (int i = 0; i < count; ++i) {
626       attachments_with_format[2*i] = attachments[i];
627       attachments_with_format[2*i + 1] = bpp;
628    }
629 
630    buffer =
631       dri2_wl_get_buffers_with_format(driDrawable,
632                                       width, height,
633                                       attachments_with_format, count,
634                                       out_count, loaderPrivate);
635 
636    free(attachments_with_format);
637 
638    return buffer;
639 }
640 
641 static int
image_get_buffers(__DRIdrawable * driDrawable,unsigned int format,uint32_t * stamp,void * loaderPrivate,uint32_t buffer_mask,struct __DRIimageList * buffers)642 image_get_buffers(__DRIdrawable *driDrawable,
643                   unsigned int format,
644                   uint32_t *stamp,
645                   void *loaderPrivate,
646                   uint32_t buffer_mask,
647                   struct __DRIimageList *buffers)
648 {
649    struct dri2_egl_surface *dri2_surf = loaderPrivate;
650 
651    if (update_buffers(dri2_surf) < 0)
652       return 0;
653 
654    buffers->image_mask = __DRI_IMAGE_BUFFER_BACK;
655    buffers->back = dri2_surf->back->dri_image;
656 
657    return 1;
658 }
659 
660 static void
dri2_wl_flush_front_buffer(__DRIdrawable * driDrawable,void * loaderPrivate)661 dri2_wl_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
662 {
663    (void) driDrawable;
664    (void) loaderPrivate;
665 }
666 
667 static const __DRIdri2LoaderExtension dri2_loader_extension = {
668    .base = { __DRI_DRI2_LOADER, 3 },
669 
670    .getBuffers           = dri2_wl_get_buffers,
671    .flushFrontBuffer     = dri2_wl_flush_front_buffer,
672    .getBuffersWithFormat = dri2_wl_get_buffers_with_format,
673 };
674 
675 static const __DRIimageLoaderExtension image_loader_extension = {
676    .base = { __DRI_IMAGE_LOADER, 1 },
677 
678    .getBuffers          = image_get_buffers,
679    .flushFrontBuffer    = dri2_wl_flush_front_buffer,
680 };
681 
682 static void
wayland_throttle_callback(void * data,struct wl_callback * callback,uint32_t time)683 wayland_throttle_callback(void *data,
684                           struct wl_callback *callback,
685                           uint32_t time)
686 {
687    struct dri2_egl_surface *dri2_surf = data;
688 
689    dri2_surf->throttle_callback = NULL;
690    wl_callback_destroy(callback);
691 }
692 
693 static const struct wl_callback_listener throttle_listener = {
694    .done = wayland_throttle_callback
695 };
696 
697 static EGLBoolean
get_fourcc(struct dri2_egl_display * dri2_dpy,__DRIimage * image,int * fourcc)698 get_fourcc(struct dri2_egl_display *dri2_dpy,
699            __DRIimage *image, int *fourcc)
700 {
701    EGLBoolean query;
702    int dri_format;
703 
704    query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FOURCC,
705                                        fourcc);
706    if (query)
707       return true;
708 
709    query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT,
710                                        &dri_format);
711    if (!query)
712       return false;
713 
714    switch (dri_format) {
715    case __DRI_IMAGE_FORMAT_ARGB8888:
716       *fourcc = __DRI_IMAGE_FOURCC_ARGB8888;
717       return true;
718    case __DRI_IMAGE_FORMAT_XRGB8888:
719       *fourcc = __DRI_IMAGE_FOURCC_XRGB8888;
720       return true;
721    default:
722       return false;
723    }
724 }
725 
726 static struct wl_buffer *
create_wl_buffer(struct dri2_egl_display * dri2_dpy,struct dri2_egl_surface * dri2_surf,__DRIimage * image)727 create_wl_buffer(struct dri2_egl_display *dri2_dpy,
728                  struct dri2_egl_surface *dri2_surf,
729                  __DRIimage *image)
730 {
731    struct wl_buffer *ret;
732    EGLBoolean query;
733    int width, height, fourcc, num_planes;
734    uint64_t modifier = DRM_FORMAT_MOD_INVALID;
735 
736    query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_WIDTH, &width);
737    query &= dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_HEIGHT,
738                                         &height);
739    query &= get_fourcc(dri2_dpy, image, &fourcc);
740    if (!query)
741       return NULL;
742 
743    query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NUM_PLANES,
744                                        &num_planes);
745    if (!query)
746       num_planes = 1;
747 
748    if (dri2_dpy->image->base.version >= 15) {
749       int mod_hi, mod_lo;
750 
751       query = dri2_dpy->image->queryImage(image,
752                                           __DRI_IMAGE_ATTRIB_MODIFIER_UPPER,
753                                           &mod_hi);
754       query &= dri2_dpy->image->queryImage(image,
755                                            __DRI_IMAGE_ATTRIB_MODIFIER_LOWER,
756                                            &mod_lo);
757       if (query) {
758          modifier = (uint64_t) mod_hi << 32;
759          modifier |= (uint64_t) (mod_lo & 0xffffffff);
760       }
761    }
762 
763    if (dri2_dpy->wl_dmabuf && modifier != DRM_FORMAT_MOD_INVALID) {
764       struct zwp_linux_buffer_params_v1 *params;
765       int i;
766 
767       /* We don't need a wrapper for wl_dmabuf objects, because we have to
768        * create the intermediate params object; we can set the queue on this,
769        * and the wl_buffer inherits it race-free. */
770       params = zwp_linux_dmabuf_v1_create_params(dri2_dpy->wl_dmabuf);
771       if (dri2_surf)
772          wl_proxy_set_queue((struct wl_proxy *) params, dri2_surf->wl_queue);
773 
774       for (i = 0; i < num_planes; i++) {
775          __DRIimage *p_image;
776          int stride, offset;
777          int fd = -1;
778 
779          if (i == 0)
780             p_image = image;
781          else
782             p_image = dri2_dpy->image->fromPlanar(image, i, NULL);
783          if (!p_image) {
784             zwp_linux_buffer_params_v1_destroy(params);
785             return NULL;
786          }
787 
788          query = dri2_dpy->image->queryImage(p_image,
789                                              __DRI_IMAGE_ATTRIB_FD,
790                                              &fd);
791          query &= dri2_dpy->image->queryImage(p_image,
792                                               __DRI_IMAGE_ATTRIB_STRIDE,
793                                               &stride);
794          query &= dri2_dpy->image->queryImage(p_image,
795                                               __DRI_IMAGE_ATTRIB_OFFSET,
796                                               &offset);
797          if (image != p_image)
798             dri2_dpy->image->destroyImage(p_image);
799 
800          if (!query) {
801             if (fd >= 0)
802                close(fd);
803             zwp_linux_buffer_params_v1_destroy(params);
804             return NULL;
805          }
806 
807          zwp_linux_buffer_params_v1_add(params, fd, i, offset, stride,
808                                         modifier >> 32, modifier & 0xffffffff);
809          close(fd);
810       }
811 
812       ret = zwp_linux_buffer_params_v1_create_immed(params, width, height,
813                                                     fourcc, 0);
814       zwp_linux_buffer_params_v1_destroy(params);
815    } else if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) {
816       struct wl_drm *wl_drm =
817          dri2_surf ? dri2_surf->wl_drm_wrapper : dri2_dpy->wl_drm;
818       int fd, stride;
819 
820       if (num_planes > 1)
821          return NULL;
822 
823       dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &fd);
824       dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
825       ret = wl_drm_create_prime_buffer(wl_drm, fd, width, height, fourcc, 0,
826                                        stride, 0, 0, 0, 0);
827       close(fd);
828    } else {
829       struct wl_drm *wl_drm =
830          dri2_surf ? dri2_surf->wl_drm_wrapper : dri2_dpy->wl_drm;
831       int name, stride;
832 
833       if (num_planes > 1)
834          return NULL;
835 
836       dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name);
837       dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
838       ret = wl_drm_create_buffer(wl_drm, name, width, height, stride, fourcc);
839    }
840 
841    return ret;
842 }
843 
844 static EGLBoolean
try_damage_buffer(struct dri2_egl_surface * dri2_surf,const EGLint * rects,EGLint n_rects)845 try_damage_buffer(struct dri2_egl_surface *dri2_surf,
846                   const EGLint *rects,
847                   EGLint n_rects)
848 {
849    if (wl_proxy_get_version((struct wl_proxy *) dri2_surf->wl_surface_wrapper)
850        < WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION)
851       return EGL_FALSE;
852 
853    for (int i = 0; i < n_rects; i++) {
854       const int *rect = &rects[i * 4];
855 
856       wl_surface_damage_buffer(dri2_surf->wl_surface_wrapper,
857                                rect[0],
858                                dri2_surf->base.Height - rect[1] - rect[3],
859                                rect[2], rect[3]);
860    }
861    return EGL_TRUE;
862 }
863 /**
864  * Called via eglSwapBuffers(), drv->API.SwapBuffers().
865  */
866 static EGLBoolean
dri2_wl_swap_buffers_with_damage(_EGLDriver * drv,_EGLDisplay * disp,_EGLSurface * draw,const EGLint * rects,EGLint n_rects)867 dri2_wl_swap_buffers_with_damage(_EGLDriver *drv,
868                                  _EGLDisplay *disp,
869                                  _EGLSurface *draw,
870                                  const EGLint *rects,
871                                  EGLint n_rects)
872 {
873    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
874    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
875 
876    while (dri2_surf->throttle_callback != NULL)
877       if (wl_display_dispatch_queue(dri2_dpy->wl_dpy,
878                                     dri2_surf->wl_queue) == -1)
879          return -1;
880 
881    for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
882       if (dri2_surf->color_buffers[i].age > 0)
883          dri2_surf->color_buffers[i].age++;
884 
885    /* Make sure we have a back buffer in case we're swapping without ever
886     * rendering. */
887    if (get_back_bo(dri2_surf) < 0)
888       return _eglError(EGL_BAD_ALLOC, "dri2_swap_buffers");
889 
890    if (draw->SwapInterval > 0) {
891       dri2_surf->throttle_callback =
892          wl_surface_frame(dri2_surf->wl_surface_wrapper);
893       wl_callback_add_listener(dri2_surf->throttle_callback,
894                                &throttle_listener, dri2_surf);
895    }
896 
897    dri2_surf->back->age = 1;
898    dri2_surf->current = dri2_surf->back;
899    dri2_surf->back = NULL;
900 
901    if (!dri2_surf->current->wl_buffer) {
902       __DRIimage *image;
903 
904       if (dri2_dpy->is_different_gpu)
905          image = dri2_surf->current->linear_copy;
906       else
907          image = dri2_surf->current->dri_image;
908 
909       dri2_surf->current->wl_buffer =
910          create_wl_buffer(dri2_dpy, dri2_surf, image);
911 
912       wl_buffer_add_listener(dri2_surf->current->wl_buffer,
913                              &wl_buffer_listener, dri2_surf);
914    }
915 
916    wl_surface_attach(dri2_surf->wl_surface_wrapper,
917                      dri2_surf->current->wl_buffer,
918                      dri2_surf->dx, dri2_surf->dy);
919 
920    dri2_surf->wl_win->attached_width  = dri2_surf->base.Width;
921    dri2_surf->wl_win->attached_height = dri2_surf->base.Height;
922    /* reset resize growing parameters */
923    dri2_surf->dx = 0;
924    dri2_surf->dy = 0;
925 
926    /* If the compositor doesn't support damage_buffer, we deliberately
927     * ignore the damage region and post maximum damage, due to
928     * https://bugs.freedesktop.org/78190 */
929    if (!n_rects || !try_damage_buffer(dri2_surf, rects, n_rects))
930       wl_surface_damage(dri2_surf->wl_surface_wrapper,
931                         0, 0, INT32_MAX, INT32_MAX);
932 
933    if (dri2_dpy->is_different_gpu) {
934       _EGLContext *ctx = _eglGetCurrentContext();
935       struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
936       dri2_dpy->image->blitImage(dri2_ctx->dri_context,
937                                  dri2_surf->current->linear_copy,
938                                  dri2_surf->current->dri_image,
939                                  0, 0, dri2_surf->base.Width,
940                                  dri2_surf->base.Height,
941                                  0, 0, dri2_surf->base.Width,
942                                  dri2_surf->base.Height, 0);
943    }
944 
945    dri2_flush_drawable_for_swapbuffers(disp, draw);
946    dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);
947 
948    wl_surface_commit(dri2_surf->wl_surface_wrapper);
949 
950    /* If we're not waiting for a frame callback then we'll at least throttle
951     * to a sync callback so that we always give a chance for the compositor to
952     * handle the commit and send a release event before checking for a free
953     * buffer */
954    if (dri2_surf->throttle_callback == NULL) {
955       dri2_surf->throttle_callback = wl_display_sync(dri2_surf->wl_dpy_wrapper);
956       wl_callback_add_listener(dri2_surf->throttle_callback,
957                                &throttle_listener, dri2_surf);
958    }
959 
960    wl_display_flush(dri2_dpy->wl_dpy);
961 
962    return EGL_TRUE;
963 }
964 
965 static EGLint
dri2_wl_query_buffer_age(_EGLDriver * drv,_EGLDisplay * disp,_EGLSurface * surface)966 dri2_wl_query_buffer_age(_EGLDriver *drv,
967                          _EGLDisplay *disp, _EGLSurface *surface)
968 {
969    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);
970 
971    if (get_back_bo(dri2_surf) < 0) {
972       _eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age");
973       return -1;
974    }
975 
976    return dri2_surf->back->age;
977 }
978 
979 static EGLBoolean
dri2_wl_swap_buffers(_EGLDriver * drv,_EGLDisplay * disp,_EGLSurface * draw)980 dri2_wl_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
981 {
982    return dri2_wl_swap_buffers_with_damage(drv, disp, draw, NULL, 0);
983 }
984 
985 static struct wl_buffer *
dri2_wl_create_wayland_buffer_from_image(_EGLDriver * drv,_EGLDisplay * disp,_EGLImage * img)986 dri2_wl_create_wayland_buffer_from_image(_EGLDriver *drv,
987                                           _EGLDisplay *disp,
988                                           _EGLImage *img)
989 {
990    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
991    struct dri2_egl_image *dri2_img = dri2_egl_image(img);
992    __DRIimage *image = dri2_img->dri_image;
993    struct wl_buffer *buffer;
994    int format;
995 
996    dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &format);
997    switch (format) {
998    case __DRI_IMAGE_FORMAT_ARGB2101010:
999       if (!(dri2_dpy->formats & HAS_ARGB2101010))
1000          goto bad_format;
1001       break;
1002    case __DRI_IMAGE_FORMAT_XRGB2101010:
1003       if (!(dri2_dpy->formats & HAS_XRGB2101010))
1004          goto bad_format;
1005       break;
1006    case __DRI_IMAGE_FORMAT_ARGB8888:
1007       if (!(dri2_dpy->formats & HAS_ARGB8888))
1008          goto bad_format;
1009       break;
1010    case __DRI_IMAGE_FORMAT_XRGB8888:
1011       if (!(dri2_dpy->formats & HAS_XRGB8888))
1012          goto bad_format;
1013       break;
1014    default:
1015       goto bad_format;
1016    }
1017 
1018    buffer = create_wl_buffer(dri2_dpy, NULL, image);
1019 
1020    /* The buffer object will have been created with our internal event queue
1021     * because it is using wl_dmabuf/wl_drm as a proxy factory. We want the
1022     * buffer to be used by the application so we'll reset it to the display's
1023     * default event queue. This isn't actually racy, as the only event the
1024     * buffer can get is a buffer release, which doesn't happen with an explicit
1025     * attach. */
1026    if (buffer)
1027       wl_proxy_set_queue((struct wl_proxy *) buffer, NULL);
1028 
1029    return buffer;
1030 
1031 bad_format:
1032    _eglError(EGL_BAD_MATCH, "unsupported image format");
1033    return NULL;
1034 }
1035 
1036 static int
dri2_wl_authenticate(_EGLDisplay * disp,uint32_t id)1037 dri2_wl_authenticate(_EGLDisplay *disp, uint32_t id)
1038 {
1039    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1040    int ret = 0;
1041 
1042    if (dri2_dpy->is_render_node) {
1043       _eglLog(_EGL_WARNING, "wayland-egl: client asks server to "
1044                             "authenticate for render-nodes");
1045       return 0;
1046    }
1047    dri2_dpy->authenticated = false;
1048 
1049    wl_drm_authenticate(dri2_dpy->wl_drm, id);
1050    if (roundtrip(dri2_dpy) < 0)
1051       ret = -1;
1052 
1053    if (!dri2_dpy->authenticated)
1054       ret = -1;
1055 
1056    /* reset authenticated */
1057    dri2_dpy->authenticated = true;
1058 
1059    return ret;
1060 }
1061 
1062 static void
drm_handle_device(void * data,struct wl_drm * drm,const char * device)1063 drm_handle_device(void *data, struct wl_drm *drm, const char *device)
1064 {
1065    struct dri2_egl_display *dri2_dpy = data;
1066    drm_magic_t magic;
1067 
1068    dri2_dpy->device_name = strdup(device);
1069    if (!dri2_dpy->device_name)
1070       return;
1071 
1072    dri2_dpy->fd = loader_open_device(dri2_dpy->device_name);
1073    if (dri2_dpy->fd == -1) {
1074       _eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)",
1075               dri2_dpy->device_name, strerror(errno));
1076       return;
1077    }
1078 
1079    if (drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER) {
1080       dri2_dpy->authenticated = true;
1081    } else {
1082       drmGetMagic(dri2_dpy->fd, &magic);
1083       wl_drm_authenticate(dri2_dpy->wl_drm, magic);
1084    }
1085 }
1086 
1087 static void
drm_handle_format(void * data,struct wl_drm * drm,uint32_t format)1088 drm_handle_format(void *data, struct wl_drm *drm, uint32_t format)
1089 {
1090    struct dri2_egl_display *dri2_dpy = data;
1091 
1092    switch (format) {
1093    case WL_DRM_FORMAT_ARGB2101010:
1094       dri2_dpy->formats |= HAS_ARGB2101010;
1095       break;
1096    case WL_DRM_FORMAT_XRGB2101010:
1097       dri2_dpy->formats |= HAS_XRGB2101010;
1098       break;
1099    case WL_DRM_FORMAT_ARGB8888:
1100       dri2_dpy->formats |= HAS_ARGB8888;
1101       break;
1102    case WL_DRM_FORMAT_XRGB8888:
1103       dri2_dpy->formats |= HAS_XRGB8888;
1104       break;
1105    case WL_DRM_FORMAT_RGB565:
1106       dri2_dpy->formats |= HAS_RGB565;
1107       break;
1108    }
1109 }
1110 
1111 static void
drm_handle_capabilities(void * data,struct wl_drm * drm,uint32_t value)1112 drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t value)
1113 {
1114    struct dri2_egl_display *dri2_dpy = data;
1115 
1116    dri2_dpy->capabilities = value;
1117 }
1118 
1119 static void
drm_handle_authenticated(void * data,struct wl_drm * drm)1120 drm_handle_authenticated(void *data, struct wl_drm *drm)
1121 {
1122    struct dri2_egl_display *dri2_dpy = data;
1123 
1124    dri2_dpy->authenticated = true;
1125 }
1126 
1127 static const struct wl_drm_listener drm_listener = {
1128    .device = drm_handle_device,
1129    .format = drm_handle_format,
1130    .authenticated = drm_handle_authenticated,
1131    .capabilities = drm_handle_capabilities
1132 };
1133 
1134 static void
dmabuf_ignore_format(void * data,struct zwp_linux_dmabuf_v1 * dmabuf,uint32_t format)1135 dmabuf_ignore_format(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
1136                      uint32_t format)
1137 {
1138    /* formats are implicitly advertised by the 'modifier' event, so ignore */
1139 }
1140 
1141 static void
dmabuf_handle_modifier(void * data,struct zwp_linux_dmabuf_v1 * dmabuf,uint32_t format,uint32_t modifier_hi,uint32_t modifier_lo)1142 dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
1143                        uint32_t format, uint32_t modifier_hi,
1144                        uint32_t modifier_lo)
1145 {
1146    struct dri2_egl_display *dri2_dpy = data;
1147    uint64_t *mod = NULL;
1148 
1149    if (modifier_hi == (DRM_FORMAT_MOD_INVALID >> 32) &&
1150        modifier_lo == (DRM_FORMAT_MOD_INVALID & 0xffffffff))
1151       return;
1152 
1153    switch (format) {
1154    case WL_DRM_FORMAT_ARGB2101010:
1155       mod = u_vector_add(&dri2_dpy->wl_modifiers.argb2101010);
1156       dri2_dpy->formats |= HAS_ARGB2101010;
1157       break;
1158    case WL_DRM_FORMAT_XRGB2101010:
1159       mod = u_vector_add(&dri2_dpy->wl_modifiers.xrgb2101010);
1160       dri2_dpy->formats |= HAS_XRGB2101010;
1161       break;
1162    case WL_DRM_FORMAT_ARGB8888:
1163       mod = u_vector_add(&dri2_dpy->wl_modifiers.argb8888);
1164       dri2_dpy->formats |= HAS_ARGB8888;
1165       break;
1166    case WL_DRM_FORMAT_XRGB8888:
1167       mod = u_vector_add(&dri2_dpy->wl_modifiers.xrgb8888);
1168       dri2_dpy->formats |= HAS_XRGB8888;
1169       break;
1170    case WL_DRM_FORMAT_RGB565:
1171       mod = u_vector_add(&dri2_dpy->wl_modifiers.rgb565);
1172       dri2_dpy->formats |= HAS_RGB565;
1173       break;
1174    default:
1175       break;
1176    }
1177 
1178    if (!mod)
1179       return;
1180 
1181    *mod = (uint64_t) modifier_hi << 32;
1182    *mod |= (uint64_t) (modifier_lo & 0xffffffff);
1183 }
1184 
1185 static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = {
1186    .format = dmabuf_ignore_format,
1187    .modifier = dmabuf_handle_modifier,
1188 };
1189 
1190 static void
registry_handle_global_drm(void * data,struct wl_registry * registry,uint32_t name,const char * interface,uint32_t version)1191 registry_handle_global_drm(void *data, struct wl_registry *registry,
1192                            uint32_t name, const char *interface,
1193                            uint32_t version)
1194 {
1195    struct dri2_egl_display *dri2_dpy = data;
1196 
1197    if (strcmp(interface, "wl_drm") == 0) {
1198       dri2_dpy->wl_drm =
1199          wl_registry_bind(registry, name, &wl_drm_interface, MIN2(version, 2));
1200       wl_drm_add_listener(dri2_dpy->wl_drm, &drm_listener, dri2_dpy);
1201    } else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0 && version >= 3) {
1202       dri2_dpy->wl_dmabuf =
1203          wl_registry_bind(registry, name, &zwp_linux_dmabuf_v1_interface,
1204                           MIN2(version, 3));
1205       zwp_linux_dmabuf_v1_add_listener(dri2_dpy->wl_dmabuf, &dmabuf_listener,
1206                                        dri2_dpy);
1207    }
1208 }
1209 
1210 static void
registry_handle_global_remove(void * data,struct wl_registry * registry,uint32_t name)1211 registry_handle_global_remove(void *data, struct wl_registry *registry,
1212                               uint32_t name)
1213 {
1214 }
1215 
1216 static const struct wl_registry_listener registry_listener_drm = {
1217    .global = registry_handle_global_drm,
1218    .global_remove = registry_handle_global_remove
1219 };
1220 
1221 static void
dri2_wl_setup_swap_interval(_EGLDisplay * disp)1222 dri2_wl_setup_swap_interval(_EGLDisplay *disp)
1223 {
1224    /* We can't use values greater than 1 on Wayland because we are using the
1225     * frame callback to synchronise the frame and the only way we be sure to
1226     * get a frame callback is to attach a new buffer. Therefore we can't just
1227     * sit drawing nothing to wait until the next ‘n’ frame callbacks */
1228 
1229    dri2_setup_swap_interval(disp, 1);
1230 }
1231 
1232 static const struct dri2_egl_display_vtbl dri2_wl_display_vtbl = {
1233    .authenticate = dri2_wl_authenticate,
1234    .create_window_surface = dri2_wl_create_window_surface,
1235    .create_pixmap_surface = dri2_wl_create_pixmap_surface,
1236    .create_pbuffer_surface = dri2_fallback_create_pbuffer_surface,
1237    .destroy_surface = dri2_wl_destroy_surface,
1238    .create_image = dri2_create_image_khr,
1239    .swap_buffers = dri2_wl_swap_buffers,
1240    .swap_buffers_with_damage = dri2_wl_swap_buffers_with_damage,
1241    .swap_buffers_region = dri2_fallback_swap_buffers_region,
1242    .set_damage_region = dri2_fallback_set_damage_region,
1243    .post_sub_buffer = dri2_fallback_post_sub_buffer,
1244    .copy_buffers = dri2_fallback_copy_buffers,
1245    .query_buffer_age = dri2_wl_query_buffer_age,
1246    .create_wayland_buffer_from_image = dri2_wl_create_wayland_buffer_from_image,
1247    .get_sync_values = dri2_fallback_get_sync_values,
1248    .get_dri_drawable = dri2_surface_get_dri_drawable,
1249 };
1250 
1251 static const __DRIextension *dri2_loader_extensions[] = {
1252    &dri2_loader_extension.base,
1253    &image_loader_extension.base,
1254    &image_lookup_extension.base,
1255    &use_invalidate.base,
1256    NULL,
1257 };
1258 
1259 static const __DRIextension *image_loader_extensions[] = {
1260    &image_loader_extension.base,
1261    &image_lookup_extension.base,
1262    &use_invalidate.base,
1263    NULL,
1264 };
1265 
1266 static EGLBoolean
dri2_wl_add_configs_for_visuals(_EGLDriver * drv,_EGLDisplay * disp)1267 dri2_wl_add_configs_for_visuals(_EGLDriver *drv, _EGLDisplay *disp)
1268 {
1269    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1270    static const struct {
1271       const char *format_name;
1272       int has_format;
1273       unsigned int rgba_masks[4];
1274    } visuals[] = {
1275       { "XRGB2101010", HAS_XRGB2101010, { 0x3ff00000, 0xffc00, 0x3ff, 0 } },
1276       { "ARGB2101010", HAS_ARGB2101010, { 0x3ff00000, 0xffc00, 0x3ff, 0xc0000000 } },
1277       { "XRGB8888", HAS_XRGB8888, { 0xff0000, 0xff00, 0x00ff, 0 } },
1278       { "ARGB8888", HAS_ARGB8888, { 0xff0000, 0xff00, 0x00ff, 0xff000000 } },
1279       { "RGB565",   HAS_RGB565,   { 0x00f800, 0x07e0, 0x001f, 0 } },
1280    };
1281    unsigned int format_count[ARRAY_SIZE(visuals)] = { 0 };
1282    unsigned int count = 0;
1283 
1284    for (unsigned i = 0; dri2_dpy->driver_configs[i]; i++) {
1285       for (unsigned j = 0; j < ARRAY_SIZE(visuals); j++) {
1286          struct dri2_egl_config *dri2_conf;
1287 
1288          if (!(dri2_dpy->formats & visuals[j].has_format))
1289             continue;
1290 
1291          dri2_conf = dri2_add_config(disp, dri2_dpy->driver_configs[i],
1292                count + 1, EGL_WINDOW_BIT, NULL, visuals[j].rgba_masks);
1293          if (dri2_conf) {
1294             if (dri2_conf->base.ConfigID == count + 1)
1295                count++;
1296             format_count[j]++;
1297          }
1298       }
1299    }
1300 
1301    for (unsigned i = 0; i < ARRAY_SIZE(format_count); i++) {
1302       if (!format_count[i]) {
1303          _eglLog(_EGL_DEBUG, "No DRI config supports native format %s",
1304                  visuals[i].format_name);
1305       }
1306    }
1307 
1308    return (count != 0);
1309 }
1310 
1311 static EGLBoolean
dri2_initialize_wayland_drm(_EGLDriver * drv,_EGLDisplay * disp)1312 dri2_initialize_wayland_drm(_EGLDriver *drv, _EGLDisplay *disp)
1313 {
1314    struct dri2_egl_display *dri2_dpy;
1315 
1316    loader_set_logger(_eglLog);
1317 
1318    dri2_dpy = calloc(1, sizeof *dri2_dpy);
1319    if (!dri2_dpy)
1320       return _eglError(EGL_BAD_ALLOC, "eglInitialize");
1321 
1322    dri2_dpy->fd = -1;
1323    disp->DriverData = (void *) dri2_dpy;
1324    if (disp->PlatformDisplay == NULL) {
1325       dri2_dpy->wl_dpy = wl_display_connect(NULL);
1326       if (dri2_dpy->wl_dpy == NULL)
1327          goto cleanup;
1328       dri2_dpy->own_device = true;
1329    } else {
1330       dri2_dpy->wl_dpy = disp->PlatformDisplay;
1331    }
1332 
1333    if (!u_vector_init(&dri2_dpy->wl_modifiers.xrgb2101010, sizeof(uint64_t), 32) ||
1334        !u_vector_init(&dri2_dpy->wl_modifiers.argb2101010, sizeof(uint64_t), 32) ||
1335        !u_vector_init(&dri2_dpy->wl_modifiers.xrgb8888, sizeof(uint64_t), 32) ||
1336        !u_vector_init(&dri2_dpy->wl_modifiers.argb8888, sizeof(uint64_t), 32) ||
1337        !u_vector_init(&dri2_dpy->wl_modifiers.rgb565, sizeof(uint64_t), 32)) {
1338       goto cleanup;
1339    }
1340 
1341    dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
1342 
1343    dri2_dpy->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy);
1344    if (dri2_dpy->wl_dpy_wrapper == NULL)
1345       goto cleanup;
1346 
1347    wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_dpy_wrapper,
1348                       dri2_dpy->wl_queue);
1349 
1350    if (dri2_dpy->own_device)
1351       wl_display_dispatch_pending(dri2_dpy->wl_dpy);
1352 
1353    dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy_wrapper);
1354    wl_registry_add_listener(dri2_dpy->wl_registry,
1355                             &registry_listener_drm, dri2_dpy);
1356    if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_drm == NULL)
1357       goto cleanup;
1358 
1359    if (roundtrip(dri2_dpy) < 0 || dri2_dpy->fd == -1)
1360       goto cleanup;
1361 
1362    if (roundtrip(dri2_dpy) < 0 || !dri2_dpy->authenticated)
1363       goto cleanup;
1364 
1365    dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd,
1366                                                &dri2_dpy->is_different_gpu);
1367    if (dri2_dpy->is_different_gpu) {
1368       free(dri2_dpy->device_name);
1369       dri2_dpy->device_name = loader_get_device_name_for_fd(dri2_dpy->fd);
1370       if (!dri2_dpy->device_name) {
1371          _eglError(EGL_BAD_ALLOC, "wayland-egl: failed to get device name "
1372                                   "for requested GPU");
1373          goto cleanup;
1374       }
1375    }
1376 
1377    /* we have to do the check now, because loader_get_user_preferred_fd
1378     * will return a render-node when the requested gpu is different
1379     * to the server, but also if the client asks for the same gpu than
1380     * the server by requesting its pci-id */
1381    dri2_dpy->is_render_node = drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER;
1382 
1383    dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd);
1384    if (dri2_dpy->driver_name == NULL) {
1385       _eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name");
1386       goto cleanup;
1387    }
1388 
1389    /* render nodes cannot use Gem names, and thus do not support
1390     * the __DRI_DRI2_LOADER extension */
1391    if (!dri2_dpy->is_render_node) {
1392       dri2_dpy->loader_extensions = dri2_loader_extensions;
1393       if (!dri2_load_driver(disp)) {
1394          _eglError(EGL_BAD_ALLOC, "DRI2: failed to load driver");
1395          goto cleanup;
1396       }
1397    } else {
1398       dri2_dpy->loader_extensions = image_loader_extensions;
1399       if (!dri2_load_driver_dri3(disp)) {
1400          _eglError(EGL_BAD_ALLOC, "DRI3: failed to load driver");
1401          goto cleanup;
1402       }
1403    }
1404 
1405    if (!dri2_create_screen(disp))
1406       goto cleanup;
1407 
1408    if (!dri2_setup_extensions(disp))
1409       goto cleanup;
1410 
1411    dri2_setup_screen(disp);
1412 
1413    dri2_wl_setup_swap_interval(disp);
1414 
1415    /* To use Prime, we must have _DRI_IMAGE v7 at least.
1416     * createImageFromFds support indicates that Prime export/import
1417     * is supported by the driver. Fall back to
1418     * gem names if we don't have Prime support. */
1419 
1420    if (dri2_dpy->image->base.version < 7 ||
1421        dri2_dpy->image->createImageFromFds == NULL)
1422       dri2_dpy->capabilities &= ~WL_DRM_CAPABILITY_PRIME;
1423 
1424    /* We cannot use Gem names with render-nodes, only prime fds (dma-buf).
1425     * The server needs to accept them */
1426    if (dri2_dpy->is_render_node &&
1427        !(dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME)) {
1428       _eglLog(_EGL_WARNING, "wayland-egl: display is not render-node capable");
1429       goto cleanup;
1430    }
1431 
1432    if (dri2_dpy->is_different_gpu &&
1433        (dri2_dpy->image->base.version < 9 ||
1434         dri2_dpy->image->blitImage == NULL)) {
1435       _eglLog(_EGL_WARNING, "wayland-egl: Different GPU selected, but the "
1436                             "Image extension in the driver is not "
1437                             "compatible. Version 9 or later and blitImage() "
1438                             "are required");
1439       goto cleanup;
1440    }
1441 
1442    if (!dri2_wl_add_configs_for_visuals(drv, disp)) {
1443       _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to add configs");
1444       goto cleanup;
1445    }
1446 
1447    dri2_set_WL_bind_wayland_display(drv, disp);
1448    /* When cannot convert EGLImage to wl_buffer when on a different gpu,
1449     * because the buffer of the EGLImage has likely a tiling mode the server
1450     * gpu won't support. These is no way to check for now. Thus do not support the
1451     * extension */
1452    if (!dri2_dpy->is_different_gpu)
1453       disp->Extensions.WL_create_wayland_buffer_from_image = EGL_TRUE;
1454 
1455    disp->Extensions.EXT_buffer_age = EGL_TRUE;
1456 
1457    disp->Extensions.EXT_swap_buffers_with_damage = EGL_TRUE;
1458 
1459    /* Fill vtbl last to prevent accidentally calling virtual function during
1460     * initialization.
1461     */
1462    dri2_dpy->vtbl = &dri2_wl_display_vtbl;
1463 
1464    return EGL_TRUE;
1465 
1466  cleanup:
1467    dri2_display_destroy(disp);
1468    return EGL_FALSE;
1469 }
1470 
1471 static int
dri2_wl_swrast_get_stride_for_format(int format,int w)1472 dri2_wl_swrast_get_stride_for_format(int format, int w)
1473 {
1474    if (format == WL_SHM_FORMAT_RGB565)
1475       return 2 * w;
1476    else /* ARGB8888 || XRGB8888 || ARGB2101010 || XRGB2101010 */
1477       return 4 * w;
1478 }
1479 
1480 /*
1481  * Taken from weston shared/os-compatibility.c
1482  */
1483 
1484 #ifndef HAVE_MKOSTEMP
1485 
1486 static int
set_cloexec_or_close(int fd)1487 set_cloexec_or_close(int fd)
1488 {
1489    long flags;
1490 
1491    if (fd == -1)
1492       return -1;
1493 
1494    flags = fcntl(fd, F_GETFD);
1495    if (flags == -1)
1496       goto err;
1497 
1498    if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
1499       goto err;
1500 
1501    return fd;
1502 
1503 err:
1504    close(fd);
1505    return -1;
1506 }
1507 
1508 #endif
1509 
1510 /*
1511  * Taken from weston shared/os-compatibility.c
1512  */
1513 
1514 static int
create_tmpfile_cloexec(char * tmpname)1515 create_tmpfile_cloexec(char *tmpname)
1516 {
1517    int fd;
1518 
1519 #ifdef HAVE_MKOSTEMP
1520    fd = mkostemp(tmpname, O_CLOEXEC);
1521    if (fd >= 0)
1522       unlink(tmpname);
1523 #else
1524    fd = mkstemp(tmpname);
1525    if (fd >= 0) {
1526       fd = set_cloexec_or_close(fd);
1527       unlink(tmpname);
1528    }
1529 #endif
1530 
1531    return fd;
1532 }
1533 
1534 /*
1535  * Taken from weston shared/os-compatibility.c
1536  *
1537  * Create a new, unique, anonymous file of the given size, and
1538  * return the file descriptor for it. The file descriptor is set
1539  * CLOEXEC. The file is immediately suitable for mmap()'ing
1540  * the given size at offset zero.
1541  *
1542  * The file should not have a permanent backing store like a disk,
1543  * but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
1544  *
1545  * The file name is deleted from the file system.
1546  *
1547  * The file is suitable for buffer sharing between processes by
1548  * transmitting the file descriptor over Unix sockets using the
1549  * SCM_RIGHTS methods.
1550  *
1551  * If the C library implements posix_fallocate(), it is used to
1552  * guarantee that disk space is available for the file at the
1553  * given size. If disk space is insufficent, errno is set to ENOSPC.
1554  * If posix_fallocate() is not supported, program may receive
1555  * SIGBUS on accessing mmap()'ed file contents instead.
1556  */
1557 static int
os_create_anonymous_file(off_t size)1558 os_create_anonymous_file(off_t size)
1559 {
1560    static const char templ[] = "/mesa-shared-XXXXXX";
1561    const char *path;
1562    char *name;
1563    int fd;
1564    int ret;
1565 
1566    path = getenv("XDG_RUNTIME_DIR");
1567    if (!path) {
1568       errno = ENOENT;
1569       return -1;
1570    }
1571 
1572    name = malloc(strlen(path) + sizeof(templ));
1573    if (!name)
1574       return -1;
1575 
1576    strcpy(name, path);
1577    strcat(name, templ);
1578 
1579    fd = create_tmpfile_cloexec(name);
1580 
1581    free(name);
1582 
1583    if (fd < 0)
1584       return -1;
1585 
1586    ret = ftruncate(fd, size);
1587    if (ret < 0) {
1588       close(fd);
1589       return -1;
1590    }
1591 
1592    return fd;
1593 }
1594 
1595 
1596 static EGLBoolean
dri2_wl_swrast_allocate_buffer(struct dri2_egl_surface * dri2_surf,int format,int w,int h,void ** data,int * size,struct wl_buffer ** buffer)1597 dri2_wl_swrast_allocate_buffer(struct dri2_egl_surface *dri2_surf,
1598                                int format, int w, int h,
1599                                void **data, int *size,
1600                                struct wl_buffer **buffer)
1601 {
1602    struct dri2_egl_display *dri2_dpy =
1603       dri2_egl_display(dri2_surf->base.Resource.Display);
1604    struct wl_shm_pool *pool;
1605    int fd, stride, size_map;
1606    void *data_map;
1607 
1608    stride = dri2_wl_swrast_get_stride_for_format(format, w);
1609    size_map = h * stride;
1610 
1611    /* Create a sharable buffer */
1612    fd = os_create_anonymous_file(size_map);
1613    if (fd < 0)
1614       return EGL_FALSE;
1615 
1616    data_map = mmap(NULL, size_map, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1617    if (data_map == MAP_FAILED) {
1618       close(fd);
1619       return EGL_FALSE;
1620    }
1621 
1622    /* Share it in a wl_buffer */
1623    pool = wl_shm_create_pool(dri2_dpy->wl_shm, fd, size_map);
1624    wl_proxy_set_queue((struct wl_proxy *)pool, dri2_surf->wl_queue);
1625    *buffer = wl_shm_pool_create_buffer(pool, 0, w, h, stride, format);
1626    wl_shm_pool_destroy(pool);
1627    close(fd);
1628 
1629    *data = data_map;
1630    *size = size_map;
1631    return EGL_TRUE;
1632 }
1633 
1634 static int
swrast_update_buffers(struct dri2_egl_surface * dri2_surf)1635 swrast_update_buffers(struct dri2_egl_surface *dri2_surf)
1636 {
1637    struct dri2_egl_display *dri2_dpy =
1638       dri2_egl_display(dri2_surf->base.Resource.Display);
1639 
1640    /* we need to do the following operations only once per frame */
1641    if (dri2_surf->back)
1642       return 0;
1643 
1644    if (dri2_surf->base.Width != dri2_surf->wl_win->width ||
1645        dri2_surf->base.Height != dri2_surf->wl_win->height) {
1646 
1647       dri2_wl_release_buffers(dri2_surf);
1648 
1649       dri2_surf->base.Width  = dri2_surf->wl_win->width;
1650       dri2_surf->base.Height = dri2_surf->wl_win->height;
1651       dri2_surf->dx = dri2_surf->wl_win->dx;
1652       dri2_surf->dy = dri2_surf->wl_win->dy;
1653       dri2_surf->current = NULL;
1654    }
1655 
1656    /* find back buffer */
1657 
1658    /* There might be a buffer release already queued that wasn't processed */
1659    wl_display_dispatch_queue_pending(dri2_dpy->wl_dpy, dri2_surf->wl_queue);
1660 
1661    /* try get free buffer already created */
1662    for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
1663       if (!dri2_surf->color_buffers[i].locked &&
1664           dri2_surf->color_buffers[i].wl_buffer) {
1665           dri2_surf->back = &dri2_surf->color_buffers[i];
1666           break;
1667       }
1668    }
1669 
1670    /* else choose any another free location */
1671    if (!dri2_surf->back) {
1672       for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
1673          if (!dri2_surf->color_buffers[i].locked) {
1674              dri2_surf->back = &dri2_surf->color_buffers[i];
1675              if (!dri2_wl_swrast_allocate_buffer(dri2_surf,
1676                                                  dri2_surf->format,
1677                                                  dri2_surf->base.Width,
1678                                                  dri2_surf->base.Height,
1679                                                  &dri2_surf->back->data,
1680                                                  &dri2_surf->back->data_size,
1681                                                  &dri2_surf->back->wl_buffer)) {
1682                 _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer");
1683                  return -1;
1684              }
1685              wl_buffer_add_listener(dri2_surf->back->wl_buffer,
1686                                     &wl_buffer_listener, dri2_surf);
1687              break;
1688          }
1689       }
1690    }
1691 
1692    if (!dri2_surf->back) {
1693       _eglError(EGL_BAD_ALLOC, "failed to find free buffer");
1694       return -1;
1695    }
1696 
1697    dri2_surf->back->locked = true;
1698 
1699    /* If we have an extra unlocked buffer at this point, we had to do triple
1700     * buffering for a while, but now can go back to just double buffering.
1701     * That means we can free any unlocked buffer now. */
1702    for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
1703       if (!dri2_surf->color_buffers[i].locked &&
1704           dri2_surf->color_buffers[i].wl_buffer) {
1705          wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
1706          munmap(dri2_surf->color_buffers[i].data,
1707                 dri2_surf->color_buffers[i].data_size);
1708          dri2_surf->color_buffers[i].wl_buffer = NULL;
1709          dri2_surf->color_buffers[i].data = NULL;
1710       }
1711    }
1712 
1713    return 0;
1714 }
1715 
1716 static void*
dri2_wl_swrast_get_frontbuffer_data(struct dri2_egl_surface * dri2_surf)1717 dri2_wl_swrast_get_frontbuffer_data(struct dri2_egl_surface *dri2_surf)
1718 {
1719    /* if there has been a resize: */
1720    if (!dri2_surf->current)
1721       return NULL;
1722 
1723    return dri2_surf->current->data;
1724 }
1725 
1726 static void*
dri2_wl_swrast_get_backbuffer_data(struct dri2_egl_surface * dri2_surf)1727 dri2_wl_swrast_get_backbuffer_data(struct dri2_egl_surface *dri2_surf)
1728 {
1729    assert(dri2_surf->back);
1730    return dri2_surf->back->data;
1731 }
1732 
1733 static void
dri2_wl_swrast_commit_backbuffer(struct dri2_egl_surface * dri2_surf)1734 dri2_wl_swrast_commit_backbuffer(struct dri2_egl_surface *dri2_surf)
1735 {
1736    struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);
1737 
1738    while (dri2_surf->throttle_callback != NULL)
1739       if (wl_display_dispatch_queue(dri2_dpy->wl_dpy,
1740                                     dri2_surf->wl_queue) == -1)
1741          return;
1742 
1743    if (dri2_surf->base.SwapInterval > 0) {
1744       dri2_surf->throttle_callback =
1745          wl_surface_frame(dri2_surf->wl_surface_wrapper);
1746       wl_callback_add_listener(dri2_surf->throttle_callback,
1747                                &throttle_listener, dri2_surf);
1748    }
1749 
1750    dri2_surf->current = dri2_surf->back;
1751    dri2_surf->back = NULL;
1752 
1753    wl_surface_attach(dri2_surf->wl_surface_wrapper,
1754                      dri2_surf->current->wl_buffer,
1755                      dri2_surf->dx, dri2_surf->dy);
1756 
1757    dri2_surf->wl_win->attached_width  = dri2_surf->base.Width;
1758    dri2_surf->wl_win->attached_height = dri2_surf->base.Height;
1759    /* reset resize growing parameters */
1760    dri2_surf->dx = 0;
1761    dri2_surf->dy = 0;
1762 
1763    wl_surface_damage(dri2_surf->wl_surface_wrapper,
1764                      0, 0, INT32_MAX, INT32_MAX);
1765    wl_surface_commit(dri2_surf->wl_surface_wrapper);
1766 
1767    /* If we're not waiting for a frame callback then we'll at least throttle
1768     * to a sync callback so that we always give a chance for the compositor to
1769     * handle the commit and send a release event before checking for a free
1770     * buffer */
1771    if (dri2_surf->throttle_callback == NULL) {
1772       dri2_surf->throttle_callback = wl_display_sync(dri2_surf->wl_dpy_wrapper);
1773       wl_callback_add_listener(dri2_surf->throttle_callback,
1774                                &throttle_listener, dri2_surf);
1775    }
1776 
1777    wl_display_flush(dri2_dpy->wl_dpy);
1778 }
1779 
1780 static void
dri2_wl_swrast_get_drawable_info(__DRIdrawable * draw,int * x,int * y,int * w,int * h,void * loaderPrivate)1781 dri2_wl_swrast_get_drawable_info(__DRIdrawable * draw,
1782                                  int *x, int *y, int *w, int *h,
1783                                  void *loaderPrivate)
1784 {
1785    struct dri2_egl_surface *dri2_surf = loaderPrivate;
1786 
1787    (void) swrast_update_buffers(dri2_surf);
1788    *x = 0;
1789    *y = 0;
1790    *w = dri2_surf->base.Width;
1791    *h = dri2_surf->base.Height;
1792 }
1793 
1794 static void
dri2_wl_swrast_get_image(__DRIdrawable * read,int x,int y,int w,int h,char * data,void * loaderPrivate)1795 dri2_wl_swrast_get_image(__DRIdrawable * read,
1796                          int x, int y, int w, int h,
1797                          char *data, void *loaderPrivate)
1798 {
1799    struct dri2_egl_surface *dri2_surf = loaderPrivate;
1800    int copy_width = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w);
1801    int x_offset = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, x);
1802    int src_stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, dri2_surf->base.Width);
1803    int dst_stride = copy_width;
1804    char *src, *dst;
1805 
1806    src = dri2_wl_swrast_get_frontbuffer_data(dri2_surf);
1807    if (!src) {
1808       memset(data, 0, copy_width * h);
1809       return;
1810    }
1811 
1812    assert(data != src);
1813    assert(copy_width <= src_stride);
1814 
1815    src += x_offset;
1816    src += y * src_stride;
1817    dst = data;
1818 
1819    if (copy_width > src_stride-x_offset)
1820       copy_width = src_stride-x_offset;
1821    if (h > dri2_surf->base.Height-y)
1822       h = dri2_surf->base.Height-y;
1823 
1824    for (; h>0; h--) {
1825       memcpy(dst, src, copy_width);
1826       src += src_stride;
1827       dst += dst_stride;
1828    }
1829 }
1830 
1831 static void
dri2_wl_swrast_put_image2(__DRIdrawable * draw,int op,int x,int y,int w,int h,int stride,char * data,void * loaderPrivate)1832 dri2_wl_swrast_put_image2(__DRIdrawable * draw, int op,
1833                          int x, int y, int w, int h, int stride,
1834                          char *data, void *loaderPrivate)
1835 {
1836    struct dri2_egl_surface *dri2_surf = loaderPrivate;
1837    int copy_width = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w);
1838    int dst_stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, dri2_surf->base.Width);
1839    int x_offset = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, x);
1840    char *src, *dst;
1841 
1842    assert(copy_width <= stride);
1843 
1844    (void) swrast_update_buffers(dri2_surf);
1845    dst = dri2_wl_swrast_get_backbuffer_data(dri2_surf);
1846 
1847    /* partial copy, copy old content */
1848    if (copy_width < dst_stride)
1849       dri2_wl_swrast_get_image(draw, 0, 0,
1850                                dri2_surf->base.Width, dri2_surf->base.Height,
1851                                dst, loaderPrivate);
1852 
1853    dst += x_offset;
1854    dst += y * dst_stride;
1855 
1856    src = data;
1857 
1858    /* drivers expect we do these checks (and some rely on it) */
1859    if (copy_width > dst_stride-x_offset)
1860       copy_width = dst_stride-x_offset;
1861    if (h > dri2_surf->base.Height-y)
1862       h = dri2_surf->base.Height-y;
1863 
1864    for (; h>0; h--) {
1865       memcpy(dst, src, copy_width);
1866       src += stride;
1867       dst += dst_stride;
1868    }
1869    dri2_wl_swrast_commit_backbuffer(dri2_surf);
1870 }
1871 
1872 static void
dri2_wl_swrast_put_image(__DRIdrawable * draw,int op,int x,int y,int w,int h,char * data,void * loaderPrivate)1873 dri2_wl_swrast_put_image(__DRIdrawable * draw, int op,
1874                          int x, int y, int w, int h,
1875                          char *data, void *loaderPrivate)
1876 {
1877    struct dri2_egl_surface *dri2_surf = loaderPrivate;
1878    int stride;
1879 
1880    stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w);
1881    dri2_wl_swrast_put_image2(draw, op, x, y, w, h,
1882                              stride, data, loaderPrivate);
1883 }
1884 
1885 static EGLBoolean
dri2_wl_swrast_swap_buffers(_EGLDriver * drv,_EGLDisplay * disp,_EGLSurface * draw)1886 dri2_wl_swrast_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
1887 {
1888    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1889    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
1890 
1891    dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable);
1892    return EGL_TRUE;
1893 }
1894 
1895 static void
shm_handle_format(void * data,struct wl_shm * shm,uint32_t format)1896 shm_handle_format(void *data, struct wl_shm *shm, uint32_t format)
1897 {
1898    struct dri2_egl_display *dri2_dpy = data;
1899 
1900    switch (format) {
1901    case WL_SHM_FORMAT_ARGB2101010:
1902       dri2_dpy->formats |= HAS_ARGB2101010;
1903       break;
1904    case WL_SHM_FORMAT_XRGB2101010:
1905       dri2_dpy->formats |= HAS_XRGB2101010;
1906       break;
1907    case WL_SHM_FORMAT_ARGB8888:
1908       dri2_dpy->formats |= HAS_ARGB8888;
1909       break;
1910    case WL_SHM_FORMAT_XRGB8888:
1911       dri2_dpy->formats |= HAS_XRGB8888;
1912       break;
1913    case WL_SHM_FORMAT_RGB565:
1914       dri2_dpy->formats |= HAS_RGB565;
1915       break;
1916    }
1917 }
1918 
1919 static const struct wl_shm_listener shm_listener = {
1920    .format = shm_handle_format
1921 };
1922 
1923 static void
registry_handle_global_swrast(void * data,struct wl_registry * registry,uint32_t name,const char * interface,uint32_t version)1924 registry_handle_global_swrast(void *data, struct wl_registry *registry,
1925                               uint32_t name, const char *interface,
1926                               uint32_t version)
1927 {
1928    struct dri2_egl_display *dri2_dpy = data;
1929 
1930    if (strcmp(interface, "wl_shm") == 0) {
1931       dri2_dpy->wl_shm =
1932          wl_registry_bind(registry, name, &wl_shm_interface, 1);
1933       wl_shm_add_listener(dri2_dpy->wl_shm, &shm_listener, dri2_dpy);
1934    }
1935 }
1936 
1937 static const struct wl_registry_listener registry_listener_swrast = {
1938    .global = registry_handle_global_swrast,
1939    .global_remove = registry_handle_global_remove
1940 };
1941 
1942 static const struct dri2_egl_display_vtbl dri2_wl_swrast_display_vtbl = {
1943    .authenticate = NULL,
1944    .create_window_surface = dri2_wl_create_window_surface,
1945    .create_pixmap_surface = dri2_wl_create_pixmap_surface,
1946    .create_pbuffer_surface = dri2_fallback_create_pbuffer_surface,
1947    .destroy_surface = dri2_wl_destroy_surface,
1948    .create_image = dri2_create_image_khr,
1949    .swap_buffers = dri2_wl_swrast_swap_buffers,
1950    .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage,
1951    .swap_buffers_region = dri2_fallback_swap_buffers_region,
1952    .post_sub_buffer = dri2_fallback_post_sub_buffer,
1953    .copy_buffers = dri2_fallback_copy_buffers,
1954    .query_buffer_age = dri2_fallback_query_buffer_age,
1955    .create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image,
1956    .get_sync_values = dri2_fallback_get_sync_values,
1957    .get_dri_drawable = dri2_surface_get_dri_drawable,
1958 };
1959 
1960 static const __DRIswrastLoaderExtension swrast_loader_extension = {
1961    .base = { __DRI_SWRAST_LOADER, 2 },
1962 
1963    .getDrawableInfo = dri2_wl_swrast_get_drawable_info,
1964    .putImage        = dri2_wl_swrast_put_image,
1965    .getImage        = dri2_wl_swrast_get_image,
1966    .putImage2       = dri2_wl_swrast_put_image2,
1967 };
1968 
1969 static const __DRIextension *swrast_loader_extensions[] = {
1970    &swrast_loader_extension.base,
1971    &image_lookup_extension.base,
1972    NULL,
1973 };
1974 
1975 static EGLBoolean
dri2_initialize_wayland_swrast(_EGLDriver * drv,_EGLDisplay * disp)1976 dri2_initialize_wayland_swrast(_EGLDriver *drv, _EGLDisplay *disp)
1977 {
1978    struct dri2_egl_display *dri2_dpy;
1979 
1980    loader_set_logger(_eglLog);
1981 
1982    dri2_dpy = calloc(1, sizeof *dri2_dpy);
1983    if (!dri2_dpy)
1984       return _eglError(EGL_BAD_ALLOC, "eglInitialize");
1985 
1986    dri2_dpy->fd = -1;
1987    disp->DriverData = (void *) dri2_dpy;
1988    if (disp->PlatformDisplay == NULL) {
1989       dri2_dpy->wl_dpy = wl_display_connect(NULL);
1990       if (dri2_dpy->wl_dpy == NULL)
1991          goto cleanup;
1992       dri2_dpy->own_device = true;
1993    } else {
1994       dri2_dpy->wl_dpy = disp->PlatformDisplay;
1995    }
1996 
1997    dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
1998 
1999    dri2_dpy->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy);
2000    if (dri2_dpy->wl_dpy_wrapper == NULL)
2001       goto cleanup;
2002 
2003    wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_dpy_wrapper,
2004                       dri2_dpy->wl_queue);
2005 
2006    if (dri2_dpy->own_device)
2007       wl_display_dispatch_pending(dri2_dpy->wl_dpy);
2008 
2009    dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy_wrapper);
2010    wl_registry_add_listener(dri2_dpy->wl_registry,
2011                             &registry_listener_swrast, dri2_dpy);
2012 
2013    if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_shm == NULL)
2014       goto cleanup;
2015 
2016    if (roundtrip(dri2_dpy) < 0 || dri2_dpy->formats == 0)
2017       goto cleanup;
2018 
2019    dri2_dpy->driver_name = strdup("swrast");
2020    if (!dri2_load_driver_swrast(disp))
2021       goto cleanup;
2022 
2023    dri2_dpy->loader_extensions = swrast_loader_extensions;
2024 
2025    if (!dri2_create_screen(disp))
2026       goto cleanup;
2027 
2028    if (!dri2_setup_extensions(disp))
2029       goto cleanup;
2030 
2031    dri2_setup_screen(disp);
2032 
2033    dri2_wl_setup_swap_interval(disp);
2034 
2035    if (!dri2_wl_add_configs_for_visuals(drv, disp)) {
2036       _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to add configs");
2037       goto cleanup;
2038    }
2039 
2040    /* Fill vtbl last to prevent accidentally calling virtual function during
2041     * initialization.
2042     */
2043    dri2_dpy->vtbl = &dri2_wl_swrast_display_vtbl;
2044 
2045    return EGL_TRUE;
2046 
2047  cleanup:
2048    dri2_display_destroy(disp);
2049    return EGL_FALSE;
2050 }
2051 
2052 EGLBoolean
dri2_initialize_wayland(_EGLDriver * drv,_EGLDisplay * disp)2053 dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp)
2054 {
2055    EGLBoolean initialized = EGL_FALSE;
2056 
2057    if (!disp->Options.ForceSoftware)
2058       initialized = dri2_initialize_wayland_drm(drv, disp);
2059 
2060    if (!initialized)
2061       initialized = dri2_initialize_wayland_swrast(drv, disp);
2062 
2063    return initialized;
2064 
2065 }
2066 
2067 void
dri2_teardown_wayland(struct dri2_egl_display * dri2_dpy)2068 dri2_teardown_wayland(struct dri2_egl_display *dri2_dpy)
2069 {
2070    if (dri2_dpy->wl_drm)
2071       wl_drm_destroy(dri2_dpy->wl_drm);
2072    if (dri2_dpy->wl_dmabuf)
2073       zwp_linux_dmabuf_v1_destroy(dri2_dpy->wl_dmabuf);
2074    if (dri2_dpy->wl_shm)
2075       wl_shm_destroy(dri2_dpy->wl_shm);
2076    if (dri2_dpy->wl_registry)
2077       wl_registry_destroy(dri2_dpy->wl_registry);
2078    if (dri2_dpy->wl_queue)
2079       wl_event_queue_destroy(dri2_dpy->wl_queue);
2080    if (dri2_dpy->wl_dpy_wrapper)
2081       wl_proxy_wrapper_destroy(dri2_dpy->wl_dpy_wrapper);
2082    u_vector_finish(&dri2_dpy->wl_modifiers.argb2101010);
2083    u_vector_finish(&dri2_dpy->wl_modifiers.xrgb2101010);
2084    u_vector_finish(&dri2_dpy->wl_modifiers.argb8888);
2085    u_vector_finish(&dri2_dpy->wl_modifiers.xrgb8888);
2086    u_vector_finish(&dri2_dpy->wl_modifiers.rgb565);
2087    if (dri2_dpy->own_device)
2088       wl_display_disconnect(dri2_dpy->wl_dpy);
2089 }
2090