From 87dad42c79010430be785a04a88155f4f3a12594 Mon Sep 17 00:00:00 2001 From: GeorgH93 Date: Sun, 1 Aug 2021 00:37:11 +0200 Subject: [PATCH] Move Drawable draw call recording logic out of renderer --- .../ExampleApps/CubesExampleApp.cpp | 3 +- openVulkanoCpp/Scene/DrawEncoder.cpp | 42 +++++++++++++ openVulkanoCpp/Scene/DrawEncoder.hpp | 59 +++++++++++++++++++ openVulkanoCpp/Scene/Drawable.cpp | 30 +++------- openVulkanoCpp/Scene/Drawable.hpp | 36 +++-------- openVulkanoCpp/Scene/Geometry.hpp | 3 +- openVulkanoCpp/Scene/Node.hpp | 1 + openVulkanoCpp/Scene/SimpleDrawable.cpp | 25 ++++++++ openVulkanoCpp/Scene/SimpleDrawable.hpp | 45 ++++++++++++++ openVulkanoCpp/Vulkan/Renderer.cpp | 21 +------ openVulkanoCpp/Vulkan/Renderer.hpp | 2 + .../Scene/SimpleDrawableVulkanEncoder.cpp | 34 +++++++++++ .../Vulkan/Scene/VulkanGeometry.hpp | 1 + openVulkanoCpp/Vulkan/VulkanDrawContext.hpp | 19 ++++++ 14 files changed, 251 insertions(+), 70 deletions(-) create mode 100644 openVulkanoCpp/Scene/DrawEncoder.cpp create mode 100644 openVulkanoCpp/Scene/DrawEncoder.hpp create mode 100644 openVulkanoCpp/Scene/SimpleDrawable.cpp create mode 100644 openVulkanoCpp/Scene/SimpleDrawable.hpp create mode 100644 openVulkanoCpp/Vulkan/Scene/SimpleDrawableVulkanEncoder.cpp create mode 100644 openVulkanoCpp/Vulkan/VulkanDrawContext.hpp diff --git a/openVulkanoCpp/ExampleApps/CubesExampleApp.cpp b/openVulkanoCpp/ExampleApps/CubesExampleApp.cpp index 2327fb2..646ed5b 100644 --- a/openVulkanoCpp/ExampleApps/CubesExampleApp.cpp +++ b/openVulkanoCpp/ExampleApps/CubesExampleApp.cpp @@ -10,6 +10,7 @@ #include "Scene/Geometry.hpp" #include "Scene/Material.hpp" #include "Scene/Vertex.hpp" +#include "Scene/SimpleDrawable.hpp" #include "Input/InputManager.hpp" #include "Host/GraphicsAppManager.hpp" #include "Math/Math.hpp" @@ -33,7 +34,7 @@ class CubesExampleAppImpl final : public CubesExampleApp openVulkanoCpp::FreeCamCameraController camController; Material mat; Shader shader; - std::vector drawablesPool; + std::vector drawablesPool; std::vector nodesPool; InputAction* actionForward; diff --git a/openVulkanoCpp/Scene/DrawEncoder.cpp b/openVulkanoCpp/Scene/DrawEncoder.cpp new file mode 100644 index 0000000..b72c52b --- /dev/null +++ b/openVulkanoCpp/Scene/DrawEncoder.cpp @@ -0,0 +1,42 @@ +/* + * 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 "DrawEncoder.hpp" +#include +#include + +namespace openVulkanoCpp::Scene +{ + namespace + { + auto& GetDrawEncoderRegistry() + { + static std::map drawEncoderRegistry; + return drawEncoderRegistry; + } + + template + void EncoderNotImplementedFunction(args... ignored) + { + throw std::runtime_error("No implementation for encoder!"); + } + } + + void* DrawEncoder::RegisterVulkanEncodeFunction(const std::type_info* type, DrawEncoder::VkEncodeFunc func) + { + GetDrawEncoderRegistry()[type].vulkan = func; + return nullptr; + } + + DrawEncoder& DrawEncoder::GetDrawEncoder(const std::type_info* type) + { + return GetDrawEncoderRegistry()[type]; + } + + DrawEncoder::DrawEncoder() + : vulkan(&EncoderNotImplementedFunction) + {} +} \ No newline at end of file diff --git a/openVulkanoCpp/Scene/DrawEncoder.hpp b/openVulkanoCpp/Scene/DrawEncoder.hpp new file mode 100644 index 0000000..4583a77 --- /dev/null +++ b/openVulkanoCpp/Scene/DrawEncoder.hpp @@ -0,0 +1,59 @@ +/* + * 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 + +namespace openVulkanoCpp +{ + namespace Vulkan + { + class VulkanDrawContext; + } + + namespace Scene + { + class Drawable; + + struct DrawEncoder + { + //region function type definitions + typedef void(* VkEncodeFunc)(Drawable*, Vulkan::VulkanDrawContext*); + //endregion + + //region DrawEncoder storage + VkEncodeFunc vulkan; + //endregion + + //region DrawEncoder constructors + DrawEncoder(); + + DrawEncoder(const DrawEncoder& other) = default; + //endregion + + //region static functions + static void* RegisterVulkanEncodeFunction(const std::type_info* type, VkEncodeFunc func); + + static DrawEncoder& GetDrawEncoder(const std::type_info* type); + //endregion + + //region Template helper functions + template + static DrawEncoder& GetDrawEncoder() + { + return { GetDrawEncoder(&typeid(T)) }; + } + + template + static void* RegisterVulkanEncodeFunction(VkEncodeFunc func) + { + return RegisterVulkanEncodeFunction(&typeid(T), func); + } + //endregion + }; + } +} \ No newline at end of file diff --git a/openVulkanoCpp/Scene/Drawable.cpp b/openVulkanoCpp/Scene/Drawable.cpp index 178f2c2..3e077d4 100644 --- a/openVulkanoCpp/Scene/Drawable.cpp +++ b/openVulkanoCpp/Scene/Drawable.cpp @@ -10,19 +10,24 @@ namespace openVulkanoCpp::Scene { + void Drawable::Close() + { + if (!m_nodes.empty()) throw std::runtime_error("Drawable is still being used!!!"); + m_scene = nullptr; + } + void Drawable::SetScene(Scene* scene) { if (m_scene == scene) return; if (scene && m_scene) throw std::runtime_error("Drawable has been associated with a scene already!"); const auto oldScene = m_scene; m_scene = scene; - if(scene) scene->RegisterDrawable(this); + if (scene) scene->RegisterDrawable(this); else if (oldScene) oldScene->RemoveDrawable(this); } void Drawable::AddNode(Node* node) { - if (!m_mesh) throw std::runtime_error("Drawable is not initialized."); if (Utils::Contains(m_nodes, node)) throw std::runtime_error("A drawable must not use the same node more than once."); m_nodes.push_back(node); } @@ -36,25 +41,4 @@ namespace openVulkanoCpp::Scene m_scene = nullptr; } } - - void Drawable::Init(Geometry* mesh, Material* material) - { - if (m_mesh || m_material) throw std::runtime_error("Drawable is already initialized."); - m_mesh = mesh; - m_material = material; - } - - void Drawable::Init(Drawable* drawable) - { - if (m_mesh || m_material) throw std::runtime_error("Drawable is already initialized."); - m_mesh = drawable->m_mesh; - m_material = drawable->m_material; - } - - void Drawable::Close() - { - if (!m_nodes.empty()) throw std::runtime_error("Drawable is still being used!!!"); - m_mesh = nullptr; - m_material = nullptr; - } } \ No newline at end of file diff --git a/openVulkanoCpp/Scene/Drawable.hpp b/openVulkanoCpp/Scene/Drawable.hpp index ed944aa..c7eacf9 100644 --- a/openVulkanoCpp/Scene/Drawable.hpp +++ b/openVulkanoCpp/Scene/Drawable.hpp @@ -7,53 +7,35 @@ #pragma once #include "Base/ICloseable.hpp" +#include "DrawEncoder.hpp" #include namespace openVulkanoCpp::Scene { class Node; class Scene; - class Geometry; - class Material; - class Drawable : virtual public ICloseable + class Drawable { std::vector m_nodes; Scene* m_scene = nullptr; - Geometry* m_mesh = nullptr; - Material* m_material = nullptr; + const DrawEncoder m_encoder; public: - Drawable() = default; + explicit Drawable(const DrawEncoder& encoder) : m_encoder(encoder) {} - explicit Drawable(const Drawable* toCopy) - { - m_mesh = toCopy->m_mesh; - m_material = toCopy->m_material; - } + ~Drawable() { if (m_scene) Drawable::Close(); } - ~Drawable() override - { - if (m_mesh) Drawable::Close(); - } + void Close(); - [[nodiscard]] Drawable* Copy() const - { - return new Drawable(this); - } - - void Init(Geometry* mesh, Material* material); - - void Init(Drawable* drawable); - - void Close() override; + [[nodiscard]] virtual Drawable* Copy() = 0; [[nodiscard]] Scene* GetScene() const { return m_scene; } - [[nodiscard]] Geometry* GetMesh() const { return m_mesh; } - [[nodiscard]] const auto& GetNodes() const { return m_nodes; } + [[nodiscard]] const DrawEncoder& GetEncoder() const { return m_encoder; } + private: friend class Node; friend class Scene; diff --git a/openVulkanoCpp/Scene/Geometry.hpp b/openVulkanoCpp/Scene/Geometry.hpp index 8a1bfdc..a72781f 100644 --- a/openVulkanoCpp/Scene/Geometry.hpp +++ b/openVulkanoCpp/Scene/Geometry.hpp @@ -23,8 +23,9 @@ namespace openVulkanoCpp UINT16 = sizeof(uint16_t), UINT32 = sizeof(uint32_t) }; - struct Geometry : public virtual ICloseable + class Geometry : public virtual ICloseable { + public: uint32_t vertexCount = 0, indexCount = 0; Vertex* vertices; void* indices; diff --git a/openVulkanoCpp/Scene/Node.hpp b/openVulkanoCpp/Scene/Node.hpp index a66a674..fab3fd6 100644 --- a/openVulkanoCpp/Scene/Node.hpp +++ b/openVulkanoCpp/Scene/Node.hpp @@ -12,6 +12,7 @@ #include "Drawable.hpp" #include "UpdateFrequency.hpp" #include +#include namespace openVulkanoCpp::Scene { diff --git a/openVulkanoCpp/Scene/SimpleDrawable.cpp b/openVulkanoCpp/Scene/SimpleDrawable.cpp new file mode 100644 index 0000000..611e827 --- /dev/null +++ b/openVulkanoCpp/Scene/SimpleDrawable.cpp @@ -0,0 +1,25 @@ +/* + * 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 "SimpleDrawable.hpp" +#include + +namespace openVulkanoCpp::Scene +{ + void SimpleDrawable::Init(Geometry* mesh, Material* material) + { + if (m_mesh || m_material) throw std::runtime_error("Drawable is already initialized."); + m_mesh = mesh; + m_material = material; + } + + void SimpleDrawable::Init(SimpleDrawable* drawable) + { + if (m_mesh || m_material) throw std::runtime_error("Drawable is already initialized."); + m_mesh = drawable->m_mesh; + m_material = drawable->m_material; + } +} \ No newline at end of file diff --git a/openVulkanoCpp/Scene/SimpleDrawable.hpp b/openVulkanoCpp/Scene/SimpleDrawable.hpp new file mode 100644 index 0000000..041c65c --- /dev/null +++ b/openVulkanoCpp/Scene/SimpleDrawable.hpp @@ -0,0 +1,45 @@ +/* + * 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 "Drawable.hpp" + +namespace openVulkanoCpp::Scene +{ + class Geometry; + class Material; + + class SimpleDrawable final : public Drawable + { + Geometry* m_mesh = nullptr; + Material* m_material = nullptr; + + public: + SimpleDrawable() : Drawable(DrawEncoder::GetDrawEncoder()) {} + + explicit SimpleDrawable(const SimpleDrawable* toCopy) + : Drawable(DrawEncoder::GetDrawEncoder()) + , m_mesh(toCopy->m_mesh) + , m_material(toCopy->m_material) + {} + + ~SimpleDrawable() + { + if (m_mesh) SimpleDrawable::Close(); + } + + void Init(Geometry* mesh, Material* material); + + void Init(SimpleDrawable* drawable); + + [[nodiscard]] Drawable* Copy() override { return new SimpleDrawable(this); } + + [[nodiscard]] Geometry* GetMesh() const { return m_mesh; } + + [[nodiscard]] Material* GetMaterial() const { return m_material; } + }; +} \ No newline at end of file diff --git a/openVulkanoCpp/Vulkan/Renderer.cpp b/openVulkanoCpp/Vulkan/Renderer.cpp index 458d0fb..307b723 100644 --- a/openVulkanoCpp/Vulkan/Renderer.cpp +++ b/openVulkanoCpp/Vulkan/Renderer.cpp @@ -5,6 +5,7 @@ */ #include "Renderer.hpp" +#include "VulkanDrawContext.hpp" #include "Scene/Shader.hpp" #include "Scene/Geometry.hpp" #include "Scene/VulkanGeometry.hpp" @@ -154,27 +155,11 @@ namespace openVulkanoCpp::Vulkan shader->Record(cmdHelper->cmdBuffer, currentImageId); Scene::Drawable** drawablePointer; + VulkanDrawContext drawContext { poolId, currentImageId, cmdHelper->cmdBuffer, this }; while((drawablePointer = jobQueue->Pop()) != nullptr) { Scene::Drawable* drawable = *drawablePointer; - Scene::Geometry* mesh = drawable->mesh; - VulkanGeometry* renderGeo = dynamic_cast(mesh->renderGeo); - if (mesh != lastGeo) - { - if (!mesh->renderGeo) renderGeo = resourceManager.PrepareGeometry(mesh); - renderGeo->RecordBind(cmdHelper->cmdBuffer); - lastGeo = mesh; - } - for(Scene::Node* node : drawable->nodes) - { - if (node != lastNode) - { - if (!node->renderNode) resourceManager.PrepareNode(node); - dynamic_cast(node->renderNode)->Record(cmdHelper->cmdBuffer, currentImageId); - lastNode = node; - } - renderGeo->RecordDraw(cmdHelper->cmdBuffer); - } + drawable->GetEncoder().vulkan(drawable, &drawContext); } cmdHelper->cmdBuffer.end(); } diff --git a/openVulkanoCpp/Vulkan/Renderer.hpp b/openVulkanoCpp/Vulkan/Renderer.hpp index 5cad618..285fc71 100644 --- a/openVulkanoCpp/Vulkan/Renderer.hpp +++ b/openVulkanoCpp/Vulkan/Renderer.hpp @@ -74,5 +74,7 @@ namespace openVulkanoCpp::Vulkan void Render(); void RecordSecondaryBuffer(Data::ReadOnlyAtomicArrayQueue* jobQueue, uint32_t poolId); + + ResourceManager& GetResourceManager() { return resourceManager; } }; } diff --git a/openVulkanoCpp/Vulkan/Scene/SimpleDrawableVulkanEncoder.cpp b/openVulkanoCpp/Vulkan/Scene/SimpleDrawableVulkanEncoder.cpp new file mode 100644 index 0000000..0158e20 --- /dev/null +++ b/openVulkanoCpp/Vulkan/Scene/SimpleDrawableVulkanEncoder.cpp @@ -0,0 +1,34 @@ +/* + * 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 "Scene/SimpleDrawable.hpp" +#include "VulkanGeometry.hpp" +#include "VulkanNode.hpp" +#include "Vulkan/VulkanDrawContext.hpp" + +using namespace openVulkanoCpp::Scene; + +namespace openVulkanoCpp::Vulkan +{ + void EncodeSimpleDrawable(Drawable* instance, Vulkan::VulkanDrawContext* drawContext) + { + Geometry* mesh = dynamic_cast(instance)->GetMesh(); + VulkanGeometry* renderGeo = dynamic_cast(mesh->renderGeo); + if (!mesh->renderGeo) renderGeo = drawContext->renderer->GetResourceManager().PrepareGeometry(mesh); + renderGeo->RecordBind(drawContext->commandBuffer); + for(Node* node : instance->GetNodes()) + { + if (!node->renderNode) drawContext->renderer->GetResourceManager().PrepareNode(node); + dynamic_cast(node->renderNode)->Record(drawContext->commandBuffer, drawContext->currentImageId); + renderGeo->RecordDraw(drawContext->commandBuffer); + } + } +} + +namespace +{ + void* simpleDrawableVulkanEncoderReg = DrawEncoder::RegisterVulkanEncodeFunction(&openVulkanoCpp::Vulkan::EncodeSimpleDrawable); +} \ No newline at end of file diff --git a/openVulkanoCpp/Vulkan/Scene/VulkanGeometry.hpp b/openVulkanoCpp/Vulkan/Scene/VulkanGeometry.hpp index 1f430c9..29e04a9 100644 --- a/openVulkanoCpp/Vulkan/Scene/VulkanGeometry.hpp +++ b/openVulkanoCpp/Vulkan/Scene/VulkanGeometry.hpp @@ -9,6 +9,7 @@ #include "IRecordable.hpp" #include "Scene/Scene.hpp" #include "Scene/Geometry.hpp" +#include "Vulkan/Resources/ManagedResource.hpp" namespace openVulkanoCpp::Vulkan { diff --git a/openVulkanoCpp/Vulkan/VulkanDrawContext.hpp b/openVulkanoCpp/Vulkan/VulkanDrawContext.hpp new file mode 100644 index 0000000..069c1fd --- /dev/null +++ b/openVulkanoCpp/Vulkan/VulkanDrawContext.hpp @@ -0,0 +1,19 @@ +/* + * 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 "Renderer.hpp" + +namespace openVulkanoCpp::Vulkan +{ + class VulkanDrawContext + { + public: + size_t encoderThreadId; + size_t currentImageId; + vk::CommandBuffer& commandBuffer; + Renderer* renderer; + }; +}