From 4feda37353d3892667b29f9301636bd726e1f86f Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Sat, 21 Mar 2026 15:36:20 -0700 Subject: [PATCH] vulkan/wsi/win32: respect acquire timeout for sw wsi When DXGI is not supported, win32 falls back to sw wsi without acquire timeout ignored. This change: 1. adds the needed acquire mutex and cond - the fail path is intentionally left untouched so that mutex and cond are both valid when wsi_win32_swapchain_destroy is called 2. adds wsi_win32_acquire_idle_cpu_image helper to respect timeout 3. adds wsi_win32_set_image_idle helper to properly signal acquire_cond for sw wsi case Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/15122 Cc: mesa-stable (cherry picked from commit af42f0c80fd4e86f2ce65b9c53a7427b6a685c26) Part-of: --- .pick_status.json | 2 +- src/vulkan/wsi/wsi_common_win32.cpp | 85 ++++++++++++++++++++++++++++- 2 files changed, 84 insertions(+), 3 deletions(-) diff --git a/.pick_status.json b/.pick_status.json index 5b72496f84c..98a7870cb83 100644 --- a/.pick_status.json +++ b/.pick_status.json @@ -624,7 +624,7 @@ "description": "vulkan/wsi/win32: respect acquire timeout for sw wsi", "nominated": true, "nomination_type": 1, - "resolution": 0, + "resolution": 1, "main_sha": null, "because_sha": null, "notes": null diff --git a/src/vulkan/wsi/wsi_common_win32.cpp b/src/vulkan/wsi/wsi_common_win32.cpp index db3730aeb03..4b822a8c6dd 100644 --- a/src/vulkan/wsi/wsi_common_win32.cpp +++ b/src/vulkan/wsi/wsi_common_win32.cpp @@ -26,6 +26,9 @@ #include #include +#include "util/cnd_monotonic.h" +#include "util/timespec.h" +#include "util/u_thread.h" #include "vk_format.h" #include "vk_instance.h" #include "vk_physical_device.h" @@ -100,6 +103,8 @@ struct wsi_win32_swapchain { IDXGISwapChain3 *dxgi; struct wsi_win32 *wsi; wsi_win32_surface *surface; + mtx_t acquire_mutex; + struct u_cnd_monotonic acquire_cond; uint64_t flip_sequence; VkResult status; VkExtent2D extent; @@ -592,6 +597,10 @@ wsi_win32_swapchain_destroy(struct wsi_swapchain *drv_chain, chain->dxgi->Release(); wsi_swapchain_finish(&chain->base); + + u_cnd_monotonic_destroy(&chain->acquire_cond); + mtx_destroy(&chain->acquire_mutex); + vk_free(allocator, chain); return VK_SUCCESS; } @@ -606,6 +615,21 @@ wsi_win32_get_wsi_image(struct wsi_swapchain *drv_chain, return &chain->images[image_index].base; } +static void +wsi_win32_set_image_idle(struct wsi_win32_swapchain *chain, + struct wsi_win32_image *image) +{ + if (!chain->dxgi) + mtx_lock(&chain->acquire_mutex); + + image->state = WSI_IMAGE_IDLE; + + if (!chain->dxgi) { + u_cnd_monotonic_broadcast(&chain->acquire_cond); + mtx_unlock(&chain->acquire_mutex); + } +} + static VkResult wsi_win32_release_images(struct wsi_swapchain *drv_chain, uint32_t count, const uint32_t *indices) @@ -620,7 +644,7 @@ wsi_win32_release_images(struct wsi_swapchain *drv_chain, uint32_t index = indices[i]; assert(index < chain->base.image_count); assert(chain->images[index].state == WSI_IMAGE_DRAWING); - chain->images[index].state = WSI_IMAGE_IDLE; + wsi_win32_set_image_idle(chain, &chain->images[index]); } return VK_SUCCESS; @@ -640,6 +664,44 @@ wsi_win32_find_idle_image(struct wsi_win32_swapchain *chain, return false; } +static VkResult +wsi_win32_acquire_idle_cpu_image_locked(struct wsi_win32_swapchain *chain, + const VkAcquireNextImageInfoKHR *info, + uint32_t *out_image_index) +{ + if (wsi_win32_find_idle_image(chain, out_image_index)) + return VK_SUCCESS; + + if (info->timeout == 0) + return VK_NOT_READY; + + const uint64_t abs_timeout = os_time_get_absolute_timeout(info->timeout); + struct timespec abs_timespec; + timespec_from_nsec(&abs_timespec, abs_timeout); + do { + int ret = u_cnd_monotonic_timedwait( + &chain->acquire_cond, &chain->acquire_mutex, &abs_timespec); + if (ret == thrd_timedout) + return VK_TIMEOUT; + else if (ret != thrd_success) + return VK_ERROR_OUT_OF_DATE_KHR; + } while (!wsi_win32_find_idle_image(chain, out_image_index)); + + return VK_SUCCESS; +} + +static inline VkResult +wsi_win32_acquire_idle_cpu_image(struct wsi_win32_swapchain *chain, + const VkAcquireNextImageInfoKHR *info, + uint32_t *out_image_index) +{ + mtx_lock(&chain->acquire_mutex); + VkResult result = wsi_win32_acquire_idle_cpu_image_locked(chain, info, + out_image_index); + mtx_unlock(&chain->acquire_mutex); + return result; +} + static VkResult wsi_win32_acquire_next_image(struct wsi_swapchain *drv_chain, const VkAcquireNextImageInfoKHR *info, @@ -652,6 +714,10 @@ wsi_win32_acquire_next_image(struct wsi_swapchain *drv_chain, if (chain->status != VK_SUCCESS) return chain->status; + /* acquire timeout has to be explicitly handled for sw wsi */ + if (!chain->dxgi) + return wsi_win32_acquire_idle_cpu_image(chain, info, image_index); + if (wsi_win32_find_idle_image(chain, image_index)) return VK_SUCCESS; @@ -743,7 +809,7 @@ wsi_win32_queue_present(struct wsi_swapchain *drv_chain, if (!StretchBlt(chain->chain_dc, 0, 0, chain->extent.width, chain->extent.height, image->sw.dc, 0, 0, chain->extent.width, chain->extent.height, SRCCOPY)) chain->status = VK_ERROR_MEMORY_MAP_FAILED; - image->state = WSI_IMAGE_IDLE; + wsi_win32_set_image_idle(chain, image); return chain->status; } @@ -847,6 +913,19 @@ wsi_win32_surface_create_swapchain( if (chain == NULL) return VK_ERROR_OUT_OF_HOST_MEMORY; + int ret = mtx_init(&chain->acquire_mutex, mtx_plain); + if (ret != thrd_success) { + vk_free(allocator, chain); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + ret = u_cnd_monotonic_init(&chain->acquire_cond); + if (ret != thrd_success) { + mtx_destroy(&chain->acquire_mutex); + vk_free(allocator, chain); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + struct wsi_dxgi_image_params dxgi_image_params = { { WSI_IMAGE_TYPE_DXGI }, }; @@ -866,6 +945,8 @@ wsi_win32_surface_create_swapchain( create_info, image_params, allocator); if (result != VK_SUCCESS) { + u_cnd_monotonic_destroy(&chain->acquire_cond); + mtx_destroy(&chain->acquire_mutex); vk_free(allocator, chain); return result; }