1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 18:53:28 +01:00

Make vm::get_super_ptr return contiguous memory

Cleanup RSX code complexity
This commit is contained in:
Nekotekina 2018-09-27 23:04:10 +03:00
parent 72ba062b1a
commit da6ce80f4f
13 changed files with 28 additions and 395 deletions

View File

@ -136,7 +136,6 @@ namespace utils
shm::shm(u32 size)
: m_size(::align(size, 0x10000))
, m_ptr(nullptr)
{
#ifdef _WIN32
m_handle = ::CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, 0, m_size, NULL);
@ -159,17 +158,13 @@ namespace utils
verify(HERE), ::shm_unlink("/rpcs3-mem1") >= 0;
verify(HERE), ::ftruncate(m_file, m_size) >= 0;
#endif
m_ptr = verify(HERE, this->map(nullptr));
}
shm::~shm()
{
#ifdef _WIN32
::UnmapViewOfFile(m_ptr);
::CloseHandle(m_handle);
#else
::munmap(m_ptr, m_size);
::close(m_file);
#endif
}

View File

@ -46,7 +46,6 @@ namespace utils
int m_file;
#endif
u32 m_size;
u8* m_ptr;
public:
explicit shm(u32 size);
@ -69,17 +68,6 @@ namespace utils
// Unmap shared memory, undoing map_critical
void unmap_critical(void* ptr);
// Access memory with simple range check
u8* get(u32 offset, u32 size) const
{
if (offset >= m_size || m_size - offset < size)
{
return nullptr;
}
return m_ptr + offset;
}
u32 size() const
{
return m_size;

View File

@ -33,7 +33,7 @@ error_code sys_dbg_read_process_memory(s32 pid, u32 address, u32 size, vm::ptr<v
return CELL_EFAULT;
}
std::memcpy(data.get_ptr(), vm::get_super_ptr<u8>(address, size).get(), size);
std::memcpy(data.get_ptr(), vm::get_super_ptr(address), size);
return CELL_OK;
}
@ -64,7 +64,7 @@ error_code sys_dbg_write_process_memory(s32 pid, u32 address, u32 size, vm::cptr
return CELL_EFAULT;
}
std::memcpy(vm::get_super_ptr<u8>(address, size).get(), data.get_ptr(), size);
std::memcpy(vm::get_super_ptr(address), data.get_ptr(), size);
return CELL_OK;
}

View File

@ -31,10 +31,13 @@ namespace vm
}
// Emulated virtual memory
u8* const g_base_addr = memory_reserve_4GiB(0);
u8* const g_base_addr = memory_reserve_4GiB(0x2'0000'0000);
// Unprotected virtual memory mirror
u8* const g_sudo_addr = memory_reserve_4GiB((std::uintptr_t)g_base_addr);
// Auxiliary virtual memory for executable areas
u8* const g_exec_addr = memory_reserve_4GiB((std::uintptr_t)g_base_addr);
u8* const g_exec_addr = memory_reserve_4GiB((std::uintptr_t)g_sudo_addr);
// Stats for debugging
u8* const g_stat_addr = memory_reserve_4GiB((std::uintptr_t)g_exec_addr);
@ -305,7 +308,7 @@ namespace vm
utils::memory_protect(g_base_addr + addr, size, utils::protection::rw);
std::memset(g_base_addr + addr, 0, size);
}
else if (shm->map_critical(g_base_addr + addr) != g_base_addr + addr)
else if (shm->map_critical(g_base_addr + addr) != g_base_addr + addr || shm->map_critical(g_sudo_addr + addr) != g_sudo_addr + addr)
{
fmt::throw_exception("Memory mapping failed - blame Windows (addr=0x%x, size=0x%x, flags=0x%x)", addr, size, flags);
}
@ -437,6 +440,7 @@ namespace vm
else
{
shm->unmap_critical(g_base_addr + addr);
shm->unmap_critical(g_sudo_addr + addr);
}
if (is_exec)
@ -575,6 +579,7 @@ namespace vm
// Special path for 4k-aligned pages
m_common = std::make_shared<utils::shm>(size);
verify(HERE), m_common->map_critical(vm::base(addr), utils::protection::no) == vm::base(addr);
verify(HERE), m_common->map_critical(vm::get_super_ptr(addr), utils::protection::no) == vm::get_super_ptr(addr);
}
}
@ -596,6 +601,7 @@ namespace vm
if (m_common)
{
m_common->unmap_critical(vm::base(addr));
m_common->unmap_critical(vm::get_super_ptr(addr));
}
}
}

View File

@ -12,6 +12,7 @@ class notifier;
namespace vm
{
extern u8* const g_base_addr;
extern u8* const g_sudo_addr;
extern u8* const g_exec_addr;
extern u8* const g_stat_addr;
extern u8* const g_reservations;
@ -303,32 +304,10 @@ namespace vm
}
// Access memory bypassing memory protection
template <typename T>
inline std::shared_ptr<to_be_t<T>> get_super_ptr(u32 addr, u32 count = 1)
template <typename T = u8>
inline to_be_t<T>* get_super_ptr(u32 addr)
{
const auto area = vm::get(vm::any, addr);
if (!area || addr + u64{count} * sizeof(T) > UINT32_MAX)
{
return nullptr;
}
const auto shm = area->get(addr, sizeof(T) * count);
if (!shm.second || shm.first > addr)
{
return nullptr;
}
const auto ptr = reinterpret_cast<to_be_t<T>*>(shm.second->get(addr - shm.first, sizeof(T) * count));
if (!ptr)
{
return nullptr;
}
// Create a shared pointer using the aliasing constructor
return {shm.second, ptr};
return reinterpret_cast<to_be_t<T>*>(g_sudo_addr + addr);
}
inline const be_t<u16>& read16(u32 addr)

View File

@ -2583,16 +2583,13 @@ namespace rsx
void tag_framebuffer(u32 texaddr)
{
auto super_ptr = rsx::get_super_ptr(texaddr, 4);
volatile u32 *ptr = super_ptr.get<volatile u32>();
auto ptr = vm::get_super_ptr<atomic_t<u32>>(texaddr);
*ptr = texaddr;
super_ptr.flush(0, 4);
}
bool test_framebuffer(u32 texaddr)
{
auto super_ptr = rsx::get_super_ptr(texaddr, 4);
volatile const u32 *ptr = super_ptr.get<volatile const u32>();
auto ptr = vm::get_super_ptr<atomic_t<u32>>(texaddr);
return *ptr == texaddr;
}
};

View File

@ -495,7 +495,7 @@ namespace gl
const u32 valid_length = valid_range.second;
AUDIT( valid_length > 0 );
void *dst = get_ptr_by_offset(valid_range.first, true);
void *dst = get_ptr(get_section_base() + valid_offset);
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo_id);
void *src = glMapBufferRange(GL_PIXEL_PACK_BUFFER, valid_offset, valid_length, GL_MAP_READ_BIT);
@ -588,7 +588,6 @@ namespace gl
}
}
flush_ptr_by_offset(valid_offset, valid_length);
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
glBindBuffer(GL_PIXEL_PACK_BUFFER, GL_NONE);

View File

@ -2744,22 +2744,6 @@ namespace rsx
return;
on_invalidate_memory_range(m_invalidated_memory_range);
// Clean the main memory super_ptr cache if invalidated
for (auto It = main_super_memory_block.begin(); It != main_super_memory_block.end();)
{
const auto block_range = address_range::start_length(It->first, It->second.size());
if (m_invalidated_memory_range.overlaps(block_range))
{
It = main_super_memory_block.erase(It);
}
else
{
It++;
}
}
m_invalidated_memory_range.invalidate();
}

View File

@ -430,10 +430,6 @@ namespace rsx
GcmTileInfo tiles[limits::tiles_count];
GcmZcullInfo zculls[limits::zculls_count];
// Super memory map (mapped block with r/w permissions)
std::pair<u32, std::shared_ptr<u8>> local_super_memory_block;
std::unordered_map<u32, rsx::weak_ptr> main_super_memory_block;
bool capture_current_frame = false;
void capture_frame(const std::string &name);

View File

@ -309,7 +309,7 @@ namespace vk
AUDIT( valid_length > 0 );
void* pixels_src = dma_buffer->map(valid_offset, valid_length);
void* pixels_dst = get_ptr_by_offset(valid_offset, true);
void* pixels_dst = get_ptr(get_section_base() + valid_offset);
if (real_pitch >= rsx_pitch || valid_length <= rsx_pitch)
{
@ -334,7 +334,6 @@ namespace vk
}
}
flush_ptr_by_offset(valid_offset, valid_length);
dma_buffer->unmap();
reset_write_statistics();

View File

@ -48,7 +48,6 @@ namespace rsx
address_range locked_range;
address_range cpu_range = {};
address_range confirmed_range;
weak_ptr super_ptr;
utils::protection protection = utils::protection::rw;
@ -98,8 +97,6 @@ namespace rsx
protection = utils::protection::rw;
locked = false;
super_ptr = {};
init_lockable_range(cpu_range);
}
@ -137,8 +134,6 @@ namespace rsx
if (protection == utils::protection::no)
{
super_ptr = rsx::get_super_ptr(cpu_range);
verify(HERE), super_ptr;
tag_memory();
}
else
@ -148,8 +143,6 @@ namespace rsx
//Unprotect range also invalidates secured range
confirmed_range.invalidate();
}
super_ptr = {};
}
}
@ -200,7 +193,6 @@ namespace rsx
protection = utils::protection::rw;
confirmed_range.invalidate();
super_ptr = {};
locked = false;
}
@ -324,44 +316,11 @@ namespace rsx
* Super Pointer
*/
template <typename T = void>
inline T* get_ptr_by_offset(u32 offset = 0, bool no_sync = false)
inline T* get_ptr(u32 address)
{
verify(HERE), super_ptr && cpu_range.length() >= (offset + sizeof(T));
return super_ptr.get<T>(offset, no_sync);
return reinterpret_cast<T*>(vm::g_sudo_addr + address);
}
// specialization due to sizeof(void) being illegal
inline void* get_ptr_by_offset(u32 offset, bool no_sync)
{
verify(HERE), super_ptr && cpu_range.length() >= (offset + 1);
return super_ptr.get<void>(offset, no_sync);
}
template <typename T = void>
inline T* get_ptr(u32 address, bool no_sync = false)
{
verify(HERE), cpu_range.start <= address; // super_ptr & sizeof(T) tests are done by get_ptr_by_offset
return get_ptr_by_offset<T>(address - cpu_range.start, no_sync);
}
inline void flush_ptr_by_offset(u32 offset = 0, u32 len = 0) const
{
verify(HERE), super_ptr && cpu_range.length() >= (offset + len);
super_ptr.flush(offset, len);
}
inline void flush_ptr(u32 address, u32 len = 0) const
{
verify(HERE), cpu_range.start <= address; // super_ptr & length tests are done by flush_ptr_by_offset
return flush_ptr_by_offset(address - cpu_range.start, len);
}
inline void flush_ptr(const address_range &range) const
{
return flush_ptr(range.start, range.length());
}
/**
* Memory tagging
*/
@ -372,18 +331,15 @@ namespace rsx
if (guard_policy == protect_policy_full_range)
return;
AUDIT(locked && super_ptr);
AUDIT(locked);
const address_range& range = get_confirmed_range();
volatile u32* first = get_ptr<volatile u32>(range.start, true);
volatile u32* last = get_ptr<volatile u32>(range.end - 3, true);
volatile u32* first = get_ptr<volatile u32>(range.start);
volatile u32* last = get_ptr<volatile u32>(range.end - 3);
*first = range.start;
*last = range.end;
flush_ptr(range.start, 4);
flush_ptr(range.end - 3, 4);
}
public:
@ -392,7 +348,7 @@ namespace rsx
if (guard_policy == protect_policy_full_range)
return true;
AUDIT(locked && super_ptr);
AUDIT(locked);
const auto& range = get_confirmed_range();
volatile const u32* first = get_ptr<volatile const u32>(range.start);
@ -404,7 +360,7 @@ namespace rsx
if (guard_policy == protect_policy_full_range)
return true;
AUDIT(locked && super_ptr);
AUDIT(locked);
const auto& range = get_confirmed_range();
volatile const u32* last = get_ptr<volatile const u32>(range.end-3);

View File

@ -76,94 +76,6 @@ namespace rsx
}
}
weak_ptr get_super_ptr(const address_range &range)
{
return get_super_ptr(range.start, range.length());
}
weak_ptr get_super_ptr(u32 addr, u32 len)
{
verify(HERE), g_current_renderer;
if (!g_current_renderer->local_super_memory_block.first)
{
auto block = vm::get(vm::any, 0xC0000000);
if (block)
{
g_current_renderer->local_super_memory_block.first = block->used();
g_current_renderer->local_super_memory_block.second = vm::get_super_ptr<u8>(0xC0000000, g_current_renderer->local_super_memory_block.first - 1);
if (!g_current_renderer->local_super_memory_block.second)
{
//Disjoint allocation?
LOG_ERROR(RSX, "Could not initialize contiguous RSX super-memory");
}
}
else
{
fmt::throw_exception("RSX memory not mapped!");
}
}
if (g_current_renderer->local_super_memory_block.second)
{
if (addr >= 0xC0000000 && (addr + len) <= (0xC0000000 + g_current_renderer->local_super_memory_block.first))
{
//RSX local
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<u8>(addr, len - 1))
{
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
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)
{
weak_ptr _ptr = { blocks };
auto &ret = g_current_renderer->main_super_memory_block[addr] = std::move(_ptr);
return ret;
}
}
LOG_ERROR(RSX, "Could not get super_ptr for memory block 0x%x+0x%x", addr, len);
return {};
}
/* Fast image scaling routines
* Only uses fast nearest scaling and integral scaling factors
* T - Dst type

View File

@ -39,184 +39,6 @@ namespace rsx
void reset_refs() { deref_count = 0; }
};
//Weak pointer without lock semantics
//Backed by a real shared_ptr for non-rsx memory
//Backed by a global shared pool for rsx memory
class weak_ptr
{
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)
{
_blocks.push_back({});
_blocks.back().first.reset((u8*)raw);
}
}
weak_ptr(std::shared_ptr<u8>& block, u32 size)
{
_blocks.push_back({ block, size });
_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()
{
_ptr = nullptr;
}
template <typename T = void>
T* get(u32 offset = 0, bool no_sync = false)
{
if (contiguous)
{
return (T*)((u8*)_ptr + offset);
}
else
{
if (!synchronized && !no_sync)
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(u32 offset = 0, u32 len = 0) const
{
if (contiguous)
return;
u8* src = (u8*)io_cache.data();
if (!offset && (!len || len == io_cache.size()))
{
for (const auto &block : _blocks)
{
memcpy(block.first.get(), src, block.second);
src += block.second;
}
}
else
{
auto remaining_bytes = len? len : io_cache.size() - offset;
const auto write_end = remaining_bytes + offset;
u32 write_offset;
u32 write_length;
u32 base_offset = 0;
for (const auto &block : _blocks)
{
const u32 block_end = base_offset + block.second;
if (offset >= base_offset && offset < block_end)
{
// Head
write_offset = (offset - base_offset);
write_length = std::min<u32>(block.second - write_offset, (u32)remaining_bytes);
}
else if (base_offset > offset && block_end <= write_end)
{
// Completely spanned
write_offset = 0;
write_length = block.second;
}
else if (base_offset > offset && write_end < block_end)
{
// Tail
write_offset = 0;
write_length = (u32)remaining_bytes;
}
else
{
// No overlap; skip
write_length = 0;
}
if (write_length)
{
memcpy(block.first.get() + write_offset, src + (base_offset + write_offset), write_length);
verify(HERE), write_length <= remaining_bytes;
remaining_bytes -= write_length;
if (!remaining_bytes)
break;
}
base_offset += block.second;
}
}
}
u32 size() const
{
return contiguous ? _blocks[0].second : (u32)io_cache.size();
}
operator bool() const
{
return (_ptr != nullptr || _blocks.size() > 1);
}
};
// Acquire memory mirror with r/w permissions
weak_ptr get_super_ptr(const address_range &range);
weak_ptr get_super_ptr(u32 addr, u32 size);
/**
* Holds information about a framebuffer
*/