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