Merge pull request #6945 from Themaister/master

Vulkan: WSI stability fixes
This commit is contained in:
Twinaphex 2018-07-04 21:04:08 +02:00 committed by GitHub
commit 63a071b85a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

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