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