Fix issue with freeing resources

This commit is contained in:
Georg Hagen
2024-07-11 13:22:01 +02:00
parent 22cb48be89
commit 313b01db1b
16 changed files with 300 additions and 156 deletions

View File

@@ -53,7 +53,6 @@ namespace OpenVulkano::Vulkan
ResourceManager::ResourceManager()
{
static_assert(sizeof(DescriptorSetLayoutBinding) == sizeof(vk::DescriptorSetLayoutBinding));
freeFunction = [this](ManagedBuffer* buffer) { this->FreeBuffer(buffer); };
}
ResourceManager::~ResourceManager() noexcept
@@ -70,7 +69,7 @@ namespace OpenVulkano::Vulkan
frameResources = Array<FrameResources>(static_cast<size_t>(buffers), context->device.get());
toFree.resize(buffers);
memPool.Init(context->device.get(), buffers);
transferQueue = this->device.getQueue(context->device->queueIndices.transfer, 0);
@@ -100,16 +99,20 @@ namespace OpenVulkano::Vulkan
transferQueue = nullptr;
geometries.clear();
nodes.clear();
textures.clear();
cameras.clear();
uniforms.clear();
device.destroyDescriptorPool(descriptorPool);
allocations.clear();
toFree.clear();
recycleBuffers.clear();
descriptorSetLayoutCache.clear();
for (auto& sampler : samplerCache)
{
device.destroy(sampler.second);
}
samplerCache.clear();
for(auto& layout : descriptorSetLayoutCache)
{
device.destroy(layout.second);
}
descriptorSetLayoutCache.clear();
shaders.clear();
device = nullptr;
}
@@ -119,7 +122,7 @@ namespace OpenVulkano::Vulkan
void ResourceManager::StartFrame(uint64_t frameId)
{
currentBuffer = frameId;
FreeBuffers();
memPool.StartFrame(frameId);
device.resetCommandPool(frameResources[currentBuffer].cmdPool, {});
GetCmdBuffer().begin({ vk::CommandBufferUsageFlagBits::eOneTimeSubmit });
}
@@ -145,12 +148,10 @@ namespace OpenVulkano::Vulkan
const std::unique_lock lock(mutex);
if(!geometry->renderGeo)
{
ManagedBuffer::Ptr vertexBuffer(
CreateDeviceOnlyBufferWithData(sizeof(Vertex) * geometry->GetVertexCount(), vk::BufferUsageFlagBits::eVertexBuffer, geometry->GetVertices()),
freeFunction);
ManagedBuffer::Ptr indexBuffer(
CreateDeviceOnlyBufferWithData(Utils::EnumAsInt(geometry->indexType) * geometry->GetIndexCount(), vk::BufferUsageFlagBits::eIndexBuffer, geometry->GetIndices()),
freeFunction);
ManagedBuffer::Ptr vertexBuffer =
CreateDeviceOnlyBufferWithData(sizeof(Vertex) * geometry->GetVertexCount(), vk::BufferUsageFlagBits::eVertexBuffer, geometry->GetVertices());
ManagedBuffer::Ptr indexBuffer =
CreateDeviceOnlyBufferWithData(Utils::EnumAsInt(geometry->indexType) * geometry->GetIndexCount(), vk::BufferUsageFlagBits::eIndexBuffer, geometry->GetIndices());
VulkanGeometry* vkGeo = new VulkanGeometry(geometry, vertexBuffer, indexBuffer);
geometries.emplace_back(vkGeo);
geometry->renderGeo = vkGeo;
@@ -173,7 +174,7 @@ namespace OpenVulkano::Vulkan
if (!node->renderNode)
{
UniformBuffer* uBuffer = new UniformBuffer();
ManagedBuffer* buffer;
ManagedBuffer::Ptr buffer;
VulkanNode* vkNode;
const vk::DeviceSize allocSize = Utils::Align(sizeof(Math::Matrix4f), uniformBufferAlignment);
vk::DeviceSize frameSize = 0;
@@ -182,7 +183,7 @@ namespace OpenVulkano::Vulkan
frameSize = allocSize;
vkNode = new VulkanNodeDynamic();
const uint32_t imgs = context->swapChain.GetImageCount();
buffer = CreateBuffer(imgs * allocSize, vk::BufferUsageFlagBits::eUniformBuffer, vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible);
buffer = memPool.CreateBuffer(imgs * allocSize, vk::BufferUsageFlagBits::eUniformBuffer, vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible);
buffer->Map();
}
else
@@ -191,7 +192,7 @@ namespace OpenVulkano::Vulkan
buffer = CreateDeviceOnlyBufferWithData(Scene::Node::SIZE, vk::BufferUsageFlagBits::eUniformBuffer, &node->worldMat);
}
uBuffer->Init(buffer, frameSize, allocSize, GetDescriptorLayoutSet(Scene::Node::DESCRIPTOR_SET_LAYOUT_BINDING), Scene::Node::DESCRIPTOR_SET_LAYOUT_BINDING, 0);
uBuffer->Init(std::move(buffer), frameSize, allocSize, GetDescriptorLayoutSet(Scene::Node::DESCRIPTOR_SET_LAYOUT_BINDING), Scene::Node::DESCRIPTOR_SET_LAYOUT_BINDING, 0);
vkNode->Init(node, uBuffer);
node->renderNode = vkNode;
nodes.emplace_back(vkNode);
@@ -206,12 +207,13 @@ namespace OpenVulkano::Vulkan
{
const vk::DeviceSize allocSize = Utils::Align(Scene::Camera::SIZE, uniformBufferAlignment);
const uint32_t imgs = context->swapChain.GetImageCount();
ManagedBuffer* buffer = CreateBuffer(imgs * allocSize, vk::BufferUsageFlagBits::eUniformBuffer, vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible);
ManagedBuffer::Ptr buffer = memPool.CreateBuffer(imgs * allocSize, vk::BufferUsageFlagBits::eUniformBuffer, vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible);
buffer->Map();
UniformBuffer* uBuffer = new UniformBuffer();
uBuffer->Init(buffer, allocSize, allocSize, GetDescriptorLayoutSet(Scene::Camera::DESCRIPTOR_SET_LAYOUT_BINDING), Scene::Camera::DESCRIPTOR_SET_LAYOUT_BINDING, 1);
uBuffer->Init(std::move(buffer), allocSize, allocSize, GetDescriptorLayoutSet(Scene::Camera::DESCRIPTOR_SET_LAYOUT_BINDING), Scene::Camera::DESCRIPTOR_SET_LAYOUT_BINDING, 1);
VulkanCamera* vkCam = new VulkanCamera();
vkCam->Init(camera, uBuffer);
cameras.emplace_back(vkCam);
camera->renderCamera = vkCam;
}
return static_cast<VulkanCamera*>(camera->renderCamera);
@@ -225,7 +227,7 @@ namespace OpenVulkano::Vulkan
auto buffer = CreateDeviceOnlyBufferWithData(allocSize, vk::BufferUsageFlagBits::eUniformBuffer, data);
UniformBuffer* uBuffer = new UniformBuffer();
uBuffer->Init(buffer, 0, allocSize, GetDescriptorLayoutSet(binding), binding, setId);
uBuffer->Init(std::move(buffer), 0, allocSize, GetDescriptorLayoutSet(binding), binding, setId);
return uBuffer;
}
@@ -240,23 +242,10 @@ namespace OpenVulkano::Vulkan
return &layout;
}
ManagedBuffer* ResourceManager::CreateSharedMemoryBuffer(const size_t size)
MemoryPool::ManagedBufferPtr ResourceManager::CreateSharedMemoryBuffer(const size_t size)
{
const std::unique_lock lock(mutex);
if (!recycleBuffers.empty())
{
for(auto buff : recycleBuffers)
{
if (buff->size == size)
{
Logger::DATA->info("Recycle Buffer");
Utils::Remove(recycleBuffers, buff);
return buff;
}
}
}
ManagedBuffer* buffer = CreateBuffer(size, vk::BufferUsageFlagBits::eVertexBuffer, vk::MemoryPropertyFlagBits::eHostCoherent/* | vk::MemoryPropertyFlagBits::eDeviceLocal*/);
return buffer;
return memPool.CreateSharedMemoryBuffer(size);
}
void ResourceManager::RemoveShader(VulkanShader* shader)
@@ -270,37 +259,9 @@ namespace OpenVulkano::Vulkan
shaders.erase(object);
}
void ResourceManager::FreeBuffer(ManagedBuffer* buffer)
{
if (buffer)
toFree[currentBuffer].push_back(buffer);
}
void ResourceManager::DoFreeBuffer(ManagedBuffer* buffer)
{
if (buffer->IsLast())
{
device.destroyBuffer(buffer->buffer);
buffer->allocation->used -= buffer->size;
}
else
{
recycleBuffers.push_back(buffer);
}
}
void ResourceManager::FreeBuffers()
{
for (auto& i : toFree[currentBuffer])
{
DoFreeBuffer(i);
}
toFree[currentBuffer].clear();
}
void ResourceManager::CopyDataToImage(vk::DeviceSize size, void* data, Image* image)
{
ManagedBuffer* uploadBuffer = CreateBuffer(size, vk::BufferUsageFlagBits::eTransferSrc, vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible);
ManagedBuffer::Ptr uploadBuffer = memPool.CreateBuffer(size, vk::BufferUsageFlagBits::eTransferSrc, vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible);
uploadBuffer->Copy(data, size, 0);
image->SetLayout(GetCmdBuffer(), vk::ImageAspectFlagBits::eColor, vk::ImageLayout::eTransferDstOptimal);
@@ -312,66 +273,17 @@ namespace OpenVulkano::Vulkan
// TODO set access masks for mip and array layers
//GetCmdBuffer().pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, 0, nullptr, 0, nullptr, 1, &barrier );
FreeBuffer(uploadBuffer);
}
ManagedBuffer* ResourceManager::CreateDeviceOnlyBufferWithData(vk::DeviceSize size, vk::BufferUsageFlagBits usage, const void* data)
ManagedBuffer::Ptr ResourceManager::CreateDeviceOnlyBufferWithData(vk::DeviceSize size, vk::BufferUsageFlagBits usage, const void* data)
{
ManagedBuffer* target = CreateBuffer(size, usage | vk::BufferUsageFlagBits::eTransferDst, vk::MemoryPropertyFlagBits::eDeviceLocal);
ManagedBuffer* uploadBuffer = CreateBuffer(size, vk::BufferUsageFlagBits::eTransferSrc, vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible);
ManagedBuffer::Ptr target = memPool.CreateBuffer(size, usage | vk::BufferUsageFlagBits::eTransferDst, vk::MemoryPropertyFlagBits::eDeviceLocal);
ManagedBuffer::Ptr uploadBuffer = memPool.CreateBuffer(size, vk::BufferUsageFlagBits::eTransferSrc, vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible);
uploadBuffer->Copy(data, size, 0);
RecordCopy(uploadBuffer->buffer, target->buffer, size);
FreeBuffer(uploadBuffer);
return target;
}
ManagedBuffer* ResourceManager::CreateBuffer(vk::DeviceSize size, const vk::BufferUsageFlags& usage, const vk::MemoryPropertyFlags& properties)
{
size = Utils::Align(size, 16);
vk::BufferCreateInfo bufferCreateInfo = { {}, size, usage, vk::SharingMode::eExclusive };
vk::Buffer buffer = device.createBuffer(bufferCreateInfo);
const vk::MemoryRequirements memoryRequirements = device.getBufferMemoryRequirements(buffer);
uint32_t memtype = context->device->GetMemoryType(memoryRequirements.memoryTypeBits, properties);
if (memoryRequirements.size != size)
{
Logger::DATA->debug("Memory Requirement Size ({0}) != Size ({1})", memoryRequirements.size, size);
size = memoryRequirements.size;
device.destroy(buffer);
bufferCreateInfo.size = size;
buffer = device.createBuffer(bufferCreateInfo);
}
MemoryAllocation* allocation = GetFreeMemoryAllocation(size, memoryRequirements.alignment, memtype);
uint32_t offset = Utils::Align(allocation->used, memoryRequirements.alignment);
device.bindBufferMemory(buffer, allocation->memory, offset);
allocation->used += size + (offset - allocation->used);
return new ManagedBuffer{ allocation, offset, size, buffer, usage, properties, nullptr };
}
MemoryAllocation* ResourceManager::CreateMemoryAllocation(size_t size, uint32_t type, bool addToCache)
{
MemoryAllocation* alloc = new MemoryAllocation(size, type, device);
const vk::MemoryAllocateInfo allocInfo = { size, type };
alloc->memory = device.allocateMemory(allocInfo);
if (addToCache) allocations.emplace_back(alloc);
return alloc;
}
MemoryAllocation* ResourceManager::GetFreeMemoryAllocation(size_t size, vk::DeviceSize alignment, uint32_t type, bool createIfAllFull)
{
MemoryAllocation* alloc = nullptr;
for (auto& allocation : allocations)
{
if (allocation->type == type && allocation->FreeSpace(alignment) >= size)
{
alloc = allocation.get();
break;
}
}
if(!alloc && createIfAllFull) alloc = CreateMemoryAllocation(64_MiB, type, true);
return alloc;
}
VulkanShader* ResourceManager::CreateShader(Scene::Shader* shader)
{
const std::unique_lock lock(mutex);
@@ -394,6 +306,8 @@ namespace OpenVulkano::Vulkan
vkTexture->Init(this, texture, GetDescriptorLayoutSet(Scene::Texture::DESCRIPTOR_SET_LAYOUT_BINDING), Scene::Texture::DESCRIPTOR_SET_LAYOUT_BINDING);
textures.emplace_back(vkTexture);
return vkTexture;
}
@@ -403,7 +317,7 @@ namespace OpenVulkano::Vulkan
if (buffer->renderBuffer) return static_cast<VulkanUniformBuffer*>(buffer->renderBuffer);
VulkanUniformBuffer* vkBuffer;
ManagedBuffer* mBuffer;
ManagedBuffer::Ptr mBuffer;
const vk::DeviceSize allocSize = Utils::Align(buffer->size, uniformBufferAlignment);
vk::DeviceSize frameSize = 0;
if (buffer->GetUpdateFrequency() != Scene::UpdateFrequency::Never)
@@ -411,7 +325,7 @@ namespace OpenVulkano::Vulkan
frameSize = allocSize;
vkBuffer = new VulkanUniformBufferDynamic();
const uint32_t imgs = context->swapChain.GetImageCount();
mBuffer = CreateBuffer(imgs * allocSize, vk::BufferUsageFlagBits::eUniformBuffer, vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible);
mBuffer = memPool.CreateBuffer(imgs * allocSize, vk::BufferUsageFlagBits::eUniformBuffer, vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible);
mBuffer->Map();
}
else
@@ -423,9 +337,11 @@ namespace OpenVulkano::Vulkan
UniformBuffer* uBuffer = new UniformBuffer();
uBuffer->Init(mBuffer, 0, mBuffer->size, GetDescriptorLayoutSet(buffer->binding), buffer->binding, buffer->setId);
const uint64_t s = mBuffer->size;
uBuffer->Init(std::move(mBuffer), 0, s, GetDescriptorLayoutSet(buffer->binding), buffer->binding, buffer->setId);
vkBuffer->Init(buffer, uBuffer);
uniforms.emplace_back(vkBuffer);
return vkBuffer;
}