From ba11ea2eb938e8feec100ac7dc8583c3f16e753a Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Fri, 7 Aug 2026 15:54:08 -0400 Subject: [PATCH] [TEST] Adjustment AHB to tiled-gpu-v2 state --- src/common/heap_tracker.cpp | 48 +++------- src/common/heap_tracker.h | 3 - src/common/host_memory.cpp | 95 ++++++------------- src/common/host_memory.h | 2 - .../vulkan_common/vulkan_memory_allocator.cpp | 22 ++--- 5 files changed, 49 insertions(+), 121 deletions(-) diff --git a/src/common/heap_tracker.cpp b/src/common/heap_tracker.cpp index 0ca8683a34..b72abb16d8 100644 --- a/src/common/heap_tracker.cpp +++ b/src/common/heap_tracker.cpp @@ -4,43 +4,34 @@ // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include +#include #include "common/heap_tracker.h" #include "common/logging.h" #include "common/assert.h" -#include "common/memory_detect.h" namespace Common { namespace { -s64 GetMaxPermissibleResidentMapCount(const Common::HostMemory& buffer) { +s64 GetMaxPermissibleResidentMapCount() { // Default value. - constexpr s64 DefaultMaxMapCount = 65530; + s64 value = 65530; // Try to read how many mappings we can make. - const u64 reported = Common::GetMaxMapCount(); - const s64 value = reported != 0 ? static_cast(reported) : DefaultMaxMapCount; + std::ifstream s("/proc/sys/vm/max_map_count"); + s >> value; // Print, for debug. LOG_INFO(HW_Memory, "Current maximum map count: {}", value); // Allow 20000 maps for other code and to account for split inaccuracy. - constexpr s64 ForeignMapReservation = 20000; - - const size_t hardware_buffer_windows = buffer.BackingHardwareBuffers().size(); - const s64 unmergeable_window_boundaries = - hardware_buffer_windows != 0 ? static_cast(hardware_buffer_windows) + 1 : 0; - - return std::max(value - ForeignMapReservation - unmergeable_window_boundaries, 0); + return std::max(value - 20000, 0); } } // namespace HeapTracker::HeapTracker(Common::HostMemory& buffer) - : m_buffer(buffer), - m_has_hardware_buffer_backing(!buffer.BackingHardwareBuffers().empty()), - m_max_resident_map_count(GetMaxPermissibleResidentMapCount(buffer)) {} + : m_buffer(buffer), m_max_resident_map_count(GetMaxPermissibleResidentMapCount()) {} HeapTracker::~HeapTracker() = default; void HeapTracker::Map(size_t virtual_offset, size_t host_offset, size_t length, @@ -94,8 +85,7 @@ void HeapTracker::Unmap(size_t virtual_offset, size_t size, bool is_separate_hea // If resident, erase from resident map. if (item->is_resident) { - m_resident_map_count -= this->HostMapCount(item->paddr, item->size); - ASSERT(m_resident_map_count >= 0); + ASSERT(--m_resident_map_count >= 0); m_resident_mappings.erase(m_resident_mappings.iterator_to(*item)); } @@ -201,7 +191,7 @@ bool HeapTracker::DeferredMapSeparateHeap(size_t virtual_offset) { // This map is now resident. it->is_resident = true; - m_resident_map_count += this->HostMapCount(it->paddr, it->size); + m_resident_map_count++; m_resident_mappings.insert(*it); } @@ -223,17 +213,17 @@ void HeapTracker::RebuildSeparateHeapAddressSpace() { // Despite being worse in theory, this has proven to be better in practice than more // regularly dumping a smaller amount, because it significantly reduces average case // lock contention. - s64 const desired_count = (std::min)(m_resident_map_count, m_max_resident_map_count) / 2; + std::size_t const desired_count = (std::min)(m_resident_map_count, m_max_resident_map_count) / 2; + std::size_t const evict_count = m_resident_map_count - desired_count; auto it = m_resident_mappings.begin(); - while (m_resident_map_count > desired_count && it != m_resident_mappings.end()) { + for (size_t i = 0; i < evict_count && it != m_resident_mappings.end(); i++) { // Unmark and unmap. it->is_resident = false; m_buffer.Unmap(it->vaddr, it->size, false); // Advance. - m_resident_map_count -= this->HostMapCount(it->paddr, it->size); - ASSERT(m_resident_map_count >= 0); + ASSERT(--m_resident_map_count >= 0); it = m_resident_mappings.erase(it); } } @@ -255,7 +245,6 @@ void HeapTracker::SplitHeapMapLocked(VAddr offset) { // Cache the original values. auto* const left = std::addressof(*it); const size_t orig_size = left->size; - const s64 orig_host_map_count = this->HostMapCount(left->paddr, orig_size); // Adjust the left map. const size_t left_size = offset - left->vaddr; @@ -277,20 +266,11 @@ void HeapTracker::SplitHeapMapLocked(VAddr offset) { // If resident, also insert into resident map. if (right->is_resident) { - m_resident_map_count += this->HostMapCount(left->paddr, left->size) + - this->HostMapCount(right->paddr, right->size) - - orig_host_map_count; + m_resident_map_count++; m_resident_mappings.insert(*right); } } -s64 HeapTracker::HostMapCount(PAddr paddr, size_t size) const { - if (!m_has_hardware_buffer_backing) { - return size != 0 ? 1 : 0; - } - return static_cast(m_buffer.BackingMapCount(paddr, size)); -} - HeapTracker::AddrTree::iterator HeapTracker::GetNearestHeapMapLocked(VAddr offset) { const SeparateHeapMap key{ .vaddr = offset, diff --git a/src/common/heap_tracker.h b/src/common/heap_tracker.h index 8be66a1d4d..9cc25f7964 100644 --- a/src/common/heap_tracker.h +++ b/src/common/heap_tracker.h @@ -85,13 +85,10 @@ private: AddrTree::iterator GetNearestHeapMapLocked(VAddr offset); - s64 HostMapCount(PAddr paddr, size_t size) const; - void RebuildSeparateHeapAddressSpace(); private: Common::HostMemory& m_buffer; - const bool m_has_hardware_buffer_backing; const s64 m_max_resident_map_count; std::shared_mutex m_rebuild_lock{}; diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index 88b71b32d3..cb7ec1ffa7 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -670,37 +670,44 @@ public: return ok; } - size_t ComputeAhbWindowCount(size_t window_size) const { + size_t ComputeAhbBudget(size_t window_size) const { const u64 total_physical = Common::GetMemInfo().TotalPhysicalMemory; if (total_physical == 0) { LOG_WARNING(HW_Memory, "Host memory size is unknown, not committing hardware buffers"); return 0; } - constexpr u64 MinimumTotalPhysical = 5632ULL << 20; + constexpr u64 MinimumTotalPhysical = 7ULL << 30; if (total_physical < MinimumTotalPhysical) { LOG_INFO(HW_Memory, "Skipping hardware buffer backing, {} MiB of RAM is below the {} MiB minimum", total_physical >> 20, MinimumTotalPhysical >> 20); return 0; } - constexpr u64 MaxWindows = 2; - u64 windows = MaxWindows; - windows = (std::min)(windows, (total_physical / 6) / window_size); + const u64 max_map_count = Common::GetMaxMapCount(); + constexpr u64 ReservedMaps = 24576; + if (max_map_count == 0 || max_map_count <= ReservedMaps) { + LOG_WARNING(HW_Memory, + "Skipping hardware buffer backing, vm.max_map_count is unknown or too low"); + return 0; + } + u64 budget = total_physical / 6; + budget = (std::min)(budget, (max_map_count - ReservedMaps) * PageAlignment); const u64 available = Common::GetAvailablePhysicalMemory(); if (available != 0) { constexpr u64 Headroom = 2ULL << 30; - const u64 spare = available > Headroom ? available - Headroom : 0; - windows = (std::min)(windows, spare / window_size); + budget = (std::min)(budget, available > Headroom ? available - Headroom : 0); } - windows = (std::min)(windows, static_cast(backing_size) / window_size); - if (windows == 0) { + budget = (std::min)(budget, static_cast(backing_size)); + budget = Common::AlignDown(budget, window_size); + constexpr u64 MinimumBudget = 256ULL << 20; + if (budget < MinimumBudget) { LOG_INFO(HW_Memory, - "Skipping hardware buffer backing, no {} MiB window fits on a {} MiB system " - "with {} MiB available", - window_size >> 20, total_physical >> 20, available >> 20); + "Skipping hardware buffer backing, only {} MiB could be committed on a {} MiB " + "system with {} MiB available and vm.max_map_count {}", + budget >> 20, total_physical >> 20, available >> 20, max_map_count); return 0; } - return static_cast(windows); + return static_cast(budget); } bool InitAhbBacking() { @@ -713,38 +720,25 @@ public: LOG_WARNING(HW_Memory, "AHardwareBuffer_getNativeHandle is not available"); return false; } - constexpr size_t WindowCandidates[] = { - 512ULL << 20, - 256ULL << 20, - 128ULL << 20, - 64ULL << 20, - }; - static_assert(WindowCandidates[0] <= 0xFFFFFFFFull, - "AHARDWAREBUFFER_FORMAT_BLOB encodes its size in a u32 width"); - size_t window_size = 0; - for (const size_t candidate : WindowCandidates) { - const AHardwareBuffer_Desc candidate_desc = MakeBlobDesc(candidate); - if (AHardwareBuffer_isSupported(&candidate_desc) != 0) { - window_size = candidate; - break; - } - LOG_INFO(HW_Memory, "Allocator rejects {} MiB hardware buffer windows", candidate >> 20); - } - if (window_size == 0) { - LOG_WARNING(HW_Memory, "No hardware buffer window size is supported"); + constexpr size_t window_size = 64ULL << 20; + const AHardwareBuffer_Desc window_desc = MakeBlobDesc(window_size); + if (AHardwareBuffer_isSupported(&window_desc) == 0) { + LOG_WARNING(HW_Memory, "Allocator rejects {} MiB hardware buffer windows", + window_size >> 20); return false; } - const size_t num_windows = ComputeAhbWindowCount(window_size); - if (num_windows == 0) { + const size_t budget = ComputeAhbBudget(window_size); + if (budget == 0) { return false; } if (!ProbeAhbBacking(get_native_handle)) { return false; } const size_t aligned_backing = Common::AlignDown(backing_size, window_size); - const size_t region_size = num_windows * window_size; + const size_t region_size = (std::min)(budget, aligned_backing); const size_t region_base = Common::AlignDown( (std::min)(preferred_offset, aligned_backing - region_size), window_size); + const size_t num_windows = region_size / window_size; std::vector buffers; std::vector buffer_fds; @@ -852,29 +846,6 @@ public: } } - size_t BackingMapCount(size_t host_offset, size_t length) const noexcept { - if (length == 0) { - return 0; - } - if (ahb_bytes == 0) { - return 1; - } - size_t count = 0; - while (length > 0) { - size_t chunk = length; - if (host_offset < ahb_base) { - chunk = (std::min)(chunk, ahb_base - host_offset); - } else if (host_offset < ahb_base + ahb_bytes) { - const size_t local = (host_offset - ahb_base) % ahb_window_size; - chunk = (std::min)(chunk, ahb_window_size - local); - } - host_offset += chunk; - length -= chunk; - ++count; - } - return count; - } - std::span AhbWindows() const noexcept { return ahb_windows; } @@ -1132,14 +1103,6 @@ std::span HostMemory::BackingHardwareBuffers() const noe #endif } -size_t HostMemory::BackingMapCount(size_t host_offset, size_t length) const noexcept { -#ifdef __ANDROID__ - return impl ? impl->BackingMapCount(host_offset, length) : (length != 0 ? 1 : 0); -#else - return length != 0 ? 1 : 0; -#endif -} - size_t HostMemory::BackingHardwareBufferWindowSize() const noexcept { #ifdef __ANDROID__ return impl ? impl->AhbWindowSize() : 0; diff --git a/src/common/host_memory.h b/src/common/host_memory.h index a70ceebc20..13d4830028 100644 --- a/src/common/host_memory.h +++ b/src/common/host_memory.h @@ -71,8 +71,6 @@ public: return backing_size; } - [[nodiscard]] size_t BackingMapCount(size_t host_offset, size_t length) const noexcept; - [[nodiscard]] std::span BackingHardwareBuffers() const noexcept; [[nodiscard]] size_t BackingHardwareBufferWindowSize() const noexcept; diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp index a8d04a6ed9..f498c2c287 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp @@ -233,10 +233,10 @@ namespace Vulkan { size)) { return; } - if (device.IsTiler()) { + if (!hardware_buffers.empty()) { LOG_INFO(Render_Vulkan, - "Unified memory disabled, hardware buffer import is the only path supported " - "by tiler drivers"); + "Unified memory disabled, guest memory is backed by hardware buffers that " + "could not be imported"); return; } if (ImportHostPointer(base, size)) { @@ -260,8 +260,7 @@ namespace Vulkan { return false; } using namespace Common::Literals; - constexpr VkDeviceSize DesktopWindowSize = 4_GiB; - VkDeviceSize candidate_window = DesktopWindowSize; + VkDeviceSize candidate_window = 1_GiB; const u64 max_buffer_size = device.GetMaxBufferSize(); if (max_buffer_size != 0 && max_buffer_size < candidate_window) { candidate_window = max_buffer_size; @@ -325,11 +324,9 @@ namespace Vulkan { logical.DestroyBufferRaw(new_buffer); break; } - constexpr VkDeviceSize MaxHeapFractionDenominator = 2; const u32 heap_index = memory_props.memoryTypes[*type_index].heapIndex; const VkDeviceSize heap_size = memory_props.memoryHeaps[heap_index].size; - const VkDeviceSize heap_import_limit = heap_size / MaxHeapFractionDenominator; - if (imported_size + window_len > heap_import_limit) { + if (imported_size + window_len > heap_size / 2) { LOG_INFO(Render_Vulkan, "Stopping guest memory import at {} MiB to leave room on heap {} of {} MiB", imported_size >> 20, heap_index, heap_size >> 20); @@ -382,14 +379,7 @@ namespace Vulkan { !device.IsExtExternalMemoryAhbSupported()) { return false; } - using namespace Common::Literals; - u64 max_allocation_size = device.GetMaxMemoryAllocationSize(); - if (device.IsTiler()) { - constexpr u64 TilerAllocationLimit = 1_GiB; - max_allocation_size = max_allocation_size != 0 - ? (std::min)(max_allocation_size, TilerAllocationLimit) - : TilerAllocationLimit; - } + const u64 max_allocation_size = device.GetMaxMemoryAllocationSize(); if (max_allocation_size != 0 && hardware_buffer_window > max_allocation_size) { LOG_WARNING(Render_Vulkan, "Hardware buffer windows of {} MiB exceed the {} MiB allocation limit",