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