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