mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-09 13:36:35 +00:00
[TEST] Refactor on memory collections
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <bitset>
|
||||
#include <chrono>
|
||||
#include <optional>
|
||||
@@ -732,7 +733,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||
.device = *logical,
|
||||
.preferredLargeHeapBlockSize = is_integrated
|
||||
? (64u * 1024u * 1024u)
|
||||
: (256u * 1024u * 1024u),
|
||||
: (128u * 1024u * 1024u),
|
||||
.pAllocationCallbacks = nullptr,
|
||||
.pDeviceMemoryCallbacks = nullptr,
|
||||
.pHeapSizeLimit = nullptr,
|
||||
@@ -1444,6 +1445,23 @@ std::optional<size_t> Device::GetSamplerHeapBudget() const {
|
||||
return sampler_heap_budget;
|
||||
}
|
||||
|
||||
Device::MemoryBudgetInfo Device::GetMemoryBudgetInfo() const {
|
||||
std::array<VmaBudget, VK_MAX_MEMORY_HEAPS> budgets{};
|
||||
vmaGetHeapBudgets(allocator, budgets.data());
|
||||
MemoryBudgetInfo info{};
|
||||
for (const size_t heap : valid_heap_memory) {
|
||||
info.usage += budgets[heap].usage;
|
||||
info.budget += budgets[heap].budget;
|
||||
info.block_bytes += budgets[heap].statistics.blockBytes;
|
||||
info.allocation_bytes += budgets[heap].statistics.allocationBytes;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
void Device::TickAllocatorFrame() const {
|
||||
vmaSetCurrentFrameIndex(allocator, ++allocator_frame_index);
|
||||
}
|
||||
|
||||
u64 Device::GetDeviceMemoryUsage() const {
|
||||
VkPhysicalDeviceMemoryBudgetPropertiesEXT budget;
|
||||
budget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT;
|
||||
@@ -1493,9 +1511,12 @@ void Device::CollectPhysicalMemoryInfo() {
|
||||
device_access_memory -= reserve_memory;
|
||||
if (Settings::values.vram_usage_mode.GetValue() != Settings::VramUsageMode::Aggressive) {
|
||||
// Account for resolution scaling in memory limits
|
||||
const size_t normal_memory = 6_GiB;
|
||||
const size_t scaler_memory = 1_GiB * Settings::values.resolution_info.ScaleUp(1);
|
||||
device_access_memory = std::min<u64>(device_access_memory, normal_memory + scaler_memory);
|
||||
const u64 normal_memory = 6_GiB;
|
||||
const u64 scaler_memory = 1_GiB * Settings::values.resolution_info.ScaleUp(1);
|
||||
const u64 baseline = normal_memory + scaler_memory;
|
||||
const u64 proportional = (device_access_memory / 4) * 3;
|
||||
device_access_memory =
|
||||
std::min<u64>(device_access_memory, std::max<u64>(baseline, proportional));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,6 +255,17 @@ public:
|
||||
return allocator;
|
||||
}
|
||||
|
||||
struct MemoryBudgetInfo {
|
||||
u64 usage;
|
||||
u64 budget;
|
||||
u64 block_bytes;
|
||||
u64 allocation_bytes;
|
||||
};
|
||||
|
||||
MemoryBudgetInfo GetMemoryBudgetInfo() const;
|
||||
|
||||
void TickAllocatorFrame() const;
|
||||
|
||||
/// Returns the logical device.
|
||||
const vk::Device& GetLogical() const {
|
||||
return logical;
|
||||
@@ -1060,6 +1071,7 @@ private:
|
||||
private:
|
||||
VkInstance instance; ///< Vulkan instance.
|
||||
VmaAllocator allocator; ///< VMA allocator.
|
||||
mutable u32 allocator_frame_index{};
|
||||
vk::DeviceDispatch dld; ///< Device function pointers.
|
||||
vk::PhysicalDevice physical; ///< Physical device.
|
||||
vk::Device logical; ///< Logical device.
|
||||
|
||||
@@ -224,6 +224,27 @@ namespace Vulkan {
|
||||
|
||||
MemoryAllocator::~MemoryAllocator() = default;
|
||||
|
||||
void MemoryAllocator::SetReclaimCallback(ReclaimCallback callback) {
|
||||
reclaim_callback = std::move(callback);
|
||||
owner_thread = std::this_thread::get_id();
|
||||
}
|
||||
|
||||
bool MemoryAllocator::ReclaimAtLeast(u64 hint_bytes) const {
|
||||
if (!reclaim_callback || in_reclaim) {
|
||||
return false;
|
||||
}
|
||||
in_reclaim = true;
|
||||
const u64 freed = reclaim_callback(hint_bytes);
|
||||
in_reclaim = false;
|
||||
return freed > 0;
|
||||
}
|
||||
|
||||
void MemoryAllocator::AssertOwnerThread() const {
|
||||
DEBUG_ASSERT_MSG(owner_thread == std::thread::id{} ||
|
||||
owner_thread == std::this_thread::get_id(),
|
||||
"VmaAllocator is externally synchronized but was used off-thread");
|
||||
}
|
||||
|
||||
vk::Image MemoryAllocator::CreateImage(const VkImageCreateInfo &ci) const
|
||||
{
|
||||
const VmaAllocationCreateInfo alloc_ci = {
|
||||
@@ -240,7 +261,26 @@ namespace Vulkan {
|
||||
VkImage handle{};
|
||||
VmaAllocation allocation{};
|
||||
VmaAllocationInfo alloc_info{};
|
||||
vk::Check(vmaCreateImage(allocator, &ci, &alloc_ci, &handle, &allocation, &alloc_info));
|
||||
AssertOwnerThread();
|
||||
|
||||
VkResult res = vmaCreateImage(allocator, &ci, &alloc_ci, &handle, &allocation, &alloc_info);
|
||||
|
||||
if (res != VK_SUCCESS && ReclaimAtLeast(IMAGE_RECLAIM_HINT)) {
|
||||
res = vmaCreateImage(allocator, &ci, &alloc_ci, &handle, &allocation, &alloc_info);
|
||||
}
|
||||
|
||||
if (res != VK_SUCCESS) {
|
||||
auto relaxed_ci = alloc_ci;
|
||||
relaxed_ci.flags &= ~VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT;
|
||||
res = vmaCreateImage(allocator, &ci, &relaxed_ci, &handle, &allocation, &alloc_info);
|
||||
|
||||
if (res != VK_SUCCESS) {
|
||||
relaxed_ci.preferredFlags &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
res = vmaCreateImage(allocator, &ci, &relaxed_ci, &handle, &allocation, &alloc_info);
|
||||
}
|
||||
}
|
||||
|
||||
vk::Check(res);
|
||||
|
||||
// Log GPU memory allocation for images
|
||||
if (GPU::Logging::IsActive() &&
|
||||
@@ -277,7 +317,28 @@ namespace Vulkan {
|
||||
VmaAllocation allocation{};
|
||||
VkMemoryPropertyFlags property_flags{};
|
||||
|
||||
vk::Check(vmaCreateBuffer(allocator, &ci, &alloc_ci, &handle, &allocation, &alloc_info));
|
||||
AssertOwnerThread();
|
||||
|
||||
VkResult res = vmaCreateBuffer(allocator, &ci, &alloc_ci, &handle, &allocation, &alloc_info);
|
||||
|
||||
if (res != VK_SUCCESS && ReclaimAtLeast(ci.size)) {
|
||||
res = vmaCreateBuffer(allocator, &ci, &alloc_ci, &handle, &allocation, &alloc_info);
|
||||
}
|
||||
|
||||
if (res != VK_SUCCESS) {
|
||||
auto relaxed_ci = alloc_ci;
|
||||
relaxed_ci.flags &= ~VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT;
|
||||
res = vmaCreateBuffer(allocator, &ci, &relaxed_ci, &handle, &allocation, &alloc_info);
|
||||
|
||||
if (res != VK_SUCCESS &&
|
||||
(relaxed_ci.preferredFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) {
|
||||
relaxed_ci.preferredFlags &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
res = vmaCreateBuffer(allocator, &ci, &relaxed_ci, &handle, &allocation,
|
||||
&alloc_info);
|
||||
}
|
||||
}
|
||||
|
||||
vk::Check(res);
|
||||
vmaGetAllocationMemoryProperties(allocator, allocation, &property_flags);
|
||||
|
||||
// Log GPU memory allocation for buffers
|
||||
|
||||
@@ -6,8 +6,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <span>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_types.h"
|
||||
@@ -120,7 +122,17 @@ namespace Vulkan {
|
||||
/// Commits memory required by the buffer and binds it (for buffers created outside VMA).
|
||||
MemoryCommit Commit(const vk::Buffer &buffer, MemoryUsage usage);
|
||||
|
||||
using ReclaimCallback = std::function<u64(u64)>;
|
||||
|
||||
void SetReclaimCallback(ReclaimCallback callback);
|
||||
|
||||
private:
|
||||
bool ReclaimAtLeast(u64 hint_bytes) const;
|
||||
|
||||
void AssertOwnerThread() const;
|
||||
|
||||
static constexpr u64 IMAGE_RECLAIM_HINT = 64ULL * 1024 * 1024;
|
||||
|
||||
static bool IsAutoUsage(VmaMemoryUsage u) noexcept {
|
||||
switch (u) {
|
||||
case VMA_MEMORY_USAGE_AUTO:
|
||||
@@ -137,6 +149,9 @@ namespace Vulkan {
|
||||
const VkPhysicalDeviceMemoryProperties properties; ///< Physical device memory properties.
|
||||
VkDeviceSize buffer_image_granularity; ///< Adjacent buffer/image granularity
|
||||
u32 valid_memory_types{~0u};
|
||||
ReclaimCallback reclaim_callback;
|
||||
mutable bool in_reclaim{false};
|
||||
std::thread::id owner_thread;
|
||||
};
|
||||
|
||||
} // namespace Vulkan
|
||||
|
||||
Reference in New Issue
Block a user