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