aboutsummaryrefslogtreecommitdiff
path: root/src/video_core/memory_manager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/memory_manager.cpp')
-rw-r--r--src/video_core/memory_manager.cpp30
1 files changed, 22 insertions, 8 deletions
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp
index 2dd8b04656..9111ba10d2 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -14,6 +14,7 @@
#include "core/hle/kernel/k_process.h"
#include "memory_manager.h"
#include "video_core/guest_memory.h"
+#include "video_core/nx2.h"
#include "video_core/host1x/host1x.h"
#include "video_core/invalidation_accumulator.h"
#include "video_core/memory_manager.h"
@@ -119,7 +120,6 @@ GPUVAddr MemoryManager::PageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] DAddr de
if (entry_type == EntryType::Mapped) {
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{};
@@ -130,6 +130,7 @@ GPUVAddr MemoryManager::PageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] DAddr de
modified_size = 0;
}
};
+ for (u64 offset{}; offset < size; offset += page_size) {
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);
@@ -149,14 +150,13 @@ 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();
+ kind_map.Map(gpu_addr, gpu_addr + size, kind);
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 = [&] {
@@ -165,6 +165,7 @@ GPUVAddr MemoryManager::BigPageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] DAddr
modified_size = 0;
}
};
+ for (u64 offset{}; offset < size; offset += big_page_size) {
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);
@@ -201,8 +202,8 @@ 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);
}
@@ -300,6 +301,12 @@ void MemoryManager::Write(GPUVAddr addr, T data) {
std::memcpy(page_pointer, &data, sizeof(T));
return;
}
+ // A Switch 2 sparse block nobody wrote yet gets its memory now.
+ Tegra::Nx2BackSparseWrite(addr, sizeof(T));
+ if (auto page_pointer{GetPointer(addr)}; page_pointer) {
+ std::memcpy(page_pointer, &data, sizeof(T));
+ return;
+ }
ASSERT(false);
}
@@ -411,8 +418,12 @@ void MemoryManager::ReadBlockImpl(GPUVAddr gpu_src_addr, void* dest_buffer, std:
if (!unsafe) {
rasterizer->FlushRegion(dev_addr_base, copy_amount, which);
}
- u8* physical = memory.GetPointer<u8>(dev_addr_base);
- std::memcpy(dest_buffer, physical, copy_amount);
+ // A device page without memory (a sparse block nobody wrote yet) reads zero.
+ if (const u8* physical = memory.GetPointer<u8>(dev_addr_base)) [[likely]] {
+ std::memcpy(dest_buffer, physical, copy_amount);
+ } else {
+ std::memset(dest_buffer, 0, copy_amount);
+ }
dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount;
};
auto mapped_big = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
@@ -454,6 +465,8 @@ void MemoryManager::ReadBlockUnsafe(GPUVAddr gpu_src_addr, void* dest_buffer, co
}
void MemoryManager::WriteBlockImpl(GPUVAddr gpu_dest_addr, const void* src_buffer, std::size_t size, [[maybe_unused]] VideoCommon::CacheType which, bool unsafe) {
+ // Give Switch 2 sparse pages the write lands on their memory first (otherwise it is dropped).
+ Tegra::Nx2BackSparseWrite(gpu_dest_addr, size);
auto just_advance = [&]([[maybe_unused]] std::size_t page_index, [[maybe_unused]] std::size_t offset, std::size_t copy_amount) {
src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
};
@@ -462,8 +475,9 @@ void MemoryManager::WriteBlockImpl(GPUVAddr gpu_dest_addr, const void* src_buffe
if (!unsafe) {
rasterizer->InvalidateRegion(dev_addr_base, copy_amount, which);
}
- u8* physical = memory.GetPointer<u8>(dev_addr_base);
- std::memcpy(physical, src_buffer, copy_amount);
+ if (u8* physical = memory.GetPointer<u8>(dev_addr_base)) [[likely]] {
+ std::memcpy(physical, src_buffer, copy_amount);
+ }
src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
};
auto mapped_big = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {