From 7ab1792ef73407d3c9ff83a8aed06f9acaf0ca0e Mon Sep 17 00:00:00 2001 From: kd-11 Date: Thu, 27 Jul 2017 16:29:08 +0300 Subject: [PATCH] rsx: Implement conditional locks --- rpcs3/Emu/RSX/GL/GLTextureCache.cpp | 2 +- rpcs3/Emu/RSX/GL/GLTextureCache.h | 25 +++++++++++----------- rpcs3/Emu/RSX/VK/VKTextureCache.h | 24 ++-------------------- rpcs3/Emu/RSX/rsx_utils.h | 32 +++++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 35 deletions(-) diff --git a/rpcs3/Emu/RSX/GL/GLTextureCache.cpp b/rpcs3/Emu/RSX/GL/GLTextureCache.cpp index 935a1c2e20..2ba489f825 100644 --- a/rpcs3/Emu/RSX/GL/GLTextureCache.cpp +++ b/rpcs3/Emu/RSX/GL/GLTextureCache.cpp @@ -14,7 +14,7 @@ namespace gl cached_texture_section* section_to_post = nullptr; { - std::lock_guard lock(m_section_mutex); + rsx::conditional_lock lock(in_access_violation_handler, m_section_mutex); for (cached_texture_section &tex : no_access_memory_sections) { diff --git a/rpcs3/Emu/RSX/GL/GLTextureCache.h b/rpcs3/Emu/RSX/GL/GLTextureCache.h index 8ede3c3fee..77a0959038 100644 --- a/rpcs3/Emu/RSX/GL/GLTextureCache.h +++ b/rpcs3/Emu/RSX/GL/GLTextureCache.h @@ -11,6 +11,7 @@ #include #include +#include "Utilities/mutex.h" #include "Emu/System.h" #include "GLRenderTargets.h" #include "../Common/TextureUtils.h" @@ -449,14 +450,15 @@ namespace gl blitter m_hw_blitter; - std::mutex m_section_mutex; + std::atomic_bool in_access_violation_handler = { false }; + shared_mutex m_section_mutex; GLGSRender *m_renderer; std::thread::id m_renderer_thread; cached_texture_section *find_texture_from_dimensions(u32 texaddr, u32 w, u32 h) { - std::lock_guard lock(m_section_mutex); + reader_lock lock(m_section_mutex); for (cached_texture_section &tex : read_only_memory_sections) { @@ -473,7 +475,7 @@ namespace gl */ cached_texture_section *find_texture_from_range(u32 texaddr, u32 range) { - std::lock_guard lock(m_section_mutex); + reader_lock lock(m_section_mutex); auto test = std::make_pair(texaddr, range); for (cached_texture_section &tex : read_only_memory_sections) @@ -860,7 +862,7 @@ namespace gl gl_texture.init(index, tex); - std::lock_guard lock(m_section_mutex); + writer_lock lock(m_section_mutex); cached_texture_section &cached = create_texture(gl_texture.id(), texaddr, (const u32)get_texture_size(tex), tex_width, tex_height); cached.protect(utils::protection::ro); @@ -872,7 +874,7 @@ namespace gl void save_rtt(u32 base, u32 size) { - std::lock_guard lock(m_section_mutex); + writer_lock lock(m_section_mutex); cached_texture_section *region = find_cached_rtt_section(base, size); @@ -896,7 +898,7 @@ namespace gl void lock_rtt_region(const u32 base, const u32 size, const u16 width, const u16 height, const u16 pitch, const texture::format format, const texture::type type, const bool swap_bytes, gl::texture &source) { - std::lock_guard lock(m_section_mutex); + writer_lock lock(m_section_mutex); cached_texture_section *region = create_locked_view_of_section(base, size); @@ -942,12 +944,11 @@ namespace gl //TODO: Optimize this function! //Multi-pass checking is slow. Pre-calculate dependency tree at section creation + rsx::conditional_lock lock(in_access_violation_handler, m_section_mutex); if (address >= read_only_range.first && address < read_only_range.second) { - std::lock_guard lock(m_section_mutex); - for (int i = 0; i < read_only_memory_sections.size(); ++i) { auto &tex = read_only_memory_sections[i]; @@ -975,7 +976,7 @@ namespace gl if (address >= no_access_range.first && address < no_access_range.second) { - std::lock_guard lock(m_section_mutex); + rsx::conditional_lock lock(in_access_violation_handler, m_section_mutex); for (int i = 0; i < no_access_memory_sections.size(); ++i) { @@ -1007,7 +1008,7 @@ namespace gl void invalidate_range(u32 base, u32 size) { - std::lock_guard lock(m_section_mutex); + rsx::conditional_lock lock(in_access_violation_handler, m_section_mutex); std::pair range = std::make_pair(base, size); if (base < read_only_range.second && @@ -1213,7 +1214,7 @@ namespace gl glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, src.width, src.slice_h, src_gl_format, src_gl_type, src.pixels); - std::lock_guard lock(m_section_mutex); + writer_lock lock(m_section_mutex); auto §ion = create_texture(vram_texture, src_address, src.pitch * src.slice_h, src.width, src.slice_h); section.protect(utils::protection::ro); @@ -1269,7 +1270,7 @@ namespace gl //TODO: Verify if any titles ever scale into CPU memory. It defeats the purpose of uploading data to the GPU, but it could happen //If so, add this texture to the no_access queue not the read_only queue - std::lock_guard lock(m_section_mutex); + writer_lock lock(m_section_mutex); cached_texture_section &cached = create_texture(texture_id, dst.rsx_address, dst.pitch * dst.clip_height, dst.width, dst.clip_height); //These textures are completely GPU resident so we dont watch for CPU access diff --git a/rpcs3/Emu/RSX/VK/VKTextureCache.h b/rpcs3/Emu/RSX/VK/VKTextureCache.h index 14ac857ec6..9836036e89 100644 --- a/rpcs3/Emu/RSX/VK/VKTextureCache.h +++ b/rpcs3/Emu/RSX/VK/VKTextureCache.h @@ -767,11 +767,7 @@ namespace vk std::pair trampled_range = std::make_pair(0xffffffff, 0x0); std::unordered_map processed_ranges; - const bool _false = false; - const bool acquire_lock = in_access_violation_handler.compare_exchange_weak(const_cast(_false), true); - - if (acquire_lock) - m_cache_mutex.lock_shared(); + rsx::conditional_lock lock(in_access_violation_handler, m_cache_mutex); for (auto It = m_cache.begin(); It != m_cache.end(); It++) { @@ -834,12 +830,6 @@ namespace vk processed_ranges[base] = true; } - if (acquire_lock) - { - in_access_violation_handler = false; - m_cache_mutex.unlock_shared(); - } - return response; } @@ -858,11 +848,7 @@ namespace vk std::pair trampled_range = std::make_pair(0xffffffff, 0x0); std::unordered_map processed_ranges; - const bool _false = false; - const bool acquire_lock = in_access_violation_handler.compare_exchange_weak(const_cast(_false), true); - - if (acquire_lock) - m_cache_mutex.lock_shared(); + rsx::conditional_lock lock(in_access_violation_handler, m_cache_mutex); for (auto It = m_cache.begin(); It != m_cache.end(); It++) { @@ -921,12 +907,6 @@ namespace vk processed_ranges[base] = true; } - if (acquire_lock) - { - in_access_violation_handler = false; - m_cache_mutex.unlock_shared(); - } - return response; } diff --git a/rpcs3/Emu/RSX/rsx_utils.h b/rpcs3/Emu/RSX/rsx_utils.h index 7d05c776df..dbb7c0dfb7 100644 --- a/rpcs3/Emu/RSX/rsx_utils.h +++ b/rpcs3/Emu/RSX/rsx_utils.h @@ -1,6 +1,7 @@ #pragma once #include "gcm_enums.h" +#include extern "C" { @@ -206,4 +207,35 @@ namespace rsx return std::make_tuple(x, y, width, height); } + + // Conditional mutex lock for shared mutex types + // May silently fail to acquire the lock + template + struct conditional_lock + { + lock_type& _ref; + std::atomic_bool& _flag; + bool acquired = false; + + conditional_lock(std::atomic_bool& flag, lock_type& mutex): + _ref(mutex), _flag(flag) + { + const bool _false = false; + if (flag.compare_exchange_weak(const_cast(_false), true)) + { + mutex.lock_shared(); + acquired = true; + } + } + + ~conditional_lock() + { + if (acquired) + { + _ref.unlock_shared(); + _flag.store(false); + acquired = false; + } + } + }; }