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