mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-02-24 09:39:55 +00:00
vulkan: Better VkResult handling
This commit is contained in:
parent
6d6b281270
commit
91ef202ee7
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user