mirror of
https://github.com/libretro/RetroArch
synced 2025-04-15 23:42:30 +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 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
|
||||
static VKAPI_ATTR VkBool32 VKAPI_CALL vulkan_debug_cb(
|
||||
VkDebugReportFlagsEXT flags,
|
||||
@ -2278,6 +2301,32 @@ bool vulkan_surface_create(gfx_ctx_vulkan_data_t *vk,
|
||||
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)
|
||||
{
|
||||
VkPresentInfoKHR present = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
|
||||
@ -2304,10 +2353,14 @@ void vulkan_present(gfx_ctx_vulkan_data_t *vk, unsigned index)
|
||||
#endif
|
||||
err = vkQueuePresentKHR(vk->context.queue, &present);
|
||||
|
||||
#ifdef WSI_HARDENING_TEST
|
||||
trigger_spurious_error_vkresult(&err);
|
||||
#endif
|
||||
|
||||
if (err != VK_SUCCESS || result != VK_SUCCESS)
|
||||
{
|
||||
RARCH_LOG("[Vulkan]: QueuePresent failed, invalidating swapchain.\n");
|
||||
vk->context.invalid_swapchain = true;
|
||||
RARCH_LOG("[Vulkan]: QueuePresent failed, destroying swapchain.\n");
|
||||
vulkan_destroy_swapchain(vk);
|
||||
}
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
@ -2325,12 +2378,8 @@ void vulkan_context_destroy(gfx_ctx_vulkan_data_t *vk,
|
||||
|
||||
if (vk->context.device)
|
||||
vkDeviceWaitIdle(vk->context.device);
|
||||
if (vk->swapchain)
|
||||
{
|
||||
vkDestroySwapchainKHR(vk->context.device,
|
||||
vk->swapchain, NULL);
|
||||
vk->swapchain = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
vulkan_destroy_swapchain(vk);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
if (vk->context.debug_callback)
|
||||
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 };
|
||||
VkSemaphoreCreateInfo sem_info =
|
||||
{ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
|
||||
bool is_retrying = false;
|
||||
|
||||
bool is_retrying = false;
|
||||
|
||||
retry:
|
||||
if (vk->swapchain == VK_NULL_HANDLE)
|
||||
{
|
||||
/* 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;
|
||||
vulkan_acquire_clear_fences(vk);
|
||||
vulkan_acquire_wait_fences(vk);
|
||||
vk->context.invalid_swapchain = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
retry:
|
||||
vkCreateFence(vk->context.device, &fence_info, NULL, &fence);
|
||||
|
||||
err = vkAcquireNextImageKHR(vk->context.device,
|
||||
vk->swapchain, UINT64_MAX,
|
||||
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)
|
||||
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);
|
||||
|
||||
vulkan_acquire_wait_fences(vk);
|
||||
|
||||
if (err != VK_SUCCESS)
|
||||
if (err == VK_ERROR_OUT_OF_DATE_KHR)
|
||||
{
|
||||
/* Throw away the old swapchain and try again. */
|
||||
vulkan_destroy_swapchain(vk);
|
||||
|
||||
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
|
||||
{
|
||||
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;
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
RARCH_ERR("[Vulkan]: Swapchain is out of date, trying to create new one.\n");
|
||||
is_retrying = true;
|
||||
vulkan_acquire_clear_fences(vk);
|
||||
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,
|
||||
@ -2511,6 +2563,7 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
|
||||
VkCompositeAlphaFlagBitsKHR composite = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
|
||||
vkDeviceWaitIdle(vk->context.device);
|
||||
vulkan_acquire_clear_fences(vk);
|
||||
|
||||
vk->created_new_swapchain = true;
|
||||
if (vk->swapchain != VK_NULL_HANDLE &&
|
||||
@ -2613,10 +2666,8 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
|
||||
else
|
||||
swapchain_size = surface_properties.currentExtent;
|
||||
|
||||
#if 0
|
||||
/* Tests for deferred creation. */
|
||||
static unsigned retry_count = 0;
|
||||
if (++retry_count < 50)
|
||||
#ifdef WSI_HARDENING_TEST
|
||||
if (trigger_spurious_error())
|
||||
{
|
||||
surface_properties.maxImageExtent.width = 0;
|
||||
surface_properties.maxImageExtent.height = 0;
|
||||
@ -2657,11 +2708,7 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
|
||||
* 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
|
||||
* 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. */
|
||||
if (desired_swapchain_images < surface_properties.minImageCount)
|
||||
@ -2763,8 +2810,7 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
|
||||
RARCH_LOG("[Vulkan]: Got %u swapchain images.\n",
|
||||
vk->context.num_swapchain_images);
|
||||
|
||||
vulkan_acquire_clear_fences(vk);
|
||||
/* Force driver to reset swapchain image handles. */
|
||||
vk->context.invalid_swapchain = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user