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 af42f0c80f)

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/40752>
This commit is contained in:
Yiwei Zhang 2026-03-21 15:36:20 -07:00 committed by Eric Engestrom
parent 0287336eea
commit 4feda37353
2 changed files with 84 additions and 3 deletions

View file

@ -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

View file

@ -26,6 +26,9 @@
#include <stdio.h>
#include <string.h>
#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;
}