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 "vk_util.h" 35 #include "wsi_common_private.h" 36 #include "wsi_common_wayland.h" 37 #include "wayland-drm-client-protocol.h" 38 39 #include <util/hash_table.h> 40 #include <util/u_vector.h> 41 42 #define typed_memcpy(dest, src, count) ({ \ 43 STATIC_ASSERT(sizeof(*src) == sizeof(*dest)); \ 44 memcpy((dest), (src), (count) * sizeof(*(src))); \ 45 }) 46 47 struct wsi_wayland; 48 49 struct wsi_wl_display { 50 /* The real wl_display */ 51 struct wl_display * wl_display; 52 /* Actually a proxy wrapper around the event queue */ 53 struct wl_display * wl_display_wrapper; 54 struct wl_event_queue * queue; 55 struct wl_drm * drm; 56 57 struct wsi_wayland *wsi_wl; 58 /* Vector of VkFormats supported */ 59 struct u_vector formats; 60 61 uint32_t capabilities; 62 63 /* Only used for displays created by wsi_wl_display_create */ 64 uint32_t refcount; 65 }; 66 67 struct wsi_wayland { 68 struct wsi_interface base; 69 70 struct wsi_device *wsi; 71 72 const VkAllocationCallbacks *alloc; 73 VkPhysicalDevice physical_device; 74 }; 75 76 static void 77 wsi_wl_display_add_vk_format(struct wsi_wl_display *display, VkFormat format) 78 { 79 /* Don't add a format that's already in the list */ 80 VkFormat *f; 81 u_vector_foreach(f, &display->formats) 82 if (*f == format) 83 return; 84 85 /* Don't add formats that aren't renderable. */ 86 VkFormatProperties props; 87 88 display->wsi_wl->wsi->GetPhysicalDeviceFormatProperties(display->wsi_wl->physical_device, 89 format, &props); 90 if (!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) 91 return; 92 93 f = u_vector_add(&display->formats); 94 if (f) 95 *f = format; 96 } 97 98 static void 99 drm_handle_device(void *data, struct wl_drm *drm, const char *name) 100 { 101 } 102 103 static uint32_t 104 wl_drm_format_for_vk_format(VkFormat vk_format, bool alpha) 105 { 106 switch (vk_format) { 107 /* TODO: Figure out what all the formats mean and make this table 108 * correct. 109 */ 110 #if 0 111 case VK_FORMAT_R4G4B4A4_UNORM: 112 return alpha ? WL_DRM_FORMAT_ABGR4444 : WL_DRM_FORMAT_XBGR4444; 113 case VK_FORMAT_R5G6B5_UNORM: 114 return WL_DRM_FORMAT_BGR565; 115 case VK_FORMAT_R5G5B5A1_UNORM: 116 return alpha ? WL_DRM_FORMAT_ABGR1555 : WL_DRM_FORMAT_XBGR1555; 117 case VK_FORMAT_R8G8B8_UNORM: 118 return WL_DRM_FORMAT_XBGR8888; 119 case VK_FORMAT_R8G8B8A8_UNORM: 120 return alpha ? WL_DRM_FORMAT_ABGR8888 : WL_DRM_FORMAT_XBGR8888; 121 case VK_FORMAT_R10G10B10A2_UNORM: 122 return alpha ? WL_DRM_FORMAT_ABGR2101010 : WL_DRM_FORMAT_XBGR2101010; 123 case VK_FORMAT_B4G4R4A4_UNORM: 124 return alpha ? WL_DRM_FORMAT_ARGB4444 : WL_DRM_FORMAT_XRGB4444; 125 case VK_FORMAT_B5G6R5_UNORM: 126 return WL_DRM_FORMAT_RGB565; 127 case VK_FORMAT_B5G5R5A1_UNORM: 128 return alpha ? WL_DRM_FORMAT_XRGB1555 : WL_DRM_FORMAT_XRGB1555; 129 #endif 130 case VK_FORMAT_B8G8R8_UNORM: 131 case VK_FORMAT_B8G8R8_SRGB: 132 return WL_DRM_FORMAT_BGRX8888; 133 case VK_FORMAT_B8G8R8A8_UNORM: 134 case VK_FORMAT_B8G8R8A8_SRGB: 135 return alpha ? WL_DRM_FORMAT_ARGB8888 : WL_DRM_FORMAT_XRGB8888; 136 #if 0 137 case VK_FORMAT_B10G10R10A2_UNORM: 138 return alpha ? WL_DRM_FORMAT_ARGB2101010 : WL_DRM_FORMAT_XRGB2101010; 139 #endif 140 141 default: 142 assert(!"Unsupported Vulkan format"); 143 return 0; 144 } 145 } 146 147 static void 148 drm_handle_format(void *data, struct wl_drm *drm, uint32_t wl_format) 149 { 150 struct wsi_wl_display *display = data; 151 if (display->formats.element_size == 0) 152 return; 153 154 switch (wl_format) { 155 #if 0 156 case WL_DRM_FORMAT_ABGR4444: 157 case WL_DRM_FORMAT_XBGR4444: 158 wsi_wl_display_add_vk_format(display, VK_FORMAT_R4G4B4A4_UNORM); 159 break; 160 case WL_DRM_FORMAT_BGR565: 161 wsi_wl_display_add_vk_format(display, VK_FORMAT_R5G6B5_UNORM); 162 break; 163 case WL_DRM_FORMAT_ABGR1555: 164 case WL_DRM_FORMAT_XBGR1555: 165 wsi_wl_display_add_vk_format(display, VK_FORMAT_R5G5B5A1_UNORM); 166 break; 167 case WL_DRM_FORMAT_XBGR8888: 168 wsi_wl_display_add_vk_format(display, VK_FORMAT_R8G8B8_UNORM); 169 /* fallthrough */ 170 case WL_DRM_FORMAT_ABGR8888: 171 wsi_wl_display_add_vk_format(display, VK_FORMAT_R8G8B8A8_UNORM); 172 break; 173 case WL_DRM_FORMAT_ABGR2101010: 174 case WL_DRM_FORMAT_XBGR2101010: 175 wsi_wl_display_add_vk_format(display, VK_FORMAT_R10G10B10A2_UNORM); 176 break; 177 case WL_DRM_FORMAT_ARGB4444: 178 case WL_DRM_FORMAT_XRGB4444: 179 wsi_wl_display_add_vk_format(display, VK_FORMAT_B4G4R4A4_UNORM); 180 break; 181 case WL_DRM_FORMAT_RGB565: 182 wsi_wl_display_add_vk_format(display, VK_FORMAT_B5G6R5_UNORM); 183 break; 184 case WL_DRM_FORMAT_ARGB1555: 185 case WL_DRM_FORMAT_XRGB1555: 186 wsi_wl_display_add_vk_format(display, VK_FORMAT_B5G5R5A1_UNORM); 187 break; 188 #endif 189 case WL_DRM_FORMAT_XRGB8888: 190 wsi_wl_display_add_vk_format(display, VK_FORMAT_B8G8R8_SRGB); 191 wsi_wl_display_add_vk_format(display, VK_FORMAT_B8G8R8_UNORM); 192 /* fallthrough */ 193 case WL_DRM_FORMAT_ARGB8888: 194 wsi_wl_display_add_vk_format(display, VK_FORMAT_B8G8R8A8_SRGB); 195 wsi_wl_display_add_vk_format(display, VK_FORMAT_B8G8R8A8_UNORM); 196 break; 197 #if 0 198 case WL_DRM_FORMAT_ARGB2101010: 199 case WL_DRM_FORMAT_XRGB2101010: 200 wsi_wl_display_add_vk_format(display, VK_FORMAT_B10G10R10A2_UNORM); 201 break; 202 #endif 203 } 204 } 205 206 static void 207 drm_handle_authenticated(void *data, struct wl_drm *drm) 208 { 209 } 210 211 static void 212 drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t capabilities) 213 { 214 struct wsi_wl_display *display = data; 215 216 display->capabilities = capabilities; 217 } 218 219 static const struct wl_drm_listener drm_listener = { 220 drm_handle_device, 221 drm_handle_format, 222 drm_handle_authenticated, 223 drm_handle_capabilities, 224 }; 225 226 static void 227 registry_handle_global(void *data, struct wl_registry *registry, 228 uint32_t name, const char *interface, uint32_t version) 229 { 230 struct wsi_wl_display *display = data; 231 232 if (strcmp(interface, "wl_drm") == 0) { 233 assert(display->drm == NULL); 234 235 assert(version >= 2); 236 display->drm = wl_registry_bind(registry, name, &wl_drm_interface, 2); 237 238 if (display->drm) 239 wl_drm_add_listener(display->drm, &drm_listener, display); 240 } 241 } 242 243 static void 244 registry_handle_global_remove(void *data, struct wl_registry *registry, 245 uint32_t name) 246 { /* No-op */ } 247 248 static const struct wl_registry_listener registry_listener = { 249 registry_handle_global, 250 registry_handle_global_remove 251 }; 252 253 static void 254 wsi_wl_display_finish(struct wsi_wl_display *display) 255 { 256 assert(display->refcount == 0); 257 258 u_vector_finish(&display->formats); 259 if (display->drm) 260 wl_drm_destroy(display->drm); 261 if (display->wl_display_wrapper) 262 wl_proxy_wrapper_destroy(display->wl_display_wrapper); 263 if (display->queue) 264 wl_event_queue_destroy(display->queue); 265 } 266 267 static VkResult 268 wsi_wl_display_init(struct wsi_wayland *wsi_wl, 269 struct wsi_wl_display *display, 270 struct wl_display *wl_display, 271 bool get_format_list) 272 { 273 VkResult result = VK_SUCCESS; 274 memset(display, 0, sizeof(*display)); 275 276 display->wsi_wl = wsi_wl; 277 display->wl_display = wl_display; 278 279 if (get_format_list) { 280 if (!u_vector_init(&display->formats, sizeof(VkFormat), 8)) { 281 result = VK_ERROR_OUT_OF_HOST_MEMORY; 282 goto fail; 283 } 284 } 285 286 display->queue = wl_display_create_queue(wl_display); 287 if (!display->queue) { 288 result = VK_ERROR_OUT_OF_HOST_MEMORY; 289 goto fail; 290 } 291 292 display->wl_display_wrapper = wl_proxy_create_wrapper(wl_display); 293 if (!display->wl_display_wrapper) { 294 result = VK_ERROR_OUT_OF_HOST_MEMORY; 295 goto fail; 296 } 297 298 wl_proxy_set_queue((struct wl_proxy *) display->wl_display_wrapper, 299 display->queue); 300 301 struct wl_registry *registry = 302 wl_display_get_registry(display->wl_display_wrapper); 303 if (!registry) { 304 result = VK_ERROR_OUT_OF_HOST_MEMORY; 305 goto fail; 306 } 307 308 wl_registry_add_listener(registry, ®istry_listener, display); 309 310 /* Round-trip to get the wl_drm global */ 311 wl_display_roundtrip_queue(display->wl_display, display->queue); 312 313 if (!display->drm) { 314 result = VK_ERROR_SURFACE_LOST_KHR; 315 goto fail_registry; 316 } 317 318 /* Round-trip to get wl_drm formats and capabilities */ 319 wl_display_roundtrip_queue(display->wl_display, display->queue); 320 321 /* We need prime support */ 322 if (!(display->capabilities & WL_DRM_CAPABILITY_PRIME)) { 323 result = VK_ERROR_SURFACE_LOST_KHR; 324 goto fail_registry; 325 } 326 327 /* We don't need this anymore */ 328 wl_registry_destroy(registry); 329 330 display->refcount = 0; 331 332 return VK_SUCCESS; 333 334 fail_registry: 335 if (registry) 336 wl_registry_destroy(registry); 337 338 fail: 339 wsi_wl_display_finish(display); 340 return result; 341 } 342 343 static VkResult 344 wsi_wl_display_create(struct wsi_wayland *wsi, struct wl_display *wl_display, 345 struct wsi_wl_display **display_out) 346 { 347 struct wsi_wl_display *display = 348 vk_alloc(wsi->alloc, sizeof(*display), 8, 349 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 350 if (!display) 351 return VK_ERROR_OUT_OF_HOST_MEMORY; 352 353 VkResult result = wsi_wl_display_init(wsi, display, wl_display, true); 354 if (result != VK_SUCCESS) { 355 vk_free(wsi->alloc, display); 356 return result; 357 } 358 359 display->refcount++; 360 *display_out = display; 361 362 return result; 363 } 364 365 static struct wsi_wl_display * 366 wsi_wl_display_ref(struct wsi_wl_display *display) 367 { 368 display->refcount++; 369 return display; 370 } 371 372 static void 373 wsi_wl_display_unref(struct wsi_wl_display *display) 374 { 375 if (display->refcount-- > 1) 376 return; 377 378 struct wsi_wayland *wsi = display->wsi_wl; 379 wsi_wl_display_finish(display); 380 vk_free(wsi->alloc, display); 381 } 382 383 VkBool32 384 wsi_wl_get_presentation_support(struct wsi_device *wsi_device, 385 struct wl_display *wl_display) 386 { 387 struct wsi_wayland *wsi = 388 (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND]; 389 390 struct wsi_wl_display display; 391 int ret = wsi_wl_display_init(wsi, &display, wl_display, false); 392 wsi_wl_display_finish(&display); 393 394 return ret == 0; 395 } 396 397 static VkResult 398 wsi_wl_surface_get_support(VkIcdSurfaceBase *surface, 399 struct wsi_device *wsi_device, 400 const VkAllocationCallbacks *alloc, 401 uint32_t queueFamilyIndex, 402 int local_fd, 403 VkBool32* pSupported) 404 { 405 *pSupported = true; 406 407 return VK_SUCCESS; 408 } 409 410 static const VkPresentModeKHR present_modes[] = { 411 VK_PRESENT_MODE_MAILBOX_KHR, 412 VK_PRESENT_MODE_FIFO_KHR, 413 }; 414 415 static VkResult 416 wsi_wl_surface_get_capabilities(VkIcdSurfaceBase *surface, 417 VkSurfaceCapabilitiesKHR* caps) 418 { 419 /* For true mailbox mode, we need at least 4 images: 420 * 1) One to scan out from 421 * 2) One to have queued for scan-out 422 * 3) One to be currently held by the Wayland compositor 423 * 4) One to render to 424 */ 425 caps->minImageCount = 4; 426 /* There is no real maximum */ 427 caps->maxImageCount = 0; 428 429 caps->currentExtent = (VkExtent2D) { -1, -1 }; 430 caps->minImageExtent = (VkExtent2D) { 1, 1 }; 431 /* This is the maximum supported size on Intel */ 432 caps->maxImageExtent = (VkExtent2D) { 1 << 14, 1 << 14 }; 433 caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; 434 caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; 435 caps->maxImageArrayLayers = 1; 436 437 caps->supportedCompositeAlpha = 438 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR | 439 VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR; 440 441 caps->supportedUsageFlags = 442 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | 443 VK_IMAGE_USAGE_SAMPLED_BIT | 444 VK_IMAGE_USAGE_TRANSFER_DST_BIT | 445 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; 446 447 return VK_SUCCESS; 448 } 449 450 static VkResult 451 wsi_wl_surface_get_capabilities2(VkIcdSurfaceBase *surface, 452 const void *info_next, 453 VkSurfaceCapabilities2KHR* caps) 454 { 455 assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR); 456 457 return wsi_wl_surface_get_capabilities(surface, &caps->surfaceCapabilities); 458 } 459 460 static VkResult 461 wsi_wl_surface_get_formats(VkIcdSurfaceBase *icd_surface, 462 struct wsi_device *wsi_device, 463 uint32_t* pSurfaceFormatCount, 464 VkSurfaceFormatKHR* pSurfaceFormats) 465 { 466 VkIcdSurfaceWayland *surface = (VkIcdSurfaceWayland *)icd_surface; 467 struct wsi_wayland *wsi = 468 (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND]; 469 470 struct wsi_wl_display display; 471 if (wsi_wl_display_init(wsi, &display, surface->display, true)) 472 return VK_ERROR_SURFACE_LOST_KHR; 473 474 VK_OUTARRAY_MAKE(out, pSurfaceFormats, pSurfaceFormatCount); 475 476 VkFormat *disp_fmt; 477 u_vector_foreach(disp_fmt, &display.formats) { 478 vk_outarray_append(&out, out_fmt) { 479 out_fmt->format = *disp_fmt; 480 out_fmt->colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; 481 } 482 } 483 484 wsi_wl_display_finish(&display); 485 486 return vk_outarray_status(&out); 487 } 488 489 static VkResult 490 wsi_wl_surface_get_formats2(VkIcdSurfaceBase *icd_surface, 491 struct wsi_device *wsi_device, 492 const void *info_next, 493 uint32_t* pSurfaceFormatCount, 494 VkSurfaceFormat2KHR* pSurfaceFormats) 495 { 496 VkIcdSurfaceWayland *surface = (VkIcdSurfaceWayland *)icd_surface; 497 struct wsi_wayland *wsi = 498 (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND]; 499 500 struct wsi_wl_display display; 501 if (wsi_wl_display_init(wsi, &display, surface->display, true)) 502 return VK_ERROR_SURFACE_LOST_KHR; 503 504 VK_OUTARRAY_MAKE(out, pSurfaceFormats, pSurfaceFormatCount); 505 506 VkFormat *disp_fmt; 507 u_vector_foreach(disp_fmt, &display.formats) { 508 vk_outarray_append(&out, out_fmt) { 509 out_fmt->surfaceFormat.format = *disp_fmt; 510 out_fmt->surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; 511 } 512 } 513 514 wsi_wl_display_finish(&display); 515 516 return vk_outarray_status(&out); 517 } 518 519 static VkResult 520 wsi_wl_surface_get_present_modes(VkIcdSurfaceBase *surface, 521 uint32_t* pPresentModeCount, 522 VkPresentModeKHR* pPresentModes) 523 { 524 if (pPresentModes == NULL) { 525 *pPresentModeCount = ARRAY_SIZE(present_modes); 526 return VK_SUCCESS; 527 } 528 529 *pPresentModeCount = MIN2(*pPresentModeCount, ARRAY_SIZE(present_modes)); 530 typed_memcpy(pPresentModes, present_modes, *pPresentModeCount); 531 532 if (*pPresentModeCount < ARRAY_SIZE(present_modes)) 533 return VK_INCOMPLETE; 534 else 535 return VK_SUCCESS; 536 } 537 538 VkResult wsi_create_wl_surface(const VkAllocationCallbacks *pAllocator, 539 const VkWaylandSurfaceCreateInfoKHR *pCreateInfo, 540 VkSurfaceKHR *pSurface) 541 { 542 VkIcdSurfaceWayland *surface; 543 544 surface = vk_alloc(pAllocator, sizeof *surface, 8, 545 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 546 if (surface == NULL) 547 return VK_ERROR_OUT_OF_HOST_MEMORY; 548 549 surface->base.platform = VK_ICD_WSI_PLATFORM_WAYLAND; 550 surface->display = pCreateInfo->display; 551 surface->surface = pCreateInfo->surface; 552 553 *pSurface = VkIcdSurfaceBase_to_handle(&surface->base); 554 555 return VK_SUCCESS; 556 } 557 558 struct wsi_wl_image { 559 struct wsi_image base; 560 struct wl_buffer * buffer; 561 bool busy; 562 }; 563 564 struct wsi_wl_swapchain { 565 struct wsi_swapchain base; 566 567 struct wsi_wl_display *display; 568 569 struct wl_surface * surface; 570 uint32_t surface_version; 571 struct wl_drm * drm_wrapper; 572 struct wl_callback * frame; 573 574 VkExtent2D extent; 575 VkFormat vk_format; 576 uint32_t drm_format; 577 578 VkPresentModeKHR present_mode; 579 bool fifo_ready; 580 581 struct wsi_wl_image images[0]; 582 }; 583 584 static struct wsi_image * 585 wsi_wl_swapchain_get_wsi_image(struct wsi_swapchain *wsi_chain, 586 uint32_t image_index) 587 { 588 struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain; 589 return &chain->images[image_index].base; 590 } 591 592 static VkResult 593 wsi_wl_swapchain_acquire_next_image(struct wsi_swapchain *wsi_chain, 594 uint64_t timeout, 595 VkSemaphore semaphore, 596 uint32_t *image_index) 597 { 598 struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain; 599 600 int ret = wl_display_dispatch_queue_pending(chain->display->wl_display, 601 chain->display->queue); 602 /* XXX: I'm not sure if out-of-date is the right error here. If 603 * wl_display_dispatch_queue_pending fails it most likely means we got 604 * kicked by the server so this seems more-or-less correct. 605 */ 606 if (ret < 0) 607 return VK_ERROR_OUT_OF_DATE_KHR; 608 609 while (1) { 610 for (uint32_t i = 0; i < chain->base.image_count; i++) { 611 if (!chain->images[i].busy) { 612 /* We found a non-busy image */ 613 *image_index = i; 614 chain->images[i].busy = true; 615 return VK_SUCCESS; 616 } 617 } 618 619 /* This time we do a blocking dispatch because we can't go 620 * anywhere until we get an event. 621 */ 622 int ret = wl_display_roundtrip_queue(chain->display->wl_display, 623 chain->display->queue); 624 if (ret < 0) 625 return VK_ERROR_OUT_OF_DATE_KHR; 626 } 627 } 628 629 static void 630 frame_handle_done(void *data, struct wl_callback *callback, uint32_t serial) 631 { 632 struct wsi_wl_swapchain *chain = data; 633 634 chain->frame = NULL; 635 chain->fifo_ready = true; 636 637 wl_callback_destroy(callback); 638 } 639 640 static const struct wl_callback_listener frame_listener = { 641 frame_handle_done, 642 }; 643 644 static VkResult 645 wsi_wl_swapchain_queue_present(struct wsi_swapchain *wsi_chain, 646 uint32_t image_index, 647 const VkPresentRegionKHR *damage) 648 { 649 struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain; 650 651 if (chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR) { 652 while (!chain->fifo_ready) { 653 int ret = wl_display_dispatch_queue(chain->display->wl_display, 654 chain->display->queue); 655 if (ret < 0) 656 return VK_ERROR_OUT_OF_DATE_KHR; 657 } 658 } 659 660 assert(image_index < chain->base.image_count); 661 wl_surface_attach(chain->surface, chain->images[image_index].buffer, 0, 0); 662 663 if (chain->surface_version >= 4 && damage && 664 damage->pRectangles && damage->rectangleCount > 0) { 665 for (unsigned i = 0; i < damage->rectangleCount; i++) { 666 const VkRectLayerKHR *rect = &damage->pRectangles[i]; 667 assert(rect->layer == 0); 668 wl_surface_damage_buffer(chain->surface, 669 rect->offset.x, rect->offset.y, 670 rect->extent.width, rect->extent.height); 671 } 672 } else { 673 wl_surface_damage(chain->surface, 0, 0, INT32_MAX, INT32_MAX); 674 } 675 676 if (chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR) { 677 chain->frame = wl_surface_frame(chain->surface); 678 wl_callback_add_listener(chain->frame, &frame_listener, chain); 679 chain->fifo_ready = false; 680 } 681 682 chain->images[image_index].busy = true; 683 wl_surface_commit(chain->surface); 684 wl_display_flush(chain->display->wl_display); 685 686 return VK_SUCCESS; 687 } 688 689 static void 690 buffer_handle_release(void *data, struct wl_buffer *buffer) 691 { 692 struct wsi_wl_image *image = data; 693 694 assert(image->buffer == buffer); 695 696 image->busy = false; 697 } 698 699 static const struct wl_buffer_listener buffer_listener = { 700 buffer_handle_release, 701 }; 702 703 static VkResult 704 wsi_wl_image_init(struct wsi_wl_swapchain *chain, 705 struct wsi_wl_image *image, 706 const VkSwapchainCreateInfoKHR *pCreateInfo, 707 const VkAllocationCallbacks* pAllocator) 708 { 709 VkResult result; 710 711 result = wsi_create_native_image(&chain->base, pCreateInfo, &image->base); 712 if (result != VK_SUCCESS) 713 return result; 714 715 image->buffer = wl_drm_create_prime_buffer(chain->drm_wrapper, 716 image->base.fd, /* name */ 717 chain->extent.width, 718 chain->extent.height, 719 chain->drm_format, 720 image->base.offset, 721 image->base.row_pitch, 722 0, 0, 0, 0 /* unused */); 723 close(image->base.fd); 724 725 if (!image->buffer) 726 goto fail_image; 727 728 wl_buffer_add_listener(image->buffer, &buffer_listener, image); 729 730 return VK_SUCCESS; 731 732 fail_image: 733 wsi_destroy_image(&chain->base, &image->base); 734 735 return result; 736 } 737 738 static VkResult 739 wsi_wl_swapchain_destroy(struct wsi_swapchain *wsi_chain, 740 const VkAllocationCallbacks *pAllocator) 741 { 742 struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain; 743 744 for (uint32_t i = 0; i < chain->base.image_count; i++) { 745 if (chain->images[i].buffer) { 746 wl_buffer_destroy(chain->images[i].buffer); 747 wsi_destroy_image(&chain->base, &chain->images[i].base); 748 } 749 } 750 751 if (chain->frame) 752 wl_callback_destroy(chain->frame); 753 if (chain->surface) 754 wl_proxy_wrapper_destroy(chain->surface); 755 if (chain->drm_wrapper) 756 wl_proxy_wrapper_destroy(chain->drm_wrapper); 757 758 if (chain->display) 759 wsi_wl_display_unref(chain->display); 760 761 wsi_swapchain_finish(&chain->base); 762 763 vk_free(pAllocator, chain); 764 765 return VK_SUCCESS; 766 } 767 768 static VkResult 769 wsi_wl_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, 770 VkDevice device, 771 struct wsi_device *wsi_device, 772 int local_fd, 773 const VkSwapchainCreateInfoKHR* pCreateInfo, 774 const VkAllocationCallbacks* pAllocator, 775 struct wsi_swapchain **swapchain_out) 776 { 777 VkIcdSurfaceWayland *surface = (VkIcdSurfaceWayland *)icd_surface; 778 struct wsi_wayland *wsi = 779 (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND]; 780 struct wsi_wl_swapchain *chain; 781 VkResult result; 782 783 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR); 784 785 int num_images = pCreateInfo->minImageCount; 786 787 size_t size = sizeof(*chain) + num_images * sizeof(chain->images[0]); 788 chain = vk_alloc(pAllocator, size, 8, 789 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 790 if (chain == NULL) 791 return VK_ERROR_OUT_OF_HOST_MEMORY; 792 793 result = wsi_swapchain_init(wsi_device, &chain->base, device, 794 pCreateInfo, pAllocator); 795 if (result != VK_SUCCESS) { 796 vk_free(pAllocator, chain); 797 return result; 798 } 799 800 /* Mark a bunch of stuff as NULL. This way we can just call 801 * destroy_swapchain for cleanup. 802 */ 803 for (uint32_t i = 0; i < num_images; i++) 804 chain->images[i].buffer = NULL; 805 chain->surface = NULL; 806 chain->drm_wrapper = NULL; 807 chain->frame = NULL; 808 809 bool alpha = pCreateInfo->compositeAlpha == 810 VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR; 811 812 chain->base.destroy = wsi_wl_swapchain_destroy; 813 chain->base.get_wsi_image = wsi_wl_swapchain_get_wsi_image; 814 chain->base.acquire_next_image = wsi_wl_swapchain_acquire_next_image; 815 chain->base.queue_present = wsi_wl_swapchain_queue_present; 816 chain->base.present_mode = pCreateInfo->presentMode; 817 chain->base.image_count = num_images; 818 chain->extent = pCreateInfo->imageExtent; 819 chain->vk_format = pCreateInfo->imageFormat; 820 chain->drm_format = wl_drm_format_for_vk_format(chain->vk_format, alpha); 821 822 if (pCreateInfo->oldSwapchain) { 823 /* If we have an oldSwapchain parameter, copy the display struct over 824 * from the old one so we don't have to fully re-initialize it. 825 */ 826 struct wsi_wl_swapchain *old_chain = (void *)pCreateInfo->oldSwapchain; 827 chain->display = wsi_wl_display_ref(old_chain->display); 828 } else { 829 chain->display = NULL; 830 result = wsi_wl_display_create(wsi, surface->display, &chain->display); 831 if (result != VK_SUCCESS) 832 goto fail; 833 } 834 835 chain->surface = wl_proxy_create_wrapper(surface->surface); 836 if (!chain->surface) { 837 result = VK_ERROR_OUT_OF_HOST_MEMORY; 838 goto fail; 839 } 840 wl_proxy_set_queue((struct wl_proxy *) chain->surface, 841 chain->display->queue); 842 chain->surface_version = wl_proxy_get_version((void *)surface->surface); 843 844 chain->drm_wrapper = wl_proxy_create_wrapper(chain->display->drm); 845 if (!chain->drm_wrapper) { 846 result = VK_ERROR_OUT_OF_HOST_MEMORY; 847 goto fail; 848 } 849 wl_proxy_set_queue((struct wl_proxy *) chain->drm_wrapper, 850 chain->display->queue); 851 852 chain->fifo_ready = true; 853 854 for (uint32_t i = 0; i < chain->base.image_count; i++) { 855 result = wsi_wl_image_init(chain, &chain->images[i], 856 pCreateInfo, pAllocator); 857 if (result != VK_SUCCESS) 858 goto fail; 859 chain->images[i].busy = false; 860 } 861 862 *swapchain_out = &chain->base; 863 864 return VK_SUCCESS; 865 866 fail: 867 wsi_wl_swapchain_destroy(&chain->base, pAllocator); 868 869 return result; 870 } 871 872 VkResult 873 wsi_wl_init_wsi(struct wsi_device *wsi_device, 874 const VkAllocationCallbacks *alloc, 875 VkPhysicalDevice physical_device) 876 { 877 struct wsi_wayland *wsi; 878 VkResult result; 879 880 wsi = vk_alloc(alloc, sizeof(*wsi), 8, 881 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 882 if (!wsi) { 883 result = VK_ERROR_OUT_OF_HOST_MEMORY; 884 goto fail; 885 } 886 887 wsi->physical_device = physical_device; 888 wsi->alloc = alloc; 889 wsi->wsi = wsi_device; 890 891 wsi->base.get_support = wsi_wl_surface_get_support; 892 wsi->base.get_capabilities = wsi_wl_surface_get_capabilities; 893 wsi->base.get_capabilities2 = wsi_wl_surface_get_capabilities2; 894 wsi->base.get_formats = wsi_wl_surface_get_formats; 895 wsi->base.get_formats2 = wsi_wl_surface_get_formats2; 896 wsi->base.get_present_modes = wsi_wl_surface_get_present_modes; 897 wsi->base.create_swapchain = wsi_wl_surface_create_swapchain; 898 899 wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND] = &wsi->base; 900 901 return VK_SUCCESS; 902 903 fail: 904 wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND] = NULL; 905 906 return result; 907 } 908 909 void 910 wsi_wl_finish_wsi(struct wsi_device *wsi_device, 911 const VkAllocationCallbacks *alloc) 912 { 913 struct wsi_wayland *wsi = 914 (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND]; 915 if (!wsi) 916 return; 917 918 vk_free(alloc, wsi); 919 } 920