#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 #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 #include namespace Libs::Graphics { 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(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(budgets[i].usage), static_cast(budgets[i].budget), static_cast(budgets[i].statistics.allocationBytes), static_cast(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(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(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(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.allocation != nullptr); VmaAllocationCreateInfo alloc_info {}; alloc_info.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; vk::Image::CType native_image = VK_NULL_HANDLE; const auto result = static_cast( vmaCreateImage(allocator, static_cast(image_info), &alloc_info, &native_image, &image.allocation, nullptr)); image.image = native_image; if (result != vk::Result::eSuccess) { LogMemoryBudget(); return false; } image.format = image_info.format; image.image_type = image_info.imageType; image.extent = image_info.extent; image.layers = image_info.arrayLayers; image.mip_levels = image_info.mipLevels; image.samples = static_cast(image_info.samples); image.usage = image_info.usage; image.flags = image_info.flags; image.state = {.layout = image_info.initialLayout}; image.subresource_states.clear(); return true; } void GraphicContext::DeleteImage(VulkanImage& image) { KYTY_PROFILER_FUNCTION(); EXIT_IF(allocator == nullptr || image.image == nullptr || image.allocation == nullptr); vmaDestroyImage(allocator, image.image, image.allocation); image.image = nullptr; image.allocation = nullptr; } } // namespace Libs::Graphics