Files
Seele/src/Engine/Graphics/Vulkan/VulkanAllocator.cpp
T

124 lines
3.8 KiB
C++

#include "VulkanAllocator.h"
#include "VulkanGraphics.h"
#include "VulkanInitializer.h"
#include "Math/MemCRC.h"
using namespace Seele::Vulkan;
SubAllocation::SubAllocation(Allocation* owner, uint32 allocatedOffset, uint32 size, uint32 alignedOffset, uint32 allocatedSize)
: owner(owner)
, size(size)
, allocatedOffset(allocatedOffset)
, alignedOffset(alignedOffset)
, allocatedSize(allocatedSize)
{
}
Allocation::Allocation(PGraphics graphics, Allocator* allocator, uint32 size, uint32 memoryTypeIndex, VkMemoryPropertyFlags properties, bool isDedicated)
: device(graphics->getDevice())
, allocator(allocator)
, bytesAllocated(0)
, bytesUsed(0)
, properties(properties)
, memoryTypeIndex(memoryTypeIndex)
{
VkMemoryAllocateInfo allocInfo =
init::MemoryAllocateInfo();
allocInfo.allocationSize = size;
allocInfo.memoryTypeIndex = memoryTypeIndex;
VK_CHECK(vkAllocateMemory(device, &allocInfo, nullptr, &allocatedMemory));
bytesAllocated = size;
PSubAllocation freeRange = new SubAllocation(this, 0, size, 0, size);
freeRanges.add(freeRange);
}
PSubAllocation Allocation::getSuballocation(uint32 requestedSize, uint32 alignment)
{
if (isDedicated)
{
if (activeAllocations.size() == 0)
{
assert(requestedSize == bytesAllocated);
activeAllocations.add(freeRanges.back());
freeRanges.clear();
}
else
{
return nullptr;
}
}
for (int i = 0; i < freeRanges.size(); ++i)
{
PSubAllocation freeAllocation = freeRanges[i];
uint32 allocatedOffset = freeAllocation->allocatedOffset;
uint32 alignedOffset = align(allocatedOffset, alignment);
uint32 alignmentAdjustment = alignedOffset - allocatedOffset;
uint32 size = alignmentAdjustment + requestedSize;
if (freeAllocation->size == size)
{
freeRanges.remove(i);
activeAllocations.add(freeAllocation);
return freeAllocation;
}
else if (size < freeAllocation->allocatedSize)
{
freeAllocation->size -= size;
freeAllocation->allocatedSize -= size;
freeAllocation->allocatedOffset += allocatedOffset;
freeAllocation->alignedOffset += allocatedOffset;
PSubAllocation subAlloc = new SubAllocation(this, allocatedOffset, size, alignedOffset, size);
activeAllocations.add(subAlloc);
return subAlloc;
}
}
return nullptr;
}
Allocator::Allocator(PGraphics graphics)
: graphics(graphics)
{
vkGetPhysicalDeviceMemoryProperties(graphics->getPhysicalDevice(), &memProperties);
heaps.resize(memProperties.memoryHeapCount);
for (size_t i = 0; i < memProperties.memoryHeapCount; i++)
{
VkMemoryHeap memoryHeap = memProperties.memoryHeaps[i];
HeapInfo& heapInfo = heaps[i];
heapInfo.maxSize = memoryHeap.size;
}
}
Allocator::~Allocator()
{
}
PSubAllocation Allocator::allocate(uint64 size, const VkMemoryRequirements2& memRequirements2, VkMemoryPropertyFlags properties)
{
// no suitable allocations found, allocate new block
const VkMemoryRequirements& requirements = memRequirements2.memoryRequirements;
uint32 memoryTypeIndex;
VK_CHECK(findMemoryType(requirements.memoryTypeBits, properties, &memoryTypeIndex));
bool isDedicated = memRequirements2.pNext != nullptr;
PAllocation newAllocation = new Allocation(graphics, this, MemoryBlockSize, memoryTypeIndex, properties, isDedicated);
uint32 heapIndex = memProperties.memoryTypes[memoryTypeIndex].heapIndex;
heaps[heapIndex].allocations.add(newAllocation);
return newAllocation->getSuballocation(size, requirements.alignment);
}
VkResult Allocator::findMemoryType(uint32 typeBits, VkMemoryPropertyFlags properties, uint32* typeIndex)
{
for (int memoryIndex = 0; memoryIndex < memProperties.memoryTypeCount && typeBits; ++memoryIndex)
{
if ((typeBits & 1) == 1)
{
if ((memProperties.memoryTypes[memoryIndex].propertyFlags & properties) == properties)
{
*typeIndex = memoryIndex;
return VK_SUCCESS;
}
}
typeBits >>= 1;
}
return VK_ERROR_FORMAT_NOT_SUPPORTED;
}