mirror of https://github.com/RPCS3/rpcs3.git
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)
|
void VKGSRender::flip(int buffer)
|
||||||
{
|
{
|
||||||
|
@ -2399,8 +2465,12 @@ void VKGSRender::flip(int buffer)
|
||||||
|
|
||||||
continue;
|
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:
|
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
|
else
|
||||||
{
|
{
|
||||||
/**
|
//Recreate the swapchain to resize it
|
||||||
* Waiting for the commands to process does not work reliably as the fence can be signaled before swap images are released
|
//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
|
||||||
* and there are no explicit methods to ensure that the presentation engine is not using the images at all.
|
reinitialize_swapchain();
|
||||||
*/
|
|
||||||
|
|
||||||
//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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::chrono::time_point<steady_clock> flip_end = steady_clock::now();
|
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 process_swap_request(frame_context_t *ctx, bool free_resources = false);
|
||||||
void advance_queued_frames();
|
void advance_queued_frames();
|
||||||
void present(frame_context_t *ctx);
|
void present(frame_context_t *ctx);
|
||||||
|
void reinitialize_swapchain();
|
||||||
|
|
||||||
void begin_render_pass();
|
void begin_render_pass();
|
||||||
void close_render_pass();
|
void close_render_pass();
|
||||||
|
|
|
@ -373,6 +373,104 @@ namespace vk
|
||||||
return (g_num_processed_frames > 0)? g_num_processed_frames - 1: 0;
|
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,
|
VKAPI_ATTR VkBool32 VKAPI_CALL dbgFunc(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType,
|
||||||
uint64_t srcObject, size_t location, int32_t msgCode,
|
uint64_t srcObject, size_t location, int32_t msgCode,
|
||||||
const char *pLayerPrefix, const char *pMsg, void *pUserData)
|
const char *pLayerPrefix, const char *pMsg, void *pUserData)
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace rsx
|
||||||
|
|
||||||
namespace vk
|
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_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);
|
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_current_frame_id();
|
||||||
const u64 get_last_completed_frame_id();
|
const u64 get_last_completed_frame_id();
|
||||||
|
|
||||||
|
void die_with_error(std::string faulting_addr, VkResult error_code);
|
||||||
|
|
||||||
struct memory_type_mapping
|
struct memory_type_mapping
|
||||||
{
|
{
|
||||||
uint32_t host_visible_coherent;
|
uint32_t host_visible_coherent;
|
||||||
|
|
Loading…
Reference in New Issue