/* Created on: Nov 24, 2019 Copyright 2019 flyinghead This file is part of Flycast. Flycast is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Flycast is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Flycast. If not, see . */ #pragma once #include "vulkan.h" #include "vk_mem_alloc.h" class VMAllocator; class Allocation { public: Allocation() = default; Allocation(const Allocation& other) = delete; Allocation& operator=(const Allocation& other) = delete; Allocation(Allocation&& other) : allocator(other.allocator), allocation(other.allocation), allocInfo(other.allocInfo) { other.allocator = VK_NULL_HANDLE; other.allocation = VK_NULL_HANDLE; } Allocation& operator=(Allocation&& other) { std::swap(this->allocator, other.allocator); std::swap(this->allocation, other.allocation); std::swap(this->allocInfo, other.allocInfo); return *this; } ~Allocation() { if (allocator != VK_NULL_HANDLE) vmaFreeMemory(allocator, allocation); } bool IsHostVisible() const { VkMemoryPropertyFlags flags; vmaGetMemoryTypeProperties(allocator, allocInfo.memoryType, &flags); return flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; } void *MapMemory() const { return allocInfo.pMappedData; } private: Allocation(VmaAllocator allocator, VmaAllocation allocation, VmaAllocationInfo allocInfo) : allocator(allocator), allocation(allocation), allocInfo(allocInfo) { } VmaAllocator allocator = VK_NULL_HANDLE; VmaAllocation allocation = VK_NULL_HANDLE; VmaAllocationInfo allocInfo; friend class VMAllocator; }; class VMAllocator { public: void Init(vk::PhysicalDevice physicalDevice, vk::Device device); void Term() { if (allocator != VK_NULL_HANDLE) { vmaDestroyAllocator(allocator); allocator = VK_NULL_HANDLE; } } Allocation AllocateMemory(const vk::MemoryRequirements& memoryRequirements, const VmaAllocationCreateInfo& allocCreateInfo) const { VmaAllocation vmaAllocation; VmaAllocationInfo allocInfo; VkResult rc = vmaAllocateMemory(allocator, (VkMemoryRequirements*)&memoryRequirements, &allocCreateInfo, &vmaAllocation, &allocInfo); if (rc != VK_SUCCESS) throwResultException((vk::Result)rc, "vmaAllocateMemory failed"); return Allocation(allocator, vmaAllocation, allocInfo); } Allocation AllocateForImage(const vk::Image image, const VmaAllocationCreateInfo& allocCreateInfo) const { VmaAllocation vmaAllocation; VmaAllocationInfo allocInfo; VkResult rc = vmaAllocateMemoryForImage(allocator, (VkImage)image, &allocCreateInfo, &vmaAllocation, &allocInfo); if (rc != VK_SUCCESS) throwResultException((vk::Result)rc, "vmaAllocateMemoryForImage failed"); vmaBindImageMemory(allocator, vmaAllocation, (VkImage)image); return Allocation(allocator, vmaAllocation, allocInfo); } Allocation AllocateForBuffer(const vk::Buffer buffer, const VmaAllocationCreateInfo& allocCreateInfo) const { VmaAllocation vmaAllocation; VmaAllocationInfo allocInfo; VkResult rc = vmaAllocateMemoryForBuffer(allocator, (VkBuffer)buffer, &allocCreateInfo, &vmaAllocation, &allocInfo); if (rc != VK_SUCCESS) throwResultException((vk::Result)rc, "vmaAllocateMemoryForBuffer failed"); vmaBindBufferMemory(allocator, vmaAllocation, (VkBuffer)buffer); return Allocation(allocator, vmaAllocation, allocInfo); } void PrintStats() const { VmaStats stats; vmaCalculateStats(allocator, &stats); NOTICE_LOG(RENDERER, "Vma stats: %d chunks, %d allocs, %llu bytes used, %llu free", stats.total.blockCount, stats.total.allocationCount, (unsigned long long)stats.total.usedBytes, (unsigned long long)stats.total.unusedBytes); } private: VmaAllocator allocator = VK_NULL_HANDLE; };