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