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#include "kopper_interface.h" 49 50#include <wayland-egl-backend.h> 51#include <wayland-client.h> 52#include "wayland-drm-client-protocol.h" 53#include "linux-dmabuf-unstable-v1-client-protocol.h" 54 55/* 56 * The index of entries in this table is used as a bitmask in 57 * dri2_dpy->formats.formats_bitmap, which tracks the formats supported 58 * by our server. 59 */ 60static const struct dri2_wl_visual { 61 const char *format_name; 62 uint32_t wl_drm_format; 63 uint32_t wl_shm_format; 64 int dri_image_format; 65 /* alt_dri_image_format is a substitute wl_buffer format to use for a 66 * wl-server unsupported dri_image_format, ie. some other dri_image_format in 67 * the table, of the same precision but with different channel ordering, or 68 * __DRI_IMAGE_FORMAT_NONE if an alternate format is not needed or supported. 69 * The code checks if alt_dri_image_format can be used as a fallback for a 70 * dri_image_format for a given wl-server implementation. 71 */ 72 int alt_dri_image_format; 73 int bpp; 74 int rgba_shifts[4]; 75 unsigned int rgba_sizes[4]; 76} dri2_wl_visuals[] = { 77 { 78 "ABGR16F", 79 WL_DRM_FORMAT_ABGR16F, WL_SHM_FORMAT_ABGR16161616F, 80 __DRI_IMAGE_FORMAT_ABGR16161616F, 0, 64, 81 { 0, 16, 32, 48 }, 82 { 16, 16, 16, 16 }, 83 }, 84 { 85 "XBGR16F", 86 WL_DRM_FORMAT_XBGR16F, WL_SHM_FORMAT_XBGR16161616F, 87 __DRI_IMAGE_FORMAT_XBGR16161616F, 0, 64, 88 { 0, 16, 32, -1 }, 89 { 16, 16, 16, 0 }, 90 }, 91 { 92 "XRGB2101010", 93 WL_DRM_FORMAT_XRGB2101010, WL_SHM_FORMAT_XRGB2101010, 94 __DRI_IMAGE_FORMAT_XRGB2101010, __DRI_IMAGE_FORMAT_XBGR2101010, 32, 95 { 20, 10, 0, -1 }, 96 { 10, 10, 10, 0 }, 97 }, 98 { 99 "ARGB2101010", 100 WL_DRM_FORMAT_ARGB2101010, WL_SHM_FORMAT_ARGB2101010, 101 __DRI_IMAGE_FORMAT_ARGB2101010, __DRI_IMAGE_FORMAT_ABGR2101010, 32, 102 { 20, 10, 0, 30 }, 103 { 10, 10, 10, 2 }, 104 }, 105 { 106 "XBGR2101010", 107 WL_DRM_FORMAT_XBGR2101010, WL_SHM_FORMAT_XBGR2101010, 108 __DRI_IMAGE_FORMAT_XBGR2101010, __DRI_IMAGE_FORMAT_XRGB2101010, 32, 109 { 0, 10, 20, -1 }, 110 { 10, 10, 10, 0 }, 111 }, 112 { 113 "ABGR2101010", 114 WL_DRM_FORMAT_ABGR2101010, WL_SHM_FORMAT_ABGR2101010, 115 __DRI_IMAGE_FORMAT_ABGR2101010, __DRI_IMAGE_FORMAT_ARGB2101010, 32, 116 { 0, 10, 20, 30 }, 117 { 10, 10, 10, 2 }, 118 }, 119 { 120 "XRGB8888", 121 WL_DRM_FORMAT_XRGB8888, WL_SHM_FORMAT_XRGB8888, 122 __DRI_IMAGE_FORMAT_XRGB8888, __DRI_IMAGE_FORMAT_NONE, 32, 123 { 16, 8, 0, -1 }, 124 { 8, 8, 8, 0 }, 125 }, 126 { 127 "ARGB8888", 128 WL_DRM_FORMAT_ARGB8888, WL_SHM_FORMAT_ARGB8888, 129 __DRI_IMAGE_FORMAT_ARGB8888, __DRI_IMAGE_FORMAT_NONE, 32, 130 { 16, 8, 0, 24 }, 131 { 8, 8, 8, 8 }, 132 }, 133 { 134 "ABGR8888", 135 WL_DRM_FORMAT_ABGR8888, WL_SHM_FORMAT_ABGR8888, 136 __DRI_IMAGE_FORMAT_ABGR8888, __DRI_IMAGE_FORMAT_NONE, 32, 137 { 0, 8, 16, 24 }, 138 { 8, 8, 8, 8 }, 139 }, 140 { 141 "XBGR8888", 142 WL_DRM_FORMAT_XBGR8888, WL_SHM_FORMAT_XBGR8888, 143 __DRI_IMAGE_FORMAT_XBGR8888, __DRI_IMAGE_FORMAT_NONE, 32, 144 { 0, 8, 16, -1 }, 145 { 8, 8, 8, 0 }, 146 }, 147 { 148 "RGB565", 149 WL_DRM_FORMAT_RGB565, WL_SHM_FORMAT_RGB565, 150 __DRI_IMAGE_FORMAT_RGB565, __DRI_IMAGE_FORMAT_NONE, 16, 151 { 11, 5, 0, -1 }, 152 { 5, 6, 5, 0 }, 153 }, 154}; 155 156static int 157dri2_wl_visual_idx_from_config(struct dri2_egl_display *dri2_dpy, 158 const __DRIconfig *config, 159 bool force_opaque) 160{ 161 int shifts[4]; 162 unsigned int sizes[4]; 163 164 dri2_get_shifts_and_sizes(dri2_dpy->core, config, shifts, sizes); 165 166 for (unsigned int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) { 167 const struct dri2_wl_visual *wl_visual = &dri2_wl_visuals[i]; 168 169 int cmp_rgb_shifts = memcmp(shifts, wl_visual->rgba_shifts, 170 3 * sizeof(shifts[0])); 171 int cmp_rgb_sizes = memcmp(sizes, wl_visual->rgba_sizes, 172 3 * sizeof(sizes[0])); 173 174 if (cmp_rgb_shifts == 0 && cmp_rgb_sizes == 0 && 175 wl_visual->rgba_shifts[3] == (force_opaque ? -1 : shifts[3]) && 176 wl_visual->rgba_sizes[3] == (force_opaque ? 0 : sizes[3])) { 177 return i; 178 } 179 } 180 181 return -1; 182} 183 184static int 185dri2_wl_visual_idx_from_fourcc(uint32_t fourcc) 186{ 187 for (int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) { 188 /* wl_drm format codes overlap with DRIImage FourCC codes for all formats 189 * we support. */ 190 if (dri2_wl_visuals[i].wl_drm_format == fourcc) 191 return i; 192 } 193 194 return -1; 195} 196 197static int 198dri2_wl_visual_idx_from_dri_image_format(uint32_t dri_image_format) 199{ 200 for (int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) { 201 if (dri2_wl_visuals[i].dri_image_format == dri_image_format) 202 return i; 203 } 204 205 return -1; 206} 207 208static int 209dri2_wl_visual_idx_from_shm_format(uint32_t shm_format) 210{ 211 for (int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) { 212 if (dri2_wl_visuals[i].wl_shm_format == shm_format) 213 return i; 214 } 215 216 return -1; 217} 218 219bool 220dri2_wl_is_format_supported(void* user_data, uint32_t format) 221{ 222 _EGLDisplay *disp = (_EGLDisplay *) user_data; 223 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 224 int j = dri2_wl_visual_idx_from_fourcc(format); 225 226 if (j == -1) 227 return false; 228 229 for (int i = 0; dri2_dpy->driver_configs[i]; i++) 230 if (j == dri2_wl_visual_idx_from_config(dri2_dpy, 231 dri2_dpy->driver_configs[i], 232 false)) 233 return true; 234 235 return false; 236} 237 238static int 239roundtrip(struct dri2_egl_display *dri2_dpy) 240{ 241 return wl_display_roundtrip_queue(dri2_dpy->wl_dpy, dri2_dpy->wl_queue); 242} 243 244static void 245wl_buffer_release(void *data, struct wl_buffer *buffer) 246{ 247 struct dri2_egl_surface *dri2_surf = data; 248 int i; 249 250 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); ++i) 251 if (dri2_surf->color_buffers[i].wl_buffer == buffer) 252 break; 253 254 assert (i < ARRAY_SIZE(dri2_surf->color_buffers)); 255 256 if (dri2_surf->color_buffers[i].wl_release) { 257 wl_buffer_destroy(buffer); 258 dri2_surf->color_buffers[i].wl_release = false; 259 dri2_surf->color_buffers[i].wl_buffer = NULL; 260 dri2_surf->color_buffers[i].age = 0; 261 } 262 263 dri2_surf->color_buffers[i].locked = false; 264} 265 266static const struct wl_buffer_listener wl_buffer_listener = { 267 .release = wl_buffer_release 268}; 269 270static void 271dri2_wl_formats_fini(struct dri2_wl_formats *formats) 272{ 273 unsigned int i; 274 275 for (i = 0; i < formats->num_formats; i++) 276 u_vector_finish(&formats->modifiers[i]); 277 278 free(formats->modifiers); 279 free(formats->formats_bitmap); 280} 281 282static int 283dri2_wl_formats_init(struct dri2_wl_formats *formats) 284{ 285 unsigned int i, j; 286 287 /* formats->formats_bitmap tells us if a format in dri2_wl_visuals is present 288 * or not. So we must compute the amount of unsigned int's needed to 289 * represent all the formats of dri2_wl_visuals. We use BITSET_WORDS for 290 * this task. */ 291 formats->num_formats = ARRAY_SIZE(dri2_wl_visuals); 292 formats->formats_bitmap = calloc(BITSET_WORDS(formats->num_formats), 293 sizeof(*formats->formats_bitmap)); 294 if (!formats->formats_bitmap) 295 goto err; 296 297 /* Here we have an array of u_vector's to store the modifiers supported by 298 * each format in the bitmask. */ 299 formats->modifiers = calloc(formats->num_formats, 300 sizeof(*formats->modifiers)); 301 if (!formats->modifiers) 302 goto err_modifier; 303 304 for (i = 0; i < formats->num_formats; i++) 305 if (!u_vector_init_pow2(&formats->modifiers[i], 4, sizeof(uint64_t))) { 306 j = i; 307 goto err_vector_init; 308 } 309 310 return 0; 311 312err_vector_init: 313 for (i = 0; i < j; i++) 314 u_vector_finish(&formats->modifiers[i]); 315 free(formats->modifiers); 316err_modifier: 317 free(formats->formats_bitmap); 318err: 319 _eglError(EGL_BAD_ALLOC, "dri2_wl_formats_init"); 320 return -1; 321} 322 323static void 324dmabuf_feedback_format_table_fini(struct dmabuf_feedback_format_table *format_table) 325{ 326 if (format_table->data && format_table->data != MAP_FAILED) 327 munmap(format_table->data, format_table->size); 328} 329 330static void 331dmabuf_feedback_format_table_init(struct dmabuf_feedback_format_table *format_table) 332{ 333 memset(format_table, 0, sizeof(*format_table)); 334} 335 336static void 337dmabuf_feedback_tranche_fini(struct dmabuf_feedback_tranche *tranche) 338{ 339 dri2_wl_formats_fini(&tranche->formats); 340} 341 342static int 343dmabuf_feedback_tranche_init(struct dmabuf_feedback_tranche *tranche) 344{ 345 memset(tranche, 0, sizeof(*tranche)); 346 347 if (dri2_wl_formats_init(&tranche->formats) < 0) 348 return -1; 349 350 return 0; 351} 352 353static void 354dmabuf_feedback_fini(struct dmabuf_feedback *dmabuf_feedback) 355{ 356 dmabuf_feedback_tranche_fini(&dmabuf_feedback->pending_tranche); 357 358 util_dynarray_foreach(&dmabuf_feedback->tranches, 359 struct dmabuf_feedback_tranche, tranche) 360 dmabuf_feedback_tranche_fini(tranche); 361 util_dynarray_fini(&dmabuf_feedback->tranches); 362 363 dmabuf_feedback_format_table_fini(&dmabuf_feedback->format_table); 364} 365 366static int 367dmabuf_feedback_init(struct dmabuf_feedback *dmabuf_feedback) 368{ 369 memset(dmabuf_feedback, 0, sizeof(*dmabuf_feedback)); 370 371 if (dmabuf_feedback_tranche_init(&dmabuf_feedback->pending_tranche) < 0) 372 return -1; 373 374 util_dynarray_init(&dmabuf_feedback->tranches, NULL); 375 376 dmabuf_feedback_format_table_init(&dmabuf_feedback->format_table); 377 378 return 0; 379} 380 381static void 382resize_callback(struct wl_egl_window *wl_win, void *data) 383{ 384 struct dri2_egl_surface *dri2_surf = data; 385 struct dri2_egl_display *dri2_dpy = 386 dri2_egl_display(dri2_surf->base.Resource.Display); 387 388 if (dri2_surf->base.Width == wl_win->width && 389 dri2_surf->base.Height == wl_win->height) 390 return; 391 392 dri2_surf->resized = true; 393 394 /* Update the surface size as soon as native window is resized; from user 395 * pov, this makes the effect that resize is done immediately after native 396 * window resize, without requiring to wait until the first draw. 397 * 398 * A more detailed and lengthy explanation can be found at 399 * https://lists.freedesktop.org/archives/mesa-dev/2018-June/196474.html 400 */ 401 if (!dri2_surf->back) { 402 dri2_surf->base.Width = wl_win->width; 403 dri2_surf->base.Height = wl_win->height; 404 } 405 dri2_dpy->flush->invalidate(dri2_surf->dri_drawable); 406} 407 408static void 409destroy_window_callback(void *data) 410{ 411 struct dri2_egl_surface *dri2_surf = data; 412 dri2_surf->wl_win = NULL; 413} 414 415static struct wl_surface * 416get_wl_surface_proxy(struct wl_egl_window *window) 417{ 418 /* Version 3 of wl_egl_window introduced a version field at the same 419 * location where a pointer to wl_surface was stored. Thus, if 420 * window->version is dereferenceable, we've been given an older version of 421 * wl_egl_window, and window->version points to wl_surface */ 422 if (_eglPointerIsDereferencable((void *)(window->version))) { 423 return wl_proxy_create_wrapper((void *)(window->version)); 424 } 425 return wl_proxy_create_wrapper(window->surface); 426} 427 428static void 429surface_dmabuf_feedback_format_table(void *data, 430 struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1, 431 int32_t fd, uint32_t size) 432{ 433 struct dri2_egl_surface *dri2_surf = data; 434 struct dmabuf_feedback *feedback = &dri2_surf->pending_dmabuf_feedback; 435 436 feedback->format_table.size = size; 437 feedback->format_table.data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); 438 439 close(fd); 440} 441 442static void 443surface_dmabuf_feedback_main_device(void *data, 444 struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback, 445 struct wl_array *device) 446{ 447 struct dri2_egl_surface *dri2_surf = data; 448 struct dmabuf_feedback *feedback = &dri2_surf->pending_dmabuf_feedback; 449 450 memcpy(&feedback->main_device, device->data, sizeof(feedback->main_device)); 451 452 /* Compositors may support switching render devices and change the main 453 * device of the dma-buf feedback. In this case, when we reallocate the 454 * buffers of the surface we must ensure that it is not allocated in memory 455 * that is only visible to the GPU that EGL is using, as the compositor will 456 * have to import them to the render device it is using. 457 * 458 * TODO: we still don't know how to allocate such buffers. 459 */ 460 if (dri2_surf->dmabuf_feedback.main_device != 0 && 461 (feedback->main_device != dri2_surf->dmabuf_feedback.main_device)) 462 dri2_surf->compositor_using_another_device = true; 463 else 464 dri2_surf->compositor_using_another_device = false; 465} 466 467static void 468surface_dmabuf_feedback_tranche_target_device(void *data, 469 struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback, 470 struct wl_array *device) 471{ 472 struct dri2_egl_surface *dri2_surf = data; 473 struct dmabuf_feedback *feedback = &dri2_surf->pending_dmabuf_feedback; 474 475 memcpy(&feedback->pending_tranche.target_device, device->data, 476 sizeof(feedback->pending_tranche.target_device)); 477} 478 479static void 480surface_dmabuf_feedback_tranche_flags(void *data, 481 struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback, 482 uint32_t flags) 483{ 484 struct dri2_egl_surface *dri2_surf = data; 485 struct dmabuf_feedback *feedback = &dri2_surf->pending_dmabuf_feedback; 486 487 feedback->pending_tranche.flags = flags; 488} 489 490static void 491surface_dmabuf_feedback_tranche_formats(void *data, 492 struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback, 493 struct wl_array *indices) 494{ 495 struct dri2_egl_surface *dri2_surf = data; 496 struct dmabuf_feedback *feedback = &dri2_surf->pending_dmabuf_feedback; 497 uint64_t *modifier_ptr, modifier; 498 uint32_t format; 499 uint16_t *index; 500 int visual_idx; 501 502 /* Compositor may advertise or not a format table. If it does, we use it. 503 * Otherwise, we steal the most recent advertised format table. If we don't have 504 * a most recent advertised format table, compositor did something wrong. */ 505 if (feedback->format_table.data == NULL) { 506 feedback->format_table = dri2_surf->dmabuf_feedback.format_table; 507 dmabuf_feedback_format_table_init(&dri2_surf->dmabuf_feedback.format_table); 508 } 509 if (feedback->format_table.data == MAP_FAILED) { 510 _eglLog(_EGL_WARNING, "wayland-egl: we could not map the format table " 511 "so we won't be able to use this batch of dma-buf " 512 "feedback events."); 513 return; 514 } 515 if (feedback->format_table.data == NULL) { 516 _eglLog(_EGL_WARNING, "wayland-egl: compositor didn't advertise a format " 517 "table, so we won't be able to use this batch of dma-buf " 518 "feedback events."); 519 return; 520 } 521 522 wl_array_for_each(index, indices) { 523 format = feedback->format_table.data[*index].format; 524 modifier = feedback->format_table.data[*index].modifier; 525 526 /* Skip formats that are not the one the surface is already using. We 527 * can't switch to another format. */ 528 if (format != dri2_surf->format) 529 continue; 530 531 /* We are sure that the format is supported because of the check above. */ 532 visual_idx = dri2_wl_visual_idx_from_fourcc(format); 533 assert(visual_idx != -1); 534 535 BITSET_SET(feedback->pending_tranche.formats.formats_bitmap, visual_idx); 536 modifier_ptr = 537 u_vector_add(&feedback->pending_tranche.formats.modifiers[visual_idx]); 538 if (modifier_ptr) 539 *modifier_ptr = modifier; 540 } 541} 542 543static void 544surface_dmabuf_feedback_tranche_done(void *data, 545 struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback) 546{ 547 struct dri2_egl_surface *dri2_surf = data; 548 struct dmabuf_feedback *feedback = &dri2_surf->pending_dmabuf_feedback; 549 550 /* Add tranche to array of tranches. */ 551 util_dynarray_append(&feedback->tranches, struct dmabuf_feedback_tranche, 552 feedback->pending_tranche); 553 554 dmabuf_feedback_tranche_init(&feedback->pending_tranche); 555} 556 557static void 558surface_dmabuf_feedback_done(void *data, 559 struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback) 560{ 561 struct dri2_egl_surface *dri2_surf = data; 562 563 /* The dma-buf feedback protocol states that surface dma-buf feedback should 564 * be sent by the compositor only if its buffers are using a suboptimal pair 565 * of format and modifier. We can't change the buffer format, but we can 566 * reallocate with another modifier. So we raise this flag in order to force 567 * buffer reallocation based on the dma-buf feedback sent. */ 568 dri2_surf->received_dmabuf_feedback = true; 569 570 dmabuf_feedback_fini(&dri2_surf->dmabuf_feedback); 571 dri2_surf->dmabuf_feedback = dri2_surf->pending_dmabuf_feedback; 572 dmabuf_feedback_init(&dri2_surf->pending_dmabuf_feedback); 573} 574 575static const struct zwp_linux_dmabuf_feedback_v1_listener 576surface_dmabuf_feedback_listener = { 577 .format_table = surface_dmabuf_feedback_format_table, 578 .main_device = surface_dmabuf_feedback_main_device, 579 .tranche_target_device = surface_dmabuf_feedback_tranche_target_device, 580 .tranche_flags = surface_dmabuf_feedback_tranche_flags, 581 .tranche_formats = surface_dmabuf_feedback_tranche_formats, 582 .tranche_done = surface_dmabuf_feedback_tranche_done, 583 .done = surface_dmabuf_feedback_done, 584}; 585 586/** 587 * Called via eglCreateWindowSurface(), drv->CreateWindowSurface(). 588 */ 589static _EGLSurface * 590dri2_wl_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf, 591 void *native_window, const EGLint *attrib_list) 592{ 593 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 594 struct dri2_egl_config *dri2_conf = dri2_egl_config(conf); 595 struct wl_egl_window *window = native_window; 596 struct dri2_egl_surface *dri2_surf; 597 struct zwp_linux_dmabuf_v1 *dmabuf_wrapper; 598 int visual_idx; 599 const __DRIconfig *config; 600 601 if (!window) { 602 _eglError(EGL_BAD_NATIVE_WINDOW, "dri2_create_surface"); 603 return NULL; 604 } 605 606 if (window->driver_private) { 607 _eglError(EGL_BAD_ALLOC, "dri2_create_surface"); 608 return NULL; 609 } 610 611 dri2_surf = calloc(1, sizeof *dri2_surf); 612 if (!dri2_surf) { 613 _eglError(EGL_BAD_ALLOC, "dri2_create_surface"); 614 return NULL; 615 } 616 617 if (!dri2_init_surface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf, 618 attrib_list, false, native_window)) 619 goto cleanup_surf; 620 621 config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT, 622 dri2_surf->base.GLColorspace); 623 624 if (!config) { 625 _eglError(EGL_BAD_MATCH, "Unsupported surfacetype/colorspace configuration"); 626 goto cleanup_surf; 627 } 628 629 dri2_surf->base.Width = window->width; 630 dri2_surf->base.Height = window->height; 631 632#ifndef NDEBUG 633 /* Enforce that every visual has an opaque variant (requirement to support 634 * EGL_EXT_present_opaque) 635 */ 636 for (unsigned int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) { 637 const struct dri2_wl_visual *transparent_visual = &dri2_wl_visuals[i]; 638 if (transparent_visual->rgba_sizes[3] == 0) { 639 continue; 640 } 641 642 bool found_opaque_equivalent = false; 643 for (unsigned int j = 0; j < ARRAY_SIZE(dri2_wl_visuals); j++) { 644 const struct dri2_wl_visual *opaque_visual = &dri2_wl_visuals[j]; 645 if (opaque_visual->rgba_sizes[3] != 0) { 646 continue; 647 } 648 649 int cmp_rgb_shifts = memcmp(transparent_visual->rgba_shifts, 650 opaque_visual->rgba_shifts, 651 3 * sizeof(opaque_visual->rgba_shifts[0])); 652 int cmp_rgb_sizes = memcmp(transparent_visual->rgba_sizes, 653 opaque_visual->rgba_sizes, 654 3 * sizeof(opaque_visual->rgba_sizes[0])); 655 656 if (cmp_rgb_shifts == 0 && cmp_rgb_sizes == 0) { 657 found_opaque_equivalent = true; 658 break; 659 } 660 } 661 662 assert(found_opaque_equivalent); 663 } 664#endif 665 666 visual_idx = dri2_wl_visual_idx_from_config(dri2_dpy, config, 667 dri2_surf->base.PresentOpaque); 668 assert(visual_idx != -1); 669 670 if (dri2_dpy->wl_dmabuf || dri2_dpy->wl_drm) { 671 dri2_surf->format = dri2_wl_visuals[visual_idx].wl_drm_format; 672 } else { 673 assert(dri2_dpy->wl_shm); 674 dri2_surf->format = dri2_wl_visuals[visual_idx].wl_shm_format; 675 } 676 677 dri2_surf->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy); 678 if (!dri2_surf->wl_queue) { 679 _eglError(EGL_BAD_ALLOC, "dri2_create_surface"); 680 goto cleanup_surf; 681 } 682 683 if (dri2_dpy->wl_drm) { 684 dri2_surf->wl_drm_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_drm); 685 if (!dri2_surf->wl_drm_wrapper) { 686 _eglError(EGL_BAD_ALLOC, "dri2_create_surface"); 687 goto cleanup_queue; 688 } 689 wl_proxy_set_queue((struct wl_proxy *)dri2_surf->wl_drm_wrapper, 690 dri2_surf->wl_queue); 691 } 692 693 dri2_surf->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy); 694 if (!dri2_surf->wl_dpy_wrapper) { 695 _eglError(EGL_BAD_ALLOC, "dri2_create_surface"); 696 goto cleanup_drm; 697 } 698 wl_proxy_set_queue((struct wl_proxy *)dri2_surf->wl_dpy_wrapper, 699 dri2_surf->wl_queue); 700 701 dri2_surf->wl_surface_wrapper = get_wl_surface_proxy(window); 702 if (!dri2_surf->wl_surface_wrapper) { 703 _eglError(EGL_BAD_ALLOC, "dri2_create_surface"); 704 goto cleanup_dpy_wrapper; 705 } 706 wl_proxy_set_queue((struct wl_proxy *)dri2_surf->wl_surface_wrapper, 707 dri2_surf->wl_queue); 708 709 if (dri2_dpy->wl_dmabuf && zwp_linux_dmabuf_v1_get_version(dri2_dpy->wl_dmabuf) >= 710 ZWP_LINUX_DMABUF_V1_GET_SURFACE_FEEDBACK_SINCE_VERSION) { 711 dmabuf_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dmabuf); 712 if (!dmabuf_wrapper) { 713 _eglError(EGL_BAD_ALLOC, "dri2_create_surface"); 714 goto cleanup_surf_wrapper; 715 } 716 wl_proxy_set_queue((struct wl_proxy *)dmabuf_wrapper, 717 dri2_surf->wl_queue); 718 dri2_surf->wl_dmabuf_feedback = 719 zwp_linux_dmabuf_v1_get_surface_feedback(dmabuf_wrapper, 720 dri2_surf->wl_surface_wrapper); 721 wl_proxy_wrapper_destroy(dmabuf_wrapper); 722 723 zwp_linux_dmabuf_feedback_v1_add_listener(dri2_surf->wl_dmabuf_feedback, 724 &surface_dmabuf_feedback_listener, 725 dri2_surf); 726 727 if (dmabuf_feedback_init(&dri2_surf->pending_dmabuf_feedback) < 0) { 728 zwp_linux_dmabuf_feedback_v1_destroy(dri2_surf->wl_dmabuf_feedback); 729 goto cleanup_surf_wrapper; 730 } 731 if (dmabuf_feedback_init(&dri2_surf->dmabuf_feedback) < 0) { 732 dmabuf_feedback_fini(&dri2_surf->pending_dmabuf_feedback); 733 zwp_linux_dmabuf_feedback_v1_destroy(dri2_surf->wl_dmabuf_feedback); 734 goto cleanup_surf_wrapper; 735 } 736 737 if (roundtrip(dri2_dpy) < 0) 738 goto cleanup_dmabuf_feedback; 739 } 740 741 dri2_surf->wl_win = window; 742 dri2_surf->wl_win->driver_private = dri2_surf; 743 dri2_surf->wl_win->destroy_window_callback = destroy_window_callback; 744 if (dri2_dpy->flush) 745 dri2_surf->wl_win->resize_callback = resize_callback; 746 747 if (!dri2_create_drawable(dri2_dpy, config, dri2_surf, dri2_surf)) 748 goto cleanup_dmabuf_feedback; 749 750 dri2_surf->base.SwapInterval = dri2_dpy->default_swap_interval; 751 752 return &dri2_surf->base; 753 754 cleanup_dmabuf_feedback: 755 if (dri2_surf->wl_dmabuf_feedback) { 756 zwp_linux_dmabuf_feedback_v1_destroy(dri2_surf->wl_dmabuf_feedback); 757 dmabuf_feedback_fini(&dri2_surf->dmabuf_feedback); 758 dmabuf_feedback_fini(&dri2_surf->pending_dmabuf_feedback); 759 } 760 cleanup_surf_wrapper: 761 wl_proxy_wrapper_destroy(dri2_surf->wl_surface_wrapper); 762 cleanup_dpy_wrapper: 763 wl_proxy_wrapper_destroy(dri2_surf->wl_dpy_wrapper); 764 cleanup_drm: 765 if (dri2_surf->wl_drm_wrapper) 766 wl_proxy_wrapper_destroy(dri2_surf->wl_drm_wrapper); 767 cleanup_queue: 768 wl_event_queue_destroy(dri2_surf->wl_queue); 769 cleanup_surf: 770 free(dri2_surf); 771 772 return NULL; 773} 774 775static _EGLSurface * 776dri2_wl_create_pixmap_surface(_EGLDisplay *disp, _EGLConfig *conf, 777 void *native_window, const EGLint *attrib_list) 778{ 779 /* From the EGL_EXT_platform_wayland spec, version 3: 780 * 781 * It is not valid to call eglCreatePlatformPixmapSurfaceEXT with a <dpy> 782 * that belongs to Wayland. Any such call fails and generates 783 * EGL_BAD_PARAMETER. 784 */ 785 _eglError(EGL_BAD_PARAMETER, "cannot create EGL pixmap surfaces on " 786 "Wayland"); 787 return NULL; 788} 789 790/** 791 * Called via eglDestroySurface(), drv->DestroySurface(). 792 */ 793static EGLBoolean 794dri2_wl_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf) 795{ 796 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 797 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); 798 799 dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable); 800 801 for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { 802 if (dri2_surf->color_buffers[i].wl_buffer) 803 wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer); 804 if (dri2_surf->color_buffers[i].dri_image) 805 dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image); 806 if (dri2_surf->color_buffers[i].linear_copy) 807 dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy); 808 if (dri2_surf->color_buffers[i].data) 809 munmap(dri2_surf->color_buffers[i].data, 810 dri2_surf->color_buffers[i].data_size); 811 } 812 813 if (dri2_dpy->dri2) 814 dri2_egl_surface_free_local_buffers(dri2_surf); 815 816 if (dri2_surf->throttle_callback) 817 wl_callback_destroy(dri2_surf->throttle_callback); 818 819 if (dri2_surf->wl_win) { 820 dri2_surf->wl_win->driver_private = NULL; 821 dri2_surf->wl_win->resize_callback = NULL; 822 dri2_surf->wl_win->destroy_window_callback = NULL; 823 } 824 825 wl_proxy_wrapper_destroy(dri2_surf->wl_surface_wrapper); 826 wl_proxy_wrapper_destroy(dri2_surf->wl_dpy_wrapper); 827 if (dri2_surf->wl_drm_wrapper) 828 wl_proxy_wrapper_destroy(dri2_surf->wl_drm_wrapper); 829 if (dri2_surf->wl_dmabuf_feedback) { 830 zwp_linux_dmabuf_feedback_v1_destroy(dri2_surf->wl_dmabuf_feedback); 831 dmabuf_feedback_fini(&dri2_surf->dmabuf_feedback); 832 dmabuf_feedback_fini(&dri2_surf->pending_dmabuf_feedback); 833 } 834 wl_event_queue_destroy(dri2_surf->wl_queue); 835 836 dri2_fini_surface(surf); 837 free(surf); 838 839 return EGL_TRUE; 840} 841 842static EGLBoolean 843dri2_wl_swap_interval(_EGLDisplay *disp, _EGLSurface *surf, EGLint interval) 844{ 845 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 846 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); 847 848 if (dri2_dpy->kopper) 849 dri2_dpy->kopper->setSwapInterval(dri2_surf->dri_drawable, interval); 850 851 return EGL_TRUE; 852} 853 854static void 855dri2_wl_release_buffers(struct dri2_egl_surface *dri2_surf) 856{ 857 struct dri2_egl_display *dri2_dpy = 858 dri2_egl_display(dri2_surf->base.Resource.Display); 859 860 for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { 861 if (dri2_surf->color_buffers[i].wl_buffer) { 862 if (dri2_surf->color_buffers[i].locked) { 863 dri2_surf->color_buffers[i].wl_release = true; 864 } else { 865 wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer); 866 dri2_surf->color_buffers[i].wl_buffer = NULL; 867 } 868 } 869 if (dri2_surf->color_buffers[i].dri_image) 870 dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image); 871 if (dri2_surf->color_buffers[i].linear_copy) 872 dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy); 873 if (dri2_surf->color_buffers[i].data) 874 munmap(dri2_surf->color_buffers[i].data, 875 dri2_surf->color_buffers[i].data_size); 876 877 dri2_surf->color_buffers[i].dri_image = NULL; 878 dri2_surf->color_buffers[i].linear_copy = NULL; 879 dri2_surf->color_buffers[i].data = NULL; 880 dri2_surf->color_buffers[i].age = 0; 881 } 882 883 if (dri2_dpy->dri2) 884 dri2_egl_surface_free_local_buffers(dri2_surf); 885} 886 887static void 888create_dri_image_diff_gpu(struct dri2_egl_surface *dri2_surf, 889 unsigned int linear_dri_image_format, uint32_t use_flags) 890{ 891 struct dri2_egl_display *dri2_dpy = 892 dri2_egl_display(dri2_surf->base.Resource.Display); 893 uint64_t linear_mod; 894 895 /* The LINEAR modifier should be a perfect alias of the LINEAR use flag */ 896 linear_mod = DRM_FORMAT_MOD_LINEAR; 897 898 dri2_surf->back->linear_copy = 899 loader_dri_create_image(dri2_dpy->dri_screen, dri2_dpy->image, 900 dri2_surf->base.Width, 901 dri2_surf->base.Height, 902 linear_dri_image_format, 903 use_flags | __DRI_IMAGE_USE_LINEAR, 904 &linear_mod, 1, NULL); 905} 906 907static void 908create_dri_image_from_dmabuf_feedback(struct dri2_egl_surface *dri2_surf, 909 unsigned int dri_image_format, uint32_t use_flags) 910{ 911 struct dri2_egl_display *dri2_dpy = 912 dri2_egl_display(dri2_surf->base.Resource.Display); 913 int visual_idx; 914 uint64_t *modifiers; 915 unsigned int num_modifiers; 916 uint32_t flags; 917 918 /* We don't have valid dma-buf feedback, so return */ 919 if (dri2_surf->dmabuf_feedback.main_device == 0) 920 return; 921 922 visual_idx = dri2_wl_visual_idx_from_fourcc(dri2_surf->format); 923 assert(visual_idx != -1); 924 925 /* Iterates through the dma-buf feedback to pick a new set of modifiers. The 926 * tranches are sent in descending order of preference by the compositor, so 927 * the first set that we can pick is the best one. For now we still can't 928 * specify the target device in order to make the render device try its best 929 * to allocate memory that can be directly scanned out by the KMS device. But 930 * in the future this may change (newer versions of 931 * createImageWithModifiers). Also, we are safe to pick modifiers from 932 * tranches whose target device differs from the main device, as compositors 933 * do not expose (in dma-buf feedback tranches) formats/modifiers that are 934 * incompatible with the main device. */ 935 util_dynarray_foreach(&dri2_surf->dmabuf_feedback.tranches, 936 struct dmabuf_feedback_tranche, tranche) { 937 /* Ignore tranches that do not contain dri2_surf->format */ 938 if (!BITSET_TEST(tranche->formats.formats_bitmap, visual_idx)) 939 continue; 940 modifiers = u_vector_tail(&tranche->formats.modifiers[visual_idx]); 941 num_modifiers = u_vector_length(&tranche->formats.modifiers[visual_idx]); 942 943 /* For the purposes of this function, an INVALID modifier on 944 * its own means the modifiers aren't supported. */ 945 if (num_modifiers == 0 || 946 (num_modifiers == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID)) { 947 num_modifiers = 0; 948 modifiers = NULL; 949 } 950 951 flags = use_flags; 952 if (tranche->flags & ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT) 953 flags |= __DRI_IMAGE_USE_SCANOUT; 954 955 dri2_surf->back->dri_image = 956 loader_dri_create_image(dri2_dpy->dri_screen, dri2_dpy->image, 957 dri2_surf->base.Width, 958 dri2_surf->base.Height, 959 dri_image_format, 960 dri2_dpy->is_different_gpu ? 0 : flags, 961 modifiers, num_modifiers, NULL); 962 963 if (dri2_surf->back->dri_image) 964 return; 965 } 966} 967 968static void 969create_dri_image(struct dri2_egl_surface *dri2_surf, 970 unsigned int dri_image_format, uint32_t use_flags) 971{ 972 struct dri2_egl_display *dri2_dpy = 973 dri2_egl_display(dri2_surf->base.Resource.Display); 974 int visual_idx; 975 uint64_t *modifiers; 976 unsigned int num_modifiers; 977 978 visual_idx = dri2_wl_visual_idx_from_fourcc(dri2_surf->format); 979 modifiers = u_vector_tail(&dri2_dpy->formats.modifiers[visual_idx]); 980 num_modifiers = u_vector_length(&dri2_dpy->formats.modifiers[visual_idx]); 981 982 /* For the purposes of this function, an INVALID modifier on 983 * its own means the modifiers aren't supported. */ 984 if (num_modifiers == 0 || 985 (num_modifiers == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID)) { 986 num_modifiers = 0; 987 modifiers = NULL; 988 } 989 990 /* If our DRIImage implementation does not support createImageWithModifiers, 991 * then fall back to the old createImage, and hope it allocates an image 992 * which is acceptable to the winsys. */ 993 dri2_surf->back->dri_image = 994 loader_dri_create_image(dri2_dpy->dri_screen, dri2_dpy->image, 995 dri2_surf->base.Width, 996 dri2_surf->base.Height, 997 dri_image_format, 998 dri2_dpy->is_different_gpu ? 0 : use_flags, 999 modifiers, num_modifiers, NULL); 1000} 1001 1002static int 1003get_back_bo(struct dri2_egl_surface *dri2_surf) 1004{ 1005 struct dri2_egl_display *dri2_dpy = 1006 dri2_egl_display(dri2_surf->base.Resource.Display); 1007 int use_flags; 1008 int visual_idx; 1009 unsigned int dri_image_format; 1010 unsigned int linear_dri_image_format; 1011 1012 visual_idx = dri2_wl_visual_idx_from_fourcc(dri2_surf->format); 1013 assert(visual_idx != -1); 1014 dri_image_format = dri2_wl_visuals[visual_idx].dri_image_format; 1015 linear_dri_image_format = dri_image_format; 1016 1017 /* Substitute dri image format if server does not support original format */ 1018 if (!BITSET_TEST(dri2_dpy->formats.formats_bitmap, visual_idx)) 1019 linear_dri_image_format = dri2_wl_visuals[visual_idx].alt_dri_image_format; 1020 1021 /* These asserts hold, as long as dri2_wl_visuals[] is self-consistent and 1022 * the PRIME substitution logic in dri2_wl_add_configs_for_visuals() is free 1023 * of bugs. 1024 */ 1025 assert(linear_dri_image_format != __DRI_IMAGE_FORMAT_NONE); 1026 assert(BITSET_TEST(dri2_dpy->formats.formats_bitmap, 1027 dri2_wl_visual_idx_from_dri_image_format(linear_dri_image_format))); 1028 1029 /* There might be a buffer release already queued that wasn't processed */ 1030 wl_display_dispatch_queue_pending(dri2_dpy->wl_dpy, dri2_surf->wl_queue); 1031 1032 while (dri2_surf->back == NULL) { 1033 for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { 1034 /* Get an unlocked buffer, preferably one with a dri_buffer 1035 * already allocated. */ 1036 if (dri2_surf->color_buffers[i].locked) 1037 continue; 1038 if (dri2_surf->back == NULL) 1039 dri2_surf->back = &dri2_surf->color_buffers[i]; 1040 else if (dri2_surf->back->dri_image == NULL) 1041 dri2_surf->back = &dri2_surf->color_buffers[i]; 1042 } 1043 1044 if (dri2_surf->back) 1045 break; 1046 1047 /* If we don't have a buffer, then block on the server to release one for 1048 * us, and try again. wl_display_dispatch_queue will process any pending 1049 * events, however not all servers flush on issuing a buffer release 1050 * event. So, we spam the server with roundtrips as they always cause a 1051 * client flush. 1052 */ 1053 if (wl_display_roundtrip_queue(dri2_dpy->wl_dpy, 1054 dri2_surf->wl_queue) < 0) 1055 return -1; 1056 } 1057 1058 if (dri2_surf->back == NULL) 1059 return -1; 1060 1061 use_flags = __DRI_IMAGE_USE_SHARE | __DRI_IMAGE_USE_BACKBUFFER; 1062 1063 if (dri2_surf->base.ProtectedContent) { 1064 /* Protected buffers can't be read from another GPU */ 1065 if (dri2_dpy->is_different_gpu) 1066 return -1; 1067 use_flags |= __DRI_IMAGE_USE_PROTECTED; 1068 } 1069 1070 if (dri2_dpy->is_different_gpu && dri2_surf->back->linear_copy == NULL) { 1071 create_dri_image_diff_gpu(dri2_surf, linear_dri_image_format, use_flags); 1072 if (dri2_surf->back->linear_copy == NULL) 1073 return -1; 1074 } 1075 1076 if (dri2_surf->back->dri_image == NULL) { 1077 if (dri2_surf->wl_dmabuf_feedback) 1078 create_dri_image_from_dmabuf_feedback(dri2_surf, dri_image_format, use_flags); 1079 if (dri2_surf->back->dri_image == NULL) 1080 create_dri_image(dri2_surf, dri_image_format, use_flags); 1081 dri2_surf->back->age = 0; 1082 } 1083 1084 if (dri2_surf->back->dri_image == NULL) 1085 return -1; 1086 1087 dri2_surf->back->locked = true; 1088 1089 return 0; 1090} 1091 1092 1093static void 1094back_bo_to_dri_buffer(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer) 1095{ 1096 struct dri2_egl_display *dri2_dpy = 1097 dri2_egl_display(dri2_surf->base.Resource.Display); 1098 __DRIimage *image; 1099 int name, pitch; 1100 1101 image = dri2_surf->back->dri_image; 1102 1103 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name); 1104 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch); 1105 1106 buffer->attachment = __DRI_BUFFER_BACK_LEFT; 1107 buffer->name = name; 1108 buffer->pitch = pitch; 1109 buffer->cpp = 4; 1110 buffer->flags = 0; 1111} 1112 1113/* Value chosen empirically as a compromise between avoiding frequent 1114 * reallocations and extended time of increased memory consumption due to 1115 * unused buffers being kept. 1116 */ 1117#define BUFFER_TRIM_AGE_HYSTERESIS 20 1118 1119static int 1120update_buffers(struct dri2_egl_surface *dri2_surf) 1121{ 1122 struct dri2_egl_display *dri2_dpy = 1123 dri2_egl_display(dri2_surf->base.Resource.Display); 1124 1125 if (dri2_surf->wl_win && 1126 (dri2_surf->base.Width != dri2_surf->wl_win->width || 1127 dri2_surf->base.Height != dri2_surf->wl_win->height)) { 1128 1129 dri2_surf->base.Width = dri2_surf->wl_win->width; 1130 dri2_surf->base.Height = dri2_surf->wl_win->height; 1131 dri2_surf->dx = dri2_surf->wl_win->dx; 1132 dri2_surf->dy = dri2_surf->wl_win->dy; 1133 } 1134 1135 if (dri2_surf->resized || dri2_surf->received_dmabuf_feedback) { 1136 dri2_wl_release_buffers(dri2_surf); 1137 dri2_surf->resized = false; 1138 dri2_surf->received_dmabuf_feedback = false; 1139 } 1140 1141 if (get_back_bo(dri2_surf) < 0) { 1142 _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer"); 1143 return -1; 1144 } 1145 1146 /* If we have an extra unlocked buffer at this point, we had to do triple 1147 * buffering for a while, but now can go back to just double buffering. 1148 * That means we can free any unlocked buffer now. To avoid toggling between 1149 * going back to double buffering and needing to allocate another buffer too 1150 * fast we let the unneeded buffer sit around for a short while. */ 1151 for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { 1152 if (!dri2_surf->color_buffers[i].locked && 1153 dri2_surf->color_buffers[i].wl_buffer && 1154 dri2_surf->color_buffers[i].age > BUFFER_TRIM_AGE_HYSTERESIS) { 1155 wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer); 1156 dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image); 1157 if (dri2_dpy->is_different_gpu) 1158 dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy); 1159 dri2_surf->color_buffers[i].wl_buffer = NULL; 1160 dri2_surf->color_buffers[i].dri_image = NULL; 1161 dri2_surf->color_buffers[i].linear_copy = NULL; 1162 dri2_surf->color_buffers[i].age = 0; 1163 } 1164 } 1165 1166 return 0; 1167} 1168 1169static int 1170update_buffers_if_needed(struct dri2_egl_surface *dri2_surf) 1171{ 1172 if (dri2_surf->back != NULL) 1173 return 0; 1174 1175 return update_buffers(dri2_surf); 1176} 1177 1178static __DRIbuffer * 1179dri2_wl_get_buffers_with_format(__DRIdrawable * driDrawable, 1180 int *width, int *height, 1181 unsigned int *attachments, int count, 1182 int *out_count, void *loaderPrivate) 1183{ 1184 struct dri2_egl_surface *dri2_surf = loaderPrivate; 1185 int i, j; 1186 1187 if (update_buffers_if_needed(dri2_surf) < 0) 1188 return NULL; 1189 1190 for (i = 0, j = 0; i < 2 * count; i += 2, j++) { 1191 __DRIbuffer *local; 1192 1193 switch (attachments[i]) { 1194 case __DRI_BUFFER_BACK_LEFT: 1195 back_bo_to_dri_buffer(dri2_surf, &dri2_surf->buffers[j]); 1196 break; 1197 default: 1198 local = dri2_egl_surface_alloc_local_buffer(dri2_surf, attachments[i], 1199 attachments[i + 1]); 1200 1201 if (!local) { 1202 _eglError(EGL_BAD_ALLOC, "failed to allocate local buffer"); 1203 return NULL; 1204 } 1205 dri2_surf->buffers[j] = *local; 1206 break; 1207 } 1208 } 1209 1210 *out_count = j; 1211 if (j == 0) 1212 return NULL; 1213 1214 *width = dri2_surf->base.Width; 1215 *height = dri2_surf->base.Height; 1216 1217 return dri2_surf->buffers; 1218} 1219 1220static __DRIbuffer * 1221dri2_wl_get_buffers(__DRIdrawable * driDrawable, 1222 int *width, int *height, 1223 unsigned int *attachments, int count, 1224 int *out_count, void *loaderPrivate) 1225{ 1226 struct dri2_egl_surface *dri2_surf = loaderPrivate; 1227 unsigned int *attachments_with_format; 1228 __DRIbuffer *buffer; 1229 int visual_idx = dri2_wl_visual_idx_from_fourcc(dri2_surf->format); 1230 1231 if (visual_idx == -1) 1232 return NULL; 1233 1234 attachments_with_format = calloc(count, 2 * sizeof(unsigned int)); 1235 if (!attachments_with_format) { 1236 *out_count = 0; 1237 return NULL; 1238 } 1239 1240 for (int i = 0; i < count; ++i) { 1241 attachments_with_format[2*i] = attachments[i]; 1242 attachments_with_format[2*i + 1] = dri2_wl_visuals[visual_idx].bpp; 1243 } 1244 1245 buffer = 1246 dri2_wl_get_buffers_with_format(driDrawable, 1247 width, height, 1248 attachments_with_format, count, 1249 out_count, loaderPrivate); 1250 1251 free(attachments_with_format); 1252 1253 return buffer; 1254} 1255 1256static int 1257image_get_buffers(__DRIdrawable *driDrawable, 1258 unsigned int format, 1259 uint32_t *stamp, 1260 void *loaderPrivate, 1261 uint32_t buffer_mask, 1262 struct __DRIimageList *buffers) 1263{ 1264 struct dri2_egl_surface *dri2_surf = loaderPrivate; 1265 1266 if (update_buffers_if_needed(dri2_surf) < 0) 1267 return 0; 1268 1269 buffers->image_mask = __DRI_IMAGE_BUFFER_BACK; 1270 buffers->back = dri2_surf->back->dri_image; 1271 1272 return 1; 1273} 1274 1275static void 1276dri2_wl_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate) 1277{ 1278 (void) driDrawable; 1279 (void) loaderPrivate; 1280} 1281 1282static unsigned 1283dri2_wl_get_capability(void *loaderPrivate, enum dri_loader_cap cap) 1284{ 1285 switch (cap) { 1286 case DRI_LOADER_CAP_FP16: 1287 return 1; 1288 case DRI_LOADER_CAP_RGBA_ORDERING: 1289 return 1; 1290 default: 1291 return 0; 1292 } 1293} 1294 1295static const __DRIdri2LoaderExtension dri2_loader_extension = { 1296 .base = { __DRI_DRI2_LOADER, 4 }, 1297 1298 .getBuffers = dri2_wl_get_buffers, 1299 .flushFrontBuffer = dri2_wl_flush_front_buffer, 1300 .getBuffersWithFormat = dri2_wl_get_buffers_with_format, 1301 .getCapability = dri2_wl_get_capability, 1302}; 1303 1304static const __DRIimageLoaderExtension image_loader_extension = { 1305 .base = { __DRI_IMAGE_LOADER, 2 }, 1306 1307 .getBuffers = image_get_buffers, 1308 .flushFrontBuffer = dri2_wl_flush_front_buffer, 1309 .getCapability = dri2_wl_get_capability, 1310}; 1311 1312static void 1313wayland_throttle_callback(void *data, 1314 struct wl_callback *callback, 1315 uint32_t time) 1316{ 1317 struct dri2_egl_surface *dri2_surf = data; 1318 1319 dri2_surf->throttle_callback = NULL; 1320 wl_callback_destroy(callback); 1321} 1322 1323static const struct wl_callback_listener throttle_listener = { 1324 .done = wayland_throttle_callback 1325}; 1326 1327static EGLBoolean 1328get_fourcc(struct dri2_egl_display *dri2_dpy, 1329 __DRIimage *image, int *fourcc) 1330{ 1331 EGLBoolean query; 1332 int dri_format; 1333 int visual_idx; 1334 1335 query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FOURCC, 1336 fourcc); 1337 if (query) 1338 return true; 1339 1340 query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, 1341 &dri_format); 1342 if (!query) 1343 return false; 1344 1345 visual_idx = dri2_wl_visual_idx_from_dri_image_format(dri_format); 1346 if (visual_idx == -1) 1347 return false; 1348 1349 *fourcc = dri2_wl_visuals[visual_idx].wl_drm_format; 1350 return true; 1351} 1352 1353static struct wl_buffer * 1354create_wl_buffer(struct dri2_egl_display *dri2_dpy, 1355 struct dri2_egl_surface *dri2_surf, 1356 __DRIimage *image) 1357{ 1358 struct wl_buffer *ret = NULL; 1359 EGLBoolean query; 1360 int width, height, fourcc, num_planes; 1361 uint64_t modifier = DRM_FORMAT_MOD_INVALID; 1362 1363 query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_WIDTH, &width); 1364 query &= dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_HEIGHT, 1365 &height); 1366 query &= get_fourcc(dri2_dpy, image, &fourcc); 1367 if (!query) 1368 return NULL; 1369 1370 query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NUM_PLANES, 1371 &num_planes); 1372 if (!query) 1373 num_planes = 1; 1374 1375 if (dri2_dpy->image->base.version >= 15) { 1376 int mod_hi, mod_lo; 1377 1378 query = dri2_dpy->image->queryImage(image, 1379 __DRI_IMAGE_ATTRIB_MODIFIER_UPPER, 1380 &mod_hi); 1381 query &= dri2_dpy->image->queryImage(image, 1382 __DRI_IMAGE_ATTRIB_MODIFIER_LOWER, 1383 &mod_lo); 1384 if (query) { 1385 modifier = combine_u32_into_u64(mod_hi, mod_lo); 1386 } 1387 } 1388 1389 bool supported_modifier = false; 1390 bool mod_invalid_supported = false; 1391 int visual_idx = dri2_wl_visual_idx_from_fourcc(fourcc); 1392 assert(visual_idx != -1); 1393 1394 uint64_t *mod; 1395 u_vector_foreach(mod, &dri2_dpy->formats.modifiers[visual_idx]) { 1396 if (*mod == DRM_FORMAT_MOD_INVALID) { 1397 mod_invalid_supported = true; 1398 } 1399 if (*mod == modifier) { 1400 supported_modifier = true; 1401 break; 1402 } 1403 } 1404 if (!supported_modifier && mod_invalid_supported) { 1405 /* If the server has advertised DRM_FORMAT_MOD_INVALID then we trust 1406 * that the client has allocated the buffer with the right implicit 1407 * modifier for the format, even though it's allocated a buffer the 1408 * server hasn't explicitly claimed to support. */ 1409 modifier = DRM_FORMAT_MOD_INVALID; 1410 supported_modifier = true; 1411 } 1412 1413 if (dri2_dpy->wl_dmabuf && supported_modifier) { 1414 struct zwp_linux_buffer_params_v1 *params; 1415 int i; 1416 1417 /* We don't need a wrapper for wl_dmabuf objects, because we have to 1418 * create the intermediate params object; we can set the queue on this, 1419 * and the wl_buffer inherits it race-free. */ 1420 params = zwp_linux_dmabuf_v1_create_params(dri2_dpy->wl_dmabuf); 1421 if (dri2_surf) 1422 wl_proxy_set_queue((struct wl_proxy *) params, dri2_surf->wl_queue); 1423 1424 for (i = 0; i < num_planes; i++) { 1425 __DRIimage *p_image; 1426 int stride, offset; 1427 int fd = -1; 1428 1429 p_image = dri2_dpy->image->fromPlanar(image, i, NULL); 1430 if (!p_image) { 1431 assert(i == 0); 1432 p_image = image; 1433 } 1434 1435 query = dri2_dpy->image->queryImage(p_image, 1436 __DRI_IMAGE_ATTRIB_FD, 1437 &fd); 1438 query &= dri2_dpy->image->queryImage(p_image, 1439 __DRI_IMAGE_ATTRIB_STRIDE, 1440 &stride); 1441 query &= dri2_dpy->image->queryImage(p_image, 1442 __DRI_IMAGE_ATTRIB_OFFSET, 1443 &offset); 1444 if (image != p_image) 1445 dri2_dpy->image->destroyImage(p_image); 1446 1447 if (!query) { 1448 if (fd >= 0) 1449 close(fd); 1450 zwp_linux_buffer_params_v1_destroy(params); 1451 return NULL; 1452 } 1453 1454 zwp_linux_buffer_params_v1_add(params, fd, i, offset, stride, 1455 modifier >> 32, modifier & 0xffffffff); 1456 close(fd); 1457 } 1458 1459 ret = zwp_linux_buffer_params_v1_create_immed(params, width, height, 1460 fourcc, 0); 1461 zwp_linux_buffer_params_v1_destroy(params); 1462 } else { 1463 struct wl_drm *wl_drm = 1464 dri2_surf ? dri2_surf->wl_drm_wrapper : dri2_dpy->wl_drm; 1465 int fd = -1, stride; 1466 1467 if (num_planes > 1) 1468 return NULL; 1469 1470 query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &fd); 1471 query &= dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride); 1472 if (!query) { 1473 if (fd >= 0) 1474 close(fd); 1475 return NULL; 1476 } 1477 1478 ret = wl_drm_create_prime_buffer(wl_drm, fd, width, height, fourcc, 0, 1479 stride, 0, 0, 0, 0); 1480 close(fd); 1481 } 1482 1483 return ret; 1484} 1485 1486static EGLBoolean 1487try_damage_buffer(struct dri2_egl_surface *dri2_surf, 1488 const EGLint *rects, 1489 EGLint n_rects) 1490{ 1491 if (wl_proxy_get_version((struct wl_proxy *) dri2_surf->wl_surface_wrapper) 1492 < WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION) 1493 return EGL_FALSE; 1494 1495 for (int i = 0; i < n_rects; i++) { 1496 const int *rect = &rects[i * 4]; 1497 1498 wl_surface_damage_buffer(dri2_surf->wl_surface_wrapper, 1499 rect[0], 1500 dri2_surf->base.Height - rect[1] - rect[3], 1501 rect[2], rect[3]); 1502 } 1503 return EGL_TRUE; 1504} 1505 1506/** 1507 * Called via eglSwapBuffers(), drv->SwapBuffers(). 1508 */ 1509static EGLBoolean 1510dri2_wl_swap_buffers_with_damage(_EGLDisplay *disp, 1511 _EGLSurface *draw, 1512 const EGLint *rects, 1513 EGLint n_rects) 1514{ 1515 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 1516 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); 1517 1518 if (!dri2_surf->wl_win) 1519 return _eglError(EGL_BAD_NATIVE_WINDOW, "dri2_swap_buffers"); 1520 1521 while (dri2_surf->throttle_callback != NULL) 1522 if (wl_display_dispatch_queue(dri2_dpy->wl_dpy, 1523 dri2_surf->wl_queue) == -1) 1524 return -1; 1525 1526 for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) 1527 if (dri2_surf->color_buffers[i].age > 0) 1528 dri2_surf->color_buffers[i].age++; 1529 1530 /* Make sure we have a back buffer in case we're swapping without ever 1531 * rendering. */ 1532 if (update_buffers_if_needed(dri2_surf) < 0) 1533 return _eglError(EGL_BAD_ALLOC, "dri2_swap_buffers"); 1534 1535 if (draw->SwapInterval > 0) { 1536 dri2_surf->throttle_callback = 1537 wl_surface_frame(dri2_surf->wl_surface_wrapper); 1538 wl_callback_add_listener(dri2_surf->throttle_callback, 1539 &throttle_listener, dri2_surf); 1540 } 1541 1542 dri2_surf->back->age = 1; 1543 dri2_surf->current = dri2_surf->back; 1544 dri2_surf->back = NULL; 1545 1546 if (!dri2_surf->current->wl_buffer) { 1547 __DRIimage *image; 1548 1549 if (dri2_dpy->is_different_gpu) 1550 image = dri2_surf->current->linear_copy; 1551 else 1552 image = dri2_surf->current->dri_image; 1553 1554 dri2_surf->current->wl_buffer = 1555 create_wl_buffer(dri2_dpy, dri2_surf, image); 1556 1557 dri2_surf->current->wl_release = false; 1558 1559 wl_buffer_add_listener(dri2_surf->current->wl_buffer, 1560 &wl_buffer_listener, dri2_surf); 1561 } 1562 1563 wl_surface_attach(dri2_surf->wl_surface_wrapper, 1564 dri2_surf->current->wl_buffer, 1565 dri2_surf->dx, dri2_surf->dy); 1566 1567 dri2_surf->wl_win->attached_width = dri2_surf->base.Width; 1568 dri2_surf->wl_win->attached_height = dri2_surf->base.Height; 1569 /* reset resize growing parameters */ 1570 dri2_surf->dx = 0; 1571 dri2_surf->dy = 0; 1572 1573 /* If the compositor doesn't support damage_buffer, we deliberately 1574 * ignore the damage region and post maximum damage, due to 1575 * https://bugs.freedesktop.org/78190 */ 1576 if (!n_rects || !try_damage_buffer(dri2_surf, rects, n_rects)) 1577 wl_surface_damage(dri2_surf->wl_surface_wrapper, 1578 0, 0, INT32_MAX, INT32_MAX); 1579 1580 if (dri2_dpy->is_different_gpu) { 1581 _EGLContext *ctx = _eglGetCurrentContext(); 1582 struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); 1583 dri2_dpy->image->blitImage(dri2_ctx->dri_context, 1584 dri2_surf->current->linear_copy, 1585 dri2_surf->current->dri_image, 1586 0, 0, dri2_surf->base.Width, 1587 dri2_surf->base.Height, 1588 0, 0, dri2_surf->base.Width, 1589 dri2_surf->base.Height, 0); 1590 } 1591 1592 dri2_flush_drawable_for_swapbuffers(disp, draw); 1593 dri2_dpy->flush->invalidate(dri2_surf->dri_drawable); 1594 1595 wl_surface_commit(dri2_surf->wl_surface_wrapper); 1596 1597 /* If we're not waiting for a frame callback then we'll at least throttle 1598 * to a sync callback so that we always give a chance for the compositor to 1599 * handle the commit and send a release event before checking for a free 1600 * buffer */ 1601 if (dri2_surf->throttle_callback == NULL) { 1602 dri2_surf->throttle_callback = wl_display_sync(dri2_surf->wl_dpy_wrapper); 1603 wl_callback_add_listener(dri2_surf->throttle_callback, 1604 &throttle_listener, dri2_surf); 1605 } 1606 1607 wl_display_flush(dri2_dpy->wl_dpy); 1608 1609 return EGL_TRUE; 1610} 1611 1612static EGLint 1613dri2_wl_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surface) 1614{ 1615 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface); 1616 1617 if (update_buffers_if_needed(dri2_surf) < 0) { 1618 _eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age"); 1619 return -1; 1620 } 1621 1622 return dri2_surf->back->age; 1623} 1624 1625static EGLBoolean 1626dri2_wl_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw) 1627{ 1628 return dri2_wl_swap_buffers_with_damage(disp, draw, NULL, 0); 1629} 1630 1631static struct wl_buffer * 1632dri2_wl_create_wayland_buffer_from_image(_EGLDisplay *disp, _EGLImage *img) 1633{ 1634 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 1635 struct dri2_egl_image *dri2_img = dri2_egl_image(img); 1636 __DRIimage *image = dri2_img->dri_image; 1637 struct wl_buffer *buffer; 1638 int format, visual_idx; 1639 1640 /* Check the upstream display supports this buffer's format. */ 1641 dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &format); 1642 visual_idx = dri2_wl_visual_idx_from_dri_image_format(format); 1643 if (visual_idx == -1) 1644 goto bad_format; 1645 1646 if (!BITSET_TEST(dri2_dpy->formats.formats_bitmap, visual_idx)) 1647 goto bad_format; 1648 1649 buffer = create_wl_buffer(dri2_dpy, NULL, image); 1650 1651 /* The buffer object will have been created with our internal event queue 1652 * because it is using wl_dmabuf/wl_drm as a proxy factory. We want the 1653 * buffer to be used by the application so we'll reset it to the display's 1654 * default event queue. This isn't actually racy, as the only event the 1655 * buffer can get is a buffer release, which doesn't happen with an explicit 1656 * attach. */ 1657 if (buffer) 1658 wl_proxy_set_queue((struct wl_proxy *) buffer, NULL); 1659 1660 return buffer; 1661 1662bad_format: 1663 _eglError(EGL_BAD_MATCH, "unsupported image format"); 1664 return NULL; 1665} 1666 1667static int 1668dri2_wl_authenticate(_EGLDisplay *disp, uint32_t id) 1669{ 1670 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 1671 int ret = 0; 1672 1673 if (dri2_dpy->is_render_node) { 1674 _eglLog(_EGL_WARNING, "wayland-egl: client asks server to " 1675 "authenticate for render-nodes"); 1676 return 0; 1677 } 1678 dri2_dpy->authenticated = false; 1679 1680 wl_drm_authenticate(dri2_dpy->wl_drm, id); 1681 if (roundtrip(dri2_dpy) < 0) 1682 ret = -1; 1683 1684 if (!dri2_dpy->authenticated) 1685 ret = -1; 1686 1687 /* reset authenticated */ 1688 dri2_dpy->authenticated = true; 1689 1690 return ret; 1691} 1692 1693static void 1694drm_handle_device(void *data, struct wl_drm *drm, const char *device) 1695{ 1696 struct dri2_egl_display *dri2_dpy = data; 1697 drm_magic_t magic; 1698 1699 dri2_dpy->device_name = strdup(device); 1700 if (!dri2_dpy->device_name) 1701 return; 1702 1703 dri2_dpy->fd = loader_open_device(dri2_dpy->device_name); 1704 if (dri2_dpy->fd == -1) { 1705 _eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)", 1706 dri2_dpy->device_name, strerror(errno)); 1707 free(dri2_dpy->device_name); 1708 dri2_dpy->device_name = NULL; 1709 return; 1710 } 1711 1712 if (drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER) { 1713 dri2_dpy->authenticated = true; 1714 } else { 1715 if (drmGetMagic(dri2_dpy->fd, &magic)) { 1716 close(dri2_dpy->fd); 1717 dri2_dpy->fd = -1; 1718 free(dri2_dpy->device_name); 1719 dri2_dpy->device_name = NULL; 1720 _eglLog(_EGL_WARNING, "wayland-egl: drmGetMagic failed"); 1721 return; 1722 } 1723 wl_drm_authenticate(dri2_dpy->wl_drm, magic); 1724 } 1725} 1726 1727static void 1728drm_handle_format(void *data, struct wl_drm *drm, uint32_t format) 1729{ 1730 struct dri2_egl_display *dri2_dpy = data; 1731 int visual_idx = dri2_wl_visual_idx_from_fourcc(format); 1732 1733 if (visual_idx == -1) 1734 return; 1735 1736 BITSET_SET(dri2_dpy->formats.formats_bitmap, visual_idx); 1737} 1738 1739static void 1740drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t value) 1741{ 1742 struct dri2_egl_display *dri2_dpy = data; 1743 1744 dri2_dpy->capabilities = value; 1745} 1746 1747static void 1748drm_handle_authenticated(void *data, struct wl_drm *drm) 1749{ 1750 struct dri2_egl_display *dri2_dpy = data; 1751 1752 dri2_dpy->authenticated = true; 1753} 1754 1755static const struct wl_drm_listener drm_listener = { 1756 .device = drm_handle_device, 1757 .format = drm_handle_format, 1758 .authenticated = drm_handle_authenticated, 1759 .capabilities = drm_handle_capabilities 1760}; 1761 1762static void 1763dmabuf_ignore_format(void *data, struct zwp_linux_dmabuf_v1 *dmabuf, 1764 uint32_t format) 1765{ 1766 /* formats are implicitly advertised by the 'modifier' event, so ignore */ 1767} 1768 1769static void 1770dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *dmabuf, 1771 uint32_t format, uint32_t modifier_hi, 1772 uint32_t modifier_lo) 1773{ 1774 struct dri2_egl_display *dri2_dpy = data; 1775 int visual_idx = dri2_wl_visual_idx_from_fourcc(format); 1776 uint64_t *mod; 1777 1778 /* Ignore this if the compositor advertised dma-buf feedback. From version 4 1779 * onwards (when dma-buf feedback was introduced), the compositor should not 1780 * advertise this event anymore, but let's keep this for safety. */ 1781 if (dri2_dpy->wl_dmabuf_feedback) 1782 return; 1783 1784 if (visual_idx == -1) 1785 return; 1786 1787 BITSET_SET(dri2_dpy->formats.formats_bitmap, visual_idx); 1788 1789 mod = u_vector_add(&dri2_dpy->formats.modifiers[visual_idx]); 1790 if (mod) 1791 *mod = combine_u32_into_u64(modifier_hi, modifier_lo); 1792} 1793 1794static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = { 1795 .format = dmabuf_ignore_format, 1796 .modifier = dmabuf_handle_modifier, 1797}; 1798 1799static void 1800wl_drm_bind(struct dri2_egl_display *dri2_dpy) 1801{ 1802 dri2_dpy->wl_drm = wl_registry_bind(dri2_dpy->wl_registry, dri2_dpy->wl_drm_name, 1803 &wl_drm_interface, dri2_dpy->wl_drm_version); 1804 wl_drm_add_listener(dri2_dpy->wl_drm, &drm_listener, dri2_dpy); 1805} 1806 1807static void 1808default_dmabuf_feedback_format_table(void *data, 1809 struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1, 1810 int32_t fd, uint32_t size) 1811{ 1812 struct dri2_egl_display *dri2_dpy = data; 1813 1814 dri2_dpy->format_table.size = size; 1815 dri2_dpy->format_table.data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); 1816 1817 close(fd); 1818} 1819 1820static void 1821default_dmabuf_feedback_main_device(void *data, 1822 struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback, 1823 struct wl_array *device) 1824{ 1825 struct dri2_egl_display *dri2_dpy = data; 1826 char *node; 1827 int fd; 1828 dev_t dev; 1829 1830 /* Given the device, look for a render node and try to open it. */ 1831 memcpy(&dev, device->data, sizeof(dev)); 1832 node = loader_get_render_node(dev); 1833 if (!node) 1834 return; 1835 fd = loader_open_device(node); 1836 if (fd == -1) { 1837 free(node); 1838 return; 1839 } 1840 1841 dri2_dpy->device_name = node; 1842 dri2_dpy->fd = fd; 1843 dri2_dpy->authenticated = true; 1844} 1845 1846static void 1847default_dmabuf_feedback_tranche_target_device(void *data, 1848 struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback, 1849 struct wl_array *device) 1850{ 1851 /* ignore this event */ 1852} 1853 1854static void 1855default_dmabuf_feedback_tranche_flags(void *data, 1856 struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback, 1857 uint32_t flags) 1858{ 1859 /* ignore this event */ 1860} 1861 1862static void 1863default_dmabuf_feedback_tranche_formats(void *data, 1864 struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback, 1865 struct wl_array *indices) 1866{ 1867 struct dri2_egl_display *dri2_dpy = data; 1868 uint64_t *modifier_ptr, modifier; 1869 uint32_t format; 1870 uint16_t *index; 1871 int visual_idx; 1872 1873 if (dri2_dpy->format_table.data == MAP_FAILED) { 1874 _eglLog(_EGL_WARNING, "wayland-egl: we could not map the format table " 1875 "so we won't be able to use this batch of dma-buf " 1876 "feedback events."); 1877 return; 1878 } 1879 if (dri2_dpy->format_table.data == NULL) { 1880 _eglLog(_EGL_WARNING, "wayland-egl: compositor didn't advertise a format " 1881 "table, so we won't be able to use this batch of dma-buf " 1882 "feedback events."); 1883 return; 1884 } 1885 1886 wl_array_for_each(index, indices) { 1887 format = dri2_dpy->format_table.data[*index].format; 1888 modifier = dri2_dpy->format_table.data[*index].modifier; 1889 1890 /* skip formats that we don't support */ 1891 visual_idx = dri2_wl_visual_idx_from_fourcc(format); 1892 if (visual_idx == -1) 1893 continue; 1894 1895 BITSET_SET(dri2_dpy->formats.formats_bitmap, visual_idx); 1896 modifier_ptr = u_vector_add(&dri2_dpy->formats.modifiers[visual_idx]); 1897 if (modifier_ptr) 1898 *modifier_ptr = modifier; 1899 } 1900} 1901 1902static void 1903default_dmabuf_feedback_tranche_done(void *data, 1904 struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback) 1905{ 1906 /* ignore this event */ 1907} 1908 1909static void 1910default_dmabuf_feedback_done(void *data, 1911 struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback) 1912{ 1913 /* ignore this event */ 1914} 1915 1916static const struct zwp_linux_dmabuf_feedback_v1_listener 1917dmabuf_feedback_listener = { 1918 .format_table = default_dmabuf_feedback_format_table, 1919 .main_device = default_dmabuf_feedback_main_device, 1920 .tranche_target_device = default_dmabuf_feedback_tranche_target_device, 1921 .tranche_flags = default_dmabuf_feedback_tranche_flags, 1922 .tranche_formats = default_dmabuf_feedback_tranche_formats, 1923 .tranche_done = default_dmabuf_feedback_tranche_done, 1924 .done = default_dmabuf_feedback_done, 1925}; 1926 1927static void 1928registry_handle_global_drm(void *data, struct wl_registry *registry, 1929 uint32_t name, const char *interface, 1930 uint32_t version) 1931{ 1932 struct dri2_egl_display *dri2_dpy = data; 1933 1934 if (strcmp(interface, "wl_drm") == 0) { 1935 dri2_dpy->wl_drm_version = MIN2(version, 2); 1936 dri2_dpy->wl_drm_name = name; 1937 } else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0 && version >= 3) { 1938 dri2_dpy->wl_dmabuf = 1939 wl_registry_bind(registry, name, &zwp_linux_dmabuf_v1_interface, 1940 MIN2(version, ZWP_LINUX_DMABUF_V1_GET_DEFAULT_FEEDBACK_SINCE_VERSION)); 1941 zwp_linux_dmabuf_v1_add_listener(dri2_dpy->wl_dmabuf, &dmabuf_listener, 1942 dri2_dpy); 1943 } 1944} 1945 1946static void 1947registry_handle_global_remove(void *data, struct wl_registry *registry, 1948 uint32_t name) 1949{ 1950} 1951 1952static const struct wl_registry_listener registry_listener_drm = { 1953 .global = registry_handle_global_drm, 1954 .global_remove = registry_handle_global_remove 1955}; 1956 1957static void 1958dri2_wl_setup_swap_interval(_EGLDisplay *disp) 1959{ 1960 /* We can't use values greater than 1 on Wayland because we are using the 1961 * frame callback to synchronise the frame and the only way we be sure to 1962 * get a frame callback is to attach a new buffer. Therefore we can't just 1963 * sit drawing nothing to wait until the next ‘n’ frame callbacks */ 1964 1965 dri2_setup_swap_interval(disp, 1); 1966} 1967 1968static const struct dri2_egl_display_vtbl dri2_wl_display_vtbl = { 1969 .authenticate = dri2_wl_authenticate, 1970 .create_window_surface = dri2_wl_create_window_surface, 1971 .create_pixmap_surface = dri2_wl_create_pixmap_surface, 1972 .destroy_surface = dri2_wl_destroy_surface, 1973 .swap_interval = dri2_wl_swap_interval, 1974 .create_image = dri2_create_image_khr, 1975 .swap_buffers = dri2_wl_swap_buffers, 1976 .swap_buffers_with_damage = dri2_wl_swap_buffers_with_damage, 1977 .query_buffer_age = dri2_wl_query_buffer_age, 1978 .create_wayland_buffer_from_image = dri2_wl_create_wayland_buffer_from_image, 1979 .get_dri_drawable = dri2_surface_get_dri_drawable, 1980}; 1981 1982static const __DRIextension *dri2_loader_extensions[] = { 1983 &dri2_loader_extension.base, 1984 &image_loader_extension.base, 1985 &image_lookup_extension.base, 1986 &use_invalidate.base, 1987 NULL, 1988}; 1989 1990static const __DRIextension *image_loader_extensions[] = { 1991 &image_loader_extension.base, 1992 &image_lookup_extension.base, 1993 &use_invalidate.base, 1994 NULL, 1995}; 1996 1997static EGLBoolean 1998dri2_wl_add_configs_for_visuals(_EGLDisplay *disp) 1999{ 2000 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 2001 unsigned int format_count[ARRAY_SIZE(dri2_wl_visuals)] = { 0 }; 2002 unsigned int count = 0; 2003 bool assigned; 2004 2005 for (unsigned i = 0; dri2_dpy->driver_configs[i]; i++) { 2006 assigned = false; 2007 2008 for (unsigned j = 0; j < ARRAY_SIZE(dri2_wl_visuals); j++) { 2009 struct dri2_egl_config *dri2_conf; 2010 2011 if (!BITSET_TEST(dri2_dpy->formats.formats_bitmap, j)) 2012 continue; 2013 2014 dri2_conf = dri2_add_config(disp, dri2_dpy->driver_configs[i], 2015 count + 1, EGL_WINDOW_BIT, NULL, dri2_wl_visuals[j].rgba_shifts, dri2_wl_visuals[j].rgba_sizes); 2016 if (dri2_conf) { 2017 if (dri2_conf->base.ConfigID == count + 1) 2018 count++; 2019 format_count[j]++; 2020 assigned = true; 2021 } 2022 } 2023 2024 if (!assigned && dri2_dpy->is_different_gpu) { 2025 struct dri2_egl_config *dri2_conf; 2026 int alt_dri_image_format, c, s; 2027 2028 /* No match for config. Try if we can blitImage convert to a visual */ 2029 c = dri2_wl_visual_idx_from_config(dri2_dpy, 2030 dri2_dpy->driver_configs[i], 2031 false); 2032 2033 if (c == -1) 2034 continue; 2035 2036 /* Find optimal target visual for blitImage conversion, if any. */ 2037 alt_dri_image_format = dri2_wl_visuals[c].alt_dri_image_format; 2038 s = dri2_wl_visual_idx_from_dri_image_format(alt_dri_image_format); 2039 2040 if (s == -1 || !BITSET_TEST(dri2_dpy->formats.formats_bitmap, s)) 2041 continue; 2042 2043 /* Visual s works for the Wayland server, and c can be converted into s 2044 * by our client gpu during PRIME blitImage conversion to a linear 2045 * wl_buffer, so add visual c as supported by the client renderer. 2046 */ 2047 dri2_conf = dri2_add_config(disp, dri2_dpy->driver_configs[i], 2048 count + 1, EGL_WINDOW_BIT, NULL, 2049 dri2_wl_visuals[c].rgba_shifts, 2050 dri2_wl_visuals[c].rgba_sizes); 2051 if (dri2_conf) { 2052 if (dri2_conf->base.ConfigID == count + 1) 2053 count++; 2054 format_count[c]++; 2055 if (format_count[c] == 1) 2056 _eglLog(_EGL_DEBUG, "Client format %s to server format %s via " 2057 "PRIME blitImage.", dri2_wl_visuals[c].format_name, 2058 dri2_wl_visuals[s].format_name); 2059 } 2060 } 2061 } 2062 2063 for (unsigned i = 0; i < ARRAY_SIZE(format_count); i++) { 2064 if (!format_count[i]) { 2065 _eglLog(_EGL_DEBUG, "No DRI config supports native format %s", 2066 dri2_wl_visuals[i].format_name); 2067 } 2068 } 2069 2070 return (count != 0); 2071} 2072 2073static EGLBoolean 2074dri2_initialize_wayland_drm(_EGLDisplay *disp) 2075{ 2076 _EGLDevice *dev; 2077 struct dri2_egl_display *dri2_dpy; 2078 2079 dri2_dpy = calloc(1, sizeof *dri2_dpy); 2080 if (!dri2_dpy) 2081 return _eglError(EGL_BAD_ALLOC, "eglInitialize"); 2082 2083 dri2_dpy->fd = -1; 2084 disp->DriverData = (void *) dri2_dpy; 2085 2086 if (dri2_wl_formats_init(&dri2_dpy->formats) < 0) 2087 goto cleanup; 2088 2089 if (disp->PlatformDisplay == NULL) { 2090 dri2_dpy->wl_dpy = wl_display_connect(NULL); 2091 if (dri2_dpy->wl_dpy == NULL) 2092 goto cleanup; 2093 dri2_dpy->own_device = true; 2094 } else { 2095 dri2_dpy->wl_dpy = disp->PlatformDisplay; 2096 } 2097 2098 dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy); 2099 2100 dri2_dpy->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy); 2101 if (dri2_dpy->wl_dpy_wrapper == NULL) 2102 goto cleanup; 2103 2104 wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_dpy_wrapper, 2105 dri2_dpy->wl_queue); 2106 2107 if (dri2_dpy->own_device) 2108 wl_display_dispatch_pending(dri2_dpy->wl_dpy); 2109 2110 dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy_wrapper); 2111 wl_registry_add_listener(dri2_dpy->wl_registry, 2112 ®istry_listener_drm, dri2_dpy); 2113 2114 if (roundtrip(dri2_dpy) < 0) 2115 goto cleanup; 2116 2117 /* Get default dma-buf feedback */ 2118 if (dri2_dpy->wl_dmabuf && zwp_linux_dmabuf_v1_get_version(dri2_dpy->wl_dmabuf) >= 2119 ZWP_LINUX_DMABUF_V1_GET_DEFAULT_FEEDBACK_SINCE_VERSION) { 2120 dmabuf_feedback_format_table_init(&dri2_dpy->format_table); 2121 dri2_dpy->wl_dmabuf_feedback = 2122 zwp_linux_dmabuf_v1_get_default_feedback(dri2_dpy->wl_dmabuf); 2123 zwp_linux_dmabuf_feedback_v1_add_listener(dri2_dpy->wl_dmabuf_feedback, 2124 &dmabuf_feedback_listener, dri2_dpy); 2125 } 2126 2127 if (roundtrip(dri2_dpy) < 0) 2128 goto cleanup; 2129 2130 /* Destroy the default dma-buf feedback and the format table. */ 2131 if (dri2_dpy->wl_dmabuf_feedback) { 2132 zwp_linux_dmabuf_feedback_v1_destroy(dri2_dpy->wl_dmabuf_feedback); 2133 dri2_dpy->wl_dmabuf_feedback = NULL; 2134 dmabuf_feedback_format_table_fini(&dri2_dpy->format_table); 2135 } 2136 2137 /* We couldn't retrieve a render node from the dma-buf feedback (or the 2138 * feedback was not advertised at all), so we must fallback to wl_drm. */ 2139 if (dri2_dpy->fd == -1) { 2140 /* wl_drm not advertised by compositor, so can't continue */ 2141 if (dri2_dpy->wl_drm_name == 0) 2142 goto cleanup; 2143 wl_drm_bind(dri2_dpy); 2144 2145 if (dri2_dpy->wl_drm == NULL) 2146 goto cleanup; 2147 if (roundtrip(dri2_dpy) < 0 || dri2_dpy->fd == -1) 2148 goto cleanup; 2149 2150 if (!dri2_dpy->authenticated && 2151 (roundtrip(dri2_dpy) < 0 || !dri2_dpy->authenticated)) 2152 goto cleanup; 2153 } 2154 2155 dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd, 2156 &dri2_dpy->is_different_gpu); 2157 dev = _eglAddDevice(dri2_dpy->fd, false); 2158 if (!dev) { 2159 _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to find EGLDevice"); 2160 goto cleanup; 2161 } 2162 2163 disp->Device = dev; 2164 2165 if (dri2_dpy->is_different_gpu) { 2166 free(dri2_dpy->device_name); 2167 dri2_dpy->device_name = loader_get_device_name_for_fd(dri2_dpy->fd); 2168 if (!dri2_dpy->device_name) { 2169 _eglError(EGL_BAD_ALLOC, "wayland-egl: failed to get device name " 2170 "for requested GPU"); 2171 goto cleanup; 2172 } 2173 } 2174 2175 /* we have to do the check now, because loader_get_user_preferred_fd 2176 * will return a render-node when the requested gpu is different 2177 * to the server, but also if the client asks for the same gpu than 2178 * the server by requesting its pci-id */ 2179 dri2_dpy->is_render_node = drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER; 2180 2181 dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd); 2182 if (dri2_dpy->driver_name == NULL) { 2183 _eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name"); 2184 goto cleanup; 2185 } 2186 2187 /* render nodes cannot use Gem names, and thus do not support 2188 * the __DRI_DRI2_LOADER extension */ 2189 if (!dri2_dpy->is_render_node) { 2190 dri2_dpy->loader_extensions = dri2_loader_extensions; 2191 if (!dri2_load_driver(disp)) { 2192 _eglError(EGL_BAD_ALLOC, "DRI2: failed to load driver"); 2193 goto cleanup; 2194 } 2195 } else { 2196 dri2_dpy->loader_extensions = image_loader_extensions; 2197 if (!dri2_load_driver_dri3(disp)) { 2198 _eglError(EGL_BAD_ALLOC, "DRI3: failed to load driver"); 2199 goto cleanup; 2200 } 2201 } 2202 2203 if (!dri2_create_screen(disp)) 2204 goto cleanup; 2205 2206 if (!dri2_setup_extensions(disp)) 2207 goto cleanup; 2208 2209 dri2_setup_screen(disp); 2210 2211 dri2_wl_setup_swap_interval(disp); 2212 2213 if (dri2_dpy->wl_drm) { 2214 /* To use Prime, we must have _DRI_IMAGE v7 at least. createImageFromFds 2215 * support indicates that Prime export/import is supported by the driver. 2216 * We deprecated the support to GEM names API, so we bail out if the 2217 * driver does not suport Prime. */ 2218 if (!(dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) || 2219 (dri2_dpy->image->base.version < 7) || 2220 (dri2_dpy->image->createImageFromFds == NULL)) { 2221 _eglLog(_EGL_WARNING, "wayland-egl: display does not support prime"); 2222 goto cleanup; 2223 } 2224 } 2225 2226 if (dri2_dpy->is_different_gpu && 2227 (dri2_dpy->image->base.version < 9 || 2228 dri2_dpy->image->blitImage == NULL)) { 2229 _eglLog(_EGL_WARNING, "wayland-egl: Different GPU selected, but the " 2230 "Image extension in the driver is not " 2231 "compatible. Version 9 or later and blitImage() " 2232 "are required"); 2233 goto cleanup; 2234 } 2235 2236 if (!dri2_wl_add_configs_for_visuals(disp)) { 2237 _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to add configs"); 2238 goto cleanup; 2239 } 2240 2241 dri2_set_WL_bind_wayland_display(disp); 2242 /* When cannot convert EGLImage to wl_buffer when on a different gpu, 2243 * because the buffer of the EGLImage has likely a tiling mode the server 2244 * gpu won't support. These is no way to check for now. Thus do not support the 2245 * extension */ 2246 if (!dri2_dpy->is_different_gpu) 2247 disp->Extensions.WL_create_wayland_buffer_from_image = EGL_TRUE; 2248 2249 disp->Extensions.EXT_buffer_age = EGL_TRUE; 2250 2251 disp->Extensions.EXT_swap_buffers_with_damage = EGL_TRUE; 2252 2253 disp->Extensions.EXT_present_opaque = EGL_TRUE; 2254 2255 /* Fill vtbl last to prevent accidentally calling virtual function during 2256 * initialization. 2257 */ 2258 dri2_dpy->vtbl = &dri2_wl_display_vtbl; 2259 2260 return EGL_TRUE; 2261 2262 cleanup: 2263 dri2_display_destroy(disp); 2264 return EGL_FALSE; 2265} 2266 2267static int 2268dri2_wl_swrast_get_stride_for_format(int format, int w) 2269{ 2270 int visual_idx = dri2_wl_visual_idx_from_shm_format(format); 2271 2272 assume(visual_idx != -1); 2273 2274 return w * (dri2_wl_visuals[visual_idx].bpp / 8); 2275} 2276 2277static EGLBoolean 2278dri2_wl_swrast_allocate_buffer(struct dri2_egl_surface *dri2_surf, 2279 int format, int w, int h, 2280 void **data, int *size, 2281 struct wl_buffer **buffer) 2282{ 2283 struct dri2_egl_display *dri2_dpy = 2284 dri2_egl_display(dri2_surf->base.Resource.Display); 2285 struct wl_shm_pool *pool; 2286 int fd, stride, size_map; 2287 void *data_map; 2288 2289 stride = dri2_wl_swrast_get_stride_for_format(format, w); 2290 size_map = h * stride; 2291 2292 /* Create a shareable buffer */ 2293 fd = os_create_anonymous_file(size_map, NULL); 2294 if (fd < 0) 2295 return EGL_FALSE; 2296 2297 data_map = mmap(NULL, size_map, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 2298 if (data_map == MAP_FAILED) { 2299 close(fd); 2300 return EGL_FALSE; 2301 } 2302 2303 /* Share it in a wl_buffer */ 2304 pool = wl_shm_create_pool(dri2_dpy->wl_shm, fd, size_map); 2305 wl_proxy_set_queue((struct wl_proxy *)pool, dri2_surf->wl_queue); 2306 *buffer = wl_shm_pool_create_buffer(pool, 0, w, h, stride, format); 2307 wl_shm_pool_destroy(pool); 2308 close(fd); 2309 2310 *data = data_map; 2311 *size = size_map; 2312 return EGL_TRUE; 2313} 2314 2315static int 2316swrast_update_buffers(struct dri2_egl_surface *dri2_surf) 2317{ 2318 struct dri2_egl_display *dri2_dpy = 2319 dri2_egl_display(dri2_surf->base.Resource.Display); 2320 bool zink = dri2_surf->base.Resource.Display->Options.Zink; 2321 2322 /* we need to do the following operations only once per frame */ 2323 if (dri2_surf->back) 2324 return 0; 2325 2326 if (dri2_surf->wl_win && 2327 (dri2_surf->base.Width != dri2_surf->wl_win->width || 2328 dri2_surf->base.Height != dri2_surf->wl_win->height)) { 2329 2330 if (!zink) 2331 dri2_wl_release_buffers(dri2_surf); 2332 2333 dri2_surf->base.Width = dri2_surf->wl_win->width; 2334 dri2_surf->base.Height = dri2_surf->wl_win->height; 2335 dri2_surf->dx = dri2_surf->wl_win->dx; 2336 dri2_surf->dy = dri2_surf->wl_win->dy; 2337 dri2_surf->current = NULL; 2338 } 2339 2340 /* find back buffer */ 2341 2342 /* There might be a buffer release already queued that wasn't processed */ 2343 wl_display_dispatch_queue_pending(dri2_dpy->wl_dpy, dri2_surf->wl_queue); 2344 2345 /* try get free buffer already created */ 2346 for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { 2347 if (!dri2_surf->color_buffers[i].locked && 2348 dri2_surf->color_buffers[i].wl_buffer) { 2349 dri2_surf->back = &dri2_surf->color_buffers[i]; 2350 break; 2351 } 2352 } 2353 2354 /* else choose any another free location */ 2355 if (!dri2_surf->back) { 2356 for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { 2357 if (!dri2_surf->color_buffers[i].locked) { 2358 dri2_surf->back = &dri2_surf->color_buffers[i]; 2359 if (zink) 2360 continue; 2361 if (!dri2_wl_swrast_allocate_buffer(dri2_surf, 2362 dri2_surf->format, 2363 dri2_surf->base.Width, 2364 dri2_surf->base.Height, 2365 &dri2_surf->back->data, 2366 &dri2_surf->back->data_size, 2367 &dri2_surf->back->wl_buffer)) { 2368 _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer"); 2369 return -1; 2370 } 2371 wl_buffer_add_listener(dri2_surf->back->wl_buffer, 2372 &wl_buffer_listener, dri2_surf); 2373 break; 2374 } 2375 } 2376 } 2377 2378 if (!dri2_surf->back) { 2379 _eglError(EGL_BAD_ALLOC, "failed to find free buffer"); 2380 return -1; 2381 } 2382 2383 dri2_surf->back->locked = true; 2384 2385 /* If we have an extra unlocked buffer at this point, we had to do triple 2386 * buffering for a while, but now can go back to just double buffering. 2387 * That means we can free any unlocked buffer now. To avoid toggling between 2388 * going back to double buffering and needing to allocate another buffer too 2389 * fast we let the unneeded buffer sit around for a short while. */ 2390 for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { 2391 if (!dri2_surf->color_buffers[i].locked && 2392 dri2_surf->color_buffers[i].wl_buffer && 2393 dri2_surf->color_buffers[i].age > BUFFER_TRIM_AGE_HYSTERESIS) { 2394 if (!zink) { 2395 wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer); 2396 munmap(dri2_surf->color_buffers[i].data, 2397 dri2_surf->color_buffers[i].data_size); 2398 } 2399 dri2_surf->color_buffers[i].wl_buffer = NULL; 2400 dri2_surf->color_buffers[i].data = NULL; 2401 dri2_surf->color_buffers[i].age = 0; 2402 } 2403 } 2404 2405 return 0; 2406} 2407 2408static void* 2409dri2_wl_swrast_get_frontbuffer_data(struct dri2_egl_surface *dri2_surf) 2410{ 2411 /* if there has been a resize: */ 2412 if (!dri2_surf->current) 2413 return NULL; 2414 2415 return dri2_surf->current->data; 2416} 2417 2418static void* 2419dri2_wl_swrast_get_backbuffer_data(struct dri2_egl_surface *dri2_surf) 2420{ 2421 assert(dri2_surf->back); 2422 return dri2_surf->back->data; 2423} 2424 2425static void 2426dri2_wl_swrast_commit_backbuffer(struct dri2_egl_surface *dri2_surf) 2427{ 2428 struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display); 2429 2430 while (dri2_surf->throttle_callback != NULL) 2431 if (wl_display_dispatch_queue(dri2_dpy->wl_dpy, 2432 dri2_surf->wl_queue) == -1) 2433 return; 2434 2435 if (dri2_surf->base.SwapInterval > 0) { 2436 dri2_surf->throttle_callback = 2437 wl_surface_frame(dri2_surf->wl_surface_wrapper); 2438 wl_callback_add_listener(dri2_surf->throttle_callback, 2439 &throttle_listener, dri2_surf); 2440 } 2441 2442 dri2_surf->current = dri2_surf->back; 2443 dri2_surf->back = NULL; 2444 2445 wl_surface_attach(dri2_surf->wl_surface_wrapper, 2446 dri2_surf->current->wl_buffer, 2447 dri2_surf->dx, dri2_surf->dy); 2448 2449 dri2_surf->wl_win->attached_width = dri2_surf->base.Width; 2450 dri2_surf->wl_win->attached_height = dri2_surf->base.Height; 2451 /* reset resize growing parameters */ 2452 dri2_surf->dx = 0; 2453 dri2_surf->dy = 0; 2454 2455 wl_surface_damage(dri2_surf->wl_surface_wrapper, 2456 0, 0, INT32_MAX, INT32_MAX); 2457 wl_surface_commit(dri2_surf->wl_surface_wrapper); 2458 2459 /* If we're not waiting for a frame callback then we'll at least throttle 2460 * to a sync callback so that we always give a chance for the compositor to 2461 * handle the commit and send a release event before checking for a free 2462 * buffer */ 2463 if (dri2_surf->throttle_callback == NULL) { 2464 dri2_surf->throttle_callback = wl_display_sync(dri2_surf->wl_dpy_wrapper); 2465 wl_callback_add_listener(dri2_surf->throttle_callback, 2466 &throttle_listener, dri2_surf); 2467 } 2468 2469 wl_display_flush(dri2_dpy->wl_dpy); 2470} 2471 2472static void 2473dri2_wl_swrast_get_drawable_info(__DRIdrawable * draw, 2474 int *x, int *y, int *w, int *h, 2475 void *loaderPrivate) 2476{ 2477 struct dri2_egl_surface *dri2_surf = loaderPrivate; 2478 2479 (void) swrast_update_buffers(dri2_surf); 2480 *x = 0; 2481 *y = 0; 2482 *w = dri2_surf->base.Width; 2483 *h = dri2_surf->base.Height; 2484} 2485 2486static void 2487dri2_wl_swrast_get_image(__DRIdrawable * read, 2488 int x, int y, int w, int h, 2489 char *data, void *loaderPrivate) 2490{ 2491 struct dri2_egl_surface *dri2_surf = loaderPrivate; 2492 int copy_width = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w); 2493 int x_offset = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, x); 2494 int src_stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, dri2_surf->base.Width); 2495 int dst_stride = copy_width; 2496 char *src, *dst; 2497 2498 src = dri2_wl_swrast_get_frontbuffer_data(dri2_surf); 2499 if (!src) { 2500 memset(data, 0, copy_width * h); 2501 return; 2502 } 2503 2504 assert(data != src); 2505 assert(copy_width <= src_stride); 2506 2507 src += x_offset; 2508 src += y * src_stride; 2509 dst = data; 2510 2511 if (copy_width > src_stride-x_offset) 2512 copy_width = src_stride-x_offset; 2513 if (h > dri2_surf->base.Height-y) 2514 h = dri2_surf->base.Height-y; 2515 2516 for (; h>0; h--) { 2517 memcpy(dst, src, copy_width); 2518 src += src_stride; 2519 dst += dst_stride; 2520 } 2521} 2522 2523static void 2524dri2_wl_swrast_put_image2(__DRIdrawable * draw, int op, 2525 int x, int y, int w, int h, int stride, 2526 char *data, void *loaderPrivate) 2527{ 2528 struct dri2_egl_surface *dri2_surf = loaderPrivate; 2529 int copy_width = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w); 2530 int dst_stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, dri2_surf->base.Width); 2531 int x_offset = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, x); 2532 char *src, *dst; 2533 2534 assert(copy_width <= stride); 2535 2536 (void) swrast_update_buffers(dri2_surf); 2537 dst = dri2_wl_swrast_get_backbuffer_data(dri2_surf); 2538 2539 /* partial copy, copy old content */ 2540 if (copy_width < dst_stride) 2541 dri2_wl_swrast_get_image(draw, 0, 0, 2542 dri2_surf->base.Width, dri2_surf->base.Height, 2543 dst, loaderPrivate); 2544 2545 dst += x_offset; 2546 dst += y * dst_stride; 2547 2548 src = data; 2549 2550 /* drivers expect we do these checks (and some rely on it) */ 2551 if (copy_width > dst_stride-x_offset) 2552 copy_width = dst_stride-x_offset; 2553 if (h > dri2_surf->base.Height-y) 2554 h = dri2_surf->base.Height-y; 2555 2556 for (; h>0; h--) { 2557 memcpy(dst, src, copy_width); 2558 src += stride; 2559 dst += dst_stride; 2560 } 2561 dri2_wl_swrast_commit_backbuffer(dri2_surf); 2562} 2563 2564static void 2565dri2_wl_swrast_put_image(__DRIdrawable * draw, int op, 2566 int x, int y, int w, int h, 2567 char *data, void *loaderPrivate) 2568{ 2569 struct dri2_egl_surface *dri2_surf = loaderPrivate; 2570 int stride; 2571 2572 stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w); 2573 dri2_wl_swrast_put_image2(draw, op, x, y, w, h, 2574 stride, data, loaderPrivate); 2575} 2576 2577static EGLBoolean 2578dri2_wl_swrast_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw) 2579{ 2580 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 2581 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); 2582 2583 if (!dri2_surf->wl_win) 2584 return _eglError(EGL_BAD_NATIVE_WINDOW, "dri2_swap_buffers"); 2585 2586 dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable); 2587 if (disp->Options.Zink) { 2588 dri2_surf->current = dri2_surf->back; 2589 dri2_surf->back = NULL; 2590 } 2591 return EGL_TRUE; 2592} 2593 2594static void 2595shm_handle_format(void *data, struct wl_shm *shm, uint32_t format) 2596{ 2597 struct dri2_egl_display *dri2_dpy = data; 2598 int visual_idx = dri2_wl_visual_idx_from_shm_format(format); 2599 2600 if (visual_idx == -1) 2601 return; 2602 2603 BITSET_SET(dri2_dpy->formats.formats_bitmap, visual_idx); 2604} 2605 2606static const struct wl_shm_listener shm_listener = { 2607 .format = shm_handle_format 2608}; 2609 2610static void 2611registry_handle_global_swrast(void *data, struct wl_registry *registry, 2612 uint32_t name, const char *interface, 2613 uint32_t version) 2614{ 2615 struct dri2_egl_display *dri2_dpy = data; 2616 2617 if (strcmp(interface, "wl_shm") == 0) { 2618 dri2_dpy->wl_shm = 2619 wl_registry_bind(registry, name, &wl_shm_interface, 1); 2620 wl_shm_add_listener(dri2_dpy->wl_shm, &shm_listener, dri2_dpy); 2621 } 2622} 2623 2624static const struct wl_registry_listener registry_listener_swrast = { 2625 .global = registry_handle_global_swrast, 2626 .global_remove = registry_handle_global_remove 2627}; 2628 2629static const struct dri2_egl_display_vtbl dri2_wl_swrast_display_vtbl = { 2630 .authenticate = NULL, 2631 .create_window_surface = dri2_wl_create_window_surface, 2632 .create_pixmap_surface = dri2_wl_create_pixmap_surface, 2633 .destroy_surface = dri2_wl_destroy_surface, 2634 .create_image = dri2_create_image_khr, 2635 .swap_buffers = dri2_wl_swrast_swap_buffers, 2636 .get_dri_drawable = dri2_surface_get_dri_drawable, 2637}; 2638 2639static const __DRIswrastLoaderExtension swrast_loader_extension = { 2640 .base = { __DRI_SWRAST_LOADER, 2 }, 2641 2642 .getDrawableInfo = dri2_wl_swrast_get_drawable_info, 2643 .putImage = dri2_wl_swrast_put_image, 2644 .getImage = dri2_wl_swrast_get_image, 2645 .putImage2 = dri2_wl_swrast_put_image2, 2646}; 2647 2648static void 2649kopperSetSurfaceCreateInfo(void *_draw, struct kopper_loader_info *out) 2650{ 2651 struct dri2_egl_surface *dri2_surf = _draw; 2652 struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display); 2653 VkWaylandSurfaceCreateInfoKHR *wlsci = &out->wl; 2654 2655 wlsci->sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; 2656 wlsci->pNext = NULL; 2657 wlsci->flags = 0; 2658 wlsci->display = dri2_dpy->wl_dpy; 2659 wlsci->surface = dri2_surf->wl_surface_wrapper; 2660} 2661 2662static const __DRIkopperLoaderExtension kopper_loader_extension = { 2663 .base = { __DRI_KOPPER_LOADER, 1 }, 2664 2665 .SetSurfaceCreateInfo = kopperSetSurfaceCreateInfo, 2666}; 2667static const __DRIextension *swrast_loader_extensions[] = { 2668 &swrast_loader_extension.base, 2669 &image_lookup_extension.base, 2670 &kopper_loader_extension.base, 2671 NULL, 2672}; 2673 2674static EGLBoolean 2675dri2_initialize_wayland_swrast(_EGLDisplay *disp) 2676{ 2677 _EGLDevice *dev; 2678 struct dri2_egl_display *dri2_dpy; 2679 2680 dri2_dpy = calloc(1, sizeof *dri2_dpy); 2681 if (!dri2_dpy) 2682 return _eglError(EGL_BAD_ALLOC, "eglInitialize"); 2683 2684 dri2_dpy->fd = -1; 2685 disp->DriverData = (void *) dri2_dpy; 2686 2687 if (dri2_wl_formats_init(&dri2_dpy->formats) < 0) 2688 goto cleanup; 2689 2690 if (disp->PlatformDisplay == NULL) { 2691 dri2_dpy->wl_dpy = wl_display_connect(NULL); 2692 if (dri2_dpy->wl_dpy == NULL) 2693 goto cleanup; 2694 dri2_dpy->own_device = true; 2695 } else { 2696 dri2_dpy->wl_dpy = disp->PlatformDisplay; 2697 } 2698 2699 dev = _eglAddDevice(dri2_dpy->fd, true); 2700 if (!dev) { 2701 _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to find EGLDevice"); 2702 goto cleanup; 2703 } 2704 2705 disp->Device = dev; 2706 2707 dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy); 2708 2709 dri2_dpy->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy); 2710 if (dri2_dpy->wl_dpy_wrapper == NULL) 2711 goto cleanup; 2712 2713 wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_dpy_wrapper, 2714 dri2_dpy->wl_queue); 2715 2716 if (dri2_dpy->own_device) 2717 wl_display_dispatch_pending(dri2_dpy->wl_dpy); 2718 2719 dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy_wrapper); 2720 wl_registry_add_listener(dri2_dpy->wl_registry, 2721 ®istry_listener_swrast, dri2_dpy); 2722 2723 if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_shm == NULL) 2724 goto cleanup; 2725 2726 if (roundtrip(dri2_dpy) < 0 || !BITSET_TEST_RANGE(dri2_dpy->formats.formats_bitmap, 2727 0, dri2_dpy->formats.num_formats)) 2728 goto cleanup; 2729 2730 dri2_dpy->driver_name = strdup(disp->Options.Zink ? "zink" : "swrast"); 2731 if (!dri2_load_driver_swrast(disp)) 2732 goto cleanup; 2733 2734 dri2_dpy->loader_extensions = swrast_loader_extensions; 2735 2736 if (!dri2_create_screen(disp)) 2737 goto cleanup; 2738 2739 if (!dri2_setup_extensions(disp)) 2740 goto cleanup; 2741 2742 dri2_setup_screen(disp); 2743 2744 dri2_wl_setup_swap_interval(disp); 2745 2746 if (!dri2_wl_add_configs_for_visuals(disp)) { 2747 _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to add configs"); 2748 goto cleanup; 2749 } 2750 2751 /* Fill vtbl last to prevent accidentally calling virtual function during 2752 * initialization. 2753 */ 2754 dri2_dpy->vtbl = &dri2_wl_swrast_display_vtbl; 2755 2756 return EGL_TRUE; 2757 2758 cleanup: 2759 dri2_display_destroy(disp); 2760 return EGL_FALSE; 2761} 2762 2763EGLBoolean 2764dri2_initialize_wayland(_EGLDisplay *disp) 2765{ 2766 if (disp->Options.ForceSoftware) 2767 return dri2_initialize_wayland_swrast(disp); 2768 else 2769 return dri2_initialize_wayland_drm(disp); 2770} 2771 2772void 2773dri2_teardown_wayland(struct dri2_egl_display *dri2_dpy) 2774{ 2775 dri2_wl_formats_fini(&dri2_dpy->formats); 2776 if (dri2_dpy->wl_drm) 2777 wl_drm_destroy(dri2_dpy->wl_drm); 2778 if (dri2_dpy->wl_dmabuf) 2779 zwp_linux_dmabuf_v1_destroy(dri2_dpy->wl_dmabuf); 2780 if (dri2_dpy->wl_shm) 2781 wl_shm_destroy(dri2_dpy->wl_shm); 2782 if (dri2_dpy->wl_registry) 2783 wl_registry_destroy(dri2_dpy->wl_registry); 2784 if (dri2_dpy->wl_queue) 2785 wl_event_queue_destroy(dri2_dpy->wl_queue); 2786 if (dri2_dpy->wl_dpy_wrapper) 2787 wl_proxy_wrapper_destroy(dri2_dpy->wl_dpy_wrapper); 2788 2789 if (dri2_dpy->own_device) 2790 wl_display_disconnect(dri2_dpy->wl_dpy); 2791} 2792