zink: defer swapchain updates for interval changes if acquired image is active

in the case where an app triggers a swap interval change mid-frame, this handling
previously triggered an immediate swapchain retire and then presented the new swapchain
which had yet to be rendered to

instead, defer swapchain updates to immediately after present when things are
safe to ensure that the right image is always presented

Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/14104

cc: mesa-stable

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/37894>
This commit is contained in:
Mike Blumenkrantz
2025-10-15 12:25:38 -04:00
parent 673351bbf3
commit db9dbcbec0

View File

@@ -931,6 +931,12 @@ zink_kopper_present_queue(struct zink_screen *screen, struct zink_resource *res,
memset(&res->damage, 0, sizeof(res->damage));
cdt->swapchain->images[res->obj->dt_idx].acquired = NULL;
res->obj->dt_idx = UINT32_MAX;
/* pick up pending present mode updates here */
if (cdt->present_mode != cdt->swapchain->scci.presentMode) {
VkResult ret = update_swapchain(screen, cdt, cdt->caps.currentExtent.width, cdt->caps.currentExtent.height);
if (ret != VK_SUCCESS)
mesa_loge("zink: failed to set swap interval!");
}
}
void
@@ -1202,11 +1208,13 @@ zink_kopper_set_swap_interval(struct pipe_screen *pscreen, struct pipe_resource
if (old_present_mode == cdt->present_mode)
return;
VkResult ret = update_swapchain(screen, cdt, cdt->caps.currentExtent.width, cdt->caps.currentExtent.height);
if (ret == VK_SUCCESS)
return;
cdt->present_mode = old_present_mode;
mesa_loge("zink: failed to set swap interval!");
if (res->obj->dt_idx == UINT32_MAX) {
/* only update swapchain when there is no current acquire to avoid flickering */
VkResult ret = update_swapchain(screen, cdt, cdt->caps.currentExtent.width, cdt->caps.currentExtent.height);
if (ret != VK_SUCCESS)
mesa_loge("zink: failed to set swap interval!");
}
}
int