[buffer_cache, memory, pipeline] Added translation entry structure and update buffer cache handling

This commit is contained in:
CamilleLaVey
2026-02-10 22:24:21 -04:00
committed by crueter
parent ef730ed490
commit 901f556af5
9 changed files with 407 additions and 36 deletions
+10
View File
@@ -127,6 +127,11 @@ public:
void UpdatePagesCachedBatch(std::span<const std::pair<DAddr, size_t>> ranges, s32 delta);
private:
struct TranslationEntry {
DAddr guest_page{};
u8* host_ptr{};
};
// Internal helper that performs the update assuming the caller already holds the necessary lock.
void UpdatePagesCachedCountNoLock(DAddr addr, size_t size, s32 delta);
@@ -195,6 +200,11 @@ private:
}
Common::VirtualBuffer<VAddr> cpu_backing_address;
inline static thread_local TranslationEntry t_slot0{};
inline static thread_local TranslationEntry t_slot1{};
inline static thread_local TranslationEntry t_slot2{};
inline static thread_local TranslationEntry t_slot3{};
inline static thread_local u32 cache_cursor = 0;
using CounterType = u8;
using CounterAtomicType = std::atomic_uint8_t;
static constexpr size_t subentries = 8 / sizeof(CounterType);
+97 -1
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
@@ -247,6 +247,10 @@ void DeviceMemoryManager<Traits>::Map(DAddr address, VAddr virtual_address, size
}
impl->multi_dev_address.Register(new_dev, start_id);
}
t_slot0 = {};
t_slot1 = {};
t_slot2 = {};
t_slot3 = {};
if (track) {
TrackContinuityImpl(address, virtual_address, size, asid);
}
@@ -278,6 +282,10 @@ void DeviceMemoryManager<Traits>::Unmap(DAddr address, size_t size) {
compressed_device_addr[phys_addr - 1] = new_start | MULTI_FLAG;
}
}
t_slot0 = {};
t_slot1 = {};
t_slot2 = {};
t_slot3 = {};
}
template <typename Traits>
void DeviceMemoryManager<Traits>::TrackContinuityImpl(DAddr address, VAddr virtual_address,
@@ -417,6 +425,50 @@ void DeviceMemoryManager<Traits>::WalkBlock(DAddr addr, std::size_t size, auto o
template <typename Traits>
void DeviceMemoryManager<Traits>::ReadBlock(DAddr address, void* dest_pointer, size_t size) {
device_inter->FlushRegion(address, size);
const std::size_t page_offset = address & Memory::YUZU_PAGEMASK;
if (size <= Memory::YUZU_PAGESIZE - page_offset) {
const DAddr guest_page = address & ~static_cast<DAddr>(Memory::YUZU_PAGEMASK);
if (t_slot0.guest_page == guest_page && t_slot0.host_ptr != nullptr) {
std::memcpy(dest_pointer, t_slot0.host_ptr + page_offset, size);
return;
}
if (t_slot1.guest_page == guest_page && t_slot1.host_ptr != nullptr) {
std::memcpy(dest_pointer, t_slot1.host_ptr + page_offset, size);
return;
}
if (t_slot2.guest_page == guest_page && t_slot2.host_ptr != nullptr) {
std::memcpy(dest_pointer, t_slot2.host_ptr + page_offset, size);
return;
}
if (t_slot3.guest_page == guest_page && t_slot3.host_ptr != nullptr) {
std::memcpy(dest_pointer, t_slot3.host_ptr + page_offset, size);
return;
}
const std::size_t page_index = address >> Memory::YUZU_PAGEBITS;
const auto phys_addr = compressed_physical_ptr[page_index];
if (phys_addr != 0) {
auto* const mem_ptr = GetPointerFromRaw<u8>(
(static_cast<PAddr>(phys_addr - 1) << Memory::YUZU_PAGEBITS));
switch (cache_cursor & 3U) {
case 0:
t_slot0 = TranslationEntry{.guest_page = guest_page, .host_ptr = mem_ptr};
break;
case 1:
t_slot1 = TranslationEntry{.guest_page = guest_page, .host_ptr = mem_ptr};
break;
case 2:
t_slot2 = TranslationEntry{.guest_page = guest_page, .host_ptr = mem_ptr};
break;
default:
t_slot3 = TranslationEntry{.guest_page = guest_page, .host_ptr = mem_ptr};
break;
}
cache_cursor = (cache_cursor + 1) & 3U;
std::memcpy(dest_pointer, mem_ptr + page_offset, size);
return;
}
}
WalkBlock(
address, size,
[&](size_t copy_amount, DAddr current_vaddr) {
@@ -455,6 +507,50 @@ void DeviceMemoryManager<Traits>::WriteBlock(DAddr address, const void* src_poin
template <typename Traits>
void DeviceMemoryManager<Traits>::ReadBlockUnsafe(DAddr address, void* dest_pointer, size_t size) {
const std::size_t page_offset = address & Memory::YUZU_PAGEMASK;
if (size <= Memory::YUZU_PAGESIZE - page_offset) {
const DAddr guest_page = address & ~static_cast<DAddr>(Memory::YUZU_PAGEMASK);
if (t_slot0.guest_page == guest_page && t_slot0.host_ptr != nullptr) {
std::memcpy(dest_pointer, t_slot0.host_ptr + page_offset, size);
return;
}
if (t_slot1.guest_page == guest_page && t_slot1.host_ptr != nullptr) {
std::memcpy(dest_pointer, t_slot1.host_ptr + page_offset, size);
return;
}
if (t_slot2.guest_page == guest_page && t_slot2.host_ptr != nullptr) {
std::memcpy(dest_pointer, t_slot2.host_ptr + page_offset, size);
return;
}
if (t_slot3.guest_page == guest_page && t_slot3.host_ptr != nullptr) {
std::memcpy(dest_pointer, t_slot3.host_ptr + page_offset, size);
return;
}
const std::size_t page_index = address >> Memory::YUZU_PAGEBITS;
const auto phys_addr = compressed_physical_ptr[page_index];
if (phys_addr != 0) {
auto* const mem_ptr = GetPointerFromRaw<u8>(
(static_cast<PAddr>(phys_addr - 1) << Memory::YUZU_PAGEBITS));
switch (cache_cursor & 3U) {
case 0:
t_slot0 = TranslationEntry{.guest_page = guest_page, .host_ptr = mem_ptr};
break;
case 1:
t_slot1 = TranslationEntry{.guest_page = guest_page, .host_ptr = mem_ptr};
break;
case 2:
t_slot2 = TranslationEntry{.guest_page = guest_page, .host_ptr = mem_ptr};
break;
default:
t_slot3 = TranslationEntry{.guest_page = guest_page, .host_ptr = mem_ptr};
break;
}
cache_cursor = (cache_cursor + 1) & 3U;
std::memcpy(dest_pointer, mem_ptr + page_offset, size);
return;
}
}
WalkBlock(
address, size,
[&](size_t copy_amount, DAddr current_vaddr) {