Improve resource handling
This commit is contained in:
@@ -59,6 +59,8 @@ namespace openVulkanoCpp
|
||||
|
||||
void SetMatrix(const Math::Matrix4f& mat);
|
||||
|
||||
[[nodiscard]] Math::Matrix3f GetRotationMatrix() const { return static_cast<const Math::Matrix3f>(localMat); }
|
||||
|
||||
[[nodiscard]] const Math::Matrix4f& GetMatrix() const { return localMat; }
|
||||
|
||||
[[nodiscard]] const Math::Matrix4f& GetWorldMatrix() const { return worldMat; }
|
||||
|
||||
@@ -150,10 +150,11 @@ namespace openVulkanoCpp::Vulkan
|
||||
{
|
||||
Scene::Drawable* drawable = *drawablePointer;
|
||||
Scene::Geometry* mesh = drawable->mesh;
|
||||
VulkanGeometry* renderGeo = dynamic_cast<VulkanGeometry*>(mesh->renderGeo);
|
||||
if (mesh != lastGeo)
|
||||
{
|
||||
if (!mesh->renderGeo) resourceManager.PrepareGeometry(mesh);
|
||||
dynamic_cast<VulkanGeometry*>(mesh->renderGeo)->Record(cmdHelper->cmdBuffer, currentImageId);
|
||||
if (!mesh->renderGeo) renderGeo = resourceManager.PrepareGeometry(mesh);
|
||||
renderGeo->RecordBind(cmdHelper->cmdBuffer);
|
||||
lastGeo = mesh;
|
||||
}
|
||||
for(Scene::Node* node : drawable->nodes)
|
||||
@@ -164,7 +165,7 @@ namespace openVulkanoCpp::Vulkan
|
||||
dynamic_cast<VulkanNode*>(node->renderNode)->Record(cmdHelper->cmdBuffer, currentImageId);
|
||||
lastNode = node;
|
||||
}
|
||||
cmdHelper->cmdBuffer.drawIndexed(mesh->GetIndexCount(), 1, 0, 0, 0);
|
||||
renderGeo->RecordDraw(cmdHelper->cmdBuffer);
|
||||
}
|
||||
}
|
||||
cmdHelper->cmdBuffer.end();
|
||||
|
||||
@@ -10,172 +10,169 @@
|
||||
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
namespace openVulkanoCpp
|
||||
namespace openVulkanoCpp::Vulkan
|
||||
{
|
||||
namespace Vulkan
|
||||
struct MemoryAllocation
|
||||
{
|
||||
struct MemoryAllocation
|
||||
vk::DeviceMemory memory;
|
||||
size_t used;
|
||||
const size_t size;
|
||||
const uint32_t type;
|
||||
const vk::Device device;
|
||||
void* mapped;
|
||||
|
||||
private:
|
||||
uint32_t mappedCount;
|
||||
static constexpr uint32_t CHILD_MAPPED_FLAG = 1u << 31;
|
||||
|
||||
public:
|
||||
MemoryAllocation(size_t size, uint32_t type, vk::Device device):
|
||||
memory(nullptr), used(0), size(size), type(type), device(device), mapped(nullptr), mappedCount(0)
|
||||
{
|
||||
vk::DeviceMemory memory;
|
||||
size_t used;
|
||||
const size_t size;
|
||||
const uint32_t type;
|
||||
const vk::Device device;
|
||||
void* mapped;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t mappedCount;
|
||||
static constexpr uint32_t CHILD_MAPPED_FLAG = 1u << 31;
|
||||
[[nodiscard]] size_t FreeSpace() const
|
||||
{
|
||||
return size - used;
|
||||
}
|
||||
|
||||
public:
|
||||
MemoryAllocation(size_t size, uint32_t type, vk::Device device):
|
||||
memory(nullptr), used(0), size(size), type(type), device(device), mapped(nullptr), mappedCount(0)
|
||||
void HandleChildMappingValidation() const;
|
||||
|
||||
void* Map()
|
||||
{
|
||||
HandleChildMappingValidation();
|
||||
if (!mapped)
|
||||
{
|
||||
mapped = device.mapMemory(memory, 0, size, vk::MemoryMapFlags());
|
||||
}
|
||||
mappedCount++;
|
||||
return mapped;
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t FreeSpace() const
|
||||
void UnMap()
|
||||
{
|
||||
if (mappedCount > 0)
|
||||
{
|
||||
return size - used;
|
||||
}
|
||||
|
||||
void HandleChildMappingValidation() const;
|
||||
|
||||
void* Map()
|
||||
{
|
||||
HandleChildMappingValidation();
|
||||
if (!mapped)
|
||||
{
|
||||
mapped = device.mapMemory(memory, 0, size, vk::MemoryMapFlags());
|
||||
}
|
||||
mappedCount++;
|
||||
return mapped;
|
||||
}
|
||||
|
||||
void UnMap()
|
||||
{
|
||||
if (mappedCount > 0)
|
||||
{
|
||||
mappedCount--;
|
||||
if (mappedCount == 0)
|
||||
{
|
||||
device.unmapMemory(memory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IsChildMapped() const
|
||||
{
|
||||
return mappedCount & CHILD_MAPPED_FLAG;
|
||||
}
|
||||
|
||||
void* MapChild(size_t offset, vk::DeviceSize size)
|
||||
{
|
||||
HandleChildMappingValidation();
|
||||
mappedCount |= CHILD_MAPPED_FLAG;
|
||||
mappedCount++;
|
||||
return device.mapMemory(memory, offset, size, vk::MemoryMapFlags());
|
||||
}
|
||||
|
||||
void UnMapChild()
|
||||
{
|
||||
mappedCount &= ~CHILD_MAPPED_FLAG;
|
||||
mappedCount--;
|
||||
if (mappedCount == 0)
|
||||
{
|
||||
device.unmapMemory(memory);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
struct ManagedBuffer
|
||||
[[nodiscard]] bool IsChildMapped() const
|
||||
{
|
||||
MemoryAllocation* allocation;
|
||||
vk::DeviceSize offset, size;
|
||||
vk::Buffer buffer;
|
||||
vk::BufferUsageFlags usage;
|
||||
vk::MemoryPropertyFlags properties;
|
||||
void* mapped = nullptr;
|
||||
return mappedCount & CHILD_MAPPED_FLAG;
|
||||
}
|
||||
|
||||
bool IsLast() const
|
||||
void* MapChild(size_t offset, vk::DeviceSize size)
|
||||
{
|
||||
HandleChildMappingValidation();
|
||||
mappedCount |= CHILD_MAPPED_FLAG;
|
||||
mappedCount++;
|
||||
return device.mapMemory(memory, offset, size, vk::MemoryMapFlags());
|
||||
}
|
||||
|
||||
void UnMapChild()
|
||||
{
|
||||
mappedCount &= ~CHILD_MAPPED_FLAG;
|
||||
mappedCount--;
|
||||
if (mappedCount == 0)
|
||||
{
|
||||
return (offset + size == allocation->used);
|
||||
device.unmapMemory(memory);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
bool IsMapped() const
|
||||
{
|
||||
return mapped || allocation->mapped;
|
||||
}
|
||||
struct ManagedBuffer
|
||||
{
|
||||
MemoryAllocation* allocation;
|
||||
vk::DeviceSize offset, size;
|
||||
vk::Buffer buffer;
|
||||
vk::BufferUsageFlags usage;
|
||||
vk::MemoryPropertyFlags properties;
|
||||
void* mapped = nullptr;
|
||||
|
||||
/**
|
||||
* \brief Maps the buffer into the memory of the host.
|
||||
* \tparam T The type of the buffers data.
|
||||
* \param offset The offset from where to map the buffer.
|
||||
* \param size The size to be mapped. VK_WHOLE_SIZE to map the whole buffer.
|
||||
* \pparam longTermMapping If the mapping is intended to be held long term. Short term mappings must be freed before mapping a different region in the same memory allocation for them to work reliable with all drivers.
|
||||
* \return The pointer to the mapped buffer.
|
||||
*/
|
||||
template <typename T = void>
|
||||
T* Map(size_t offset = 0, vk::DeviceSize size = VK_WHOLE_SIZE, bool longTermMapping = true)
|
||||
[[nodiscard]] bool IsLast() const
|
||||
{
|
||||
return (offset + size == allocation->used);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool IsMapped() const
|
||||
{
|
||||
return mapped || allocation->mapped;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Maps the buffer into the memory of the host.
|
||||
* \tparam T The type of the buffers data.
|
||||
* \param offset The offset from where to map the buffer.
|
||||
* \param size The size to be mapped. VK_WHOLE_SIZE to map the whole buffer.
|
||||
* \pparam longTermMapping If the mapping is intended to be held long term. Short term mappings must be freed before mapping a different region in the same memory allocation for them to work reliable with all drivers.
|
||||
* \return The pointer to the mapped buffer.
|
||||
*/
|
||||
template <typename T = void>
|
||||
T* Map(size_t offset = 0, vk::DeviceSize size = VK_WHOLE_SIZE, bool longTermMapping = true)
|
||||
{
|
||||
if (!mapped)
|
||||
{
|
||||
if (!mapped)
|
||||
if (allocation->mapped || longTermMapping)
|
||||
{
|
||||
if (allocation->mapped || longTermMapping)
|
||||
{
|
||||
mapped = static_cast<uint8_t*>(allocation->Map()) + offset + this->offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (size == VK_WHOLE_SIZE) size = this->size;
|
||||
mapped = allocation->MapChild(this->offset + offset, size);
|
||||
}
|
||||
|
||||
return static_cast<T*>(mapped);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Un-maps the buffer from the host.
|
||||
*/
|
||||
void UnMap()
|
||||
{
|
||||
if (mapped)
|
||||
{
|
||||
if (allocation->mapped)
|
||||
{
|
||||
allocation->UnMap();
|
||||
}
|
||||
else
|
||||
{
|
||||
allocation->UnMapChild();
|
||||
}
|
||||
mapped = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Copy(void* data)
|
||||
{
|
||||
if (mapped)
|
||||
{
|
||||
memcpy(mapped, data, size);
|
||||
mapped = static_cast<uint8_t*>(allocation->Map()) + offset + this->offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
void* dataMapped = Map(0, VK_WHOLE_SIZE, false);
|
||||
memcpy(dataMapped, data, size);
|
||||
UnMap();
|
||||
if (size == VK_WHOLE_SIZE) size = this->size;
|
||||
mapped = allocation->MapChild(this->offset + offset, size);
|
||||
}
|
||||
}
|
||||
|
||||
void Copy(void* data, uint32_t size, uint32_t offset)
|
||||
return static_cast<T*>(mapped);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Un-maps the buffer from the host.
|
||||
*/
|
||||
void UnMap()
|
||||
{
|
||||
if (mapped)
|
||||
{
|
||||
if(mapped) memcpy(static_cast<char*>(mapped) + offset, data, size);
|
||||
if (allocation->mapped)
|
||||
{
|
||||
allocation->UnMap();
|
||||
}
|
||||
else
|
||||
{
|
||||
void* dataMapped = Map(offset, size, false);
|
||||
memcpy(dataMapped, data, size);
|
||||
UnMap();
|
||||
allocation->UnMapChild();
|
||||
}
|
||||
mapped = nullptr;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void Copy(void* data)
|
||||
{
|
||||
if (mapped)
|
||||
{
|
||||
memcpy(mapped, data, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
void* dataMapped = Map(0, VK_WHOLE_SIZE, false);
|
||||
memcpy(dataMapped, data, size);
|
||||
UnMap();
|
||||
}
|
||||
}
|
||||
|
||||
void Copy(void* data, uint32_t size, uint32_t offset)
|
||||
{
|
||||
if(mapped) memcpy(static_cast<char*>(mapped) + offset, data, size);
|
||||
else
|
||||
{
|
||||
void* dataMapped = Map(offset, size, false);
|
||||
memcpy(dataMapped, data, size);
|
||||
UnMap();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
|
||||
namespace openVulkanoCpp::Vulkan
|
||||
{
|
||||
ResourceManager* ResourceManager::INSTANCE;
|
||||
|
||||
ResourceManager::ResourceManager() = default;
|
||||
|
||||
ResourceManager::~ResourceManager() noexcept
|
||||
@@ -39,6 +41,8 @@ namespace openVulkanoCpp::Vulkan
|
||||
toFree.resize(buffers);
|
||||
|
||||
transferQueue = this->device.getQueue(context->device->queueIndices.transfer, 0);
|
||||
|
||||
INSTANCE = this;
|
||||
}
|
||||
|
||||
void ResourceManager::Close()
|
||||
@@ -82,17 +86,18 @@ namespace openVulkanoCpp::Vulkan
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceManager::PrepareGeometry(Scene::Geometry* geometry)
|
||||
VulkanGeometry* ResourceManager::PrepareGeometry(Scene::Geometry* geometry)
|
||||
{
|
||||
const std::unique_lock lock(mutex);
|
||||
if(!geometry->renderGeo)
|
||||
{
|
||||
VulkanGeometry* vkGeometry = new VulkanGeometry();
|
||||
ManagedBuffer* vertexBuffer = CreateDeviceOnlyBufferWithData(sizeof(Vertex) * geometry->GetVertexCount(), vk::BufferUsageFlagBits::eVertexBuffer, geometry->GetVertices());
|
||||
ManagedBuffer* indexBuffer = CreateDeviceOnlyBufferWithData(Utils::EnumAsInt(geometry->indexType) * geometry->GetIndexCount(), vk::BufferUsageFlagBits::eIndexBuffer, geometry->GetIndices());
|
||||
vkGeometry->Init(geometry, vertexBuffer->buffer, indexBuffer->buffer);
|
||||
geometry->renderGeo = vkGeometry;
|
||||
VulkanGeometry* vkGeo = new VulkanGeometry(geometry, vertexBuffer, indexBuffer);
|
||||
geometry->renderGeo = vkGeo;
|
||||
return vkGeo;
|
||||
}
|
||||
return dynamic_cast<VulkanGeometry*>(geometry->renderGeo);
|
||||
}
|
||||
|
||||
void ResourceManager::PrepareMaterial(Scene::Material* material)
|
||||
@@ -131,6 +136,13 @@ namespace openVulkanoCpp::Vulkan
|
||||
}
|
||||
}
|
||||
|
||||
ManagedBuffer* ResourceManager::CreateSharedMemoryBuffer(const size_t size)
|
||||
{
|
||||
const std::unique_lock lock(mutex);
|
||||
ManagedBuffer* buffer = CreateBuffer(size, vk::BufferUsageFlagBits::eVertexBuffer, vk::MemoryPropertyFlagBits::eHostCoherent);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void ResourceManager::RemoveShader(VulkanShader* shader)
|
||||
{
|
||||
Utils::Remove(shaders, shader);
|
||||
|
||||
@@ -23,6 +23,8 @@ namespace openVulkanoCpp
|
||||
|
||||
namespace Vulkan
|
||||
{
|
||||
class VulkanGeometry;
|
||||
|
||||
class ResourceManager : virtual public ICloseable, virtual public IShaderOwner
|
||||
{
|
||||
Context* context;
|
||||
@@ -42,7 +44,10 @@ namespace openVulkanoCpp
|
||||
int buffers = -1, currentBuffer = -1;
|
||||
|
||||
public:
|
||||
static ResourceManager* INSTANCE;
|
||||
|
||||
ResourceManager();
|
||||
|
||||
virtual ~ResourceManager() noexcept;
|
||||
|
||||
void Init(Context* context, int buffers = 2);
|
||||
@@ -55,7 +60,7 @@ namespace openVulkanoCpp
|
||||
|
||||
void Resize();
|
||||
|
||||
void PrepareGeometry(Scene::Geometry* geometry);
|
||||
VulkanGeometry* PrepareGeometry(Scene::Geometry* geometry);
|
||||
|
||||
void PrepareMaterial(Scene::Material* material);
|
||||
|
||||
@@ -63,6 +68,8 @@ namespace openVulkanoCpp
|
||||
|
||||
void RemoveShader(VulkanShader* shader) override;
|
||||
|
||||
ManagedBuffer* CreateSharedMemoryBuffer(size_t size);
|
||||
|
||||
protected: // Allocation management
|
||||
void FreeBuffer(ManagedBuffer* buffer);
|
||||
|
||||
|
||||
@@ -9,40 +9,52 @@
|
||||
#include "IRecordable.hpp"
|
||||
#include "Scene/Scene.hpp"
|
||||
|
||||
namespace openVulkanoCpp
|
||||
namespace openVulkanoCpp::Vulkan
|
||||
{
|
||||
namespace Vulkan
|
||||
class VulkanGeometry final : virtual public ICloseable
|
||||
{
|
||||
class VulkanGeometry : virtual public IRecordable, virtual public ICloseable
|
||||
Scene::Geometry* m_geometry;
|
||||
ManagedBuffer* m_vertexBuffer;
|
||||
ManagedBuffer* m_indexBuffer;
|
||||
vk::IndexType m_indexType;
|
||||
vk::DeviceSize m_offsets = 0;
|
||||
|
||||
public:
|
||||
VulkanGeometry() : m_geometry(nullptr), m_vertexBuffer(nullptr)
|
||||
, m_indexBuffer(nullptr), m_indexType(vk::IndexType::eUint32)
|
||||
{}
|
||||
|
||||
VulkanGeometry(Scene::Geometry* geo, ManagedBuffer* vertexBuffer, ManagedBuffer* indexBuffer)
|
||||
: m_geometry(geo), m_vertexBuffer(vertexBuffer), m_indexBuffer(indexBuffer)
|
||||
, m_indexType((geo->indexType == Scene::VertexIndexType::UINT16) ? vk::IndexType::eUint16 : vk::IndexType::eUint32)
|
||||
{}
|
||||
|
||||
~VulkanGeometry() override
|
||||
{
|
||||
Scene::Geometry* geometry = nullptr;
|
||||
vk::Buffer vertexBuffer, indexBuffer;
|
||||
vk::IndexType indexType;
|
||||
vk::DeviceSize* offsets = new vk::DeviceSize();
|
||||
if (m_vertexBuffer) VulkanGeometry::Close();
|
||||
}
|
||||
|
||||
public:
|
||||
VulkanGeometry() = default;
|
||||
virtual ~VulkanGeometry() { if (vertexBuffer) VulkanGeometry::Close(); };
|
||||
void Init(Scene::Geometry* geo, ManagedBuffer* vertexBuffer, ManagedBuffer* indexBuffer)
|
||||
{
|
||||
m_geometry = geo;
|
||||
m_vertexBuffer = vertexBuffer;
|
||||
m_indexBuffer = indexBuffer;
|
||||
m_indexType = (geo->indexType == Scene::VertexIndexType::UINT16) ? vk::IndexType::eUint16 : vk::IndexType::eUint32;
|
||||
}
|
||||
|
||||
void Init(Scene::Geometry* geo, vk::Buffer vertexBuffer, vk::Buffer indexBuffer)
|
||||
{
|
||||
this->geometry = geo;
|
||||
offsets[0] = 0;
|
||||
indexType = (geo->indexType == Scene::VertexIndexType::UINT16) ? vk::IndexType::eUint16 : vk::IndexType::eUint32;
|
||||
this->vertexBuffer = vertexBuffer;
|
||||
this->indexBuffer = indexBuffer;
|
||||
}
|
||||
void RecordBind(vk::CommandBuffer& cmdBuffer)
|
||||
{
|
||||
cmdBuffer.bindVertexBuffers(0, 1, &m_vertexBuffer->buffer, &m_offsets);
|
||||
cmdBuffer.bindIndexBuffer(m_indexBuffer->buffer, 0, m_indexType);
|
||||
}
|
||||
|
||||
void Record(vk::CommandBuffer& cmdBuffer, uint32_t bufferId) override
|
||||
{
|
||||
cmdBuffer.bindVertexBuffers(0, 1, &vertexBuffer, offsets);
|
||||
cmdBuffer.bindIndexBuffer(indexBuffer, 0, indexType);
|
||||
}
|
||||
void RecordDraw(vk::CommandBuffer& cmdBuffer)
|
||||
{
|
||||
cmdBuffer.drawIndexed(m_geometry->GetIndexCount(), 1, 0, 0, 0);
|
||||
}
|
||||
|
||||
void Close() override
|
||||
{
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
void Close() override
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user