From ee009ec99c976ff6663419dee3835d0f4d3e6262 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Mon, 1 Jan 2018 11:43:06 +0300 Subject: [PATCH] rsx: Robustness fixes - Track last working state and reset to it if RSX starts to desync -- This is especially useful when running vulkan since the renderer will easily outpace the rest of the system when merely recording draw commands - Ignore empty sets -- Mark empty/invalid IB sets as having 0 element counts. --- rpcs3/Emu/Cell/lv2/sys_rsx.cpp | 1 + rpcs3/Emu/RSX/GL/GLVertexBuffers.cpp | 6 ++++++ rpcs3/Emu/RSX/RSXThread.cpp | 32 ++++++++++++++++++++++------ rpcs3/Emu/RSX/RSXThread.h | 2 ++ rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp | 13 ++++++++--- rpcs3/Emu/RSX/rsx_methods.cpp | 2 ++ 6 files changed, 46 insertions(+), 10 deletions(-) diff --git a/rpcs3/Emu/Cell/lv2/sys_rsx.cpp b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp index a8d17c8703..a5e27ec7e0 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rsx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp @@ -244,6 +244,7 @@ s32 sys_rsx_context_attribute(s32 context_id, u32 package_id, u64 a3, u64 a4, u6 render->ctrl->get = a3; render->ctrl->put = a4; render->internal_get = a3; + render->restore_point = a3; render->unpause(); break; diff --git a/rpcs3/Emu/RSX/GL/GLVertexBuffers.cpp b/rpcs3/Emu/RSX/GL/GLVertexBuffers.cpp index d988aa9a4e..e930bd85e4 100644 --- a/rpcs3/Emu/RSX/GL/GLVertexBuffers.cpp +++ b/rpcs3/Emu/RSX/GL/GLVertexBuffers.cpp @@ -134,6 +134,12 @@ namespace command.raw_index_buffer, ptr, type, rsx::method_registers.current_draw_clause.primitive, rsx::method_registers.current_draw_clause.first_count_commands, vertex_count); + if (min_index >= max_index) + { + //empty set, do not draw + return{ 0, 0, 0, 0, std::make_tuple(get_index_type(type), offset_in_index_buffer) }; + } + //check for vertex arrays with frquency modifiers for (auto &block : m_vertex_layout.interleaved_blocks) { diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 31bed4dcde..fd2b2189c5 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -388,6 +388,7 @@ namespace rsx continue; } + while (Emu.IsPaused()) std::this_thread::sleep_for(10ms); @@ -490,6 +491,22 @@ namespace rsx while (external_interrupt_lock.load()) _mm_pause(); } + //Set up restore state if needed + if (sync_point_request) + { + if (RSXIOMem.RealAddr(internal_get)) + { + //New internal get is valid, use it + restore_point = internal_get.load(); + } + else + { + LOG_ERROR(RSX, "Could not update FIFO restore point"); + } + + sync_point_request = false; + } + //Now load the FIFO ctrl registers ctrl->get.store(internal_get.load()); const u32 put = ctrl->put; @@ -513,13 +530,13 @@ namespace rsx if (mem_faults_count >= 3) { - LOG_ERROR(RSX, "Application has failed to recover, discarding FIFO queue"); - internal_get = put; + LOG_ERROR(RSX, "Application has failed to recover, resetting FIFO queue"); + internal_get = restore_point.load();; } else { mem_faults_count++; - std::this_thread::sleep_for(1ms); + std::this_thread::sleep_for(10ms); } invalid_command_interrupt_raised = true; @@ -581,13 +598,13 @@ namespace rsx if (mem_faults_count >= 3) { - LOG_ERROR(RSX, "Application has failed to recover, discarding FIFO queue"); - internal_get = put; + LOG_ERROR(RSX, "Application has failed to recover, resetting FIFO queue"); + internal_get = restore_point.load(); } else { mem_faults_count++; - std::this_thread::sleep_for(1ms); + std::this_thread::sleep_for(10ms); } invalid_command_interrupt_raised = true; @@ -735,7 +752,8 @@ namespace rsx { //This is almost guaranteed to be heap corruption at this point //Ignore the rest of the chain - internal_get = put; + LOG_ERROR(RSX, "FIFO contents may be corrupted. Resetting..."); + internal_get = restore_point.load(); continue; } diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index 99fdbf58db..36d3845c48 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -233,6 +233,7 @@ namespace rsx public: RsxDmaControl* ctrl = nullptr; atomic_t internal_get{ 0 }; + atomic_t restore_point{ 0 }; atomic_t external_interrupt_lock{ false }; atomic_t external_interrupt_ack{ false }; @@ -309,6 +310,7 @@ namespace rsx public: std::set m_used_gcm_commands; bool invalid_command_interrupt_raised = false; + bool sync_point_request = false; bool in_begin_end = false; bool conditional_render_test_failed = false; diff --git a/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp b/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp index 03676e19be..4614a54050 100644 --- a/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp +++ b/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp @@ -153,6 +153,9 @@ namespace dst = gsl::span(static_cast(buf), upload_size); } + std::optional> index_info = + std::make_tuple(offset_in_index_buffer, vk::get_index_type(index_type)); + /** * Upload index (and expands it if primitive type is not natively supported). */ @@ -165,6 +168,13 @@ namespace rsx::method_registers.restart_index(), command.ranges_to_fetch_in_index_buffer, [](auto prim) { return !vk::is_primitive_native(prim); }); + if (min_index >= max_index) + { + //empty set, do not draw + m_index_buffer_ring_info.unmap(); + return{ prims, 0, 0, 0, 0, index_info }; + } + if (rsx::method_registers.restart_index_enabled() && vk::emulate_primitive_restart()) { //Emulate primitive restart by breaking up the draw calls @@ -180,9 +190,6 @@ namespace m_index_buffer_ring_info.unmap(); - std::optional> index_info = - std::make_tuple(offset_in_index_buffer, vk::get_index_type(index_type)); - //check for vertex arrays with frquency modifiers for (auto &block : m_vertex_layout.interleaved_blocks) { diff --git a/rpcs3/Emu/RSX/rsx_methods.cpp b/rpcs3/Emu/RSX/rsx_methods.cpp index 1808a88fe8..197e474d7b 100644 --- a/rpcs3/Emu/RSX/rsx_methods.cpp +++ b/rpcs3/Emu/RSX/rsx_methods.cpp @@ -62,6 +62,7 @@ namespace rsx void semaphore_acquire(thread* rsx, u32 _reg, u32 arg) { + rsx->sync_point_request = true; const u32 addr = get_address(method_registers.semaphore_offset_406e(), method_registers.semaphore_context_dma_406e()); if (vm::ps3::read32(addr) == arg) return; @@ -109,6 +110,7 @@ namespace rsx void semaphore_release(thread* rsx, u32 _reg, u32 arg) { + rsx->sync_point_request = true; const u32 addr = get_address(method_registers.semaphore_offset_406e(), method_registers.semaphore_context_dma_406e()); if (addr >> 28 == 0x4)