From 07ac177c3fa6ca87521976b265dc110c0b6997b6 Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Wed, 30 Nov 2022 17:18:00 +0100 Subject: [PATCH] wsi/wayland: Implement EXT_swapchain_maintenance1. Signed-off-by: Hans-Kristian Arntzen Reviewed-by: Joshua Ashton Part-of: --- src/vulkan/wsi/wsi_common_wayland.c | 131 +++++++++++++++++++++++++++++++----- 1 file changed, 116 insertions(+), 15 deletions(-) diff --git a/src/vulkan/wsi/wsi_common_wayland.c b/src/vulkan/wsi/wsi_common_wayland.c index 86d26a8..f12e2cc 100644 --- a/src/vulkan/wsi/wsi_common_wayland.c +++ b/src/vulkan/wsi/wsi_common_wayland.c @@ -963,18 +963,56 @@ static const VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_FIFO_KHR, }; +static uint32_t +wsi_wl_surface_get_min_image_count(const VkSurfacePresentModeEXT *present_mode) +{ + if (present_mode && (present_mode->presentMode == VK_PRESENT_MODE_FIFO_KHR || + present_mode->presentMode == VK_PRESENT_MODE_FIFO_RELAXED_KHR)) { + /* If we receive a FIFO present mode, only 2 images is required for forward progress. + * Performance with 2 images will be questionable, but we only allow it for applications + * using the new API, so we don't risk breaking any existing apps this way. + * Other ICDs expose 2 images here already. */ + return 2; + } else { + /* For true mailbox mode, we need at least 4 images: + * 1) One to scan out from + * 2) One to have queued for scan-out + * 3) One to be currently held by the Wayland compositor + * 4) One to render to + */ + return 4; + } +} + +static uint32_t +wsi_wl_surface_get_min_image_count_for_mode_group(const VkSwapchainPresentModesCreateInfoEXT *modes) +{ + /* If we don't provide the PresentModeCreateInfo struct, we must be backwards compatible, + * and assume that minImageCount is the default one, i.e. 4, which supports both FIFO and MAILBOX. */ + if (!modes) { + return wsi_wl_surface_get_min_image_count(NULL); + } + + uint32_t max_required = 0; + for (uint32_t i = 0; i < modes->presentModeCount; i++) { + const VkSurfacePresentModeEXT mode = { + VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT, + NULL, + modes->pPresentModes[i] + }; + max_required = MAX2(max_required, wsi_wl_surface_get_min_image_count(&mode)); + } + + return max_required; +} + static VkResult wsi_wl_surface_get_capabilities(VkIcdSurfaceBase *surface, struct wsi_device *wsi_device, + const VkSurfacePresentModeEXT *present_mode, VkSurfaceCapabilitiesKHR* caps) { - /* For true mailbox mode, we need at least 4 images: - * 1) One to scan out from - * 2) One to have queued for scan-out - * 3) One to be currently held by the Wayland compositor - * 4) One to render to - */ - caps->minImageCount = 4; + caps->minImageCount = wsi_wl_surface_get_min_image_count(present_mode); /* There is no real maximum */ caps->maxImageCount = 0; @@ -1012,8 +1050,10 @@ wsi_wl_surface_get_capabilities2(VkIcdSurfaceBase *surface, { assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR); + const VkSurfacePresentModeEXT *present_mode = vk_find_struct_const(info_next, SURFACE_PRESENT_MODE_EXT); + VkResult result = - wsi_wl_surface_get_capabilities(surface, wsi_device, + wsi_wl_surface_get_capabilities(surface, wsi_device, present_mode, &caps->surfaceCapabilities); vk_foreach_struct(ext, caps->pNext) { @@ -1024,6 +1064,40 @@ wsi_wl_surface_get_capabilities2(VkIcdSurfaceBase *surface, break; } + case VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT: { + /* Unsupported. */ + VkSurfacePresentScalingCapabilitiesEXT *scaling = (void *)ext; + scaling->supportedPresentScaling = 0; + scaling->supportedPresentGravityX = 0; + scaling->supportedPresentGravityY = 0; + scaling->minScaledImageExtent = caps->surfaceCapabilities.minImageExtent; + scaling->maxScaledImageExtent = caps->surfaceCapabilities.maxImageExtent; + break; + } + + case VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT: { + /* Can easily toggle between FIFO and MAILBOX on Wayland. */ + assert(present_mode); + VkSurfacePresentModeCompatibilityEXT *compat = (void *)ext; + if (compat->pPresentModes) { + VK_OUTARRAY_MAKE_TYPED(VkPresentModeKHR, modes, compat->pPresentModes, &compat->presentModeCount); + /* Must always return queried present mode even when truncating. */ + vk_outarray_append_typed(VkPresentModeKHR, &modes, mode) { + *mode = present_mode->presentMode; + } + for (unsigned i = 0; i < ARRAY_SIZE(present_modes); i++) { + if (present_modes[i] != present_mode->presentMode) { + vk_outarray_append_typed(VkPresentModeKHR, &modes, mode) { + *mode = present_modes[i]; + } + } + } + } else { + compat->presentModeCount = ARRAY_SIZE(present_modes); + } + break; + } + default: /* Ignored */ break; @@ -1461,6 +1535,27 @@ wsi_wl_swapchain_get_wsi_image(struct wsi_swapchain *wsi_chain, } static VkResult +wsi_wl_swapchain_release_images(struct wsi_swapchain *wsi_chain, + uint32_t count, const uint32_t *indices) +{ + struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain; + for (uint32_t i = 0; i < count; i++) { + uint32_t index = indices[i]; + assert(chain->images[index].busy); + chain->images[index].busy = false; + } + return VK_SUCCESS; +} + +static void +wsi_wl_swapchain_set_present_mode(struct wsi_swapchain *wsi_chain, + VkPresentModeKHR mode) +{ + struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain; + chain->base.present_mode = mode; +} + +static VkResult wsi_wl_swapchain_acquire_next_image(struct wsi_swapchain *wsi_chain, const VkAcquireNextImageInfoKHR *info, uint32_t *image_index) @@ -1565,13 +1660,14 @@ wsi_wl_swapchain_queue_present(struct wsi_swapchain *wsi_chain, memcpy(image->shm_ptr, image->base.cpu_map, image->base.row_pitches[0] * chain->extent.height); } - if (chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR) { - while (!chain->fifo_ready) { - int ret = wl_display_dispatch_queue(wsi_wl_surface->display->wl_display, - wsi_wl_surface->display->queue); - if (ret < 0) - return VK_ERROR_OUT_OF_DATE_KHR; - } + + /* For EXT_swapchain_maintenance1. We might have transitioned from FIFO to MAILBOX. + * In this case we need to let the FIFO request complete, before presenting MAILBOX. */ + while (!chain->fifo_ready) { + int ret = wl_display_dispatch_queue(wsi_wl_surface->display->wl_display, + wsi_wl_surface->display->queue); + if (ret < 0) + return VK_ERROR_OUT_OF_DATE_KHR; } assert(image_index < chain->base.image_count); @@ -1594,6 +1690,9 @@ wsi_wl_swapchain_queue_present(struct wsi_swapchain *wsi_chain, chain->frame = wl_surface_frame(wsi_wl_surface->surface); wl_callback_add_listener(chain->frame, &frame_listener, chain); chain->fifo_ready = false; + } else { + /* If we present MAILBOX, any subsequent presentation in FIFO can replace this image. */ + chain->fifo_ready = true; } chain->images[image_index].busy = true; @@ -1871,6 +1970,8 @@ wsi_wl_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, chain->base.get_wsi_image = wsi_wl_swapchain_get_wsi_image; chain->base.acquire_next_image = wsi_wl_swapchain_acquire_next_image; chain->base.queue_present = wsi_wl_swapchain_queue_present; + chain->base.release_images = wsi_wl_swapchain_release_images; + chain->base.set_present_mode = wsi_wl_swapchain_set_present_mode; chain->base.present_mode = wsi_swapchain_get_present_mode(wsi_device, pCreateInfo); chain->base.image_count = num_images; chain->extent = pCreateInfo->imageExtent; -- 2.7.4