summaryrefslogtreecommitdiffstats
path: root/src/core/memory.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/memory.cpp')
-rw-r--r--src/core/memory.cpp94
1 files changed, 83 insertions, 11 deletions
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 514ba0d66..805963178 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -3,6 +3,7 @@
#include <algorithm>
#include <cstring>
+#include <span>
#include "common/assert.h"
#include "common/atomic_ops.h"
@@ -13,6 +14,7 @@
#include "common/swap.h"
#include "core/core.h"
#include "core/device_memory.h"
+#include "core/gpu_dirty_memory_manager.h"
#include "core/hardware_properties.h"
#include "core/hle/kernel/k_page_table.h"
#include "core/hle/kernel/k_process.h"
@@ -264,6 +266,22 @@ struct Memory::Impl {
ReadBlockImpl<true>(*system.ApplicationProcess(), src_addr, dest_buffer, size);
}
+ const u8* GetSpan(const VAddr src_addr, const std::size_t size) const {
+ if (current_page_table->blocks[src_addr >> YUZU_PAGEBITS] ==
+ current_page_table->blocks[(src_addr + size) >> YUZU_PAGEBITS]) {
+ return GetPointerSilent(src_addr);
+ }
+ return nullptr;
+ }
+
+ u8* GetSpan(const VAddr src_addr, const std::size_t size) {
+ if (current_page_table->blocks[src_addr >> YUZU_PAGEBITS] ==
+ current_page_table->blocks[(src_addr + size) >> YUZU_PAGEBITS]) {
+ return GetPointerSilent(src_addr);
+ }
+ return nullptr;
+ }
+
template <bool UNSAFE>
void WriteBlockImpl(const Kernel::KProcess& process, const Common::ProcessAddress dest_addr,
const void* src_buffer, const std::size_t size) {
@@ -557,7 +575,7 @@ struct Memory::Impl {
}
}
- const Common::ProcessAddress end = base + size;
+ const auto end = base + size;
ASSERT_MSG(end <= page_table.pointers.size(), "out of range mapping at {:016X}",
base + page_table.pointers.size());
@@ -568,14 +586,18 @@ struct Memory::Impl {
while (base != end) {
page_table.pointers[base].Store(nullptr, type);
page_table.backing_addr[base] = 0;
-
+ page_table.blocks[base] = 0;
base += 1;
}
} else {
+ auto orig_base = base;
while (base != end) {
- page_table.pointers[base].Store(
- system.DeviceMemory().GetPointer<u8>(target) - (base << YUZU_PAGEBITS), type);
- page_table.backing_addr[base] = GetInteger(target) - (base << YUZU_PAGEBITS);
+ auto host_ptr =
+ system.DeviceMemory().GetPointer<u8>(target) - (base << YUZU_PAGEBITS);
+ auto backing = GetInteger(target) - (base << YUZU_PAGEBITS);
+ page_table.pointers[base].Store(host_ptr, type);
+ page_table.backing_addr[base] = backing;
+ page_table.blocks[base] = orig_base << YUZU_PAGEBITS;
ASSERT_MSG(page_table.pointers[base].Pointer(),
"memory mapping base yield a nullptr within the table");
@@ -678,7 +700,7 @@ struct Memory::Impl {
LOG_ERROR(HW_Memory, "Unmapped Write{} @ 0x{:016X} = 0x{:016X}", sizeof(T) * 8,
GetInteger(vaddr), static_cast<u64>(data));
},
- [&]() { system.GPU().InvalidateRegion(GetInteger(vaddr), sizeof(T)); });
+ [&]() { HandleRasterizerWrite(GetInteger(vaddr), sizeof(T)); });
if (ptr) {
std::memcpy(ptr, &data, sizeof(T));
}
@@ -692,7 +714,7 @@ struct Memory::Impl {
LOG_ERROR(HW_Memory, "Unmapped WriteExclusive{} @ 0x{:016X} = 0x{:016X}",
sizeof(T) * 8, GetInteger(vaddr), static_cast<u64>(data));
},
- [&]() { system.GPU().InvalidateRegion(GetInteger(vaddr), sizeof(T)); });
+ [&]() { HandleRasterizerWrite(GetInteger(vaddr), sizeof(T)); });
if (ptr) {
const auto volatile_pointer = reinterpret_cast<volatile T*>(ptr);
return Common::AtomicCompareAndSwap(volatile_pointer, data, expected);
@@ -707,7 +729,7 @@ struct Memory::Impl {
LOG_ERROR(HW_Memory, "Unmapped WriteExclusive128 @ 0x{:016X} = 0x{:016X}{:016X}",
GetInteger(vaddr), static_cast<u64>(data[1]), static_cast<u64>(data[0]));
},
- [&]() { system.GPU().InvalidateRegion(GetInteger(vaddr), sizeof(u128)); });
+ [&]() { HandleRasterizerWrite(GetInteger(vaddr), sizeof(u128)); });
if (ptr) {
const auto volatile_pointer = reinterpret_cast<volatile u64*>(ptr);
return Common::AtomicCompareAndSwap(volatile_pointer, data, expected);
@@ -717,7 +739,7 @@ struct Memory::Impl {
void HandleRasterizerDownload(VAddr address, size_t size) {
const size_t core = system.GetCurrentHostThreadID();
- auto& current_area = rasterizer_areas[core];
+ auto& current_area = rasterizer_read_areas[core];
const VAddr end_address = address + size;
if (current_area.start_address <= address && end_address <= current_area.end_address)
[[likely]] {
@@ -726,9 +748,39 @@ struct Memory::Impl {
current_area = system.GPU().OnCPURead(address, size);
}
- Common::PageTable* current_page_table = nullptr;
- std::array<VideoCore::RasterizerDownloadArea, Core::Hardware::NUM_CPU_CORES> rasterizer_areas{};
+ void HandleRasterizerWrite(VAddr address, size_t size) {
+ const size_t core = system.GetCurrentHostThreadID();
+ auto& current_area = rasterizer_write_areas[core];
+ VAddr subaddress = address >> YUZU_PAGEBITS;
+ bool do_collection = current_area.last_address == subaddress;
+ if (!do_collection) [[unlikely]] {
+ do_collection = system.GPU().OnCPUWrite(address, size);
+ if (!do_collection) {
+ return;
+ }
+ current_area.last_address = subaddress;
+ }
+ gpu_dirty_managers[core].Collect(address, size);
+ }
+
+ struct GPUDirtyState {
+ VAddr last_address;
+ };
+
+ void InvalidateRegion(Common::ProcessAddress dest_addr, size_t size) {
+ system.GPU().InvalidateRegion(GetInteger(dest_addr), size);
+ }
+
+ void FlushRegion(Common::ProcessAddress dest_addr, size_t size) {
+ system.GPU().FlushRegion(GetInteger(dest_addr), size);
+ }
+
Core::System& system;
+ Common::PageTable* current_page_table = nullptr;
+ std::array<VideoCore::RasterizerDownloadArea, Core::Hardware::NUM_CPU_CORES>
+ rasterizer_read_areas{};
+ std::array<GPUDirtyState, Core::Hardware::NUM_CPU_CORES> rasterizer_write_areas{};
+ std::span<Core::GPUDirtyMemoryManager> gpu_dirty_managers;
};
Memory::Memory(Core::System& system_) : system{system_} {
@@ -857,6 +909,14 @@ void Memory::ReadBlockUnsafe(const Common::ProcessAddress src_addr, void* dest_b
impl->ReadBlockUnsafe(src_addr, dest_buffer, size);
}
+const u8* Memory::GetSpan(const VAddr src_addr, const std::size_t size) const {
+ return impl->GetSpan(src_addr, size);
+}
+
+u8* Memory::GetSpan(const VAddr src_addr, const std::size_t size) {
+ return impl->GetSpan(src_addr, size);
+}
+
void Memory::WriteBlock(const Common::ProcessAddress dest_addr, const void* src_buffer,
const std::size_t size) {
impl->WriteBlock(dest_addr, src_buffer, size);
@@ -876,6 +936,10 @@ void Memory::ZeroBlock(Common::ProcessAddress dest_addr, const std::size_t size)
impl->ZeroBlock(*system.ApplicationProcess(), dest_addr, size);
}
+void Memory::SetGPUDirtyManagers(std::span<Core::GPUDirtyMemoryManager> managers) {
+ impl->gpu_dirty_managers = managers;
+}
+
Result Memory::InvalidateDataCache(Common::ProcessAddress dest_addr, const std::size_t size) {
return impl->InvalidateDataCache(*system.ApplicationProcess(), dest_addr, size);
}
@@ -896,4 +960,12 @@ void Memory::MarkRegionDebug(Common::ProcessAddress vaddr, u64 size, bool debug)
impl->MarkRegionDebug(GetInteger(vaddr), size, debug);
}
+void Memory::InvalidateRegion(Common::ProcessAddress dest_addr, size_t size) {
+ impl->InvalidateRegion(dest_addr, size);
+}
+
+void Memory::FlushRegion(Common::ProcessAddress dest_addr, size_t size) {
+ impl->FlushRegion(dest_addr, size);
+}
+
} // namespace Core::Memory