Files
KytyPS5/src/graphics/host_gpu/vma.cpp
T

195 lines
6.4 KiB
C++

#include "graphics/host_gpu/vulkanCommon.h"
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnullability-completeness"
#pragma clang diagnostic ignored "-Wunused-private-field"
#pragma clang diagnostic ignored "-Wunused-variable"
#endif
#define VMA_IMPLEMENTATION
#include <vk_mem_alloc.h>
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/profiler.h"
#include "graphics/host_gpu/graphicContext.h"
#include "graphics/host_gpu/vma.h"
#include <algorithm>
#include <atomic>
#include <cinttypes>
namespace Libs::Graphics {
namespace {
struct MemoryStats {
std::atomic_uint64_t allocated[VK_MAX_MEMORY_TYPES] {};
std::atomic_uint64_t count[VK_MAX_MEMORY_TYPES] {};
};
MemoryStats g_memory_stats;
} // namespace
void VulkanTrackAllocation(const VulkanMemory& memory) {
g_memory_stats.allocated[memory.type] += memory.requirements.size;
g_memory_stats.count[memory.type]++;
}
void VulkanUntrackAllocation(const VulkanMemory& memory) {
EXIT_IF(g_memory_stats.allocated[memory.type] < memory.requirements.size);
EXIT_IF(g_memory_stats.count[memory.type] == 0);
g_memory_stats.allocated[memory.type] -= memory.requirements.size;
g_memory_stats.count[memory.type]--;
}
bool GraphicContext::CreateAllocator() {
KYTY_PROFILER_FUNCTION();
EXIT_IF(instance == nullptr || physical_device == nullptr || device == nullptr ||
allocator != nullptr);
VmaVulkanFunctions functions {};
functions.vkGetInstanceProcAddr = VULKAN_HPP_DEFAULT_DISPATCHER.vkGetInstanceProcAddr;
functions.vkGetDeviceProcAddr = VULKAN_HPP_DEFAULT_DISPATCHER.vkGetDeviceProcAddr;
VmaAllocatorCreateInfo info {};
info.instance = instance;
info.physicalDevice = physical_device;
info.device = device;
info.pVulkanFunctions = &functions;
info.vulkanApiVersion = VULKAN_TARGET_API_VERSION;
info.flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT;
if (memory_budget_ext_enabled) {
info.flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT;
}
const auto result = static_cast<vk::Result>(vmaCreateAllocator(&info, &allocator));
if (result != vk::Result::eSuccess) {
LOGF("vmaCreateAllocator failed: %s\n", vk::to_string(result).c_str());
return false;
}
return true;
}
void GraphicContext::DestroyAllocator() {
if (allocator == nullptr) {
return;
}
vmaDestroyAllocator(allocator);
allocator = nullptr;
}
void GraphicContext::LogMemoryBudget() const {
if (allocator == nullptr || physical_device == nullptr) {
return;
}
const auto& properties = GetPhysicalDeviceMemoryProperties();
VmaBudget budgets[VK_MAX_MEMORY_HEAPS] {};
vmaGetHeapBudgets(allocator, budgets);
for (uint32_t i = 0; i < properties.memoryHeapCount; i++) {
LOGF("VMA heap %u: usage=%" PRIu64 ", budget=%" PRIu64 ", allocation=%" PRIu64
", blocks=%" PRIu64 "\n",
i, static_cast<uint64_t>(budgets[i].usage), static_cast<uint64_t>(budgets[i].budget),
static_cast<uint64_t>(budgets[i].statistics.allocationBytes),
static_cast<uint64_t>(budgets[i].statistics.blockBytes));
}
}
uint64_t GraphicContext::GetDeviceMemoryUsage() const {
if (!CanReportMemoryUsage() || allocator == nullptr) {
return 0;
}
VmaBudget budgets[VK_MAX_MEMORY_HEAPS] {};
vmaGetHeapBudgets(allocator, budgets);
const bool discrete =
physical_device_properties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu;
uint64_t usage = 0;
for (uint32_t heap = 0; heap < physical_device_memory_properties.memoryHeapCount; heap++) {
const bool device_local =
static_cast<bool>(physical_device_memory_properties.memoryHeaps[heap].flags &
vk::MemoryHeapFlagBits::eDeviceLocal);
if (!discrete || device_local) {
usage += budgets[heap].usage;
}
}
return usage;
}
uint64_t GraphicContext::GetTotalMemoryBudget() const {
if (allocator == nullptr) {
return 0;
}
VmaBudget budgets[VK_MAX_MEMORY_HEAPS] {};
vmaGetHeapBudgets(allocator, budgets);
const bool discrete =
physical_device_properties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu;
uint64_t budget = 0;
uint64_t local = 0;
uint64_t usage = 0;
for (uint32_t heap = 0; heap < physical_device_memory_properties.memoryHeapCount; heap++) {
const auto& properties = physical_device_memory_properties.memoryHeaps[heap];
const bool device_local =
static_cast<bool>(properties.flags & vk::MemoryHeapFlagBits::eDeviceLocal);
if (device_local) {
local += properties.size;
}
if (!discrete || device_local) {
budget += CanReportMemoryUsage() ? budgets[heap].budget : properties.size;
usage += CanReportMemoryUsage() ? budgets[heap].usage : 0;
}
}
if (discrete) {
return budget - std::min<uint64_t>(budget / 8, 1024ull * 1024 * 1024);
}
constexpr uint64_t system_reserve = 8ull * 1024 * 1024 * 1024;
const auto available = budget > usage ? budget - usage : uint64_t {0};
return std::max(local, available > system_reserve ? available - system_reserve : uint64_t {0});
}
bool GraphicContext::CreateImage(const vk::ImageCreateInfo& image_info, VulkanImage& image) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(allocator == nullptr || image.image != nullptr || image.memory.allocation != nullptr);
auto& memory = image.memory;
VmaAllocationCreateInfo alloc_info {};
alloc_info.requiredFlags = static_cast<vk::MemoryPropertyFlags::MaskType>(memory.property);
alloc_info.preferredFlags =
static_cast<vk::MemoryPropertyFlags::MaskType>(memory.preferred_property);
VmaAllocationInfo allocation_result {};
vk::Image::CType native_image = VK_NULL_HANDLE;
const auto result = static_cast<vk::Result>(
vmaCreateImage(allocator, static_cast<const vk::ImageCreateInfo::NativeType*>(image_info),
&alloc_info, &native_image, &memory.allocation, &allocation_result));
image.image = native_image;
if (result != vk::Result::eSuccess) {
LogMemoryBudget();
return false;
}
device.getImageMemoryRequirements(image.image, &memory.requirements);
memory.type = allocation_result.memoryType;
VulkanTrackAllocation(memory);
return true;
}
void GraphicContext::DeleteImage(VulkanImage& image) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(allocator == nullptr || image.image == nullptr || image.memory.allocation == nullptr);
auto& memory = image.memory;
VulkanUntrackAllocation(memory);
vmaDestroyImage(allocator, image.image, memory.allocation);
image.image = nullptr;
memory.allocation = nullptr;
}
} // namespace Libs::Graphics