diff options
| author | Mike Lothian <mike@fireburn.co.uk> | 2026-09-11 14:29:15 +0100 |
|---|---|---|
| committer | Mike Lothian <mike@fireburn.co.uk> | 2026-09-11 14:29:24 +0100 |
| commit | de59cac56f332469a50b7ac59c31d693ad762927 (patch) | |
| tree | cade7bf9a81c482369ea6fee3142d5ae7af2df5c | |
| parent | 3931ccc4e2fa90e7b094c7919f98232d6b9dce9f (diff) | |
core, video_core: Fix DeviceMemoryManager unmap continuity, buffer cache bounds, and 8GB DRAM sizingcherry-pick-torzu
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_32.cpp | 4 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_64.cpp | 4 | ||||
| -rw-r--r-- | src/core/device_memory_manager.inc | 91 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/core/heap_mapper.cpp | 3 | ||||
| -rw-r--r-- | src/video_core/buffer_cache/buffer_cache.h | 38 |
5 files changed, 94 insertions, 46 deletions
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 56d76e136..d6193e7e9 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -295,7 +295,9 @@ std::shared_ptr<Dynarmic::A32::Jit> ArmDynarmic32::MakeJit(Common::PageTable* pa config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN; - config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; + if (Settings::values.cpuopt_unsafe_ignore_global_monitor.GetValue()) { + config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; + } } // Paranoia mode for debugging optimizations diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index c40ff6b83..2d676cf52 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -348,7 +348,9 @@ std::shared_ptr<Dynarmic::A64::Jit> ArmDynarmic64::MakeJit(Common::PageTable* pa config.unsafe_optimizations = true; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; config.fastmem_address_space_bits = 64; - config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; + if (Settings::values.cpuopt_unsafe_ignore_global_monitor.GetValue()) { + config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; + } } // Paranoia mode for debugging optimizations diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc index ebb9d8b1a..a3adaeda5 100644 --- a/src/core/device_memory_manager.inc +++ b/src/core/device_memory_manager.inc @@ -16,6 +16,7 @@ #include "core/device_memory.h" #include "core/device_memory_manager.h" #include "core/memory.h" +#include "hle/kernel/board/nintendo/nx/k_system_control.h" namespace Core { @@ -28,21 +29,24 @@ public: void GatherValues(u32 start_entry, Common::ScratchBuffer<u32>& buffer) { buffer.resize(8); - buffer.resize(0); - size_t index = 0; - const auto add_value = [&](u32 value) { - buffer.resize(index + 1); + const auto add_value = [&buffer](u32 value, size_t index) { + if (buffer.size() < index + 1) { + buffer.resize(index + 8); + } buffer[index++] = value; + return index; }; + size_t index = 0; u32 iter_entry = start_entry; Entry* current = &storage[iter_entry - 1]; - add_value(current->value); + index = add_value(current->value, index); while (current->next_entry != 0) { iter_entry = current->next_entry; current = &storage[iter_entry - 1]; - add_value(current->value); + index = add_value(current->value, index); } + buffer.resize(index); } u32 Register(u32 value) { @@ -163,11 +167,9 @@ template <typename Traits> DeviceMemoryManager<Traits>::DeviceMemoryManager(const DeviceMemory& device_memory_) : physical_base{reinterpret_cast<const uintptr_t>(device_memory_.buffer.BackingBasePointer())}, device_inter{nullptr}, compressed_physical_ptr(device_as_size >> Memory::YUZU_PAGEBITS), - compressed_device_addr(1ULL << ((Settings::values.memory_layout_mode.GetValue() == - Settings::MemoryLayout::Memory_4Gb - ? physical_min_bits - : physical_max_bits) - - Memory::YUZU_PAGEBITS)), + compressed_device_addr(Common::AlignUp( + Kernel::Board::Nintendo::Nx::KSystemControl::Init::GetIntendedMemorySize(), + Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS), continuity_tracker(device_as_size >> Memory::YUZU_PAGEBITS), cpu_backing_address(device_as_size >> Memory::YUZU_PAGEBITS) { impl = std::make_unique<DeviceMemoryManagerAllocator<Traits>>(); @@ -179,11 +181,9 @@ DeviceMemoryManager<Traits>::DeviceMemoryManager(const DeviceMemory& device_memo continuity_tracker[i] = 1; cpu_backing_address[i] = 0; } - const size_t total_phys = 1ULL << ((Settings::values.memory_layout_mode.GetValue() == - Settings::MemoryLayout::Memory_4Gb - ? physical_min_bits - : physical_max_bits) - - Memory::YUZU_PAGEBITS); + const size_t total_phys = Common::AlignUp( + Kernel::Board::Nintendo::Nx::KSystemControl::Init::GetIntendedMemorySize(), + Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS; for (size_t i = 0; i < total_phys; i++) { compressed_device_addr[i] = 0; } @@ -257,6 +257,7 @@ void DeviceMemoryManager<Traits>::Unmap(DAddr address, size_t size) { auto phys_addr = compressed_physical_ptr[start_page_d + i]; compressed_physical_ptr[start_page_d + i] = 0; cpu_backing_address[start_page_d + i] = 0; + continuity_tracker[start_page_d + i] = 1; if (phys_addr != 0) [[likely]] { const u32 base_dev = compressed_device_addr[phys_addr - 1U]; if ((base_dev >> MULTI_FLAG_BITS) == 0) [[likely]] { @@ -273,6 +274,16 @@ void DeviceMemoryManager<Traits>::Unmap(DAddr address, size_t size) { compressed_device_addr[phys_addr - 1] = new_start | MULTI_FLAG; } } + if (start_page_d > 0) { + for (size_t p = start_page_d; p > 0; p--) { + size_t prev_page = p - 1; + if (prev_page + continuity_tracker[prev_page] > start_page_d) { + continuity_tracker[prev_page] = static_cast<u32>(start_page_d - prev_page); + } else { + break; + } + } + } } template <typename Traits> void DeviceMemoryManager<Traits>::TrackContinuityImpl(DAddr address, VAddr virtual_address, @@ -287,7 +298,7 @@ void DeviceMemoryManager<Traits>::TrackContinuityImpl(DAddr address, VAddr virtu const VAddr new_vaddress = virtual_address + index * Memory::YUZU_PAGESIZE; const uintptr_t new_ptr = reinterpret_cast<uintptr_t>( process_memory->GetPointerSilent(Common::ProcessAddress(new_vaddress))); - if (new_ptr + page_size == last_ptr) { + if (new_ptr != 0 && last_ptr != 0 && new_ptr + page_size == last_ptr) { page_count++; } else { page_count = 1; @@ -386,26 +397,39 @@ void DeviceMemoryManager<Traits>::WalkBlock(DAddr addr, std::size_t size, auto o std::size_t page_offset = addr & Memory::YUZU_PAGEMASK; while (remaining_size) { - const size_t next_pages = static_cast<std::size_t>(continuity_tracker[page_index]); - const std::size_t copy_amount = - std::min((next_pages << Memory::YUZU_PAGEBITS) - page_offset, remaining_size); - const auto current_vaddr = - static_cast<u64>((page_index << Memory::YUZU_PAGEBITS) + page_offset); - SCOPE_EXIT{ - page_index += next_pages; - page_offset = 0; - increment(copy_amount); - remaining_size -= copy_amount; - }; - auto phys_addr = compressed_physical_ptr[page_index]; if (phys_addr == 0) { + size_t unmapped_pages = 1; + while ((unmapped_pages << Memory::YUZU_PAGEBITS) - page_offset < remaining_size && + compressed_physical_ptr[page_index + unmapped_pages] == 0) { + unmapped_pages++; + } + const std::size_t copy_amount = + std::min((unmapped_pages << Memory::YUZU_PAGEBITS) - page_offset, remaining_size); + const auto current_vaddr = + static_cast<u64>((page_index << Memory::YUZU_PAGEBITS) + page_offset); on_unmapped(copy_amount, current_vaddr); + page_index += unmapped_pages; + page_offset = 0; + increment(copy_amount); + remaining_size -= copy_amount; continue; } + + size_t next_pages = std::max<size_t>(1, static_cast<std::size_t>(continuity_tracker[page_index])); + if (compressed_physical_ptr[page_index + next_pages - 1] == 0) { + next_pages = 1; + } + const std::size_t copy_amount = + std::min((next_pages << Memory::YUZU_PAGEBITS) - page_offset, remaining_size); auto* mem_ptr = GetPointerFromRaw<u8>( (static_cast<PAddr>(phys_addr - 1) << Memory::YUZU_PAGEBITS) + page_offset); on_memory(copy_amount, mem_ptr); + + page_index += next_pages; + page_offset = 0; + increment(copy_amount); + remaining_size -= copy_amount; } } @@ -419,13 +443,10 @@ void DeviceMemoryManager<Traits>::ReadBlock(DAddr address, void* dest_pointer, s WalkBlock( address, size, [&](size_t copy_amount, DAddr current_vaddr) { - // Fill unmapped memory with a known pattern instead of zeros - constexpr u8 UNMAPPED_MEMORY_PATTERN = 0xCC; - std::memset(dest_pointer, UNMAPPED_MEMORY_PATTERN, copy_amount); + std::memset(dest_pointer, 0, copy_amount); LOG_DEBUG(HW_Memory, - "Unmapped Device ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {}). " - "Filling with pattern 0x{:02X}", - current_vaddr, address, size, UNMAPPED_MEMORY_PATTERN); + "Unmapped Device ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", + current_vaddr, address, size); }, [&](size_t copy_amount, const u8* const src_ptr) { if (src_ptr) { diff --git a/src/core/hle/service/nvdrv/core/heap_mapper.cpp b/src/core/hle/service/nvdrv/core/heap_mapper.cpp index af17e3e85..3f2418771 100644 --- a/src/core/hle/service/nvdrv/core/heap_mapper.cpp +++ b/src/core/hle/service/nvdrv/core/heap_mapper.cpp @@ -51,7 +51,8 @@ DAddr HeapMapper::Map(VAddr start, size_t size) { m_internal->m_temporary_set.ForEach([this](VAddr start_addr, VAddr end_addr) { const size_t sub_size = end_addr - start_addr; const size_t offset = start_addr - m_vaddress; - m_internal->m_device_memory.Map(m_daddress + offset, m_vaddress + offset, sub_size, m_asid); + m_internal->m_device_memory.Map(m_daddress + offset, m_vaddress + offset, sub_size, + m_asid, true); }); // Add the mapping range to the split map, to register the map and overlaps. diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index 7351e2fc3..87dda9a9b 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h @@ -1513,6 +1513,27 @@ void BufferCache<P>::MappedUploadMemory([[maybe_unused]] Buffer& buffer, if constexpr (USE_MEMORY_MAPS) { auto upload_staging = runtime.UploadStagingBuffer(total_size_bytes); const std::span<u8> staging_pointer = upload_staging.mapped_span; + if (staging_pointer.size() < total_size_bytes) { + LOG_ERROR(HW_Memory, + "BufferCache rejected short mapped upload staging allocation: " + "buffer_base=0x{:016X} buffer_size={} staging_size={} total_size={}", + buffer.CpuAddr(), buffer.SizeBytes(), staging_pointer.size(), total_size_bytes); + return; + } + for (const BufferCopy& copy : copies) { + if (copy.src_offset > staging_pointer.size() || + copy.size > staging_pointer.size() - copy.src_offset || + copy.dst_offset > buffer.SizeBytes() || + copy.size > buffer.SizeBytes() - copy.dst_offset) { + LOG_ERROR(HW_Memory, + "BufferCache rejected out-of-bounds mapped upload: buffer_base=0x{:016X} " + "buffer_size={} staging_size={} total_size={} src_offset={} dst_offset={} " + "copy_size={}", + buffer.CpuAddr(), buffer.SizeBytes(), staging_pointer.size(), + total_size_bytes, copy.src_offset, copy.dst_offset, copy.size); + return; + } + } for (BufferCopy& copy : copies) { u8* const src_pointer = staging_pointer.data() + copy.src_offset; const DAddr device_addr = buffer.CpuAddr() + copy.dst_offset; @@ -1782,15 +1803,16 @@ TextureBufferBinding BufferCache<P>::GetTextureBufferBinding(GPUVAddr gpu_addr, template <class P> std::span<const u8> BufferCache<P>::ImmediateBufferWithData(DAddr device_addr, size_t size) { - u8* const base_pointer = device_memory.GetPointer<u8>(device_addr); - if (IsRangeGranular(device_addr, size) || - base_pointer + size == device_memory.GetPointer<u8>(device_addr + size)) { - return std::span(base_pointer, size); - } else { - const std::span<u8> span = ImmediateBuffer(size); - device_memory.ReadBlockUnsafe(device_addr, span.data(), size); - return span; + if (IsRangeGranular(device_addr, size)) { + if (u8* const base_pointer = device_memory.GetPointer<u8>(device_addr)) { + return std::span(base_pointer, size); + } + } else if (u8* const span_pointer = device_memory.GetSpan(device_addr, size)) { + return std::span(span_pointer, size); } + const std::span<u8> span = ImmediateBuffer(size); + device_memory.ReadBlockUnsafe(device_addr, span.data(), size); + return span; } template <class P> |
