Fix issue with freeing resources
This commit is contained in:
@@ -50,6 +50,8 @@ namespace OpenVulkano::Vulkan
|
||||
//TODO
|
||||
|
||||
if (enableValidationLayer) Debug::CloseValidationLayers(instance);
|
||||
|
||||
instance.destroy();
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -230,6 +230,8 @@ namespace OpenVulkano::Vulkan
|
||||
void Device::Close()
|
||||
{
|
||||
device.destroyCommandPool(graphicsCommandPool);
|
||||
device.destroyPipelineCache(pipelineCache);
|
||||
device.destroy();
|
||||
//TODO fill
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,8 @@ namespace OpenVulkano
|
||||
public:
|
||||
Device(vk::PhysicalDevice& physicalDevice);
|
||||
|
||||
~Device() { if (device) Close(); }
|
||||
|
||||
[[nodiscard]] std::string GetDeviceName() const
|
||||
{
|
||||
return properties.deviceName.data();
|
||||
|
||||
@@ -26,7 +26,10 @@ namespace OpenVulkano::Vulkan
|
||||
Init(instance);
|
||||
}
|
||||
|
||||
~DeviceManager() = default;
|
||||
~DeviceManager()
|
||||
{
|
||||
if (!devices.empty()) Close();
|
||||
}
|
||||
|
||||
void Init(const vk::Instance& instance);
|
||||
|
||||
|
||||
@@ -72,9 +72,15 @@ namespace OpenVulkano::Vulkan
|
||||
|
||||
void Renderer::Close()
|
||||
{
|
||||
context.device->WaitIdle();
|
||||
for (int i = 0; i < context.swapChain.GetImageCount(); i++)
|
||||
{
|
||||
//context.device->device.destroySemaphore(waitSemaphores[i]);
|
||||
}
|
||||
uiRenderer.Close();
|
||||
resourceManager.Close();
|
||||
context.Close();
|
||||
uiRenderer.Close();
|
||||
scene = nullptr;
|
||||
}
|
||||
|
||||
std::string Renderer::GetMainRenderDeviceName()
|
||||
|
||||
@@ -9,14 +9,16 @@
|
||||
#define CRASH_ON_MULTIPLE_MAPPINGS_TO_SAME_ALLOCATION
|
||||
|
||||
#include "MemoryAllocation.hpp"
|
||||
#include "MemoryPool.hpp"
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
namespace OpenVulkano::Vulkan
|
||||
{
|
||||
struct ManagedBuffer
|
||||
class ManagedBuffer
|
||||
{
|
||||
using Ptr = std::unique_ptr<ManagedBuffer, std::function<void(ManagedBuffer*)>>;
|
||||
public:
|
||||
using Ptr = std::unique_ptr<ManagedBuffer, ManagedBufferDeleter>;
|
||||
|
||||
MemoryAllocation* allocation;
|
||||
vk::DeviceSize offset, size;
|
||||
|
||||
140
openVulkanoCpp/Vulkan/Resources/MemoryPool.cpp
Normal file
140
openVulkanoCpp/Vulkan/Resources/MemoryPool.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "MemoryPool.hpp"
|
||||
#include "ManagedBuffer.hpp"
|
||||
#include "Vulkan/Device.hpp"
|
||||
#include "Base/Logger.hpp"
|
||||
#include "Math/ByteSize.hpp"
|
||||
|
||||
namespace OpenVulkano::Vulkan
|
||||
{
|
||||
namespace
|
||||
{
|
||||
std::vector<MemoryPool*> MEM_POOLS;
|
||||
}
|
||||
|
||||
void MemoryPool::ReleaseBuffer(OpenVulkano::Vulkan::ManagedBuffer* buffer)
|
||||
{
|
||||
for (MemoryPool* memPool : MEM_POOLS)
|
||||
{
|
||||
if (memPool->FreeBuffer(buffer)) return;
|
||||
}
|
||||
delete buffer;
|
||||
}
|
||||
|
||||
MemoryPool::MemoryPool()
|
||||
{
|
||||
freeFunction = [this](ManagedBuffer* buffer) { this->FreeBuffer(buffer); };
|
||||
MEM_POOLS.push_back(this);
|
||||
Logger::RENDER->info("Created gpu memory pool");
|
||||
}
|
||||
|
||||
MemoryPool::~MemoryPool()
|
||||
{
|
||||
Utils::Remove(MEM_POOLS, this);
|
||||
Logger::RENDER->info("Destroyed gpu memory pool");
|
||||
}
|
||||
|
||||
void MemoryPool::Init(Device* dev, int bufferCount)
|
||||
{
|
||||
device = dev;
|
||||
toFree = decltype(toFree)(bufferCount);
|
||||
}
|
||||
|
||||
void MemoryPool::StartFrame(uint64_t bufferId)
|
||||
{
|
||||
currentBuffer = bufferId;
|
||||
for (ManagedBuffer* i : toFree[currentBuffer])
|
||||
{
|
||||
DoFree(i);
|
||||
}
|
||||
toFree[currentBuffer].clear();
|
||||
}
|
||||
|
||||
void MemoryPool::DoFree(ManagedBuffer* buffer)
|
||||
{
|
||||
if (buffer->IsLast())
|
||||
{
|
||||
device->device.destroyBuffer(buffer->buffer);
|
||||
buffer->allocation->used -= buffer->size;
|
||||
}
|
||||
else
|
||||
{
|
||||
recycleBuffers.push_back(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
bool MemoryPool::FreeBuffer(ManagedBuffer* buffer)
|
||||
{
|
||||
if (buffer) toFree[currentBuffer].push_back(buffer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
MemoryAllocation* MemoryPool::CreateMemoryAllocation(size_t size, uint32_t type, bool addToCache)
|
||||
{
|
||||
MemoryAllocation* alloc = new MemoryAllocation(size, type, device->device);
|
||||
const vk::MemoryAllocateInfo allocInfo = { size, type };
|
||||
alloc->memory = device->device.allocateMemory(allocInfo);
|
||||
if (addToCache) allocations.emplace_back(alloc);
|
||||
return alloc;
|
||||
}
|
||||
|
||||
MemoryAllocation* MemoryPool::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;
|
||||
}
|
||||
|
||||
MemoryPool::ManagedBufferPtr MemoryPool::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->device.createBuffer(bufferCreateInfo);
|
||||
const vk::MemoryRequirements memoryRequirements = device->device.getBufferMemoryRequirements(buffer);
|
||||
uint32_t memtype = 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->device.destroy(buffer);
|
||||
bufferCreateInfo.size = size;
|
||||
buffer = device->device.createBuffer(bufferCreateInfo);
|
||||
}
|
||||
MemoryAllocation* allocation = GetFreeMemoryAllocation(size, memoryRequirements.alignment, memtype);
|
||||
uint32_t offset = Utils::Align(allocation->used, memoryRequirements.alignment);
|
||||
device->device.bindBufferMemory(buffer, allocation->memory, offset);
|
||||
allocation->used += size + (offset - allocation->used);
|
||||
return ManagedBufferPtr{ new ManagedBuffer({allocation, offset, size, buffer, usage, properties, nullptr}) };
|
||||
}
|
||||
|
||||
MemoryPool::ManagedBufferPtr MemoryPool::CreateSharedMemoryBuffer(size_t size)
|
||||
{
|
||||
if (!recycleBuffers.empty())
|
||||
{
|
||||
for(auto buff : recycleBuffers)
|
||||
{
|
||||
if (buff->size == size)
|
||||
{
|
||||
Logger::DATA->info("Recycle Buffer");
|
||||
Utils::Remove(recycleBuffers, buff);
|
||||
return ManagedBufferPtr{ buff };
|
||||
}
|
||||
}
|
||||
}
|
||||
return CreateBuffer(size, vk::BufferUsageFlagBits::eVertexBuffer, vk::MemoryPropertyFlagBits::eHostCoherent/* | vk::MemoryPropertyFlagBits::eDeviceLocal*/);
|
||||
}
|
||||
}
|
||||
64
openVulkanoCpp/Vulkan/Resources/MemoryPool.hpp
Normal file
64
openVulkanoCpp/Vulkan/Resources/MemoryPool.hpp
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Data/Containers/Array.hpp"
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
namespace OpenVulkano::Vulkan
|
||||
{
|
||||
class Device;
|
||||
class MemoryAllocation;
|
||||
class ManagedBuffer;
|
||||
struct ManagedBufferDeleter;
|
||||
|
||||
class MemoryPool
|
||||
{
|
||||
Device* device;
|
||||
std::vector<std::unique_ptr<MemoryAllocation>> allocations;
|
||||
Array<std::vector<ManagedBuffer*>> toFree;
|
||||
std::vector<ManagedBuffer*> recycleBuffers;
|
||||
std::function<void(ManagedBuffer*)> freeFunction;
|
||||
|
||||
uint64_t currentBuffer = 0;
|
||||
|
||||
void DoFree(ManagedBuffer* buffer);
|
||||
|
||||
bool FreeBuffer(ManagedBuffer* buffer);
|
||||
public:
|
||||
using ManagedBufferPtr = std::unique_ptr<ManagedBuffer, ManagedBufferDeleter>;
|
||||
|
||||
MemoryPool();
|
||||
|
||||
~MemoryPool();
|
||||
|
||||
void Init(Device* dev, int bufferCount);
|
||||
|
||||
void StartFrame(uint64_t bufferId);
|
||||
|
||||
MemoryAllocation* CreateMemoryAllocation(size_t size, uint32_t type, bool addToCache = true);
|
||||
|
||||
MemoryAllocation* GetFreeMemoryAllocation(size_t size, vk::DeviceSize alignment, uint32_t type, bool createIfAllFull = true);
|
||||
|
||||
ManagedBufferPtr CreateBuffer(vk::DeviceSize size, const vk::BufferUsageFlags& usage, const vk::MemoryPropertyFlags& properties);
|
||||
|
||||
ManagedBufferPtr CreateSharedMemoryBuffer(size_t size);
|
||||
|
||||
static void ReleaseBuffer(ManagedBuffer* buffer);
|
||||
};
|
||||
|
||||
struct ManagedBufferDeleter
|
||||
{
|
||||
void operator()(ManagedBuffer* buffer)
|
||||
{
|
||||
MemoryPool::ReleaseBuffer(buffer);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,13 +7,16 @@
|
||||
#pragma once
|
||||
|
||||
// Workaround for libc++
|
||||
#ifndef __cpp_lib_three_way_comparison
|
||||
#define __cpp_lib_three_way_comparison 201907
|
||||
#endif
|
||||
|
||||
#include "IShaderOwner.hpp"
|
||||
#include "MemoryPool.hpp"
|
||||
#include "Base/Wrapper.hpp"
|
||||
#include "Vulkan/Image.hpp"
|
||||
#include "Scene/Shader/DescriptorInputDescription.hpp"
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
@@ -55,15 +58,15 @@ namespace OpenVulkano
|
||||
vk::Device device = nullptr;
|
||||
vk::Queue transferQueue = nullptr;
|
||||
Array<FrameResources> frameResources;
|
||||
std::vector<std::unique_ptr<MemoryAllocation>> allocations;
|
||||
std::vector<std::unique_ptr<VulkanShader>> shaders;
|
||||
std::vector<std::unique_ptr<VulkanGeometry>> geometries;
|
||||
std::vector<std::unique_ptr<VulkanNode>> nodes;
|
||||
MemoryPool memPool;
|
||||
std::vector<Unique<VulkanShader>> shaders;
|
||||
std::vector<Unique<VulkanGeometry>> geometries;
|
||||
std::vector<Unique<VulkanNode>> nodes;
|
||||
std::vector<Unique<VulkanTexture>> textures;
|
||||
std::vector<Unique<VulkanCamera>> cameras;
|
||||
std::vector<Unique<VulkanUniformBuffer>> uniforms;
|
||||
std::mutex mutex;
|
||||
vk::DeviceSize uniformBufferAlignment;
|
||||
std::vector<std::vector<ManagedBuffer*>> toFree;
|
||||
std::vector<ManagedBuffer*> recycleBuffers;
|
||||
std::function<void(ManagedBuffer*)> freeFunction;
|
||||
vk::DescriptorPool descriptorPool;
|
||||
std::map<DescriptorSetLayoutBinding, vk::DescriptorSetLayout> descriptorSetLayoutCache;
|
||||
std::map<vk::SamplerCreateInfo, vk::Sampler> samplerCache;
|
||||
@@ -105,9 +108,7 @@ namespace OpenVulkano
|
||||
|
||||
void CopyDataToImage(vk::DeviceSize size, void* data, OpenVulkano::Vulkan::Image* image);
|
||||
|
||||
ManagedBuffer* CreateSharedMemoryBuffer(size_t size);
|
||||
|
||||
void FreeBuffer(ManagedBuffer* buffer);
|
||||
MemoryPool::ManagedBufferPtr CreateSharedMemoryBuffer(size_t size);
|
||||
|
||||
[[nodiscard]] Context* GetContext() const { return context; }
|
||||
|
||||
@@ -118,23 +119,13 @@ namespace OpenVulkano
|
||||
vk::Sampler CreateSampler(const vk::SamplerCreateInfo& samplerConfig);
|
||||
|
||||
protected: // Allocation management
|
||||
void DoFreeBuffer(ManagedBuffer* buffer);
|
||||
|
||||
void FreeBuffers();
|
||||
|
||||
ManagedBuffer* CreateDeviceOnlyBufferWithData(vk::DeviceSize size, vk::BufferUsageFlagBits usage, const void* data);
|
||||
MemoryPool::ManagedBufferPtr CreateDeviceOnlyBufferWithData(vk::DeviceSize size, vk::BufferUsageFlagBits usage, const void* data);
|
||||
|
||||
inline void RecordCopy(vk::Buffer src, vk::Buffer dest, vk::DeviceSize size)
|
||||
{
|
||||
vk::BufferCopy copyRegion = { 0, 0, size };
|
||||
GetCmdBuffer().copyBuffer(src, dest, 1, ©Region);
|
||||
}
|
||||
|
||||
ManagedBuffer* CreateBuffer(vk::DeviceSize size, const vk::BufferUsageFlags& usage, const vk::MemoryPropertyFlags& properties);
|
||||
|
||||
MemoryAllocation* CreateMemoryAllocation(size_t size, uint32_t type, bool addToCache = true);
|
||||
|
||||
MemoryAllocation* GetFreeMemoryAllocation(size_t size, vk::DeviceSize alignment, uint32_t type, bool createIfAllFull = true);
|
||||
|
||||
public:
|
||||
vk::DescriptorSetLayout* GetDescriptorLayoutSet(const DescriptorSetLayoutBinding& descriptorSetLayoutBinding);
|
||||
|
||||
@@ -12,18 +12,18 @@
|
||||
|
||||
namespace OpenVulkano::Vulkan
|
||||
{
|
||||
void UniformBuffer::Init(ManagedBuffer* buffer, uint32_t frameOffset, uint32_t frameSize, vk::DescriptorSetLayout* descriptorSetLayout, const DescriptorSetLayoutBinding& binding, uint32_t setId)
|
||||
void UniformBuffer::Init(ManagedBuffer::Ptr buffer, uint32_t frameOffset, uint32_t frameSize, vk::DescriptorSetLayout* descriptorSetLayout, const DescriptorSetLayoutBinding& binding, uint32_t setId)
|
||||
{
|
||||
m_buffer = buffer;
|
||||
m_buffer = std::move(buffer);
|
||||
m_frameOffset = frameOffset;
|
||||
|
||||
const vk::DescriptorSetAllocateInfo descSetAllocInfo = { ResourceManager::INSTANCE->descriptorPool, 1, descriptorSetLayout };
|
||||
m_descriptorSet = buffer->allocation->device.allocateDescriptorSets(descSetAllocInfo)[0];
|
||||
vk::DescriptorBufferInfo bufferInfo = { buffer->buffer, 0, frameSize };
|
||||
m_descriptorSet = m_buffer->allocation->device.allocateDescriptorSets(descSetAllocInfo)[0];
|
||||
vk::DescriptorBufferInfo bufferInfo = { m_buffer->buffer, 0, frameSize };
|
||||
vk::WriteDescriptorSet writeDescriptorSet = { m_descriptorSet, binding.bindingId, 0, 1 };
|
||||
writeDescriptorSet.descriptorType = static_cast<vk::DescriptorType>(binding.descriptorType);
|
||||
writeDescriptorSet.pBufferInfo = &bufferInfo;
|
||||
buffer->allocation->device.updateDescriptorSets(1, &writeDescriptorSet, 0, nullptr);
|
||||
m_buffer->allocation->device.updateDescriptorSets(1, &writeDescriptorSet, 0, nullptr);
|
||||
m_setOffset = setId;
|
||||
m_dynamic = binding.descriptorType == DescriptorSetLayoutBinding::TYPE_UNIFORM_BUFFER_DYNAMIC || binding.descriptorType == DescriptorSetLayoutBinding::TYPE_STORAGE_BUFFER_DYNAMIC;
|
||||
}
|
||||
|
||||
@@ -7,15 +7,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "Base/ICloseable.hpp"
|
||||
#include "Vulkan/Resources/ManagedBuffer.hpp"
|
||||
#include "Vulkan/Scene/IRecordable.hpp"
|
||||
|
||||
namespace OpenVulkano::Vulkan
|
||||
{
|
||||
struct ManagedBuffer;
|
||||
class ManagedBuffer;
|
||||
|
||||
class UniformBuffer final : public IRecordable, public ICloseable
|
||||
{
|
||||
ManagedBuffer* m_buffer = nullptr;
|
||||
ManagedBuffer::Ptr m_buffer = nullptr;
|
||||
vk::DescriptorSet m_descriptorSet;
|
||||
uint32_t m_frameOffset;
|
||||
uint32_t m_setOffset, m_setCount = 1;
|
||||
@@ -27,7 +28,7 @@ namespace OpenVulkano::Vulkan
|
||||
if (m_buffer) Close();
|
||||
}
|
||||
|
||||
void Init(ManagedBuffer* buffer, uint32_t frameOffset, uint32_t frameSize, vk::DescriptorSetLayout* descriptorSetLayout, const DescriptorSetLayoutBinding& binding, uint32_t setId);
|
||||
void Init(ManagedBuffer::Ptr buffer, uint32_t frameOffset, uint32_t frameSize, vk::DescriptorSetLayout* descriptorSetLayout, const DescriptorSetLayoutBinding& binding, uint32_t setId);
|
||||
|
||||
void Close() override;
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ namespace OpenVulkano::Vulkan
|
||||
UniformBuffer* m_buffer = nullptr;
|
||||
|
||||
public:
|
||||
~VulkanCamera() override { if (m_camera) VulkanCamera::Close(); }
|
||||
|
||||
void Init(Scene::Camera* camera, UniformBuffer* uniformBuffer)
|
||||
{
|
||||
m_camera = camera;
|
||||
@@ -32,7 +34,10 @@ namespace OpenVulkano::Vulkan
|
||||
|
||||
void Close() override
|
||||
{
|
||||
m_camera->renderCamera = nullptr;
|
||||
m_buffer->Close();
|
||||
m_camera = nullptr;
|
||||
delete m_buffer;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -22,8 +22,8 @@ namespace OpenVulkano::Vulkan
|
||||
vk::DeviceSize m_offsets = 0;
|
||||
|
||||
public:
|
||||
VulkanGeometry() : m_geometry(nullptr), m_vertexBuffer(nullptr, nullptr)
|
||||
, m_indexBuffer(nullptr, nullptr), m_indexType(vk::IndexType::eUint32)
|
||||
VulkanGeometry() : m_geometry(nullptr), m_vertexBuffer(nullptr)
|
||||
, m_indexBuffer(nullptr), m_indexType(vk::IndexType::eUint32)
|
||||
{}
|
||||
|
||||
VulkanGeometry(Scene::Geometry* geo, ManagedBuffer::Ptr& vertexBuffer, ManagedBuffer::Ptr& indexBuffer)
|
||||
|
||||
@@ -37,6 +37,11 @@ namespace OpenVulkano::Vulkan
|
||||
texture->renderTexture = this;
|
||||
}
|
||||
|
||||
virtual ~VulkanTexture() override
|
||||
{
|
||||
if (m_texture) Close();
|
||||
}
|
||||
|
||||
void Close() override
|
||||
{
|
||||
Image::Close();
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "Base/UI/IVulkanWindow.hpp"
|
||||
#include "Base/EngineConfiguration.hpp"
|
||||
#include "Scene/DataFormat.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
namespace OpenVulkano::Vulkan
|
||||
{
|
||||
@@ -25,13 +24,17 @@ namespace OpenVulkano::Vulkan
|
||||
CreateSwapChain({window->GetWidth(), window->GetHeight() });
|
||||
|
||||
FrameBuffer::Init(device, vk::Extent3D(size, 1));
|
||||
|
||||
Logger::RENDER->trace("Initialized swapchain");
|
||||
}
|
||||
|
||||
void SwapChain::Close()
|
||||
{
|
||||
FrameBuffer::Close();
|
||||
DestroySwapChain();
|
||||
device = nullptr;
|
||||
FrameBuffer::Close();
|
||||
window = nullptr;
|
||||
Logger::RENDER->trace("Closed swapchain");
|
||||
}
|
||||
|
||||
void SwapChain::Resize(const uint32_t newWidth, const uint32_t newHeight)
|
||||
@@ -40,6 +43,7 @@ namespace OpenVulkano::Vulkan
|
||||
|
||||
CreateSwapChain({ newWidth, newHeight });
|
||||
FrameBuffer::Resize(vk::Extent3D(size, 1));
|
||||
Logger::RENDER->trace("Resized swapchain");
|
||||
}
|
||||
|
||||
uint32_t SwapChain::AcquireNextImage(const vk::Fence& fence)
|
||||
@@ -141,6 +145,7 @@ namespace OpenVulkano::Vulkan
|
||||
for (auto& semaphore : imageAvailableSemaphores)
|
||||
device->device.destroySemaphore(semaphore);
|
||||
imageAvailableSemaphores.clear();
|
||||
Logger::RENDER->trace("Destroyed swapchain");
|
||||
}
|
||||
|
||||
vk::PresentModeKHR SwapChain::ChosePresentMode()
|
||||
|
||||
Reference in New Issue
Block a user