rsx: Fix segmented memory access for rsx::super_ptr

This commit is contained in:
kd-11 2018-05-19 14:54:57 +03:00 committed by kd-11
parent d283200e13
commit fbf6581249
5 changed files with 129 additions and 17 deletions

View File

@ -559,6 +559,7 @@ namespace gl
}
}
flush_io();
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
glBindBuffer(GL_PIXEL_PACK_BUFFER, GL_NONE);

View File

@ -323,6 +323,7 @@ namespace vk
}
}
flush_io();
dma_buffer->unmap();
reset_write_statistics();

View File

@ -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 <typename T = void>
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<T>(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<u32, u32> get_confirmed_range() const
{
if (confirmed_range.second == 0)

View File

@ -109,14 +109,40 @@ namespace rsx
}
}
auto result = vm::get_super_ptr<u8>(addr, len - 1);
if (!result)
if (auto result = vm::get_super_ptr<u8>(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<weak_ptr::memory_block_t> 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<u8> _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

View File

@ -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<u8> _extern;
public:
using memory_block_t = std::pair<std::shared_ptr<u8>, u32>;
private:
void* _ptr = nullptr;
std::vector<memory_block_t> _blocks;
std::vector<u8> 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<u8>& block)
{
_extern = block;
_ptr = _extern.get();
_blocks.push_back({ block, 0 });
_ptr = block.get();
}
weak_ptr(std::vector<memory_block_t>& 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 <typename T = void>
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);
}
};