mirror of
https://github.com/libretro/RetroArch
synced 2025-04-16 17:43:02 +00:00
Merge pull request #6945 from Themaister/master
Vulkan: WSI stability fixes
This commit is contained in:
commit
63a071b85a
@ -43,6 +43,29 @@ static VkInstance cached_instance_vk;
|
|||||||
static VkDevice cached_device_vk;
|
static VkDevice cached_device_vk;
|
||||||
static retro_vulkan_destroy_device_t cached_destroy_device_vk;
|
static retro_vulkan_destroy_device_t cached_destroy_device_vk;
|
||||||
|
|
||||||
|
//#define WSI_HARDENING_TEST
|
||||||
|
#ifdef WSI_HARDENING_TEST
|
||||||
|
static unsigned wsi_harden_counter = 0;
|
||||||
|
static unsigned wsi_harden_counter2 = 0;
|
||||||
|
|
||||||
|
static void trigger_spurious_error_vkresult(VkResult *res)
|
||||||
|
{
|
||||||
|
++wsi_harden_counter;
|
||||||
|
if ((wsi_harden_counter & 15) == 12)
|
||||||
|
*res = VK_ERROR_OUT_OF_DATE_KHR;
|
||||||
|
else if ((wsi_harden_counter & 31) == 13)
|
||||||
|
*res = VK_ERROR_OUT_OF_DATE_KHR;
|
||||||
|
else if ((wsi_harden_counter & 15) == 6)
|
||||||
|
*res = VK_ERROR_SURFACE_LOST_KHR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool trigger_spurious_error(void)
|
||||||
|
{
|
||||||
|
++wsi_harden_counter2;
|
||||||
|
return ((wsi_harden_counter2 & 15) == 9) || ((wsi_harden_counter2 & 15) == 10);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef VULKAN_DEBUG
|
#ifdef VULKAN_DEBUG
|
||||||
static VKAPI_ATTR VkBool32 VKAPI_CALL vulkan_debug_cb(
|
static VKAPI_ATTR VkBool32 VKAPI_CALL vulkan_debug_cb(
|
||||||
VkDebugReportFlagsEXT flags,
|
VkDebugReportFlagsEXT flags,
|
||||||
@ -2278,6 +2301,32 @@ bool vulkan_surface_create(gfx_ctx_vulkan_data_t *vk,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void vulkan_destroy_swapchain(gfx_ctx_vulkan_data_t *vk)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
if (vk->swapchain != VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
vkDeviceWaitIdle(vk->context.device);
|
||||||
|
vkDestroySwapchainKHR(vk->context.device, vk->swapchain, NULL);
|
||||||
|
memset(vk->context.swapchain_images, 0, sizeof(vk->context.swapchain_images));
|
||||||
|
vk->swapchain = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < VULKAN_MAX_SWAPCHAIN_IMAGES; i++)
|
||||||
|
{
|
||||||
|
if (vk->context.swapchain_semaphores[i] != VK_NULL_HANDLE)
|
||||||
|
vkDestroySemaphore(vk->context.device,
|
||||||
|
vk->context.swapchain_semaphores[i], NULL);
|
||||||
|
if (vk->context.swapchain_fences[i] != VK_NULL_HANDLE)
|
||||||
|
vkDestroyFence(vk->context.device,
|
||||||
|
vk->context.swapchain_fences[i], NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(vk->context.swapchain_semaphores, 0, sizeof(vk->context.swapchain_semaphores));
|
||||||
|
memset(vk->context.swapchain_fences, 0, sizeof(vk->context.swapchain_fences));
|
||||||
|
}
|
||||||
|
|
||||||
void vulkan_present(gfx_ctx_vulkan_data_t *vk, unsigned index)
|
void vulkan_present(gfx_ctx_vulkan_data_t *vk, unsigned index)
|
||||||
{
|
{
|
||||||
VkPresentInfoKHR present = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
|
VkPresentInfoKHR present = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
|
||||||
@ -2304,10 +2353,14 @@ void vulkan_present(gfx_ctx_vulkan_data_t *vk, unsigned index)
|
|||||||
#endif
|
#endif
|
||||||
err = vkQueuePresentKHR(vk->context.queue, &present);
|
err = vkQueuePresentKHR(vk->context.queue, &present);
|
||||||
|
|
||||||
|
#ifdef WSI_HARDENING_TEST
|
||||||
|
trigger_spurious_error_vkresult(&err);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (err != VK_SUCCESS || result != VK_SUCCESS)
|
if (err != VK_SUCCESS || result != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
RARCH_LOG("[Vulkan]: QueuePresent failed, invalidating swapchain.\n");
|
RARCH_LOG("[Vulkan]: QueuePresent failed, destroying swapchain.\n");
|
||||||
vk->context.invalid_swapchain = true;
|
vulkan_destroy_swapchain(vk);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_THREADS
|
#ifdef HAVE_THREADS
|
||||||
@ -2325,12 +2378,8 @@ void vulkan_context_destroy(gfx_ctx_vulkan_data_t *vk,
|
|||||||
|
|
||||||
if (vk->context.device)
|
if (vk->context.device)
|
||||||
vkDeviceWaitIdle(vk->context.device);
|
vkDeviceWaitIdle(vk->context.device);
|
||||||
if (vk->swapchain)
|
|
||||||
{
|
vulkan_destroy_swapchain(vk);
|
||||||
vkDestroySwapchainKHR(vk->context.device,
|
|
||||||
vk->swapchain, NULL);
|
|
||||||
vk->swapchain = VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (destroy_surface && vk->vk_surface != VK_NULL_HANDLE)
|
if (destroy_surface && vk->vk_surface != VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
@ -2339,16 +2388,6 @@ void vulkan_context_destroy(gfx_ctx_vulkan_data_t *vk,
|
|||||||
vk->vk_surface = VK_NULL_HANDLE;
|
vk->vk_surface = VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < VULKAN_MAX_SWAPCHAIN_IMAGES; i++)
|
|
||||||
{
|
|
||||||
if (vk->context.swapchain_semaphores[i] != VK_NULL_HANDLE)
|
|
||||||
vkDestroySemaphore(vk->context.device,
|
|
||||||
vk->context.swapchain_semaphores[i], NULL);
|
|
||||||
if (vk->context.swapchain_fences[i] != VK_NULL_HANDLE)
|
|
||||||
vkDestroyFence(vk->context.device,
|
|
||||||
vk->context.swapchain_fences[i], NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef VULKAN_DEBUG
|
#ifdef VULKAN_DEBUG
|
||||||
if (vk->context.debug_callback)
|
if (vk->context.debug_callback)
|
||||||
vkDestroyDebugReportCallbackEXT(vk->context.instance, vk->context.debug_callback, NULL);
|
vkDestroyDebugReportCallbackEXT(vk->context.instance, vk->context.debug_callback, NULL);
|
||||||
@ -2423,8 +2462,10 @@ void vulkan_acquire_next_image(gfx_ctx_vulkan_data_t *vk)
|
|||||||
{ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
|
{ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
|
||||||
VkSemaphoreCreateInfo sem_info =
|
VkSemaphoreCreateInfo sem_info =
|
||||||
{ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
|
{ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
|
||||||
|
|
||||||
bool is_retrying = false;
|
bool is_retrying = false;
|
||||||
|
|
||||||
|
retry:
|
||||||
if (vk->swapchain == VK_NULL_HANDLE)
|
if (vk->swapchain == VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
/* We don't have a swapchain, try to create one now. */
|
/* We don't have a swapchain, try to create one now. */
|
||||||
@ -2441,52 +2482,63 @@ void vulkan_acquire_next_image(gfx_ctx_vulkan_data_t *vk)
|
|||||||
vk->context.current_swapchain_index = 0;
|
vk->context.current_swapchain_index = 0;
|
||||||
vulkan_acquire_clear_fences(vk);
|
vulkan_acquire_clear_fences(vk);
|
||||||
vulkan_acquire_wait_fences(vk);
|
vulkan_acquire_wait_fences(vk);
|
||||||
|
vk->context.invalid_swapchain = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
retry:
|
|
||||||
vkCreateFence(vk->context.device, &fence_info, NULL, &fence);
|
vkCreateFence(vk->context.device, &fence_info, NULL, &fence);
|
||||||
|
|
||||||
err = vkAcquireNextImageKHR(vk->context.device,
|
err = vkAcquireNextImageKHR(vk->context.device,
|
||||||
vk->swapchain, UINT64_MAX,
|
vk->swapchain, UINT64_MAX,
|
||||||
VK_NULL_HANDLE, fence, &vk->context.current_swapchain_index);
|
VK_NULL_HANDLE, fence, &vk->context.current_swapchain_index);
|
||||||
|
|
||||||
index = vk->context.current_swapchain_index;
|
|
||||||
if (vk->context.swapchain_semaphores[index] == VK_NULL_HANDLE)
|
|
||||||
vkCreateSemaphore(vk->context.device, &sem_info,
|
|
||||||
NULL, &vk->context.swapchain_semaphores[index]);
|
|
||||||
|
|
||||||
if (err == VK_SUCCESS)
|
if (err == VK_SUCCESS)
|
||||||
vkWaitForFences(vk->context.device, 1, &fence, true, UINT64_MAX);
|
vkWaitForFences(vk->context.device, 1, &fence, true, UINT64_MAX);
|
||||||
|
|
||||||
|
#ifdef WSI_HARDENING_TEST
|
||||||
|
trigger_spurious_error_vkresult(&err);
|
||||||
|
#endif
|
||||||
|
|
||||||
vkDestroyFence(vk->context.device, fence, NULL);
|
vkDestroyFence(vk->context.device, fence, NULL);
|
||||||
|
|
||||||
vulkan_acquire_wait_fences(vk);
|
if (err == VK_ERROR_OUT_OF_DATE_KHR)
|
||||||
|
|
||||||
if (err != VK_SUCCESS)
|
|
||||||
{
|
{
|
||||||
|
/* Throw away the old swapchain and try again. */
|
||||||
|
vulkan_destroy_swapchain(vk);
|
||||||
|
|
||||||
if (is_retrying)
|
if (is_retrying)
|
||||||
{
|
{
|
||||||
RARCH_ERR("[Vulkan]: Tried acquring next swapchain image after creating new one, but failed ...\n");
|
RARCH_ERR("[Vulkan]: Swapchain is out of date, trying to create new one. Have tried multiple times ...\n");
|
||||||
|
retro_sleep(10);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
RARCH_ERR("[Vulkan]: Swapchain is out of date, trying to create new one.\n");
|
||||||
RARCH_LOG("[Vulkan]: AcquireNextImage failed, invalidating swapchain.\n");
|
|
||||||
vk->context.invalid_swapchain = true;
|
|
||||||
|
|
||||||
RARCH_LOG("[Vulkan]: AcquireNextImage failed, so trying to recreate swapchain.\n");
|
|
||||||
if (!vulkan_create_swapchain(vk, vk->context.swapchain_width,
|
|
||||||
vk->context.swapchain_height, vk->context.swap_interval))
|
|
||||||
{
|
|
||||||
RARCH_ERR("[Vulkan]: Failed to create new swapchain.\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
is_retrying = true;
|
is_retrying = true;
|
||||||
|
vulkan_acquire_clear_fences(vk);
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
else if (err != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
/* We are screwed, don't try anymore. Maybe it will work later. */
|
||||||
|
vulkan_destroy_swapchain(vk);
|
||||||
|
RARCH_ERR("[Vulkan]: Failed to acquire from swapchain (err = %d).\n",
|
||||||
|
(int)err);
|
||||||
|
if (err == VK_ERROR_SURFACE_LOST_KHR)
|
||||||
|
RARCH_ERR("[Vulkan]: Got VK_ERROR_SURFACE_LOST_KHR.\n");
|
||||||
|
/* Force driver to reset swapchain image handles. */
|
||||||
|
vk->context.invalid_swapchain = true;
|
||||||
|
vulkan_acquire_clear_fences(vk);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
index = vk->context.current_swapchain_index;
|
||||||
|
if (vk->context.swapchain_semaphores[index] == VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
vkCreateSemaphore(vk->context.device, &sem_info,
|
||||||
|
NULL, &vk->context.swapchain_semaphores[index]);
|
||||||
}
|
}
|
||||||
|
vulkan_acquire_wait_fences(vk);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
|
bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
|
||||||
@ -2511,6 +2563,7 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
|
|||||||
VkCompositeAlphaFlagBitsKHR composite = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
VkCompositeAlphaFlagBitsKHR composite = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||||
|
|
||||||
vkDeviceWaitIdle(vk->context.device);
|
vkDeviceWaitIdle(vk->context.device);
|
||||||
|
vulkan_acquire_clear_fences(vk);
|
||||||
|
|
||||||
vk->created_new_swapchain = true;
|
vk->created_new_swapchain = true;
|
||||||
if (vk->swapchain != VK_NULL_HANDLE &&
|
if (vk->swapchain != VK_NULL_HANDLE &&
|
||||||
@ -2613,10 +2666,8 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
|
|||||||
else
|
else
|
||||||
swapchain_size = surface_properties.currentExtent;
|
swapchain_size = surface_properties.currentExtent;
|
||||||
|
|
||||||
#if 0
|
#ifdef WSI_HARDENING_TEST
|
||||||
/* Tests for deferred creation. */
|
if (trigger_spurious_error())
|
||||||
static unsigned retry_count = 0;
|
|
||||||
if (++retry_count < 50)
|
|
||||||
{
|
{
|
||||||
surface_properties.maxImageExtent.width = 0;
|
surface_properties.maxImageExtent.width = 0;
|
||||||
surface_properties.maxImageExtent.height = 0;
|
surface_properties.maxImageExtent.height = 0;
|
||||||
@ -2657,10 +2708,6 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
|
|||||||
* We hard sync against the swapchain, so if we have 2 images,
|
* We hard sync against the swapchain, so if we have 2 images,
|
||||||
* we would be unable to overlap CPU and GPU, which can get very slow
|
* we would be unable to overlap CPU and GPU, which can get very slow
|
||||||
* for GPU-rendered cores. */
|
* for GPU-rendered cores. */
|
||||||
desired_swapchain_images = 3;
|
|
||||||
|
|
||||||
/* Limit latency. */
|
|
||||||
if (desired_swapchain_images > settings->uints.video_max_swapchain_images)
|
|
||||||
desired_swapchain_images = settings->uints.video_max_swapchain_images;
|
desired_swapchain_images = settings->uints.video_max_swapchain_images;
|
||||||
|
|
||||||
/* Clamp images requested to what is supported by the implementation. */
|
/* Clamp images requested to what is supported by the implementation. */
|
||||||
@ -2763,8 +2810,7 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
|
|||||||
RARCH_LOG("[Vulkan]: Got %u swapchain images.\n",
|
RARCH_LOG("[Vulkan]: Got %u swapchain images.\n",
|
||||||
vk->context.num_swapchain_images);
|
vk->context.num_swapchain_images);
|
||||||
|
|
||||||
vulkan_acquire_clear_fences(vk);
|
/* Force driver to reset swapchain image handles. */
|
||||||
vk->context.invalid_swapchain = true;
|
vk->context.invalid_swapchain = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user