rsx: Implement conditional locks

This commit is contained in:
kd-11 2017-07-27 16:29:08 +03:00
parent 40d305b35d
commit 7ab1792ef7
4 changed files with 48 additions and 35 deletions

View File

@ -14,7 +14,7 @@ namespace gl
cached_texture_section* section_to_post = nullptr; cached_texture_section* section_to_post = nullptr;
{ {
std::lock_guard<std::mutex> lock(m_section_mutex); rsx::conditional_lock<shared_mutex> lock(in_access_violation_handler, m_section_mutex);
for (cached_texture_section &tex : no_access_memory_sections) for (cached_texture_section &tex : no_access_memory_sections)
{ {

View File

@ -11,6 +11,7 @@
#include <condition_variable> #include <condition_variable>
#include <chrono> #include <chrono>
#include "Utilities/mutex.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "GLRenderTargets.h" #include "GLRenderTargets.h"
#include "../Common/TextureUtils.h" #include "../Common/TextureUtils.h"
@ -449,14 +450,15 @@ namespace gl
blitter m_hw_blitter; 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; GLGSRender *m_renderer;
std::thread::id m_renderer_thread; std::thread::id m_renderer_thread;
cached_texture_section *find_texture_from_dimensions(u32 texaddr, u32 w, u32 h) cached_texture_section *find_texture_from_dimensions(u32 texaddr, u32 w, u32 h)
{ {
std::lock_guard<std::mutex> lock(m_section_mutex); reader_lock lock(m_section_mutex);
for (cached_texture_section &tex : read_only_memory_sections) 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) cached_texture_section *find_texture_from_range(u32 texaddr, u32 range)
{ {
std::lock_guard<std::mutex> lock(m_section_mutex); reader_lock lock(m_section_mutex);
auto test = std::make_pair(texaddr, range); auto test = std::make_pair(texaddr, range);
for (cached_texture_section &tex : read_only_memory_sections) for (cached_texture_section &tex : read_only_memory_sections)
@ -860,7 +862,7 @@ namespace gl
gl_texture.init(index, tex); gl_texture.init(index, tex);
std::lock_guard<std::mutex> 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_texture_section &cached = create_texture(gl_texture.id(), texaddr, (const u32)get_texture_size(tex), tex_width, tex_height);
cached.protect(utils::protection::ro); cached.protect(utils::protection::ro);
@ -872,7 +874,7 @@ namespace gl
void save_rtt(u32 base, u32 size) void save_rtt(u32 base, u32 size)
{ {
std::lock_guard<std::mutex> lock(m_section_mutex); writer_lock lock(m_section_mutex);
cached_texture_section *region = find_cached_rtt_section(base, size); 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) 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<std::mutex> lock(m_section_mutex); writer_lock lock(m_section_mutex);
cached_texture_section *region = create_locked_view_of_section(base, size); cached_texture_section *region = create_locked_view_of_section(base, size);
@ -942,12 +944,11 @@ namespace gl
//TODO: Optimize this function! //TODO: Optimize this function!
//Multi-pass checking is slow. Pre-calculate dependency tree at section creation //Multi-pass checking is slow. Pre-calculate dependency tree at section creation
rsx::conditional_lock<shared_mutex> lock(in_access_violation_handler, m_section_mutex);
if (address >= read_only_range.first && if (address >= read_only_range.first &&
address < read_only_range.second) address < read_only_range.second)
{ {
std::lock_guard<std::mutex> lock(m_section_mutex);
for (int i = 0; i < read_only_memory_sections.size(); ++i) for (int i = 0; i < read_only_memory_sections.size(); ++i)
{ {
auto &tex = read_only_memory_sections[i]; auto &tex = read_only_memory_sections[i];
@ -975,7 +976,7 @@ namespace gl
if (address >= no_access_range.first && if (address >= no_access_range.first &&
address < no_access_range.second) address < no_access_range.second)
{ {
std::lock_guard<std::mutex> lock(m_section_mutex); rsx::conditional_lock<shared_mutex> lock(in_access_violation_handler, m_section_mutex);
for (int i = 0; i < no_access_memory_sections.size(); ++i) for (int i = 0; i < no_access_memory_sections.size(); ++i)
{ {
@ -1007,7 +1008,7 @@ namespace gl
void invalidate_range(u32 base, u32 size) void invalidate_range(u32 base, u32 size)
{ {
std::lock_guard<std::mutex> lock(m_section_mutex); rsx::conditional_lock<shared_mutex> lock(in_access_violation_handler, m_section_mutex);
std::pair<u32, u32> range = std::make_pair(base, size); std::pair<u32, u32> range = std::make_pair(base, size);
if (base < read_only_range.second && if (base < read_only_range.second &&
@ -1213,7 +1214,7 @@ namespace gl
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 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); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, src.width, src.slice_h, src_gl_format, src_gl_type, src.pixels);
std::lock_guard<std::mutex> lock(m_section_mutex); writer_lock lock(m_section_mutex);
auto &section = create_texture(vram_texture, src_address, src.pitch * src.slice_h, src.width, src.slice_h); auto &section = create_texture(vram_texture, src_address, src.pitch * src.slice_h, src.width, src.slice_h);
section.protect(utils::protection::ro); 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 //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 //If so, add this texture to the no_access queue not the read_only queue
std::lock_guard<std::mutex> 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); 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 //These textures are completely GPU resident so we dont watch for CPU access

View File

@ -767,11 +767,7 @@ namespace vk
std::pair<u32, u32> trampled_range = std::make_pair(0xffffffff, 0x0); std::pair<u32, u32> trampled_range = std::make_pair(0xffffffff, 0x0);
std::unordered_map<u32, bool> processed_ranges; std::unordered_map<u32, bool> processed_ranges;
const bool _false = false; rsx::conditional_lock<shared_mutex> lock(in_access_violation_handler, m_cache_mutex);
const bool acquire_lock = in_access_violation_handler.compare_exchange_weak(const_cast<bool&>(_false), true);
if (acquire_lock)
m_cache_mutex.lock_shared();
for (auto It = m_cache.begin(); It != m_cache.end(); It++) for (auto It = m_cache.begin(); It != m_cache.end(); It++)
{ {
@ -834,12 +830,6 @@ namespace vk
processed_ranges[base] = true; processed_ranges[base] = true;
} }
if (acquire_lock)
{
in_access_violation_handler = false;
m_cache_mutex.unlock_shared();
}
return response; return response;
} }
@ -858,11 +848,7 @@ namespace vk
std::pair<u32, u32> trampled_range = std::make_pair(0xffffffff, 0x0); std::pair<u32, u32> trampled_range = std::make_pair(0xffffffff, 0x0);
std::unordered_map<u32, bool> processed_ranges; std::unordered_map<u32, bool> processed_ranges;
const bool _false = false; rsx::conditional_lock<shared_mutex> lock(in_access_violation_handler, m_cache_mutex);
const bool acquire_lock = in_access_violation_handler.compare_exchange_weak(const_cast<bool&>(_false), true);
if (acquire_lock)
m_cache_mutex.lock_shared();
for (auto It = m_cache.begin(); It != m_cache.end(); It++) for (auto It = m_cache.begin(); It != m_cache.end(); It++)
{ {
@ -921,12 +907,6 @@ namespace vk
processed_ranges[base] = true; processed_ranges[base] = true;
} }
if (acquire_lock)
{
in_access_violation_handler = false;
m_cache_mutex.unlock_shared();
}
return response; return response;
} }

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "gcm_enums.h" #include "gcm_enums.h"
#include <atomic>
extern "C" extern "C"
{ {
@ -206,4 +207,35 @@ namespace rsx
return std::make_tuple(x, y, width, height); return std::make_tuple(x, y, width, height);
} }
// Conditional mutex lock for shared mutex types
// May silently fail to acquire the lock
template <typename lock_type>
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<bool&>(_false), true))
{
mutex.lock_shared();
acquired = true;
}
}
~conditional_lock()
{
if (acquired)
{
_ref.unlock_shared();
_flag.store(false);
acquired = false;
}
}
};
} }