From fbf65812496091e265ad3bba180d9ebf09e53e99 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sat, 19 May 2018 14:54:57 +0300 Subject: [PATCH] rsx: Fix segmented memory access for rsx::super_ptr --- rpcs3/Emu/RSX/GL/GLTextureCache.h | 1 + rpcs3/Emu/RSX/VK/VKTextureCache.h | 1 + rpcs3/Emu/RSX/rsx_cache.h | 13 ++++- rpcs3/Emu/RSX/rsx_utils.cpp | 36 ++++++++++-- rpcs3/Emu/RSX/rsx_utils.h | 95 ++++++++++++++++++++++++++++--- 5 files changed, 129 insertions(+), 17 deletions(-) diff --git a/rpcs3/Emu/RSX/GL/GLTextureCache.h b/rpcs3/Emu/RSX/GL/GLTextureCache.h index cf14bc84aa..4eaf1aa029 100644 --- a/rpcs3/Emu/RSX/GL/GLTextureCache.h +++ b/rpcs3/Emu/RSX/GL/GLTextureCache.h @@ -559,6 +559,7 @@ namespace gl } } + flush_io(); glUnmapBuffer(GL_PIXEL_PACK_BUFFER); glBindBuffer(GL_PIXEL_PACK_BUFFER, GL_NONE); diff --git a/rpcs3/Emu/RSX/VK/VKTextureCache.h b/rpcs3/Emu/RSX/VK/VKTextureCache.h index 16a573ebb5..1f21b80aa6 100644 --- a/rpcs3/Emu/RSX/VK/VKTextureCache.h +++ b/rpcs3/Emu/RSX/VK/VKTextureCache.h @@ -323,6 +323,7 @@ namespace vk } } + flush_io(); dma_buffer->unmap(); reset_write_statistics(); diff --git a/rpcs3/Emu/RSX/rsx_cache.h b/rpcs3/Emu/RSX/rsx_cache.h index d045d01fc4..f59d963f75 100644 --- a/rpcs3/Emu/RSX/rsx_cache.h +++ b/rpcs3/Emu/RSX/rsx_cache.h @@ -43,6 +43,8 @@ namespace rsx *first = cpu_address_base + confirmed_range.first; *last = cpu_address_base + valid_limit - 4; + + locked_memory_ptr.flush(); } } @@ -319,13 +321,13 @@ namespace rsx } template - T* get_raw_ptr(u32 offset = 0) const + T* get_raw_ptr(u32 offset = 0) { verify(HERE), locked_memory_ptr; return locked_memory_ptr.get(offset); } - bool test_memory_head() const + bool test_memory_head() { if (!locked_memory_ptr) { @@ -336,7 +338,7 @@ namespace rsx return (*first == (cpu_address_base + confirmed_range.first)); } - bool test_memory_tail() const + bool test_memory_tail() { if (!locked_memory_ptr) { @@ -348,6 +350,11 @@ namespace rsx return (*last == (cpu_address_base + valid_limit - 4)); } + void flush_io() const + { + locked_memory_ptr.flush(); + } + std::pair get_confirmed_range() const { if (confirmed_range.second == 0) diff --git a/rpcs3/Emu/RSX/rsx_utils.cpp b/rpcs3/Emu/RSX/rsx_utils.cpp index e18898723e..d13e77f34a 100644 --- a/rpcs3/Emu/RSX/rsx_utils.cpp +++ b/rpcs3/Emu/RSX/rsx_utils.cpp @@ -109,14 +109,40 @@ namespace rsx } } - auto result = vm::get_super_ptr(addr, len - 1); - if (!result) + if (auto result = vm::get_super_ptr(addr, len - 1)) { - //Probably allocated as split blocks?? - LOG_ERROR(RSX, "Could not get super_ptr for memory block 0x%x+0x%x", addr, len); + return { result }; } - return { result }; + //Probably allocated as split blocks. Try to grab separate chunks + std::vector blocks; + const u32 limit = addr + len; + u32 next = addr; + u32 remaining = len; + + while (true) + { + auto region = vm::get(vm::any, next)->get(next, 1); + if (!region.second) + { + break; + } + + const u32 block_offset = next - region.first; + const u32 block_length = std::min(remaining, region.second->size() - block_offset); + std::shared_ptr _ptr = { region.second, region.second->get(block_offset, block_length) }; + blocks.push_back({_ptr, block_length}); + + remaining -= block_length; + next = region.first + region.second->size(); + if (next >= limit) + { + return { blocks }; + } + } + + LOG_ERROR(RSX, "Could not get super_ptr for memory block 0x%x+0x%x", addr, len); + return {}; } /* Fast image scaling routines diff --git a/rpcs3/Emu/RSX/rsx_utils.h b/rpcs3/Emu/RSX/rsx_utils.h index c52ea6d6a4..74706180e9 100644 --- a/rpcs3/Emu/RSX/rsx_utils.h +++ b/rpcs3/Emu/RSX/rsx_utils.h @@ -35,21 +35,60 @@ namespace rsx //Weak pointer without lock semantics //Backed by a real shared_ptr for non-rsx memory //Backed by a global shared pool for rsx memory - struct weak_ptr + class weak_ptr { - void* _ptr; - std::shared_ptr _extern; + public: + using memory_block_t = std::pair, u32>; + private: + void* _ptr = nullptr; + std::vector _blocks; + std::vector io_cache; + bool contiguous = true; + bool synchronized = true; + + public: weak_ptr(void* raw, bool is_rsx_mem = true) { _ptr = raw; - if (!is_rsx_mem) _extern.reset((u8*)raw); + + if (!is_rsx_mem) + { + _blocks.push_back({}); + _blocks.back().first.reset((u8*)raw); + } } weak_ptr(std::shared_ptr& block) { - _extern = block; - _ptr = _extern.get(); + _blocks.push_back({ block, 0 }); + _ptr = block.get(); + } + + weak_ptr(std::vector& blocks) + { + verify(HERE), blocks.size() > 0; + + _blocks = std::move(blocks); + _ptr = nullptr; + + if (blocks.size() == 1) + { + _ptr = _blocks[0].first.get(); + contiguous = true; + } + else + { + u32 block_length = 0; + for (const auto &block : _blocks) + { + block_length += block.second; + } + + io_cache.resize(block_length); + contiguous = false; + synchronized = false; + } } weak_ptr() @@ -58,14 +97,52 @@ namespace rsx } template - T* get(u32 offset = 0) const + T* get(u32 offset = 0) { - return (T*)((u8*)_ptr + offset); + if (contiguous) + { + return (T*)((u8*)_ptr + offset); + } + else + { + if (!synchronized) + sync(); + + return (T*)(io_cache.data() + offset); + } + } + + void sync() + { + if (synchronized) + return; + + u8* dst = (u8*)io_cache.data(); + for (const auto &block : _blocks) + { + memcpy(dst, block.first.get(), block.second); + dst += block.second; + } + + synchronized = true; + } + + void flush() const + { + if (contiguous) + return; + + u8* src = (u8*)io_cache.data(); + for (const auto &block : _blocks) + { + memcpy(block.first.get(), src, block.second); + src += block.second; + } } operator bool() const { - return (_ptr != nullptr); + return (_ptr != nullptr || _blocks.size() > 1); } };