From 25a0978a5716f7928d39d47bb12e1034c3c3a5ac Mon Sep 17 00:00:00 2001 From: Georg Hagen Date: Tue, 20 Aug 2024 23:44:17 +0200 Subject: [PATCH] Add render resouce --- openVulkanoCpp/Base/Render/RenderResource.hpp | 143 ++++++++++++++++++ openVulkanoCpp/Scene/Node.cpp | 2 +- openVulkanoCpp/Scene/Node.hpp | 4 +- .../Vulkan/Resources/ResourceManager.cpp | 11 +- openVulkanoCpp/Vulkan/Scene/VulkanNode.hpp | 34 ++--- openVulkanoCpp/Vulkan/VulkanDrawContext.cpp | 2 +- 6 files changed, 164 insertions(+), 32 deletions(-) create mode 100644 openVulkanoCpp/Base/Render/RenderResource.hpp diff --git a/openVulkanoCpp/Base/Render/RenderResource.hpp b/openVulkanoCpp/Base/Render/RenderResource.hpp new file mode 100644 index 0000000..13503e9 --- /dev/null +++ b/openVulkanoCpp/Base/Render/RenderResource.hpp @@ -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 +#include +#include + +namespace OpenVulkano +{ + class RenderResource; + + class IRenderResourceHelper + { + friend class RenderResource; + + protected: + void UpdateRenderResource(RenderResource& resource); + + void ResetRenderResource(RenderResource& resource); + + virtual void Release() = 0; + }; + + template + concept Renderable = std::is_convertible_v; + + 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 + T* As() { return static_cast(renderObject); } + + template + operator T() { return static_cast(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 + 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& copy) = delete; + + IRenderResource(IRenderResource&& move) + : m_owner(move.m_owner) + { + if (m_owner) UpdateRenderResource(GetOwnerResource()); + move.m_owner = nullptr; + } + + RenderResource& GetOwnerResource() { return static_cast(*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 RenderResourceHolder + { + RenderResource renderResource; + + protected: + RenderResourceHolder() = default; + RenderResourceHolder(const RenderResourceHolder& ignored) {} + RenderResourceHolder(RenderResourceHolder&& move) + : renderResource(std::move(move.renderResource)) + { + if (IRenderResource* renderRes = renderResource) + renderRes->UpdateAddress(static_cast(this)); + } + + ~RenderResourceHolder() = default; + + public: + operator RenderResource&() { return renderResource; } + + RenderResource& GetRenderResource() { return renderResource; } + + template + operator RT() const { return renderResource; } + + bool HasRenderResource() const { return renderResource; } + }; +} diff --git a/openVulkanoCpp/Scene/Node.cpp b/openVulkanoCpp/Scene/Node.cpp index 604cc45..c362f43 100644 --- a/openVulkanoCpp/Scene/Node.cpp +++ b/openVulkanoCpp/Scene/Node.cpp @@ -37,7 +37,7 @@ namespace OpenVulkano::Scene void Node::Close() { children.clear(); - if (renderNode) renderNode->Close(); + GetRenderResource().Release(); parent = nullptr; scene = nullptr; enabled = false; diff --git a/openVulkanoCpp/Scene/Node.hpp b/openVulkanoCpp/Scene/Node.hpp index 89be67c..70bb07f 100644 --- a/openVulkanoCpp/Scene/Node.hpp +++ b/openVulkanoCpp/Scene/Node.hpp @@ -7,6 +7,7 @@ #pragma once #include "Base/ICloseable.hpp" +#include "Base/Render/RenderResource.hpp" #include "Math/Math.hpp" #include "Math/Pose.hpp" #include "Drawable.hpp" @@ -19,7 +20,7 @@ namespace OpenVulkano::Scene { class Scene; - class Node : public ICloseable + class Node : public RenderResourceHolder, public ICloseable { friend Scene; @@ -33,7 +34,6 @@ namespace OpenVulkano::Scene std::vector children; std::vector drawables; UpdateFrequency matrixUpdateFrequency = UpdateFrequency::Never; - ICloseable* renderNode = nullptr; bool enabled = true; public: diff --git a/openVulkanoCpp/Vulkan/Resources/ResourceManager.cpp b/openVulkanoCpp/Vulkan/Resources/ResourceManager.cpp index 69e29f5..fa4f719 100644 --- a/openVulkanoCpp/Vulkan/Resources/ResourceManager.cpp +++ b/openVulkanoCpp/Vulkan/Resources/ResourceManager.cpp @@ -183,7 +183,7 @@ namespace OpenVulkano::Vulkan VulkanNode* ResourceManager::PrepareNode(Scene::Node* node) { const std::unique_lock lock(mutex); - if (!node->renderNode) + if (!node->HasRenderResource()) { UniformBuffer* uBuffer = new UniformBuffer(); ManagedBuffer::Ptr buffer; @@ -193,23 +193,22 @@ namespace OpenVulkano::Vulkan if (node->GetUpdateFrequency() != Scene::UpdateFrequency::Never) { frameSize = allocSize; - vkNode = new VulkanNodeDynamic(); + vkNode = new VulkanNodeDynamic(node, uBuffer); const uint32_t imgs = context->swapChain.GetImageCount(); buffer = memPool.CreateBuffer(imgs * allocSize, vk::BufferUsageFlagBits::eUniformBuffer, vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible); buffer->Map(); } else { - vkNode = new VulkanNode(); 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); - vkNode->Init(node, uBuffer); - node->renderNode = vkNode; nodes.emplace_back(vkNode); + return vkNode; } - return static_cast(node->renderNode); + return node->GetRenderResource(); } VulkanCamera* ResourceManager::PrepareCamera(Scene::Camera* camera) diff --git a/openVulkanoCpp/Vulkan/Scene/VulkanNode.hpp b/openVulkanoCpp/Vulkan/Scene/VulkanNode.hpp index 020c304..1e5aeab 100644 --- a/openVulkanoCpp/Vulkan/Scene/VulkanNode.hpp +++ b/openVulkanoCpp/Vulkan/Scene/VulkanNode.hpp @@ -6,28 +6,23 @@ #pragma once -#include "Base/ICloseable.hpp" +#include "Base/Render/RenderResource.hpp" #include "IRecordable.hpp" #include "Scene/Camera.hpp" #include "Vulkan/Resources/UniformBuffer.hpp" namespace OpenVulkano::Vulkan { - class VulkanNode : public IRecordable, public ICloseable + class VulkanNode : public IRenderResource, public IRecordable { public: - Scene::Node* node = nullptr; - UniformBuffer* buffer = nullptr; + Unique buffer = nullptr; - ~VulkanNode() override - { - if (node) VulkanNode::Close(); - } + ~VulkanNode() override = default; - virtual void Init(Scene::Node* node, UniformBuffer* uniformBuffer) + VulkanNode(Scene::Node* node, UniformBuffer* uniformBuffer) + : IRenderResource(node), buffer(uniformBuffer) { - this->node = node; - this->buffer = uniformBuffer; } void Record(VulkanDrawContext* context) override @@ -35,12 +30,9 @@ namespace OpenVulkano::Vulkan buffer->Record(context); } - void Close() override + void Release() override { - if (node) node->renderNode = nullptr; - delete buffer; - node = nullptr; - buffer = nullptr; + //TODO } }; @@ -48,18 +40,16 @@ namespace OpenVulkano::Vulkan { //uint32_t lastUpdate = -1; - void Init(Scene::Node* node, UniformBuffer* uniformBuffer) override - { - VulkanNode::Init(node, uniformBuffer); - //lastUpdate = -1; - } + VulkanNodeDynamic(Scene::Node* node, UniformBuffer* uniformBuffer) + : VulkanNode(node, uniformBuffer) + {} void Record(VulkanDrawContext* context) override { //if(context->currentImageId != lastUpdate) //TODO fix { //lastUpdate = bufferId; - buffer->Update(&node->worldMat, sizeof(Math::Matrix4f), context->currentImageId); + buffer->Update(&GetOwner()->worldMat, sizeof(Math::Matrix4f), context->currentImageId); } buffer->Record(context); } diff --git a/openVulkanoCpp/Vulkan/VulkanDrawContext.cpp b/openVulkanoCpp/Vulkan/VulkanDrawContext.cpp index fca2246..bc02e80 100644 --- a/openVulkanoCpp/Vulkan/VulkanDrawContext.cpp +++ b/openVulkanoCpp/Vulkan/VulkanDrawContext.cpp @@ -34,7 +34,7 @@ namespace OpenVulkano::Vulkan void VulkanDrawContext::EncodeNode(Scene::Node* node) { - VulkanNode* vkNode = static_cast(node->renderNode); + VulkanNode* vkNode = node->GetRenderResource(); if (!vkNode) { vkNode = renderer->GetResourceManager().PrepareNode(node);