1/* 2 * Copyright © 2015 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24#include <wayland-client.h> 25 26#include <assert.h> 27#include <stdlib.h> 28#include <stdio.h> 29#include <unistd.h> 30#include <errno.h> 31#include <string.h> 32#include <pthread.h> 33 34#include "drm-uapi/drm_fourcc.h" 35 36#include "vk_util.h" 37#include "wsi_common_private.h" 38#include "wsi_common_wayland.h" 39#include "wayland-drm-client-protocol.h" 40#include "linux-dmabuf-unstable-v1-client-protocol.h" 41 42#include <util/hash_table.h> 43#include <util/u_vector.h> 44 45#define typed_memcpy(dest, src, count) ({ \ 46 STATIC_ASSERT(sizeof(*src) == sizeof(*dest)); \ 47 memcpy((dest), (src), (count) * sizeof(*(src))); \ 48}) 49 50struct wsi_wayland; 51 52struct wsi_wl_display_drm { 53 struct wl_drm * wl_drm; 54 struct u_vector formats; 55 uint32_t capabilities; 56}; 57 58struct wsi_wl_display_dmabuf { 59 struct zwp_linux_dmabuf_v1 * wl_dmabuf; 60 struct u_vector formats; 61 struct { 62 struct u_vector argb8888; 63 struct u_vector xrgb8888; 64 } modifiers; 65}; 66 67struct wsi_wl_display { 68 /* The real wl_display */ 69 struct wl_display * wl_display; 70 /* Actually a proxy wrapper around the event queue */ 71 struct wl_display * wl_display_wrapper; 72 struct wl_event_queue * queue; 73 74 struct wsi_wl_display_drm drm; 75 struct wsi_wl_display_dmabuf dmabuf; 76 77 struct wsi_wayland *wsi_wl; 78 79 /* Points to formats in wsi_wl_display_drm or wsi_wl_display_dmabuf */ 80 struct u_vector * formats; 81 82 /* Only used for displays created by wsi_wl_display_create */ 83 uint32_t refcount; 84}; 85 86struct wsi_wayland { 87 struct wsi_interface base; 88 89 struct wsi_device *wsi; 90 91 const VkAllocationCallbacks *alloc; 92 VkPhysicalDevice physical_device; 93}; 94 95static void 96wsi_wl_display_add_vk_format(struct wsi_wl_display *display, 97 struct u_vector *formats, VkFormat format) 98{ 99 /* Don't add a format that's already in the list */ 100 VkFormat *f; 101 u_vector_foreach(f, formats) 102 if (*f == format) 103 return; 104 105 /* Don't add formats that aren't renderable. */ 106 VkFormatProperties props; 107 108 display->wsi_wl->wsi->GetPhysicalDeviceFormatProperties(display->wsi_wl->physical_device, 109 format, &props); 110 if (!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) 111 return; 112 113 f = u_vector_add(formats); 114 if (f) 115 *f = format; 116} 117 118static void 119wsi_wl_display_add_wl_format(struct wsi_wl_display *display, 120 struct u_vector *formats, uint32_t wl_format) 121{ 122 switch (wl_format) { 123#if 0 124 case WL_DRM_FORMAT_ABGR4444: 125 case WL_DRM_FORMAT_XBGR4444: 126 wsi_wl_display_add_vk_format(display, formats, 127 VK_FORMAT_R4G4B4A4_UNORM); 128 break; 129 case WL_DRM_FORMAT_BGR565: 130 wsi_wl_display_add_vk_format(display, formats, 131 VK_FORMAT_R5G6B5_UNORM); 132 break; 133 case WL_DRM_FORMAT_ABGR1555: 134 case WL_DRM_FORMAT_XBGR1555: 135 wsi_wl_display_add_vk_format(display, formats, 136 VK_FORMAT_R5G5B5A1_UNORM); 137 break; 138 case WL_DRM_FORMAT_XBGR8888: 139 wsi_wl_display_add_vk_format(display, formats, 140 VK_FORMAT_R8G8B8_UNORM); 141 /* fallthrough */ 142 case WL_DRM_FORMAT_ABGR8888: 143 wsi_wl_display_add_vk_format(display, formats, 144 VK_FORMAT_R8G8B8A8_UNORM); 145 break; 146 case WL_DRM_FORMAT_ABGR2101010: 147 case WL_DRM_FORMAT_XBGR2101010: 148 wsi_wl_display_add_vk_format(display, formats, 149 VK_FORMAT_R10G10B10A2_UNORM); 150 break; 151 case WL_DRM_FORMAT_ARGB4444: 152 case WL_DRM_FORMAT_XRGB4444: 153 wsi_wl_display_add_vk_format(display, formats, 154 VK_FORMAT_B4G4R4A4_UNORM); 155 break; 156 case WL_DRM_FORMAT_RGB565: 157 wsi_wl_display_add_vk_format(display, formats, 158 VK_FORMAT_B5G6R5_UNORM); 159 break; 160 case WL_DRM_FORMAT_ARGB1555: 161 case WL_DRM_FORMAT_XRGB1555: 162 wsi_wl_display_add_vk_format(display, formats, 163 VK_FORMAT_B5G5R5A1_UNORM); 164 break; 165#endif 166 case WL_DRM_FORMAT_XRGB8888: 167 wsi_wl_display_add_vk_format(display, formats, 168 VK_FORMAT_B8G8R8_SRGB); 169 wsi_wl_display_add_vk_format(display, formats, 170 VK_FORMAT_B8G8R8_UNORM); 171 /* fallthrough */ 172 case WL_DRM_FORMAT_ARGB8888: 173 wsi_wl_display_add_vk_format(display, formats, 174 VK_FORMAT_B8G8R8A8_SRGB); 175 wsi_wl_display_add_vk_format(display, formats, 176 VK_FORMAT_B8G8R8A8_UNORM); 177 break; 178#if 0 179 case WL_DRM_FORMAT_ARGB2101010: 180 case WL_DRM_FORMAT_XRGB2101010: 181 wsi_wl_display_add_vk_format(display, formats, 182 VK_FORMAT_B10G10R10A2_UNORM); 183 break; 184#endif 185 } 186} 187 188static void 189drm_handle_device(void *data, struct wl_drm *drm, const char *name) 190{ 191} 192 193static uint32_t 194wl_drm_format_for_vk_format(VkFormat vk_format, bool alpha) 195{ 196 switch (vk_format) { 197 /* TODO: Figure out what all the formats mean and make this table 198 * correct. 199 */ 200#if 0 201 case VK_FORMAT_R4G4B4A4_UNORM: 202 return alpha ? WL_DRM_FORMAT_ABGR4444 : WL_DRM_FORMAT_XBGR4444; 203 case VK_FORMAT_R5G6B5_UNORM: 204 return WL_DRM_FORMAT_BGR565; 205 case VK_FORMAT_R5G5B5A1_UNORM: 206 return alpha ? WL_DRM_FORMAT_ABGR1555 : WL_DRM_FORMAT_XBGR1555; 207 case VK_FORMAT_R8G8B8_UNORM: 208 return WL_DRM_FORMAT_XBGR8888; 209 case VK_FORMAT_R8G8B8A8_UNORM: 210 return alpha ? WL_DRM_FORMAT_ABGR8888 : WL_DRM_FORMAT_XBGR8888; 211 case VK_FORMAT_R10G10B10A2_UNORM: 212 return alpha ? WL_DRM_FORMAT_ABGR2101010 : WL_DRM_FORMAT_XBGR2101010; 213 case VK_FORMAT_B4G4R4A4_UNORM: 214 return alpha ? WL_DRM_FORMAT_ARGB4444 : WL_DRM_FORMAT_XRGB4444; 215 case VK_FORMAT_B5G6R5_UNORM: 216 return WL_DRM_FORMAT_RGB565; 217 case VK_FORMAT_B5G5R5A1_UNORM: 218 return alpha ? WL_DRM_FORMAT_XRGB1555 : WL_DRM_FORMAT_XRGB1555; 219#endif 220 case VK_FORMAT_B8G8R8_UNORM: 221 case VK_FORMAT_B8G8R8_SRGB: 222 return WL_DRM_FORMAT_BGRX8888; 223 case VK_FORMAT_B8G8R8A8_UNORM: 224 case VK_FORMAT_B8G8R8A8_SRGB: 225 return alpha ? WL_DRM_FORMAT_ARGB8888 : WL_DRM_FORMAT_XRGB8888; 226#if 0 227 case VK_FORMAT_B10G10R10A2_UNORM: 228 return alpha ? WL_DRM_FORMAT_ARGB2101010 : WL_DRM_FORMAT_XRGB2101010; 229#endif 230 231 default: 232 assert(!"Unsupported Vulkan format"); 233 return 0; 234 } 235} 236 237static void 238drm_handle_format(void *data, struct wl_drm *drm, uint32_t wl_format) 239{ 240 struct wsi_wl_display *display = data; 241 if (display->drm.formats.element_size == 0) 242 return; 243 244 wsi_wl_display_add_wl_format(display, &display->drm.formats, wl_format); 245} 246 247static void 248drm_handle_authenticated(void *data, struct wl_drm *drm) 249{ 250} 251 252static void 253drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t capabilities) 254{ 255 struct wsi_wl_display *display = data; 256 257 display->drm.capabilities = capabilities; 258} 259 260static const struct wl_drm_listener drm_listener = { 261 drm_handle_device, 262 drm_handle_format, 263 drm_handle_authenticated, 264 drm_handle_capabilities, 265}; 266 267static void 268dmabuf_handle_format(void *data, struct zwp_linux_dmabuf_v1 *dmabuf, 269 uint32_t format) 270{ 271 /* Formats are implicitly advertised by the modifier event, so we ignore 272 * them here. */ 273} 274 275static void 276dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *dmabuf, 277 uint32_t format, uint32_t modifier_hi, 278 uint32_t modifier_lo) 279{ 280 struct wsi_wl_display *display = data; 281 uint64_t *mod = NULL; 282 283 /* If we're not fetching formats, don't fetch modifiers either. */ 284 if (display->dmabuf.formats.element_size == 0) 285 return; 286 287 if (modifier_hi == (DRM_FORMAT_MOD_INVALID >> 32) && 288 modifier_lo == (DRM_FORMAT_MOD_INVALID & 0xffffffff)) 289 return; 290 291 switch (format) { 292 case WL_DRM_FORMAT_ARGB8888: 293 wsi_wl_display_add_wl_format(display, &display->dmabuf.formats, format); 294 mod = u_vector_add(&display->dmabuf.modifiers.argb8888); 295 break; 296 case WL_DRM_FORMAT_XRGB8888: 297 wsi_wl_display_add_wl_format(display, &display->dmabuf.formats, format); 298 mod = u_vector_add(&display->dmabuf.modifiers.xrgb8888); 299 break; 300 default: 301 break; 302 } 303 304 if (!mod) 305 return; 306 307 *mod = (uint64_t) modifier_hi << 32; 308 *mod |= (uint64_t) (modifier_lo & 0xffffffff); 309} 310 311static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = { 312 dmabuf_handle_format, 313 dmabuf_handle_modifier, 314}; 315 316static void 317registry_handle_global(void *data, struct wl_registry *registry, 318 uint32_t name, const char *interface, uint32_t version) 319{ 320 struct wsi_wl_display *display = data; 321 322 if (strcmp(interface, "wl_drm") == 0) { 323 assert(display->drm.wl_drm == NULL); 324 325 assert(version >= 2); 326 display->drm.wl_drm = 327 wl_registry_bind(registry, name, &wl_drm_interface, 2); 328 wl_drm_add_listener(display->drm.wl_drm, &drm_listener, display); 329 } else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0 && version >= 3 && 330 display->wsi_wl->wsi->supports_modifiers) { 331 display->dmabuf.wl_dmabuf = 332 wl_registry_bind(registry, name, &zwp_linux_dmabuf_v1_interface, 3); 333 zwp_linux_dmabuf_v1_add_listener(display->dmabuf.wl_dmabuf, 334 &dmabuf_listener, display); 335 } 336} 337 338static void 339registry_handle_global_remove(void *data, struct wl_registry *registry, 340 uint32_t name) 341{ /* No-op */ } 342 343static const struct wl_registry_listener registry_listener = { 344 registry_handle_global, 345 registry_handle_global_remove 346}; 347 348static void 349wsi_wl_display_finish(struct wsi_wl_display *display) 350{ 351 assert(display->refcount == 0); 352 353 u_vector_finish(&display->drm.formats); 354 u_vector_finish(&display->dmabuf.formats); 355 u_vector_finish(&display->dmabuf.modifiers.argb8888); 356 u_vector_finish(&display->dmabuf.modifiers.xrgb8888); 357 if (display->drm.wl_drm) 358 wl_drm_destroy(display->drm.wl_drm); 359 if (display->dmabuf.wl_dmabuf) 360 zwp_linux_dmabuf_v1_destroy(display->dmabuf.wl_dmabuf); 361 if (display->wl_display_wrapper) 362 wl_proxy_wrapper_destroy(display->wl_display_wrapper); 363 if (display->queue) 364 wl_event_queue_destroy(display->queue); 365} 366 367static VkResult 368wsi_wl_display_init(struct wsi_wayland *wsi_wl, 369 struct wsi_wl_display *display, 370 struct wl_display *wl_display, 371 bool get_format_list) 372{ 373 VkResult result = VK_SUCCESS; 374 memset(display, 0, sizeof(*display)); 375 376 display->wsi_wl = wsi_wl; 377 display->wl_display = wl_display; 378 379 if (get_format_list) { 380 if (!u_vector_init(&display->drm.formats, sizeof(VkFormat), 8) || 381 !u_vector_init(&display->dmabuf.formats, sizeof(VkFormat), 8) || 382 !u_vector_init(&display->dmabuf.modifiers.argb8888, 383 sizeof(uint64_t), 32) || 384 !u_vector_init(&display->dmabuf.modifiers.xrgb8888, 385 sizeof(uint64_t), 32)) { 386 result = VK_ERROR_OUT_OF_HOST_MEMORY; 387 goto fail; 388 } 389 } 390 391 display->queue = wl_display_create_queue(wl_display); 392 if (!display->queue) { 393 result = VK_ERROR_OUT_OF_HOST_MEMORY; 394 goto fail; 395 } 396 397 display->wl_display_wrapper = wl_proxy_create_wrapper(wl_display); 398 if (!display->wl_display_wrapper) { 399 result = VK_ERROR_OUT_OF_HOST_MEMORY; 400 goto fail; 401 } 402 403 wl_proxy_set_queue((struct wl_proxy *) display->wl_display_wrapper, 404 display->queue); 405 406 struct wl_registry *registry = 407 wl_display_get_registry(display->wl_display_wrapper); 408 if (!registry) { 409 result = VK_ERROR_OUT_OF_HOST_MEMORY; 410 goto fail; 411 } 412 413 wl_registry_add_listener(registry, ®istry_listener, display); 414 415 /* Round-trip to get wl_drms and zwp_linux_dmabuf_v1 globals */ 416 wl_display_roundtrip_queue(display->wl_display, display->queue); 417 418 /* Round-trip again to get formats, modifiers and capabilities */ 419 if (display->drm.wl_drm || display->dmabuf.wl_dmabuf) 420 wl_display_roundtrip_queue(display->wl_display, display->queue); 421 422 /* We need prime support for wl_drm */ 423 if (display->drm.wl_drm && 424 (display->drm.capabilities & WL_DRM_CAPABILITY_PRIME)) { 425 display->formats = &display->drm.formats; 426 } else if (display->dmabuf.wl_dmabuf) { 427 display->formats = &display->dmabuf.formats; 428 } 429 430 if (!display->formats) { 431 result = VK_ERROR_SURFACE_LOST_KHR; 432 goto fail_registry; 433 } 434 435 /* We don't need this anymore */ 436 wl_registry_destroy(registry); 437 438 display->refcount = 0; 439 440 return VK_SUCCESS; 441 442fail_registry: 443 if (registry) 444 wl_registry_destroy(registry); 445 446fail: 447 wsi_wl_display_finish(display); 448 return result; 449} 450 451static VkResult 452wsi_wl_display_create(struct wsi_wayland *wsi, struct wl_display *wl_display, 453 struct wsi_wl_display **display_out) 454{ 455 struct wsi_wl_display *display = 456 vk_alloc(wsi->alloc, sizeof(*display), 8, 457 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 458 if (!display) 459 return VK_ERROR_OUT_OF_HOST_MEMORY; 460 461 VkResult result = wsi_wl_display_init(wsi, display, wl_display, true); 462 if (result != VK_SUCCESS) { 463 vk_free(wsi->alloc, display); 464 return result; 465 } 466 467 display->refcount++; 468 *display_out = display; 469 470 return result; 471} 472 473static struct wsi_wl_display * 474wsi_wl_display_ref(struct wsi_wl_display *display) 475{ 476 display->refcount++; 477 return display; 478} 479 480static void 481wsi_wl_display_unref(struct wsi_wl_display *display) 482{ 483 if (display->refcount-- > 1) 484 return; 485 486 struct wsi_wayland *wsi = display->wsi_wl; 487 wsi_wl_display_finish(display); 488 vk_free(wsi->alloc, display); 489} 490 491VkBool32 492wsi_wl_get_presentation_support(struct wsi_device *wsi_device, 493 struct wl_display *wl_display) 494{ 495 struct wsi_wayland *wsi = 496 (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND]; 497 498 struct wsi_wl_display display; 499 VkResult ret = wsi_wl_display_init(wsi, &display, wl_display, false); 500 if (ret == VK_SUCCESS) 501 wsi_wl_display_finish(&display); 502 503 return ret == VK_SUCCESS; 504} 505 506static VkResult 507wsi_wl_surface_get_support(VkIcdSurfaceBase *surface, 508 struct wsi_device *wsi_device, 509 uint32_t queueFamilyIndex, 510 VkBool32* pSupported) 511{ 512 *pSupported = true; 513 514 return VK_SUCCESS; 515} 516 517static const VkPresentModeKHR present_modes[] = { 518 VK_PRESENT_MODE_MAILBOX_KHR, 519 VK_PRESENT_MODE_FIFO_KHR, 520}; 521 522static VkResult 523wsi_wl_surface_get_capabilities(VkIcdSurfaceBase *surface, 524 struct wsi_device *wsi_device, 525 VkSurfaceCapabilitiesKHR* caps) 526{ 527 /* For true mailbox mode, we need at least 4 images: 528 * 1) One to scan out from 529 * 2) One to have queued for scan-out 530 * 3) One to be currently held by the Wayland compositor 531 * 4) One to render to 532 */ 533 caps->minImageCount = 4; 534 /* There is no real maximum */ 535 caps->maxImageCount = 0; 536 537 caps->currentExtent = (VkExtent2D) { -1, -1 }; 538 caps->minImageExtent = (VkExtent2D) { 1, 1 }; 539 caps->maxImageExtent = (VkExtent2D) { 540 wsi_device->maxImageDimension2D, 541 wsi_device->maxImageDimension2D, 542 }; 543 544 caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; 545 caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; 546 caps->maxImageArrayLayers = 1; 547 548 caps->supportedCompositeAlpha = 549 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR | 550 VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR; 551 552 caps->supportedUsageFlags = 553 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | 554 VK_IMAGE_USAGE_SAMPLED_BIT | 555 VK_IMAGE_USAGE_TRANSFER_DST_BIT | 556 VK_IMAGE_USAGE_STORAGE_BIT | 557 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; 558 559 return VK_SUCCESS; 560} 561 562static VkResult 563wsi_wl_surface_get_capabilities2(VkIcdSurfaceBase *surface, 564 struct wsi_device *wsi_device, 565 const void *info_next, 566 VkSurfaceCapabilities2KHR* caps) 567{ 568 assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR); 569 570 VkResult result = 571 wsi_wl_surface_get_capabilities(surface, wsi_device, 572 &caps->surfaceCapabilities); 573 574 vk_foreach_struct(ext, caps->pNext) { 575 switch (ext->sType) { 576 case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR: { 577 VkSurfaceProtectedCapabilitiesKHR *protected = (void *)ext; 578 protected->supportsProtected = VK_FALSE; 579 break; 580 } 581 582 default: 583 /* Ignored */ 584 break; 585 } 586 } 587 588 return result; 589} 590 591static VkResult 592wsi_wl_surface_get_formats(VkIcdSurfaceBase *icd_surface, 593 struct wsi_device *wsi_device, 594 uint32_t* pSurfaceFormatCount, 595 VkSurfaceFormatKHR* pSurfaceFormats) 596{ 597 VkIcdSurfaceWayland *surface = (VkIcdSurfaceWayland *)icd_surface; 598 struct wsi_wayland *wsi = 599 (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND]; 600 601 struct wsi_wl_display display; 602 if (wsi_wl_display_init(wsi, &display, surface->display, true)) 603 return VK_ERROR_SURFACE_LOST_KHR; 604 605 VK_OUTARRAY_MAKE(out, pSurfaceFormats, pSurfaceFormatCount); 606 607 VkFormat *disp_fmt; 608 u_vector_foreach(disp_fmt, display.formats) { 609 vk_outarray_append(&out, out_fmt) { 610 out_fmt->format = *disp_fmt; 611 out_fmt->colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; 612 } 613 } 614 615 wsi_wl_display_finish(&display); 616 617 return vk_outarray_status(&out); 618} 619 620static VkResult 621wsi_wl_surface_get_formats2(VkIcdSurfaceBase *icd_surface, 622 struct wsi_device *wsi_device, 623 const void *info_next, 624 uint32_t* pSurfaceFormatCount, 625 VkSurfaceFormat2KHR* pSurfaceFormats) 626{ 627 VkIcdSurfaceWayland *surface = (VkIcdSurfaceWayland *)icd_surface; 628 struct wsi_wayland *wsi = 629 (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND]; 630 631 struct wsi_wl_display display; 632 if (wsi_wl_display_init(wsi, &display, surface->display, true)) 633 return VK_ERROR_SURFACE_LOST_KHR; 634 635 VK_OUTARRAY_MAKE(out, pSurfaceFormats, pSurfaceFormatCount); 636 637 VkFormat *disp_fmt; 638 u_vector_foreach(disp_fmt, display.formats) { 639 vk_outarray_append(&out, out_fmt) { 640 out_fmt->surfaceFormat.format = *disp_fmt; 641 out_fmt->surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; 642 } 643 } 644 645 wsi_wl_display_finish(&display); 646 647 return vk_outarray_status(&out); 648} 649 650static VkResult 651wsi_wl_surface_get_present_modes(VkIcdSurfaceBase *surface, 652 uint32_t* pPresentModeCount, 653 VkPresentModeKHR* pPresentModes) 654{ 655 if (pPresentModes == NULL) { 656 *pPresentModeCount = ARRAY_SIZE(present_modes); 657 return VK_SUCCESS; 658 } 659 660 *pPresentModeCount = MIN2(*pPresentModeCount, ARRAY_SIZE(present_modes)); 661 typed_memcpy(pPresentModes, present_modes, *pPresentModeCount); 662 663 if (*pPresentModeCount < ARRAY_SIZE(present_modes)) 664 return VK_INCOMPLETE; 665 else 666 return VK_SUCCESS; 667} 668 669static VkResult 670wsi_wl_surface_get_present_rectangles(VkIcdSurfaceBase *surface, 671 struct wsi_device *wsi_device, 672 uint32_t* pRectCount, 673 VkRect2D* pRects) 674{ 675 VK_OUTARRAY_MAKE(out, pRects, pRectCount); 676 677 vk_outarray_append(&out, rect) { 678 /* We don't know a size so just return the usual "I don't know." */ 679 *rect = (VkRect2D) { 680 .offset = { 0, 0 }, 681 .extent = { -1, -1 }, 682 }; 683 } 684 685 return vk_outarray_status(&out); 686} 687 688VkResult wsi_create_wl_surface(const VkAllocationCallbacks *pAllocator, 689 const VkWaylandSurfaceCreateInfoKHR *pCreateInfo, 690 VkSurfaceKHR *pSurface) 691{ 692 VkIcdSurfaceWayland *surface; 693 694 surface = vk_alloc(pAllocator, sizeof *surface, 8, 695 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 696 if (surface == NULL) 697 return VK_ERROR_OUT_OF_HOST_MEMORY; 698 699 surface->base.platform = VK_ICD_WSI_PLATFORM_WAYLAND; 700 surface->display = pCreateInfo->display; 701 surface->surface = pCreateInfo->surface; 702 703 *pSurface = VkIcdSurfaceBase_to_handle(&surface->base); 704 705 return VK_SUCCESS; 706} 707 708struct wsi_wl_image { 709 struct wsi_image base; 710 struct wl_buffer * buffer; 711 bool busy; 712}; 713 714struct wsi_wl_swapchain { 715 struct wsi_swapchain base; 716 717 struct wsi_wl_display *display; 718 719 struct wl_surface * surface; 720 uint32_t surface_version; 721 722 /* non-NULL when wl_drm should be used for wl_buffer creation; otherwise, 723 * zwp_linux_dmabuf_v1 should be used. 724 */ 725 struct wl_drm * drm_wrapper; 726 727 struct wl_callback * frame; 728 729 VkExtent2D extent; 730 VkFormat vk_format; 731 uint32_t drm_format; 732 733 uint32_t num_drm_modifiers; 734 const uint64_t * drm_modifiers; 735 736 VkPresentModeKHR present_mode; 737 bool fifo_ready; 738 739 struct wsi_wl_image images[0]; 740}; 741WSI_DEFINE_NONDISP_HANDLE_CASTS(wsi_wl_swapchain, VkSwapchainKHR) 742 743static struct wsi_image * 744wsi_wl_swapchain_get_wsi_image(struct wsi_swapchain *wsi_chain, 745 uint32_t image_index) 746{ 747 struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain; 748 return &chain->images[image_index].base; 749} 750 751static VkResult 752wsi_wl_swapchain_acquire_next_image(struct wsi_swapchain *wsi_chain, 753 const VkAcquireNextImageInfoKHR *info, 754 uint32_t *image_index) 755{ 756 struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain; 757 758#ifdef DEBUG 759 /* 760 * TODO: We need to implement this 761 */ 762 if (info->timeout != 0 && info->timeout != UINT64_MAX) 763 { 764 fprintf(stderr, "timeout not supported; ignoring"); 765 } 766#endif 767 768 int ret = wl_display_dispatch_queue_pending(chain->display->wl_display, 769 chain->display->queue); 770 /* XXX: I'm not sure if out-of-date is the right error here. If 771 * wl_display_dispatch_queue_pending fails it most likely means we got 772 * kicked by the server so this seems more-or-less correct. 773 */ 774 if (ret < 0) 775 return VK_ERROR_OUT_OF_DATE_KHR; 776 777 while (1) { 778 for (uint32_t i = 0; i < chain->base.image_count; i++) { 779 if (!chain->images[i].busy) { 780 /* We found a non-busy image */ 781 *image_index = i; 782 chain->images[i].busy = true; 783 return VK_SUCCESS; 784 } 785 } 786 787 /* We now have to do a blocking dispatch, because all our images 788 * are in use and we cannot return one until the server does. However, 789 * if the client has requested non-blocking ANI, then we tell it up front 790 * that we have nothing to return. 791 */ 792 if (info->timeout == 0) 793 return VK_NOT_READY; 794 795 int ret = wl_display_roundtrip_queue(chain->display->wl_display, 796 chain->display->queue); 797 if (ret < 0) 798 return VK_ERROR_OUT_OF_DATE_KHR; 799 } 800} 801 802static void 803frame_handle_done(void *data, struct wl_callback *callback, uint32_t serial) 804{ 805 struct wsi_wl_swapchain *chain = data; 806 807 chain->frame = NULL; 808 chain->fifo_ready = true; 809 810 wl_callback_destroy(callback); 811} 812 813static const struct wl_callback_listener frame_listener = { 814 frame_handle_done, 815}; 816 817static VkResult 818wsi_wl_swapchain_queue_present(struct wsi_swapchain *wsi_chain, 819 uint32_t image_index, 820 const VkPresentRegionKHR *damage) 821{ 822 struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain; 823 824 if (chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR) { 825 while (!chain->fifo_ready) { 826 int ret = wl_display_dispatch_queue(chain->display->wl_display, 827 chain->display->queue); 828 if (ret < 0) 829 return VK_ERROR_OUT_OF_DATE_KHR; 830 } 831 } 832 833 assert(image_index < chain->base.image_count); 834 wl_surface_attach(chain->surface, chain->images[image_index].buffer, 0, 0); 835 836 if (chain->surface_version >= 4 && damage && 837 damage->pRectangles && damage->rectangleCount > 0) { 838 for (unsigned i = 0; i < damage->rectangleCount; i++) { 839 const VkRectLayerKHR *rect = &damage->pRectangles[i]; 840 assert(rect->layer == 0); 841 wl_surface_damage_buffer(chain->surface, 842 rect->offset.x, rect->offset.y, 843 rect->extent.width, rect->extent.height); 844 } 845 } else { 846 wl_surface_damage(chain->surface, 0, 0, INT32_MAX, INT32_MAX); 847 } 848 849 if (chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR) { 850 chain->frame = wl_surface_frame(chain->surface); 851 wl_callback_add_listener(chain->frame, &frame_listener, chain); 852 chain->fifo_ready = false; 853 } 854 855 chain->images[image_index].busy = true; 856 wl_surface_commit(chain->surface); 857 wl_display_flush(chain->display->wl_display); 858 859 return VK_SUCCESS; 860} 861 862static void 863buffer_handle_release(void *data, struct wl_buffer *buffer) 864{ 865 struct wsi_wl_image *image = data; 866 867 assert(image->buffer == buffer); 868 869 image->busy = false; 870} 871 872static const struct wl_buffer_listener buffer_listener = { 873 buffer_handle_release, 874}; 875 876static VkResult 877wsi_wl_image_init(struct wsi_wl_swapchain *chain, 878 struct wsi_wl_image *image, 879 const VkSwapchainCreateInfoKHR *pCreateInfo, 880 const VkAllocationCallbacks* pAllocator) 881{ 882 struct wsi_wl_display *display = chain->display; 883 VkResult result; 884 885 result = wsi_create_native_image(&chain->base, pCreateInfo, 886 chain->num_drm_modifiers > 0 ? 1 : 0, 887 &chain->num_drm_modifiers, 888 &chain->drm_modifiers, &image->base); 889 890 if (result != VK_SUCCESS) 891 return result; 892 893 if (!chain->drm_wrapper) { 894 /* Only request modifiers if we have dmabuf, else it must be implicit. */ 895 assert(display->dmabuf.wl_dmabuf); 896 assert(image->base.drm_modifier != DRM_FORMAT_MOD_INVALID); 897 898 struct zwp_linux_buffer_params_v1 *params = 899 zwp_linux_dmabuf_v1_create_params(display->dmabuf.wl_dmabuf); 900 wl_proxy_set_queue((struct wl_proxy *) params, chain->display->queue); 901 902 for (int i = 0; i < image->base.num_planes; i++) { 903 zwp_linux_buffer_params_v1_add(params, 904 image->base.fds[i], 905 i, 906 image->base.offsets[i], 907 image->base.row_pitches[i], 908 image->base.drm_modifier >> 32, 909 image->base.drm_modifier & 0xffffffff); 910 close(image->base.fds[i]); 911 } 912 913 image->buffer = 914 zwp_linux_buffer_params_v1_create_immed(params, 915 chain->extent.width, 916 chain->extent.height, 917 chain->drm_format, 918 0); 919 zwp_linux_buffer_params_v1_destroy(params); 920 } else { 921 /* Without passing modifiers, we can't have multi-plane RGB images. */ 922 assert(image->base.num_planes == 1); 923 assert(image->base.drm_modifier == DRM_FORMAT_MOD_INVALID); 924 925 image->buffer = 926 wl_drm_create_prime_buffer(chain->drm_wrapper, 927 image->base.fds[0], /* name */ 928 chain->extent.width, 929 chain->extent.height, 930 chain->drm_format, 931 image->base.offsets[0], 932 image->base.row_pitches[0], 933 0, 0, 0, 0 /* unused */); 934 close(image->base.fds[0]); 935 } 936 937 if (!image->buffer) 938 goto fail_image; 939 940 wl_buffer_add_listener(image->buffer, &buffer_listener, image); 941 942 return VK_SUCCESS; 943 944fail_image: 945 wsi_destroy_image(&chain->base, &image->base); 946 947 return result; 948} 949 950static VkResult 951wsi_wl_swapchain_destroy(struct wsi_swapchain *wsi_chain, 952 const VkAllocationCallbacks *pAllocator) 953{ 954 struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain; 955 956 for (uint32_t i = 0; i < chain->base.image_count; i++) { 957 if (chain->images[i].buffer) { 958 wl_buffer_destroy(chain->images[i].buffer); 959 wsi_destroy_image(&chain->base, &chain->images[i].base); 960 } 961 } 962 963 if (chain->frame) 964 wl_callback_destroy(chain->frame); 965 if (chain->surface) 966 wl_proxy_wrapper_destroy(chain->surface); 967 if (chain->drm_wrapper) 968 wl_proxy_wrapper_destroy(chain->drm_wrapper); 969 970 if (chain->display) 971 wsi_wl_display_unref(chain->display); 972 973 wsi_swapchain_finish(&chain->base); 974 975 vk_free(pAllocator, chain); 976 977 return VK_SUCCESS; 978} 979 980static VkResult 981wsi_wl_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, 982 VkDevice device, 983 struct wsi_device *wsi_device, 984 const VkSwapchainCreateInfoKHR* pCreateInfo, 985 const VkAllocationCallbacks* pAllocator, 986 struct wsi_swapchain **swapchain_out) 987{ 988 VkIcdSurfaceWayland *surface = (VkIcdSurfaceWayland *)icd_surface; 989 struct wsi_wayland *wsi = 990 (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND]; 991 struct wsi_wl_swapchain *chain; 992 VkResult result; 993 994 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR); 995 996 int num_images = pCreateInfo->minImageCount; 997 998 size_t size = sizeof(*chain) + num_images * sizeof(chain->images[0]); 999 chain = vk_alloc(pAllocator, size, 8, 1000 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 1001 if (chain == NULL) 1002 return VK_ERROR_OUT_OF_HOST_MEMORY; 1003 1004 result = wsi_swapchain_init(wsi_device, &chain->base, device, 1005 pCreateInfo, pAllocator); 1006 if (result != VK_SUCCESS) { 1007 vk_free(pAllocator, chain); 1008 return result; 1009 } 1010 1011 /* Mark a bunch of stuff as NULL. This way we can just call 1012 * destroy_swapchain for cleanup. 1013 */ 1014 for (uint32_t i = 0; i < num_images; i++) 1015 chain->images[i].buffer = NULL; 1016 chain->surface = NULL; 1017 chain->drm_wrapper = NULL; 1018 chain->frame = NULL; 1019 1020 bool alpha = pCreateInfo->compositeAlpha == 1021 VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR; 1022 1023 chain->base.destroy = wsi_wl_swapchain_destroy; 1024 chain->base.get_wsi_image = wsi_wl_swapchain_get_wsi_image; 1025 chain->base.acquire_next_image = wsi_wl_swapchain_acquire_next_image; 1026 chain->base.queue_present = wsi_wl_swapchain_queue_present; 1027 chain->base.present_mode = wsi_swapchain_get_present_mode(wsi_device, pCreateInfo); 1028 chain->base.image_count = num_images; 1029 chain->extent = pCreateInfo->imageExtent; 1030 chain->vk_format = pCreateInfo->imageFormat; 1031 chain->drm_format = wl_drm_format_for_vk_format(chain->vk_format, alpha); 1032 1033 if (pCreateInfo->oldSwapchain) { 1034 /* If we have an oldSwapchain parameter, copy the display struct over 1035 * from the old one so we don't have to fully re-initialize it. 1036 */ 1037 WSI_FROM_HANDLE(wsi_wl_swapchain, old_chain, pCreateInfo->oldSwapchain); 1038 chain->display = wsi_wl_display_ref(old_chain->display); 1039 } else { 1040 chain->display = NULL; 1041 result = wsi_wl_display_create(wsi, surface->display, &chain->display); 1042 if (result != VK_SUCCESS) 1043 goto fail; 1044 } 1045 1046 chain->surface = wl_proxy_create_wrapper(surface->surface); 1047 if (!chain->surface) { 1048 result = VK_ERROR_OUT_OF_HOST_MEMORY; 1049 goto fail; 1050 } 1051 wl_proxy_set_queue((struct wl_proxy *) chain->surface, 1052 chain->display->queue); 1053 chain->surface_version = wl_proxy_get_version((void *)surface->surface); 1054 1055 chain->num_drm_modifiers = 0; 1056 chain->drm_modifiers = 0; 1057 1058 /* Use explicit DRM format modifiers when both the server and the driver 1059 * support them. 1060 */ 1061 if (chain->display->dmabuf.wl_dmabuf && 1062 chain->base.wsi->supports_modifiers) { 1063 struct u_vector *modifiers; 1064 switch (chain->drm_format) { 1065 case WL_DRM_FORMAT_ARGB8888: 1066 modifiers = &chain->display->dmabuf.modifiers.argb8888; 1067 break; 1068 case WL_DRM_FORMAT_XRGB8888: 1069 modifiers = &chain->display->dmabuf.modifiers.xrgb8888; 1070 break; 1071 default: 1072 modifiers = NULL; 1073 break; 1074 } 1075 1076 if (modifiers) { 1077 chain->drm_modifiers = u_vector_tail(modifiers); 1078 chain->num_drm_modifiers = u_vector_length(modifiers); 1079 } 1080 } 1081 1082 /* When there are explicit DRM format modifiers, we must use 1083 * zwp_linux_dmabuf_v1 for wl_buffer creation. Otherwise, we must use 1084 * wl_drm. 1085 */ 1086 if (!chain->num_drm_modifiers) { 1087 assert(chain->display->drm.wl_drm); 1088 1089 chain->drm_wrapper = 1090 wl_proxy_create_wrapper(chain->display->drm.wl_drm); 1091 if (!chain->drm_wrapper) { 1092 result = VK_ERROR_OUT_OF_HOST_MEMORY; 1093 goto fail; 1094 } 1095 wl_proxy_set_queue((struct wl_proxy *) chain->drm_wrapper, 1096 chain->display->queue); 1097 } 1098 1099 chain->fifo_ready = true; 1100 1101 for (uint32_t i = 0; i < chain->base.image_count; i++) { 1102 result = wsi_wl_image_init(chain, &chain->images[i], 1103 pCreateInfo, pAllocator); 1104 if (result != VK_SUCCESS) 1105 goto fail; 1106 chain->images[i].busy = false; 1107 } 1108 1109 *swapchain_out = &chain->base; 1110 1111 return VK_SUCCESS; 1112 1113fail: 1114 wsi_wl_swapchain_destroy(&chain->base, pAllocator); 1115 1116 return result; 1117} 1118 1119VkResult 1120wsi_wl_init_wsi(struct wsi_device *wsi_device, 1121 const VkAllocationCallbacks *alloc, 1122 VkPhysicalDevice physical_device) 1123{ 1124 struct wsi_wayland *wsi; 1125 VkResult result; 1126 1127 wsi = vk_alloc(alloc, sizeof(*wsi), 8, 1128 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 1129 if (!wsi) { 1130 result = VK_ERROR_OUT_OF_HOST_MEMORY; 1131 goto fail; 1132 } 1133 1134 wsi->physical_device = physical_device; 1135 wsi->alloc = alloc; 1136 wsi->wsi = wsi_device; 1137 1138 wsi->base.get_support = wsi_wl_surface_get_support; 1139 wsi->base.get_capabilities2 = wsi_wl_surface_get_capabilities2; 1140 wsi->base.get_formats = wsi_wl_surface_get_formats; 1141 wsi->base.get_formats2 = wsi_wl_surface_get_formats2; 1142 wsi->base.get_present_modes = wsi_wl_surface_get_present_modes; 1143 wsi->base.get_present_rectangles = wsi_wl_surface_get_present_rectangles; 1144 wsi->base.create_swapchain = wsi_wl_surface_create_swapchain; 1145 1146 wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND] = &wsi->base; 1147 1148 return VK_SUCCESS; 1149 1150fail: 1151 wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND] = NULL; 1152 1153 return result; 1154} 1155 1156void 1157wsi_wl_finish_wsi(struct wsi_device *wsi_device, 1158 const VkAllocationCallbacks *alloc) 1159{ 1160 struct wsi_wayland *wsi = 1161 (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND]; 1162 if (!wsi) 1163 return; 1164 1165 vk_free(alloc, wsi); 1166} 1167