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