Add render resouce

This commit is contained in:
Georg Hagen
2024-08-20 23:44:17 +02:00
parent 42f7a96f43
commit 25a0978a57
6 changed files with 164 additions and 32 deletions

View File

@@ -0,0 +1,143 @@
/*
* 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 <concepts>
#include <utility>
#include <type_traits>
namespace OpenVulkano
{
class RenderResource;
class IRenderResourceHelper
{
friend class RenderResource;
protected:
void UpdateRenderResource(RenderResource& resource);
void ResetRenderResource(RenderResource& resource);
virtual void Release() = 0;
};
template <class T>
concept Renderable = std::is_convertible_v<T, RenderResource&>;
class RenderResource final
{
friend class IRenderResourceHelper;
IRenderResourceHelper* renderObject = nullptr;
public:
RenderResource() = default;
RenderResource(const RenderResource& ignored) { /* Do not copy, copy will be created by renderer */ }
RenderResource(RenderResource&& move) : renderObject(move.renderObject) { move.renderObject = nullptr; }
~RenderResource()
{
Release();
}
void Release()
{
if (!renderObject) return;
renderObject->Release();
renderObject = nullptr;
}
template<class T>
T* As() { return static_cast<T*>(renderObject); }
template<class T>
operator T() { return static_cast<T>(renderObject); }
operator bool() const { return renderObject; }
};
inline void IRenderResourceHelper::UpdateRenderResource(RenderResource& resource)
{
resource.renderObject = this;
}
inline void IRenderResourceHelper::ResetRenderResource(RenderResource& resource)
{
resource.renderObject = nullptr;
}
template<Renderable API_INDEPENDENT_CLASS>
class IRenderResource : public IRenderResourceHelper
{
API_INDEPENDENT_CLASS* m_owner;
protected:
IRenderResource(API_INDEPENDENT_CLASS* owner) : m_owner(owner)
{
if (m_owner) UpdateRenderResource(GetOwnerResource());
}
IRenderResource(const IRenderResource<API_INDEPENDENT_CLASS>& copy) = delete;
IRenderResource(IRenderResource<API_INDEPENDENT_CLASS>&& move)
: m_owner(move.m_owner)
{
if (m_owner) UpdateRenderResource(GetOwnerResource());
move.m_owner = nullptr;
}
RenderResource& GetOwnerResource() { return static_cast<RenderResource&>(*m_owner); }
public:
virtual ~IRenderResource()
{
if (m_owner) ResetRenderResource(GetOwnerResource());
}
void UpdateAddress(API_INDEPENDENT_CLASS* owner)
{
m_owner = owner;
}
operator API_INDEPENDENT_CLASS*() const { return m_owner; }
API_INDEPENDENT_CLASS* GetOwner() const { return m_owner; }
};
/**
* This is a convenience class to create a Renderable class.
* You can also just create a RenderResource instance a conversion operator inside your own class to make it Renderable; and you probably want to delete your move constructor in that case.
*/
template <class T>
class RenderResourceHolder
{
RenderResource renderResource;
protected:
RenderResourceHolder() = default;
RenderResourceHolder(const RenderResourceHolder& ignored) {}
RenderResourceHolder(RenderResourceHolder&& move)
: renderResource(std::move(move.renderResource))
{
if (IRenderResource<T>* renderRes = renderResource)
renderRes->UpdateAddress(static_cast<T*>(this));
}
~RenderResourceHolder() = default;
public:
operator RenderResource&() { return renderResource; }
RenderResource& GetRenderResource() { return renderResource; }
template<Renderable RT>
operator RT() const { return renderResource; }
bool HasRenderResource() const { return renderResource; }
};
}

View File

@@ -37,7 +37,7 @@ namespace OpenVulkano::Scene
void Node::Close() void Node::Close()
{ {
children.clear(); children.clear();
if (renderNode) renderNode->Close(); GetRenderResource().Release();
parent = nullptr; parent = nullptr;
scene = nullptr; scene = nullptr;
enabled = false; enabled = false;

View File

@@ -7,6 +7,7 @@
#pragma once #pragma once
#include "Base/ICloseable.hpp" #include "Base/ICloseable.hpp"
#include "Base/Render/RenderResource.hpp"
#include "Math/Math.hpp" #include "Math/Math.hpp"
#include "Math/Pose.hpp" #include "Math/Pose.hpp"
#include "Drawable.hpp" #include "Drawable.hpp"
@@ -19,7 +20,7 @@ namespace OpenVulkano::Scene
{ {
class Scene; class Scene;
class Node : public ICloseable class Node : public RenderResourceHolder<Node>, public ICloseable
{ {
friend Scene; friend Scene;
@@ -33,7 +34,6 @@ namespace OpenVulkano::Scene
std::vector<Node*> children; std::vector<Node*> children;
std::vector<Drawable*> drawables; std::vector<Drawable*> drawables;
UpdateFrequency matrixUpdateFrequency = UpdateFrequency::Never; UpdateFrequency matrixUpdateFrequency = UpdateFrequency::Never;
ICloseable* renderNode = nullptr;
bool enabled = true; bool enabled = true;
public: public:

View File

@@ -183,7 +183,7 @@ namespace OpenVulkano::Vulkan
VulkanNode* ResourceManager::PrepareNode(Scene::Node* node) VulkanNode* ResourceManager::PrepareNode(Scene::Node* node)
{ {
const std::unique_lock lock(mutex); const std::unique_lock lock(mutex);
if (!node->renderNode) if (!node->HasRenderResource())
{ {
UniformBuffer* uBuffer = new UniformBuffer(); UniformBuffer* uBuffer = new UniformBuffer();
ManagedBuffer::Ptr buffer; ManagedBuffer::Ptr buffer;
@@ -193,23 +193,22 @@ namespace OpenVulkano::Vulkan
if (node->GetUpdateFrequency() != Scene::UpdateFrequency::Never) if (node->GetUpdateFrequency() != Scene::UpdateFrequency::Never)
{ {
frameSize = allocSize; frameSize = allocSize;
vkNode = new VulkanNodeDynamic(); vkNode = new VulkanNodeDynamic(node, uBuffer);
const uint32_t imgs = context->swapChain.GetImageCount(); const uint32_t imgs = context->swapChain.GetImageCount();
buffer = memPool.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(); buffer->Map();
} }
else else
{ {
vkNode = new VulkanNode();
buffer = CreateDeviceOnlyBufferWithData(Scene::Node::SIZE, vk::BufferUsageFlagBits::eUniformBuffer, &node->worldMat); buffer = CreateDeviceOnlyBufferWithData(Scene::Node::SIZE, vk::BufferUsageFlagBits::eUniformBuffer, &node->worldMat);
vkNode = new VulkanNode(node, uBuffer);
} }
uBuffer->Init(std::move(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); nodes.emplace_back(vkNode);
return vkNode;
} }
return static_cast<VulkanNode*>(node->renderNode); return node->GetRenderResource();
} }
VulkanCamera* ResourceManager::PrepareCamera(Scene::Camera* camera) VulkanCamera* ResourceManager::PrepareCamera(Scene::Camera* camera)

View File

@@ -6,28 +6,23 @@
#pragma once #pragma once
#include "Base/ICloseable.hpp" #include "Base/Render/RenderResource.hpp"
#include "IRecordable.hpp" #include "IRecordable.hpp"
#include "Scene/Camera.hpp" #include "Scene/Camera.hpp"
#include "Vulkan/Resources/UniformBuffer.hpp" #include "Vulkan/Resources/UniformBuffer.hpp"
namespace OpenVulkano::Vulkan namespace OpenVulkano::Vulkan
{ {
class VulkanNode : public IRecordable, public ICloseable class VulkanNode : public IRenderResource<Scene::Node>, public IRecordable
{ {
public: public:
Scene::Node* node = nullptr; Unique<UniformBuffer> buffer = nullptr;
UniformBuffer* buffer = nullptr;
~VulkanNode() override ~VulkanNode() override = default;
{
if (node) VulkanNode::Close();
}
virtual void Init(Scene::Node* node, UniformBuffer* uniformBuffer) VulkanNode(Scene::Node* node, UniformBuffer* uniformBuffer)
: IRenderResource<Scene::Node>(node), buffer(uniformBuffer)
{ {
this->node = node;
this->buffer = uniformBuffer;
} }
void Record(VulkanDrawContext* context) override void Record(VulkanDrawContext* context) override
@@ -35,12 +30,9 @@ namespace OpenVulkano::Vulkan
buffer->Record(context); buffer->Record(context);
} }
void Close() override void Release() override
{ {
if (node) node->renderNode = nullptr; //TODO
delete buffer;
node = nullptr;
buffer = nullptr;
} }
}; };
@@ -48,18 +40,16 @@ namespace OpenVulkano::Vulkan
{ {
//uint32_t lastUpdate = -1; //uint32_t lastUpdate = -1;
void Init(Scene::Node* node, UniformBuffer* uniformBuffer) override VulkanNodeDynamic(Scene::Node* node, UniformBuffer* uniformBuffer)
{ : VulkanNode(node, uniformBuffer)
VulkanNode::Init(node, uniformBuffer); {}
//lastUpdate = -1;
}
void Record(VulkanDrawContext* context) override void Record(VulkanDrawContext* context) override
{ {
//if(context->currentImageId != lastUpdate) //TODO fix //if(context->currentImageId != lastUpdate) //TODO fix
{ {
//lastUpdate = bufferId; //lastUpdate = bufferId;
buffer->Update(&node->worldMat, sizeof(Math::Matrix4f), context->currentImageId); buffer->Update(&GetOwner()->worldMat, sizeof(Math::Matrix4f), context->currentImageId);
} }
buffer->Record(context); buffer->Record(context);
} }

View File

@@ -34,7 +34,7 @@ namespace OpenVulkano::Vulkan
void VulkanDrawContext::EncodeNode(Scene::Node* node) void VulkanDrawContext::EncodeNode(Scene::Node* node)
{ {
VulkanNode* vkNode = static_cast<VulkanNode*>(node->renderNode); VulkanNode* vkNode = node->GetRenderResource();
if (!vkNode) if (!vkNode)
{ {
vkNode = renderer->GetResourceManager().PrepareNode(node); vkNode = renderer->GetResourceManager().PrepareNode(node);