aboutsummaryrefslogtreecommitdiff
path: root/src/video_core/memory_manager.cpp
diff options
context:
space:
mode:
authorTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-30 04:39:42 -0400
committerkraibse <33869366+kraibse@users.noreply.github.com>2026-10-30 17:27:04 +0100
commitf9fc1e10fd7ed0a1c4664d48d2f095ce8826d87b (patch)
tree5d342dcbb0eaee7c81a01d1258f3143922a80824 /src/video_core/memory_manager.cpp
parentf362528c0447c491bfe00c0bdd5d8c245396a24c (diff)
memory_manager: notify the caches once per changed range
PageTableOp and BigPageTableOp called ModifyGPUMemory for every page whose entry changed, and each call scans the texture and buffer caches. Mapping one of Mario Kart World's 1.45 GB sparse regions made ~370,000 of those scans. Runs of changed pages are now reported as one range.
Diffstat (limited to 'src/video_core/memory_manager.cpp')
-rw-r--r--src/video_core/memory_manager.cpp34
1 files changed, 32 insertions, 2 deletions
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp
index 0eae8fac24..2dd8b04656 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -120,11 +120,26 @@ GPUVAddr MemoryManager::PageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] DAddr de
page_table.ReserveRange(gpu_addr, size);
}
for (u64 offset{}; offset < size; offset += page_size) {
+ // The caches hear about each run of pages whose entry changed in one call, not page by page
+ // (a 1.45 GB Switch 2 region made ~370,000 texture cache scans).
+ GPUVAddr modified_start{};
+ u64 modified_size{};
+ const auto flush_modified = [&] {
+ if (modified_size != 0) {
+ rasterizer->ModifyGPUMemory(unique_identifier, modified_start, modified_size);
+ modified_size = 0;
+ }
+ };
const GPUVAddr current_gpu_addr = gpu_addr + offset;
[[maybe_unused]] const auto current_entry_type = GetEntry(current_gpu_addr, false);
SetEntry(current_gpu_addr, entry_type, false);
if (current_entry_type != entry_type) {
- rasterizer->ModifyGPUMemory(unique_identifier, current_gpu_addr, page_size);
+ if (modified_size == 0) {
+ modified_start = current_gpu_addr;
+ }
+ modified_size += page_size;
+ } else {
+ flush_modified();
}
if (entry_type == EntryType::Mapped) {
const DAddr current_dev_addr = dev_addr + offset;
@@ -135,17 +150,31 @@ GPUVAddr MemoryManager::PageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] DAddr de
remaining_size -= page_size;
}
kind_map.Map(gpu_addr, gpu_addr + size, kind);
+ flush_modified();
return gpu_addr;
}
GPUVAddr MemoryManager::BigPageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] DAddr dev_addr, size_t size, PTEKind kind, MemoryManager::EntryType entry_type) {
[[maybe_unused]] u64 remaining_size{size};
for (u64 offset{}; offset < size; offset += big_page_size) {
+ GPUVAddr modified_start{};
+ u64 modified_size{};
+ const auto flush_modified = [&] {
+ if (modified_size != 0) {
+ rasterizer->ModifyGPUMemory(unique_identifier, modified_start, modified_size);
+ modified_size = 0;
+ }
+ };
const GPUVAddr current_gpu_addr = gpu_addr + offset;
[[maybe_unused]] const auto current_entry_type = GetEntry(current_gpu_addr, true);
SetEntry(current_gpu_addr, entry_type, true);
if (current_entry_type != entry_type) {
- rasterizer->ModifyGPUMemory(unique_identifier, current_gpu_addr, big_page_size);
+ if (modified_size == 0) {
+ modified_start = current_gpu_addr;
+ }
+ modified_size += big_page_size;
+ } else {
+ flush_modified();
}
if (entry_type == EntryType::Mapped) {
const DAddr current_dev_addr = dev_addr + offset;
@@ -173,6 +202,7 @@ GPUVAddr MemoryManager::BigPageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] DAddr
remaining_size -= big_page_size;
}
{
+ flush_modified();
std::unique_lock<std::mutex> lock(guard);
kind_map.Map(gpu_addr, gpu_addr + size, kind);
}