Move Drawable draw call recording logic out of renderer

This commit is contained in:
2021-08-01 00:37:11 +02:00
parent 8d370c9860
commit 87dad42c79
14 changed files with 251 additions and 70 deletions

View File

@@ -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<Drawable> drawablesPool;
std::vector<SimpleDrawable> drawablesPool;
std::vector<Node> nodesPool;
InputAction* actionForward;

View File

@@ -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 <map>
#include <stdexcept>
namespace openVulkanoCpp::Scene
{
namespace
{
auto& GetDrawEncoderRegistry()
{
static std::map<const std::type_info*, DrawEncoder> drawEncoderRegistry;
return drawEncoderRegistry;
}
template<class... args>
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)
{}
}

View File

@@ -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 <typeinfo>
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<class T>
static DrawEncoder& GetDrawEncoder()
{
return { GetDrawEncoder(&typeid(T)) };
}
template<class T>
static void* RegisterVulkanEncodeFunction(VkEncodeFunc func)
{
return RegisterVulkanEncodeFunction(&typeid(T), func);
}
//endregion
};
}
}

View File

@@ -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;
}
}

View File

@@ -7,53 +7,35 @@
#pragma once
#include "Base/ICloseable.hpp"
#include "DrawEncoder.hpp"
#include <vector>
namespace openVulkanoCpp::Scene
{
class Node;
class Scene;
class Geometry;
class Material;
class Drawable : virtual public ICloseable
class Drawable
{
std::vector<Node*> 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;

View File

@@ -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;

View File

@@ -12,6 +12,7 @@
#include "Drawable.hpp"
#include "UpdateFrequency.hpp"
#include <vector>
#include <memory>
namespace openVulkanoCpp::Scene
{

View File

@@ -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 <stdexcept>
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;
}
}

View File

@@ -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<SimpleDrawable>()) {}
explicit SimpleDrawable(const SimpleDrawable* toCopy)
: Drawable(DrawEncoder::GetDrawEncoder<SimpleDrawable>())
, 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; }
};
}

View File

@@ -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<VulkanGeometry*>(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<VulkanNode*>(node->renderNode)->Record(cmdHelper->cmdBuffer, currentImageId);
lastNode = node;
}
renderGeo->RecordDraw(cmdHelper->cmdBuffer);
}
drawable->GetEncoder().vulkan(drawable, &drawContext);
}
cmdHelper->cmdBuffer.end();
}

View File

@@ -74,5 +74,7 @@ namespace openVulkanoCpp::Vulkan
void Render();
void RecordSecondaryBuffer(Data::ReadOnlyAtomicArrayQueue<Scene::Drawable*>* jobQueue, uint32_t poolId);
ResourceManager& GetResourceManager() { return resourceManager; }
};
}

View File

@@ -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<SimpleDrawable*>(instance)->GetMesh();
VulkanGeometry* renderGeo = dynamic_cast<VulkanGeometry*>(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<VulkanNode*>(node->renderNode)->Record(drawContext->commandBuffer, drawContext->currentImageId);
renderGeo->RecordDraw(drawContext->commandBuffer);
}
}
}
namespace
{
void* simpleDrawableVulkanEncoderReg = DrawEncoder::RegisterVulkanEncodeFunction<SimpleDrawable>(&openVulkanoCpp::Vulkan::EncodeSimpleDrawable);
}

View File

@@ -9,6 +9,7 @@
#include "IRecordable.hpp"
#include "Scene/Scene.hpp"
#include "Scene/Geometry.hpp"
#include "Vulkan/Resources/ManagedResource.hpp"
namespace openVulkanoCpp::Vulkan
{

View File

@@ -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;
};
}