aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMako <137927095+Takoroka@users.noreply.github.com>2026-10-30 21:10:10 -0400
committerGitHub <noreply@github.com>2026-10-30 21:10:10 -0400
commitb40ad217ab829226841cb71f6e4c5cb05977a225 (patch)
treef6401dcd82c03ce1e1b03ab728818f149a0e9277 /src
parent783ddef23ecb7ed51ef6466ad401745f85acbb7f (diff)
parentddd367a8152f1c37bfc972475b40afece2da31ac (diff)
Merge pull request #48 from Djihads80/fix/device-memory-page-runs
core: end device page runs where pages are unmapped or mapped again
Diffstat (limited to 'src')
-rw-r--r--src/core/device_memory_manager.h2
-rw-r--r--src/core/device_memory_manager.inc21
2 files changed, 23 insertions, 0 deletions
diff --git a/src/core/device_memory_manager.h b/src/core/device_memory_manager.h
index 46cda14e78..9c034f01a1 100644
--- a/src/core/device_memory_manager.h
+++ b/src/core/device_memory_manager.h
@@ -187,6 +187,8 @@ private:
void WalkBlock(const DAddr addr, const std::size_t size, auto on_unmapped, auto on_memory,
auto increment);
+ void CutContinuityAt(size_t page);
+
void InnerGatherDeviceAddresses(Common::ScratchBuffer<u32>& buffer, PAddr address);
std::unique_ptr<DeviceMemoryManagerAllocator<Traits>> impl;
diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc
index d78a229e1f..c45bc71656 100644
--- a/src/core/device_memory_manager.inc
+++ b/src/core/device_memory_manager.inc
@@ -211,9 +211,13 @@ void DeviceMemoryManager<Traits>::Map(DAddr address, VAddr virtual_address, size
std::scoped_lock lk(mapping_guard);
tracked_entries.CommitRegion(start_page_d, start_page_d + num_pages);
+ CutContinuityAt(start_page_d);
for (size_t i = 0; i < num_pages; i++) {
const VAddr new_vaddress = virtual_address + i * Memory::YUZU_PAGESIZE;
auto* ptr = process_memory->GetPointerSilent(Common::ProcessAddress(new_vaddress));
+ // One page per run unless tracked below: a run left from an earlier mapping of these
+ // device pages would make WalkBlock copy the host memory that followed that mapping.
+ tracked_entries.GetUnchecked(start_page_d + i).continuity_tracker = 0;
if (ptr == nullptr) [[unlikely]] {
tracked_entries.GetUnchecked(start_page_d + i).compressed_physical_ptr = 0;
continue;
@@ -248,11 +252,13 @@ void DeviceMemoryManager<Traits>::Unmap(DAddr address, size_t size) {
std::scoped_lock lk(mapping_guard);
tracked_entries.CommitRegion(start_page_d, start_page_d + num_pages); // should already be committed, but just in case
+ CutContinuityAt(start_page_d);
for (size_t i = 0; i < num_pages; i++) {
auto& entry = tracked_entries.GetUnchecked(start_page_d + i);
auto phys_addr = entry.compressed_physical_ptr;
entry.compressed_physical_ptr = 0;
entry.cpu_backing_address = 0;
+ entry.continuity_tracker = 0;
if (phys_addr != 0) [[likely]] {
u32& base_dev = compressed_device_addr.GetAndFault(phys_addr - 1U);
if ((base_dev >> MULTI_FLAG_BITS) == 0) [[likely]] {
@@ -270,6 +276,21 @@ void DeviceMemoryManager<Traits>::Unmap(DAddr address, size_t size) {
}
translation_generation.fetch_add(1, std::memory_order_release);
}
+
+template <typename Traits>
+void DeviceMemoryManager<Traits>::CutContinuityAt(size_t page) {
+ // Runs counted from the pages before `page` end there: the pages from `page` on are being
+ // mapped again or unmapped. A run is counted down page by page (TrackContinuityImpl), so the
+ // first page whose run already ends before `page` ends the walk.
+ for (size_t index = page; index-- > 0;) {
+ const size_t last_count = page - 1 - index;
+ if (tracked_entries[index].continuity_tracker <= last_count) {
+ break;
+ }
+ tracked_entries.GetUnchecked(index).continuity_tracker = static_cast<u32>(last_count);
+ }
+}
+
template <typename Traits>
void DeviceMemoryManager<Traits>::TrackContinuityImpl(DAddr address, VAddr virtual_address,
size_t size, Asid asid) {