From 0ec88bb65d8a990c27cd9ab1cf7ebe9e0d2f4240 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sun, 23 Apr 2017 17:17:05 +0300 Subject: [PATCH] vulkan: Mark of critical code from allowing cb split in exception handler vk: Shader loads are sacred --- rpcs3/Emu/RSX/VK/VKGSRender.cpp | 21 ++++++++++++++++++--- rpcs3/Emu/RSX/VK/VKHelpers.cpp | 17 +++++++++++++++++ rpcs3/Emu/RSX/VK/VKHelpers.h | 4 ++++ rpcs3/Emu/RSX/VK/VKTextureCache.h | 5 +++++ 4 files changed, 44 insertions(+), 3 deletions(-) diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 3b9ef001bb..cec6d34ba6 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -682,7 +682,10 @@ bool VKGSRender::on_access_violation(u32 address, bool is_writing) else { //NOTE: If the rsx::thread is trampling its own data, we have an operation that should be moved to the GPU - flush_command_queue(); + //We should never interrupt our own cb recording since some operations are not interruptible + if (!vk::is_uninterruptible()) + //TODO: Investigate driver behaviour to determine if we need a hard sync or a soft flush + flush_command_queue(); } } @@ -844,8 +847,10 @@ void VKGSRender::end() std::chrono::time_point textures_end = steady_clock::now(); m_textures_upload_time += std::chrono::duration_cast(textures_end - textures_start).count(); - //upload_vertex_data is a memory op and can trigger an access violation - //render passes are supposed to be uninterruptible, so we have to finish everything first before we start the render pass + //While vertex upload is an interruptible process, if we made it this far, there's no need to sync anything that occurs past this point + //Only textures are synchronized tightly with the GPU and they have been read back above + vk::enter_uninterruptible(); + auto upload_info = upload_vertex_data(); std::chrono::time_point vertex_end = steady_clock::now(); @@ -882,6 +887,8 @@ void VKGSRender::end() vkCmdEndRenderPass(*m_current_command_buffer); + vk::leave_uninterruptible(); + std::chrono::time_point draw_end = steady_clock::now(); m_draw_time += std::chrono::duration_cast(draw_end - vertex_end).count(); @@ -1058,6 +1065,8 @@ void VKGSRender::copy_render_targets_to_dma_location() //This is due to all the hard waits for fences //TODO: Use a command buffer array to allow explicit draw command tracking + vk::enter_uninterruptible(); + if (g_cfg_rsx_write_color_buffers) { for (u8 index = 0; index < rsx::limits::color_buffers_count; index++) @@ -1079,6 +1088,8 @@ void VKGSRender::copy_render_targets_to_dma_location() } } + vk::leave_uninterruptible(); + m_last_flushable_cb = m_current_cb_index; flush_command_queue(); @@ -1374,6 +1385,8 @@ bool VKGSRender::load_program() properties.num_targets = m_draw_buffers_count; + vk::enter_uninterruptible(); + //Load current program from buffer m_program = m_prog_buffer.getGraphicPipelineState(vertex_program, fragment_program, properties, *m_device, pipeline_layout).get(); @@ -1415,6 +1428,8 @@ bool VKGSRender::load_program() m_program->bind_uniform({ m_uniform_buffer_ring_info.heap->value, vertex_constants_offset, 512 * 4 * sizeof(float) }, VERTEX_CONSTANT_BUFFERS_BIND_SLOT, descriptor_sets); m_program->bind_uniform({ m_uniform_buffer_ring_info.heap->value, fragment_constants_offset, fragment_buffer_sz }, FRAGMENT_CONSTANT_BUFFERS_BIND_SLOT, descriptor_sets); + vk::leave_uninterruptible(); + return true; } diff --git a/rpcs3/Emu/RSX/VK/VKHelpers.cpp b/rpcs3/Emu/RSX/VK/VKHelpers.cpp index 5c6a8a608c..e96630f69e 100644 --- a/rpcs3/Emu/RSX/VK/VKHelpers.cpp +++ b/rpcs3/Emu/RSX/VK/VKHelpers.cpp @@ -11,6 +11,8 @@ namespace vk VkSampler g_null_sampler = nullptr; VkImageView g_null_image_view = nullptr; + bool g_cb_no_interrupt_flag = false; + VKAPI_ATTR void* VKAPI_CALL mem_realloc(void* pUserData, void* pOriginal, size_t size, size_t alignment, VkSystemAllocationScope allocationScope) { #ifdef _MSC_VER @@ -253,6 +255,21 @@ namespace vk vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier); } + void enter_uninterruptible() + { + g_cb_no_interrupt_flag = true; + } + + void leave_uninterruptible() + { + g_cb_no_interrupt_flag = false; + } + + bool is_uninterruptible() + { + return g_cb_no_interrupt_flag; + } + 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) diff --git a/rpcs3/Emu/RSX/VK/VKHelpers.h b/rpcs3/Emu/RSX/VK/VKHelpers.h index f2c1474fce..990ea717dd 100644 --- a/rpcs3/Emu/RSX/VK/VKHelpers.h +++ b/rpcs3/Emu/RSX/VK/VKHelpers.h @@ -78,6 +78,10 @@ namespace vk std::pair get_compatible_surface_format(rsx::surface_color_format color_format); size_t get_render_pass_location(VkFormat color_surface_format, VkFormat depth_stencil_format, u8 color_surface_count); + void enter_uninterruptible(); + void leave_uninterruptible(); + bool is_uninterruptible(); + struct memory_type_mapping { uint32_t host_visible_coherent; diff --git a/rpcs3/Emu/RSX/VK/VKTextureCache.h b/rpcs3/Emu/RSX/VK/VKTextureCache.h index c1efbee718..f1d494e92b 100644 --- a/rpcs3/Emu/RSX/VK/VKTextureCache.h +++ b/rpcs3/Emu/RSX/VK/VKTextureCache.h @@ -507,11 +507,16 @@ namespace vk mapping, subresource_range); + //We cannot split mipmap uploads across multiple command buffers (must explicitly open and close operations on the same cb) + vk::enter_uninterruptible(); + copy_mipmaped_image_using_buffer(cmd, image->value, get_subresources_layout(tex), format, !(tex.format() & CELL_GCM_TEXTURE_LN), tex.get_exact_mipmap_count(), upload_heap, upload_buffer); change_image_layout(cmd, image->value, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, subresource_range); + vk::leave_uninterruptible(); + region.reset(texaddr, range); region.create(tex.width(), height, depth, tex.get_exact_mipmap_count(), view, image); region.protect(utils::protection::ro);