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