From 38191c3013ed49a0116601d30268f0d0a5635c34 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Fri, 27 Jul 2018 00:03:55 +0300 Subject: [PATCH] rsx: Avoid acquiring the vm lock; deadlock evasion - A possible deadlock is still present if rsx is trying to get a super_ptr whilst the vm lock holder is in an access violation This patch makes this scenario very unlikely since each block need only be touched once --- rpcs3/Emu/RSX/RSXThread.cpp | 18 ++++++++++++++++++ rpcs3/Emu/RSX/RSXThread.h | 3 ++- rpcs3/Emu/RSX/VK/VKGSRender.cpp | 3 --- rpcs3/Emu/RSX/rsx_cache.h | 3 ++- rpcs3/Emu/RSX/rsx_utils.cpp | 32 +++++++++++++++++++++++--------- rpcs3/Emu/RSX/rsx_utils.h | 9 +++++++-- 6 files changed, 52 insertions(+), 16 deletions(-) diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index b957bb75b0..1430cd834a 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -1373,6 +1373,24 @@ namespace rsx for (const auto& range : m_invalidated_memory_ranges) { on_invalidate_memory_range(range.first, range.second); + + // Clean the main memory super_ptr cache if invalidated + const auto range_end = range.first + range.second; + for (auto It = main_super_memory_block.begin(); It != main_super_memory_block.end();) + { + const auto mem_start = It->first; + const auto mem_end = mem_start + It->second.size(); + const bool overlaps = (mem_start < range_end && range.first < mem_end); + + if (overlaps) + { + It = main_super_memory_block.erase(It); + } + else + { + It++; + } + } } m_invalidated_memory_ranges.clear(); diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index 06de0aa419..614b63c51e 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -382,7 +382,8 @@ namespace rsx GcmZcullInfo zculls[limits::zculls_count]; // Super memory map (mapped block with r/w permissions) - std::pair> super_memory_map; + std::pair> local_super_memory_block; + std::unordered_map main_super_memory_block; bool capture_current_frame = false; void capture_frame(const std::string &name); diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index f438fe47a0..e226b584cd 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -3113,9 +3113,6 @@ bool VKGSRender::scaled_image_from_memory(rsx::blit_src_info& src, rsx::blit_dst //Verify enough memory exists before attempting to handle data transfer check_heap_status(); - //Stop all parallel operations until this is finished - std::lock_guard lock(m_secondary_cb_guard); - if (m_texture_cache.blit(src, dst, interpolate, m_rtts, *m_current_command_buffer)) { m_samplers_dirty.store(true); diff --git a/rpcs3/Emu/RSX/rsx_cache.h b/rpcs3/Emu/RSX/rsx_cache.h index dff669bddc..9838b36784 100644 --- a/rpcs3/Emu/RSX/rsx_cache.h +++ b/rpcs3/Emu/RSX/rsx_cache.h @@ -354,7 +354,8 @@ namespace rsx void flush_io(u32 offset = 0, u32 len = 0) const { - locked_memory_ptr.flush(offset, len); + const auto write_length = len ? len : (cpu_address_range - offset); + locked_memory_ptr.flush(offset, write_length); } std::pair get_confirmed_range() const diff --git a/rpcs3/Emu/RSX/rsx_utils.cpp b/rpcs3/Emu/RSX/rsx_utils.cpp index d13e77f34a..e2c32c1f14 100644 --- a/rpcs3/Emu/RSX/rsx_utils.cpp +++ b/rpcs3/Emu/RSX/rsx_utils.cpp @@ -80,15 +80,15 @@ namespace rsx { verify(HERE), g_current_renderer; - if (!g_current_renderer->super_memory_map.first) + if (!g_current_renderer->local_super_memory_block.first) { auto block = vm::get(vm::any, 0xC0000000); if (block) { - g_current_renderer->super_memory_map.first = block->used(); - g_current_renderer->super_memory_map.second = vm::get_super_ptr(0xC0000000, g_current_renderer->super_memory_map.first - 1); + g_current_renderer->local_super_memory_block.first = block->used(); + g_current_renderer->local_super_memory_block.second = vm::get_super_ptr(0xC0000000, g_current_renderer->local_super_memory_block.first - 1); - if (!g_current_renderer->super_memory_map.second) + if (!g_current_renderer->local_super_memory_block.second) { //Disjoint allocation? LOG_ERROR(RSX, "Could not initialize contiguous RSX super-memory"); @@ -100,18 +100,30 @@ namespace rsx } } - if (g_current_renderer->super_memory_map.second) + if (g_current_renderer->local_super_memory_block.second) { - if (addr >= 0xC0000000 && (addr + len) <= (0xC0000000 + g_current_renderer->super_memory_map.first)) + if (addr >= 0xC0000000 && (addr + len) <= (0xC0000000 + g_current_renderer->local_super_memory_block.first)) { //RSX local - return { g_current_renderer->super_memory_map.second.get() + (addr - 0xC0000000) }; + return { g_current_renderer->local_super_memory_block.second.get() + (addr - 0xC0000000) }; + } + } + + const auto cached = g_current_renderer->main_super_memory_block.find(addr); + if (cached != g_current_renderer->main_super_memory_block.end()) + { + const auto& _ptr = cached->second; + if (_ptr.size() >= len) + { + return _ptr; } } if (auto result = vm::get_super_ptr(addr, len - 1)) { - return { result }; + weak_ptr _ptr = { result, len }; + auto &ret = g_current_renderer->main_super_memory_block[addr] = std::move(_ptr); + return _ptr; } //Probably allocated as split blocks. Try to grab separate chunks @@ -137,7 +149,9 @@ namespace rsx next = region.first + region.second->size(); if (next >= limit) { - return { blocks }; + weak_ptr _ptr = { blocks }; + auto &ret = g_current_renderer->main_super_memory_block[addr] = std::move(_ptr); + return ret; } } diff --git a/rpcs3/Emu/RSX/rsx_utils.h b/rpcs3/Emu/RSX/rsx_utils.h index 447a4226c7..174e760d38 100644 --- a/rpcs3/Emu/RSX/rsx_utils.h +++ b/rpcs3/Emu/RSX/rsx_utils.h @@ -60,9 +60,9 @@ namespace rsx } } - weak_ptr(std::shared_ptr& block) + weak_ptr(std::shared_ptr& block, u32 size) { - _blocks.push_back({ block, 0 }); + _blocks.push_back({ block, size }); _ptr = block.get(); } @@ -195,6 +195,11 @@ namespace rsx } } + u32 size() const + { + return contiguous ? _blocks[0].second : (u32)io_cache.size(); + } + operator bool() const { return (_ptr != nullptr || _blocks.size() > 1);