mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 10:42:36 +01:00
Make vm::get_super_ptr return contiguous memory
Cleanup RSX code complexity
This commit is contained in:
parent
72ba062b1a
commit
da6ce80f4f
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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 = {};
|
||||
}
|
||||
|
||||
}
|
||||
@ -177,7 +170,7 @@ namespace rsx
|
||||
confirmed_range = address_range::start_length(cpu_range.start + new_confirm.first, new_confirm.second);
|
||||
ASSERT(!locked || locked_range.inside(confirmed_range.to_page_range()));
|
||||
}
|
||||
|
||||
|
||||
verify(HERE), confirmed_range.inside(cpu_range);
|
||||
init_lockable_range(confirmed_range);
|
||||
}
|
||||
@ -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);
|
||||
@ -510,7 +466,7 @@ namespace rsx
|
||||
ref_cnt--;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
virtual void set_limit(u32 index, u32 limit)
|
||||
{
|
||||
ref_cnt++;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user