vulkan: Better VkResult handling

This commit is contained in:
kd-11 2017-10-10 00:03:08 +03:00
parent 6d6b281270
commit 91ef202ee7
4 changed files with 176 additions and 65 deletions

View File

@ -2271,6 +2271,72 @@ void VKGSRender::prepare_rtts()
}
}
void VKGSRender::reinitialize_swapchain()
{
/**
* Waiting for the commands to process does not work reliably as the fence can be signaled before swap images are released
* and there are no explicit methods to ensure that the presentation engine is not using the images at all.
*/
//NOTE: This operation will create a hard sync point
close_and_submit_command_buffer({}, m_current_command_buffer->submit_fence);
m_current_command_buffer->pending = true;
m_current_command_buffer->reset();
//Will have to block until rendering is completed
VkFence resize_fence = VK_NULL_HANDLE;
VkFenceCreateInfo infos = {};
infos.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
vkCreateFence((*m_device), &infos, nullptr, &resize_fence);
for (auto &ctx : frame_context_storage)
{
if (ctx.present_image == UINT32_MAX)
continue;
//Release present image by presenting it
ctx.swap_command_buffer->wait();
ctx.swap_command_buffer = nullptr;
present(&ctx);
}
vkQueueWaitIdle(m_swap_chain->get_present_queue());
vkDeviceWaitIdle(*m_device);
//Remove any old refs to the old images as they are about to be destroyed
m_framebuffers_to_clean.clear();
//Rebuild swapchain. Old swapchain destruction is handled by the init_swapchain call
m_client_width = m_frame->client_width();
m_client_height = m_frame->client_height();
m_swap_chain->init_swapchain(m_client_width, m_client_height);
//Prepare new swapchain images for use
open_command_buffer();
for (u32 i = 0; i < m_swap_chain->get_swap_image_count(); ++i)
{
vk::change_image_layout(*m_current_command_buffer, m_swap_chain->get_swap_chain_image(i),
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL,
vk::get_image_subresource_range(0, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT));
VkClearColorValue clear_color{};
auto range = vk::get_image_subresource_range(0, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT);
vkCmdClearColorImage(*m_current_command_buffer, m_swap_chain->get_swap_chain_image(i), VK_IMAGE_LAYOUT_GENERAL, &clear_color, 1, &range);
vk::change_image_layout(*m_current_command_buffer, m_swap_chain->get_swap_chain_image(i),
VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
vk::get_image_subresource_range(0, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT));
}
//Flush the command buffer
close_and_submit_command_buffer({}, resize_fence);
CHECK_RESULT(vkWaitForFences((*m_device), 1, &resize_fence, VK_TRUE, UINT64_MAX));
vkDestroyFence((*m_device), resize_fence, nullptr);
m_current_command_buffer->reset();
open_command_buffer();
}
void VKGSRender::flip(int buffer)
{
@ -2399,8 +2465,12 @@ void VKGSRender::flip(int buffer)
continue;
}
case VK_ERROR_OUT_OF_DATE_KHR:
LOG_ERROR(RSX, "vkAcquireNextImageKHR failed with VK_ERROR_OUT_OF_DATE_KHR. Flip request ignored until surface is recreated.");
reinitialize_swapchain();
return;
default:
fmt::throw_exception("vkAcquireNextImageKHR failed with status 0x%X" HERE, (u32)status);
vk::die_with_error(HERE, status);
}
}
@ -2489,69 +2559,9 @@ void VKGSRender::flip(int buffer)
}
else
{
/**
* Waiting for the commands to process does not work reliably as the fence can be signaled before swap images are released
* and there are no explicit methods to ensure that the presentation engine is not using the images at all.
*/
//NOTE: This operation will create a hard sync point
close_and_submit_command_buffer({}, m_current_command_buffer->submit_fence);
m_current_command_buffer->pending = true;
m_current_command_buffer->reset();
//Will have to block until rendering is completed
VkFence resize_fence = VK_NULL_HANDLE;
VkFenceCreateInfo infos = {};
infos.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
vkCreateFence((*m_device), &infos, nullptr, &resize_fence);
for (auto &ctx : frame_context_storage)
{
if (ctx.present_image == UINT32_MAX)
continue;
//Release present image by presenting it
ctx.swap_command_buffer->wait();
ctx.swap_command_buffer = nullptr;
present(&ctx);
}
vkQueueWaitIdle(m_swap_chain->get_present_queue());
vkDeviceWaitIdle(*m_device);
//Remove any old refs to the old images as they are about to be destroyed
m_framebuffers_to_clean.clear();
//Rebuild swapchain. Old swapchain destruction is handled by the init_swapchain call
m_client_width = m_frame->client_width();
m_client_height = m_frame->client_height();
m_swap_chain->init_swapchain(m_client_width, m_client_height);
//Prepare new swapchain images for use
open_command_buffer();
for (u32 i = 0; i < m_swap_chain->get_swap_image_count(); ++i)
{
vk::change_image_layout(*m_current_command_buffer, m_swap_chain->get_swap_chain_image(i),
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL,
vk::get_image_subresource_range(0, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT));
VkClearColorValue clear_color{};
auto range = vk::get_image_subresource_range(0, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT);
vkCmdClearColorImage(*m_current_command_buffer, m_swap_chain->get_swap_chain_image(i), VK_IMAGE_LAYOUT_GENERAL, &clear_color, 1, &range);
vk::change_image_layout(*m_current_command_buffer, m_swap_chain->get_swap_chain_image(i),
VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
vk::get_image_subresource_range(0, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT));
}
//Flush the command buffer
close_and_submit_command_buffer({}, resize_fence);
CHECK_RESULT(vkWaitForFences((*m_device), 1, &resize_fence, VK_TRUE, UINT64_MAX));
vkDestroyFence((*m_device), resize_fence, nullptr);
m_current_command_buffer->reset();
open_command_buffer();
//Recreate the swapchain to resize it
//NOTE: Nvidia driver does not invalidate the swapchain immediately on window size changes. The event will fire after a while and an OUT_OF_DATE error will be returned in subsequent rendering commands
reinitialize_swapchain();
}
std::chrono::time_point<steady_clock> flip_end = steady_clock::now();

View File

@ -289,6 +289,7 @@ private:
void process_swap_request(frame_context_t *ctx, bool free_resources = false);
void advance_queued_frames();
void present(frame_context_t *ctx);
void reinitialize_swapchain();
void begin_render_pass();
void close_render_pass();

View File

@ -373,6 +373,104 @@ namespace vk
return (g_num_processed_frames > 0)? g_num_processed_frames - 1: 0;
}
void die_with_error(std::string faulting_addr, VkResult error_code)
{
std::string error_message;
int severity = 0; //0 - die, 1 - warn, 2 - nothing
switch (error_code)
{
case VK_SUCCESS:
case VK_EVENT_SET:
case VK_EVENT_RESET:
case VK_INCOMPLETE:
return;
case VK_SUBOPTIMAL_KHR:
error_message = "Present surface is suboptimal (VK_SUBOPTIMAL_KHR)";
severity = 1;
break;
case VK_NOT_READY:
error_message = "Device or resource busy (VK_NOT_READY)";
break;
case VK_TIMEOUT:
error_message = "Timeout event (VK_TIMEOUT)";
break;
case VK_ERROR_OUT_OF_HOST_MEMORY:
error_message = "Out of host memory (system RAM) (VK_ERROR_OUT_OF_HOST_MEMORY)";
break;
case VK_ERROR_OUT_OF_DEVICE_MEMORY:
error_message = "Out of video memory (VRAM) (VK_ERROR_OUT_OF_DEVICE_MEMORY)";
break;
case VK_ERROR_INITIALIZATION_FAILED:
error_message = "Initialization failed (VK_ERROR_INITIALIZATION_FAILED)";
break;
case VK_ERROR_DEVICE_LOST:
error_message = "Device lost (Driver crashed with unspecified error or stopped responding and recovered) (VK_ERROR_DEVICE_LOST)";
break;
case VK_ERROR_MEMORY_MAP_FAILED:
error_message = "Memory map failed (VK_ERROR_MEMORY_MAP_FAILED)";
break;
case VK_ERROR_LAYER_NOT_PRESENT:
error_message = "Requested layer is not available (Try disabling debug output or install vulkan SDK) (VK_ERROR_LAYER_NOT_PRESENT)";
break;
case VK_ERROR_EXTENSION_NOT_PRESENT:
error_message = "Requested extension not available (VK_ERROR_EXTENSION_NOT_PRESENT)";
break;
case VK_ERROR_FEATURE_NOT_PRESENT:
error_message = "Requested feature not available (VK_ERROR_FEATURE_NOT_PRESENT)";
break;
case VK_ERROR_INCOMPATIBLE_DRIVER:
error_message = "Incompatible driver (VK_ERROR_INCOMPATIBLE_DRIVER)";
break;
case VK_ERROR_TOO_MANY_OBJECTS:
error_message = "Too many objects created (Out of handles) (VK_ERROR_TOO_MANY_OBJECTS)";
break;
case VK_ERROR_FORMAT_NOT_SUPPORTED:
error_message = "Format not supported (VK_ERROR_FORMAT_NOT_SUPPORTED)";
break;
case VK_ERROR_FRAGMENTED_POOL:
error_message = "Fragmented pool (VK_ERROR_FRAGMENTED_POOL)";
break;
case VK_ERROR_SURFACE_LOST_KHR:
error_message = "Surface lost (VK_ERROR_SURFACE_LOST)";
break;
case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
error_message = "Native window in use (VK_ERROR_NATIVE_WINDOW_IN_USE_KHR)";
break;
case VK_ERROR_OUT_OF_DATE_KHR:
error_message = "Present surface is out of date (VK_ERROR_OUT_OF_DATE_KHR)";
severity = 1;
break;
case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR:
error_message = "Incompatible display (VK_ERROR_INCOMPATIBLE_DISPLAY_KHR)";
break;
case VK_ERROR_VALIDATION_FAILED_EXT:
error_message = "Validation failed (VK_ERROR_INCOMPATIBLE_DISPLAY_KHR)";
break;
case VK_ERROR_INVALID_SHADER_NV:
error_message = "Invalid shader code (VK_ERROR_INVALID_SHADER_NV)";
break;
case VK_ERROR_OUT_OF_POOL_MEMORY_KHR:
error_message = "Out of pool memory (VK_ERROR_OUT_OF_POOL_MEMORY_KHR)";
break;
case VK_ERROR_INVALID_EXTERNAL_HANDLE_KHX:
error_message = "Invalid external handle (VK_ERROR_INVALID_EXTERNAL_HANDLE_KHX)";
break;
default:
error_message = fmt::format("Unknown Code (%Xh, %d)", (s32)error_code, (s32&)error_code);
break;
}
switch (severity)
{
case 0:
fmt::throw_exception("Assertion Failed! Vulkan API call failed with unrecoverable error: %s", (error_message + faulting_addr).c_str());
case 1:
LOG_ERROR(RSX, "Vulkan API call has failed with an error but will continue: %s", (error_message + faulting_addr).c_str());
break;
}
}
VKAPI_ATTR VkBool32 VKAPI_CALL dbgFunc(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType,
uint64_t srcObject, size_t location, int32_t msgCode,
const char *pLayerPrefix, const char *pMsg, void *pUserData)

View File

@ -36,7 +36,7 @@ namespace rsx
namespace vk
{
#define CHECK_RESULT(expr) { VkResult _res = (expr); if (_res != VK_SUCCESS) fmt::throw_exception("Assertion failed! Result is %Xh" HERE, (s32)_res); }
#define CHECK_RESULT(expr) { VkResult _res = (expr); if (_res != VK_SUCCESS) vk::die_with_error(HERE, _res); }
VKAPI_ATTR void *VKAPI_CALL mem_realloc(void *pUserData, void *pOriginal, size_t size, size_t alignment, VkSystemAllocationScope allocationScope);
VKAPI_ATTR void *VKAPI_CALL mem_alloc(void *pUserData, size_t size, size_t alignment, VkSystemAllocationScope allocationScope);
@ -94,6 +94,8 @@ namespace vk
const u64 get_current_frame_id();
const u64 get_last_completed_frame_id();
void die_with_error(std::string faulting_addr, VkResult error_code);
struct memory_type_mapping
{
uint32_t host_visible_coherent;