Graphics: Add SpriteChainRenderer
This commit is contained in:
parent
a18d505ae2
commit
938d965e06
|
|
@ -18,6 +18,8 @@ namespace Nz
|
||||||
{
|
{
|
||||||
class CommandBufferBuilder;
|
class CommandBufferBuilder;
|
||||||
class RenderElement;
|
class RenderElement;
|
||||||
|
class RenderFrame;
|
||||||
|
struct ElementRendererData;
|
||||||
|
|
||||||
class NAZARA_GRAPHICS_API ElementRenderer
|
class NAZARA_GRAPHICS_API ElementRenderer
|
||||||
{
|
{
|
||||||
|
|
@ -25,7 +27,16 @@ namespace Nz
|
||||||
ElementRenderer() = default;
|
ElementRenderer() = default;
|
||||||
virtual ~ElementRenderer();
|
virtual ~ElementRenderer();
|
||||||
|
|
||||||
virtual void Render(CommandBufferBuilder& commandBuffer, const Pointer<const RenderElement>* elements, std::size_t elementCount) = 0;
|
virtual std::unique_ptr<ElementRendererData> InstanciateData() = 0;
|
||||||
|
virtual void Prepare(ElementRendererData& rendererData, RenderFrame& currentFrame, const Pointer<const RenderElement>* elements, std::size_t elementCount);
|
||||||
|
virtual void Render(ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, const Pointer<const RenderElement>* elements, std::size_t elementCount) = 0;
|
||||||
|
virtual void Reset(ElementRendererData& rendererData, RenderFrame& currentFrame);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NAZARA_GRAPHICS_API ElementRendererData
|
||||||
|
{
|
||||||
|
ElementRendererData() = default;
|
||||||
|
virtual ~ElementRendererData();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,20 @@
|
||||||
#ifndef NAZARA_ENUMS_GRAPHICS_HPP
|
#ifndef NAZARA_ENUMS_GRAPHICS_HPP
|
||||||
#define NAZARA_ENUMS_GRAPHICS_HPP
|
#define NAZARA_ENUMS_GRAPHICS_HPP
|
||||||
|
|
||||||
|
#include <Nazara/Core/Algorithm.hpp>
|
||||||
|
|
||||||
namespace Nz
|
namespace Nz
|
||||||
{
|
{
|
||||||
enum class BasicRenderElement
|
enum class BasicRenderElement
|
||||||
{
|
{
|
||||||
Submesh = 0,
|
SpriteChain = 0,
|
||||||
|
Submesh = 1,
|
||||||
|
|
||||||
|
Max = Submesh
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr std::size_t BasicRenderElementCount = UnderlyingCast(BasicRenderElement::Max) + 1;
|
||||||
|
|
||||||
enum class CullTest
|
enum class CullTest
|
||||||
{
|
{
|
||||||
Box,
|
Box,
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@
|
||||||
|
|
||||||
namespace Nz
|
namespace Nz
|
||||||
{
|
{
|
||||||
|
class RenderFrame;
|
||||||
|
|
||||||
class NAZARA_GRAPHICS_API ForwardFramePipeline : public FramePipeline
|
class NAZARA_GRAPHICS_API ForwardFramePipeline : public FramePipeline
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -51,7 +53,7 @@ namespace Nz
|
||||||
BakedFrameGraph BuildFrameGraph();
|
BakedFrameGraph BuildFrameGraph();
|
||||||
|
|
||||||
void RegisterMaterialPass(MaterialPass* material);
|
void RegisterMaterialPass(MaterialPass* material);
|
||||||
void ProcessRenderQueue(CommandBufferBuilder& builder, const RenderQueue<RenderElement*>& renderQueue);
|
template<typename F> void ProcessRenderQueue(const RenderQueue<RenderElement*>& renderQueue, F&& callback);
|
||||||
void UnregisterMaterialPass(MaterialPass* material);
|
void UnregisterMaterialPass(MaterialPass* material);
|
||||||
|
|
||||||
struct MaterialData
|
struct MaterialData
|
||||||
|
|
@ -79,6 +81,7 @@ namespace Nz
|
||||||
std::size_t visibilityHash = 0;
|
std::size_t visibilityHash = 0;
|
||||||
std::vector<std::unique_ptr<RenderElement>> depthPrepassRenderElements;
|
std::vector<std::unique_ptr<RenderElement>> depthPrepassRenderElements;
|
||||||
std::vector<std::unique_ptr<RenderElement>> forwardRenderElements;
|
std::vector<std::unique_ptr<RenderElement>> forwardRenderElements;
|
||||||
|
std::vector<std::unique_ptr<ElementRendererData>> elementRendererData;
|
||||||
RenderQueueRegistry depthPrepassRegistry;
|
RenderQueueRegistry depthPrepassRegistry;
|
||||||
RenderQueueRegistry forwardRegistry;
|
RenderQueueRegistry forwardRegistry;
|
||||||
RenderQueue<RenderElement*> depthPrepassRenderQueue;
|
RenderQueue<RenderElement*> depthPrepassRenderQueue;
|
||||||
|
|
@ -100,6 +103,7 @@ namespace Nz
|
||||||
std::vector<std::unique_ptr<ElementRenderer>> m_elementRenderers;
|
std::vector<std::unique_ptr<ElementRenderer>> m_elementRenderers;
|
||||||
std::vector<VisibleRenderable> m_visibleRenderables;
|
std::vector<VisibleRenderable> m_visibleRenderables;
|
||||||
BakedFrameGraph m_bakedFrameGraph;
|
BakedFrameGraph m_bakedFrameGraph;
|
||||||
|
RenderFrame* m_currentRenderFrame;
|
||||||
bool m_rebuildFrameGraph;
|
bool m_rebuildFrameGraph;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ namespace Nz
|
||||||
{
|
{
|
||||||
class AbstractBuffer;
|
class AbstractBuffer;
|
||||||
class RenderPipeline;
|
class RenderPipeline;
|
||||||
|
class VertexDeclaration;
|
||||||
|
|
||||||
class RenderQueueRegistry
|
class RenderQueueRegistry
|
||||||
{
|
{
|
||||||
|
|
@ -26,15 +27,18 @@ namespace Nz
|
||||||
inline std::size_t FetchLayerIndex(int renderLayer) const;
|
inline std::size_t FetchLayerIndex(int renderLayer) const;
|
||||||
inline std::size_t FetchPipelineIndex(const RenderPipeline* pipeline) const;
|
inline std::size_t FetchPipelineIndex(const RenderPipeline* pipeline) const;
|
||||||
inline std::size_t FetchVertexBuffer(const AbstractBuffer* vertexBuffer) const;
|
inline std::size_t FetchVertexBuffer(const AbstractBuffer* vertexBuffer) const;
|
||||||
|
inline std::size_t FetchVertexDeclaration(const VertexDeclaration* vertexDeclaration) const;
|
||||||
|
|
||||||
inline void RegisterLayer(int renderLayer);
|
inline void RegisterLayer(int renderLayer);
|
||||||
inline void RegisterPipeline(const RenderPipeline* pipeline);
|
inline void RegisterPipeline(const RenderPipeline* pipeline);
|
||||||
inline void RegisterVertexBuffer(const AbstractBuffer* vertexBuffer);
|
inline void RegisterVertexBuffer(const AbstractBuffer* vertexBuffer);
|
||||||
|
inline void RegisterVertexDeclaration(const VertexDeclaration* vertexDeclaration);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
robin_hood::unordered_map<int, std::size_t> m_renderLayerRegistry;
|
robin_hood::unordered_map<int, std::size_t> m_renderLayerRegistry;
|
||||||
robin_hood::unordered_map<const RenderPipeline*, std::size_t> m_pipelineRegistry;
|
robin_hood::unordered_map<const RenderPipeline*, std::size_t> m_pipelineRegistry;
|
||||||
robin_hood::unordered_map<const AbstractBuffer*, std::size_t> m_vertexBufferRegistry;
|
robin_hood::unordered_map<const AbstractBuffer*, std::size_t> m_vertexBufferRegistry;
|
||||||
|
robin_hood::unordered_map<const VertexDeclaration*, std::size_t> m_vertexDeclarationRegistry;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,14 @@ namespace Nz
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::size_t RenderQueueRegistry::FetchVertexDeclaration(const VertexDeclaration* vertexDeclaration) const
|
||||||
|
{
|
||||||
|
auto it = m_vertexDeclarationRegistry.find(vertexDeclaration);
|
||||||
|
assert(it != m_vertexDeclarationRegistry.end());
|
||||||
|
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
inline void RenderQueueRegistry::RegisterLayer(int renderLayer)
|
inline void RenderQueueRegistry::RegisterLayer(int renderLayer)
|
||||||
{
|
{
|
||||||
m_renderLayerRegistry.try_emplace(renderLayer, m_renderLayerRegistry.size());
|
m_renderLayerRegistry.try_emplace(renderLayer, m_renderLayerRegistry.size());
|
||||||
|
|
@ -52,6 +60,11 @@ namespace Nz
|
||||||
{
|
{
|
||||||
m_vertexBufferRegistry.try_emplace(vertexBuffer, m_vertexBufferRegistry.size());
|
m_vertexBufferRegistry.try_emplace(vertexBuffer, m_vertexBufferRegistry.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void RenderQueueRegistry::RegisterVertexDeclaration(const VertexDeclaration* vertexDeclaration)
|
||||||
|
{
|
||||||
|
m_vertexDeclarationRegistry.try_emplace(vertexDeclaration, m_vertexDeclarationRegistry.size());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <Nazara/Graphics/DebugOff.hpp>
|
#include <Nazara/Graphics/DebugOff.hpp>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
// Copyright (C) 2017 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Engine - Graphics module"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_RENDERSUBMESH_HPP
|
||||||
|
#define NAZARA_RENDERSUBMESH_HPP
|
||||||
|
|
||||||
|
#include <Nazara/Prerequisites.hpp>
|
||||||
|
#include <Nazara/Graphics/RenderElement.hpp>
|
||||||
|
#include <Nazara/Graphics/RenderQueueRegistry.hpp>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
class AbstractBuffer;
|
||||||
|
class RenderPipeline;
|
||||||
|
class ShaderBinding;
|
||||||
|
class VertexDeclaration;
|
||||||
|
|
||||||
|
class RenderSpriteChain : public RenderElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline RenderSpriteChain(int renderLayer, std::shared_ptr<RenderPipeline> renderPipeline, std::shared_ptr<VertexDeclaration> vertexDeclaration, std::size_t spriteCount, const void* spriteData, const ShaderBinding& materialBinding, const ShaderBinding& instanceBinding);
|
||||||
|
~RenderSpriteChain() = default;
|
||||||
|
|
||||||
|
inline UInt64 ComputeSortingScore(const RenderQueueRegistry& registry) const override;
|
||||||
|
|
||||||
|
inline const ShaderBinding& GetInstanceBinding() const;
|
||||||
|
inline const ShaderBinding& GetMaterialBinding() const;
|
||||||
|
inline const RenderPipeline* GetRenderPipeline() const;
|
||||||
|
inline std::size_t GetSpriteCount() const;
|
||||||
|
inline const void* GetSpriteData() const;
|
||||||
|
inline const VertexDeclaration* GetVertexDeclaration() const;
|
||||||
|
|
||||||
|
inline void Register(RenderQueueRegistry& registry) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<RenderPipeline> m_renderPipeline;
|
||||||
|
std::shared_ptr<VertexDeclaration> m_vertexDeclaration;
|
||||||
|
std::size_t m_spriteCount;
|
||||||
|
const void* m_spriteData;
|
||||||
|
const ShaderBinding& m_instanceBinding;
|
||||||
|
const ShaderBinding& m_materialBinding;
|
||||||
|
int m_renderLayer;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Graphics/RenderSpriteChain.inl>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
// Copyright (C) 2017 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Engine - Graphics module"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#include <Nazara/Graphics/RenderSpriteChain.hpp>
|
||||||
|
#include <Nazara/Graphics/Debug.hpp>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
inline RenderSpriteChain::RenderSpriteChain(int renderLayer, std::shared_ptr<RenderPipeline> renderPipeline, std::shared_ptr<VertexDeclaration> vertexDeclaration, std::size_t spriteCount, const void* spriteData, const ShaderBinding& materialBinding, const ShaderBinding& instanceBinding) :
|
||||||
|
RenderElement(BasicRenderElement::SpriteChain),
|
||||||
|
m_renderPipeline(std::move(renderPipeline)),
|
||||||
|
m_vertexDeclaration(std::move(vertexDeclaration)),
|
||||||
|
m_spriteCount(spriteCount),
|
||||||
|
m_spriteData(spriteData),
|
||||||
|
m_instanceBinding(instanceBinding),
|
||||||
|
m_materialBinding(materialBinding),
|
||||||
|
m_renderLayer(renderLayer)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline UInt64 RenderSpriteChain::ComputeSortingScore(const RenderQueueRegistry& registry) const
|
||||||
|
{
|
||||||
|
UInt64 layerIndex = registry.FetchLayerIndex(m_renderLayer);
|
||||||
|
UInt64 elementType = GetElementType();
|
||||||
|
UInt64 pipelineIndex = registry.FetchPipelineIndex(m_renderPipeline.get());
|
||||||
|
UInt64 vertexDeclarationIndex = registry.FetchVertexDeclaration(m_vertexDeclaration.get());
|
||||||
|
|
||||||
|
// RQ index:
|
||||||
|
// - Layer (8bits)
|
||||||
|
// - Element type (4bits)
|
||||||
|
// - Pipeline (16bits)
|
||||||
|
// - VertexDeclaration (8bits)
|
||||||
|
// - ?? (24bits) - Depth?
|
||||||
|
|
||||||
|
return (layerIndex & 0xFF) << 60 |
|
||||||
|
(elementType & 0xF) << 52 |
|
||||||
|
(pipelineIndex & 0xFFFF) << 36 |
|
||||||
|
(vertexDeclarationIndex & 0xFF) << 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const ShaderBinding& RenderSpriteChain::GetInstanceBinding() const
|
||||||
|
{
|
||||||
|
return m_instanceBinding;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const ShaderBinding& RenderSpriteChain::GetMaterialBinding() const
|
||||||
|
{
|
||||||
|
return m_materialBinding;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const RenderPipeline* RenderSpriteChain::GetRenderPipeline() const
|
||||||
|
{
|
||||||
|
return m_renderPipeline.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::size_t RenderSpriteChain::GetSpriteCount() const
|
||||||
|
{
|
||||||
|
return m_spriteCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const void* RenderSpriteChain::GetSpriteData() const
|
||||||
|
{
|
||||||
|
return m_spriteData;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const VertexDeclaration* RenderSpriteChain::GetVertexDeclaration() const
|
||||||
|
{
|
||||||
|
return m_vertexDeclaration.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void RenderSpriteChain::Register(RenderQueueRegistry& registry) const
|
||||||
|
{
|
||||||
|
registry.RegisterLayer(m_renderLayer);
|
||||||
|
registry.RegisterPipeline(m_renderPipeline.get());
|
||||||
|
registry.RegisterVertexDeclaration(m_vertexDeclaration.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Graphics/DebugOff.hpp>
|
||||||
|
|
@ -27,8 +27,8 @@ namespace Nz
|
||||||
UInt64 vertexBufferIndex = registry.FetchVertexBuffer(m_vertexBuffer.get());
|
UInt64 vertexBufferIndex = registry.FetchVertexBuffer(m_vertexBuffer.get());
|
||||||
|
|
||||||
// RQ index:
|
// RQ index:
|
||||||
// - Element type (4bits)
|
|
||||||
// - Layer (8bits)
|
// - Layer (8bits)
|
||||||
|
// - Element type (4bits)
|
||||||
// - Pipeline (16bits)
|
// - Pipeline (16bits)
|
||||||
// - VertexBuffer (8bits)
|
// - VertexBuffer (8bits)
|
||||||
// - ?? (24bits) - Depth?
|
// - ?? (24bits) - Depth?
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
// Copyright (C) 2017 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Engine - Graphics module"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_SPRITE_HPP
|
||||||
|
#define NAZARA_SPRITE_HPP
|
||||||
|
|
||||||
|
#include <Nazara/Prerequisites.hpp>
|
||||||
|
#include <Nazara/Graphics/Config.hpp>
|
||||||
|
#include <Nazara/Graphics/InstancedRenderable.hpp>
|
||||||
|
#include <Nazara/Renderer/RenderPipeline.hpp>
|
||||||
|
#include <Nazara/Utility/VertexDeclaration.hpp>
|
||||||
|
#include <Nazara/Utility/VertexStruct.hpp>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
class NAZARA_GRAPHICS_API Sprite : public InstancedRenderable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Sprite(std::shared_ptr<Material> material);
|
||||||
|
Sprite(const Sprite&) = delete;
|
||||||
|
Sprite(Sprite&&) noexcept = default;
|
||||||
|
~Sprite() = default;
|
||||||
|
|
||||||
|
void BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, std::vector<std::unique_ptr<RenderElement>>& elements) const override;
|
||||||
|
|
||||||
|
const std::shared_ptr<Material>& GetMaterial(std::size_t i) const;
|
||||||
|
std::size_t GetMaterialCount() const;
|
||||||
|
|
||||||
|
inline void SetMaterial(std::shared_ptr<Material> material);
|
||||||
|
|
||||||
|
Sprite& operator=(const Sprite&) = delete;
|
||||||
|
Sprite& operator=(Sprite&&) noexcept = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::array<VertexStruct_XYZ_Color_UV, 4> m_vertices;
|
||||||
|
std::shared_ptr<Material> m_material;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Graphics/Sprite.inl>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright (C) 2017 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Engine - Graphics module"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#include <Nazara/Graphics/Sprite.hpp>
|
||||||
|
#include <cassert>
|
||||||
|
#include <Nazara/Graphics/Debug.hpp>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
inline void Sprite::SetMaterial(std::shared_ptr<Material> material)
|
||||||
|
{
|
||||||
|
m_material = std::move(material);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Graphics/DebugOff.hpp>
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
// Copyright (C) 2017 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Engine - Graphics module"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_SPRITECHAINRENDERER_HPP
|
||||||
|
#define NAZARA_SPRITECHAINRENDERER_HPP
|
||||||
|
|
||||||
|
#include <Nazara/Prerequisites.hpp>
|
||||||
|
#include <Nazara/Graphics/ElementRenderer.hpp>
|
||||||
|
#include <memory>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
class AbstractBuffer;
|
||||||
|
class RenderDevice;
|
||||||
|
class RenderPipeline;
|
||||||
|
class RenderSpriteChain;
|
||||||
|
class ShaderBinding;
|
||||||
|
|
||||||
|
class NAZARA_GRAPHICS_API SpriteChainRenderer : public ElementRenderer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SpriteChainRenderer(RenderDevice& device, std::size_t maxVertexBufferSize = 32 * 1024);
|
||||||
|
~SpriteChainRenderer() = default;
|
||||||
|
|
||||||
|
std::unique_ptr<ElementRendererData> InstanciateData();
|
||||||
|
void Prepare(ElementRendererData& rendererData, RenderFrame& currentFrame, const Pointer<const RenderElement>* elements, std::size_t elementCount);
|
||||||
|
void Render(ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, const Pointer<const RenderElement>* elements, std::size_t elementCount) override;
|
||||||
|
void Reset(ElementRendererData& rendererData, RenderFrame& currentFrame);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<AbstractBuffer> m_indexBuffer;
|
||||||
|
std::size_t m_maxVertexBufferSize;
|
||||||
|
std::size_t m_maxVertexCount;
|
||||||
|
RenderDevice& m_device;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SpriteChainRendererData : public ElementRendererData
|
||||||
|
{
|
||||||
|
struct DrawCall
|
||||||
|
{
|
||||||
|
const AbstractBuffer* vertexBuffer;
|
||||||
|
const RenderPipeline* renderPipeline;
|
||||||
|
const ShaderBinding* instanceBinding;
|
||||||
|
const ShaderBinding* materialBinding;
|
||||||
|
std::size_t firstIndex;
|
||||||
|
std::size_t quadCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DrawCallIndices
|
||||||
|
{
|
||||||
|
std::size_t start;
|
||||||
|
std::size_t count;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unordered_map<const RenderSpriteChain*, DrawCallIndices> drawCallPerElement;
|
||||||
|
std::vector<DrawCall> drawCalls;
|
||||||
|
std::vector<std::shared_ptr<AbstractBuffer>> vertexBuffers;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Graphics/SpriteChainRenderer.inl>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -2,9 +2,11 @@
|
||||||
// This file is part of the "Nazara Engine - Graphics module"
|
// This file is part of the "Nazara Engine - Graphics module"
|
||||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
#include <Nazara/Graphics/RenderSubmesh.hpp>
|
#include <Nazara/Graphics/SpriteChainRenderer.hpp>
|
||||||
#include <Nazara/Graphics/Debug.hpp>
|
#include <Nazara/Graphics/Debug.hpp>
|
||||||
|
|
||||||
namespace Nz
|
namespace Nz
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Graphics/DebugOff.hpp>
|
||||||
|
|
@ -18,7 +18,8 @@ namespace Nz
|
||||||
SubmeshRenderer() = default;
|
SubmeshRenderer() = default;
|
||||||
~SubmeshRenderer() = default;
|
~SubmeshRenderer() = default;
|
||||||
|
|
||||||
void Render(CommandBufferBuilder& commandBuffer, const Pointer<const RenderElement>* elements, std::size_t elementCount) override;
|
std::unique_ptr<ElementRendererData> InstanciateData();
|
||||||
|
void Render(ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, const Pointer<const RenderElement>* elements, std::size_t elementCount) override;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,4 +8,14 @@
|
||||||
namespace Nz
|
namespace Nz
|
||||||
{
|
{
|
||||||
ElementRenderer::~ElementRenderer() = default;
|
ElementRenderer::~ElementRenderer() = default;
|
||||||
|
|
||||||
|
void ElementRenderer::Prepare(ElementRendererData& /*rendererData*/, RenderFrame& /*currentFrame*/, const Pointer<const RenderElement>* /*elements*/, std::size_t /*elementCount*/)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ElementRenderer::Reset(ElementRendererData& /*rendererData*/, RenderFrame& /*currentFrame*/)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ElementRendererData::~ElementRendererData() = default;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
#include <Nazara/Graphics/InstancedRenderable.hpp>
|
#include <Nazara/Graphics/InstancedRenderable.hpp>
|
||||||
#include <Nazara/Graphics/Material.hpp>
|
#include <Nazara/Graphics/Material.hpp>
|
||||||
#include <Nazara/Graphics/RenderElement.hpp>
|
#include <Nazara/Graphics/RenderElement.hpp>
|
||||||
|
#include <Nazara/Graphics/SpriteChainRenderer.hpp>
|
||||||
#include <Nazara/Graphics/SubmeshRenderer.hpp>
|
#include <Nazara/Graphics/SubmeshRenderer.hpp>
|
||||||
#include <Nazara/Graphics/ViewerInstance.hpp>
|
#include <Nazara/Graphics/ViewerInstance.hpp>
|
||||||
#include <Nazara/Graphics/WorldInstance.hpp>
|
#include <Nazara/Graphics/WorldInstance.hpp>
|
||||||
|
|
@ -30,7 +31,8 @@ namespace Nz
|
||||||
m_depthPassIndex = passRegistry.GetPassIndex("DepthPass");
|
m_depthPassIndex = passRegistry.GetPassIndex("DepthPass");
|
||||||
m_forwardPassIndex = passRegistry.GetPassIndex("ForwardPass");
|
m_forwardPassIndex = passRegistry.GetPassIndex("ForwardPass");
|
||||||
|
|
||||||
m_elementRenderers.resize(1);
|
m_elementRenderers.resize(BasicRenderElementCount);
|
||||||
|
m_elementRenderers[UnderlyingCast(BasicRenderElement::SpriteChain)] = std::make_unique<SpriteChainRenderer>(*Graphics::Instance()->GetRenderDevice());
|
||||||
m_elementRenderers[UnderlyingCast(BasicRenderElement::Submesh)] = std::make_unique<SubmeshRenderer>();
|
m_elementRenderers[UnderlyingCast(BasicRenderElement::Submesh)] = std::make_unique<SubmeshRenderer>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -113,6 +115,8 @@ namespace Nz
|
||||||
|
|
||||||
void ForwardFramePipeline::Render(RenderFrame& renderFrame)
|
void ForwardFramePipeline::Render(RenderFrame& renderFrame)
|
||||||
{
|
{
|
||||||
|
m_currentRenderFrame = &renderFrame;
|
||||||
|
|
||||||
Graphics* graphics = Graphics::Instance();
|
Graphics* graphics = Graphics::Instance();
|
||||||
|
|
||||||
renderFrame.PushForRelease(std::move(m_removedWorldInstances));
|
renderFrame.PushForRelease(std::move(m_removedWorldInstances));
|
||||||
|
|
@ -167,6 +171,7 @@ namespace Nz
|
||||||
};
|
};
|
||||||
|
|
||||||
// Render queues handling
|
// Render queues handling
|
||||||
|
bool prepare = false;
|
||||||
for (auto&& [viewer, data] : m_viewers)
|
for (auto&& [viewer, data] : m_viewers)
|
||||||
{
|
{
|
||||||
auto& viewerData = data;
|
auto& viewerData = data;
|
||||||
|
|
@ -208,6 +213,7 @@ namespace Nz
|
||||||
{
|
{
|
||||||
viewerData.rebuildDepthPrepass = true;
|
viewerData.rebuildDepthPrepass = true;
|
||||||
viewerData.rebuildForwardPass = true;
|
viewerData.rebuildForwardPass = true;
|
||||||
|
prepare = true;
|
||||||
|
|
||||||
viewerData.visibilityHash = visibilityHash;
|
viewerData.visibilityHash = visibilityHash;
|
||||||
}
|
}
|
||||||
|
|
@ -256,6 +262,48 @@ namespace Nz
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (prepare)
|
||||||
|
{
|
||||||
|
for (std::size_t i = 0; i < m_elementRenderers.size(); ++i)
|
||||||
|
{
|
||||||
|
auto& elementRendererPtr = m_elementRenderers[i];
|
||||||
|
|
||||||
|
for (auto&& [_, viewerData] : m_viewers)
|
||||||
|
{
|
||||||
|
if (i >= viewerData.elementRendererData.size() || !viewerData.elementRendererData[i])
|
||||||
|
{
|
||||||
|
if (i >= viewerData.elementRendererData.size())
|
||||||
|
viewerData.elementRendererData.resize(i + 1);
|
||||||
|
|
||||||
|
viewerData.elementRendererData[i] = elementRendererPtr->InstanciateData();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elementRendererPtr)
|
||||||
|
elementRendererPtr->Reset(*viewerData.elementRendererData[i], renderFrame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto&& [_, viewerData] : m_viewers)
|
||||||
|
{
|
||||||
|
auto& rendererData = viewerData.elementRendererData;
|
||||||
|
|
||||||
|
ProcessRenderQueue(viewerData.depthPrepassRenderQueue, [&](std::size_t elementType, const Pointer<const RenderElement>* elements, std::size_t elementCount)
|
||||||
|
{
|
||||||
|
ElementRenderer& elementRenderer = *m_elementRenderers[elementType];
|
||||||
|
elementRenderer.Prepare(*rendererData[elementType], renderFrame, elements, elementCount);
|
||||||
|
});
|
||||||
|
|
||||||
|
ProcessRenderQueue(viewerData.forwardRenderQueue, [&](std::size_t elementType, const Pointer<const RenderElement>* elements, std::size_t elementCount)
|
||||||
|
{
|
||||||
|
ElementRenderer& elementRenderer = *m_elementRenderers[elementType];
|
||||||
|
elementRenderer.Prepare(*rendererData[elementType], renderFrame, elements, elementCount);
|
||||||
|
});
|
||||||
|
|
||||||
|
viewerData.rebuildForwardPass = true;
|
||||||
|
viewerData.rebuildDepthPrepass = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (m_bakedFrameGraph.Resize(renderFrame))
|
if (m_bakedFrameGraph.Resize(renderFrame))
|
||||||
{
|
{
|
||||||
const std::shared_ptr<TextureSampler>& sampler = graphics->GetSamplerCache().Get({});
|
const std::shared_ptr<TextureSampler>& sampler = graphics->GetSamplerCache().Get({});
|
||||||
|
|
@ -406,7 +454,11 @@ namespace Nz
|
||||||
|
|
||||||
builder.BindShaderBinding(Graphics::ViewerBindingSet, viewer->GetViewerInstance().GetShaderBinding());
|
builder.BindShaderBinding(Graphics::ViewerBindingSet, viewer->GetViewerInstance().GetShaderBinding());
|
||||||
|
|
||||||
ProcessRenderQueue(builder, viewerData.depthPrepassRenderQueue);
|
ProcessRenderQueue(viewerData.depthPrepassRenderQueue, [&](std::size_t elementType, const Pointer<const RenderElement>* elements, std::size_t elementCount)
|
||||||
|
{
|
||||||
|
ElementRenderer& elementRenderer = *m_elementRenderers[elementType];
|
||||||
|
elementRenderer.Render(*viewerData.elementRendererData[elementType], builder, elements, elementCount);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
FramePass& forwardPass = frameGraph.AddPass("Forward pass");
|
FramePass& forwardPass = frameGraph.AddPass("Forward pass");
|
||||||
|
|
@ -433,8 +485,12 @@ namespace Nz
|
||||||
builder.SetViewport(viewport);
|
builder.SetViewport(viewport);
|
||||||
|
|
||||||
builder.BindShaderBinding(Graphics::ViewerBindingSet, viewer->GetViewerInstance().GetShaderBinding());
|
builder.BindShaderBinding(Graphics::ViewerBindingSet, viewer->GetViewerInstance().GetShaderBinding());
|
||||||
|
|
||||||
ProcessRenderQueue(builder, viewerData.forwardRenderQueue);
|
ProcessRenderQueue(viewerData.forwardRenderQueue, [&](std::size_t elementType, const Pointer<const RenderElement>* elements, std::size_t elementCount)
|
||||||
|
{
|
||||||
|
ElementRenderer& elementRenderer = *m_elementRenderers[elementType];
|
||||||
|
elementRenderer.Render(*viewerData.elementRendererData[elementType], builder, elements, elementCount);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -462,7 +518,8 @@ namespace Nz
|
||||||
it->second.usedCount++;
|
it->second.usedCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ForwardFramePipeline::ProcessRenderQueue(CommandBufferBuilder& builder, const RenderQueue<RenderElement*>& renderQueue)
|
template<typename F>
|
||||||
|
void ForwardFramePipeline::ProcessRenderQueue(const RenderQueue<RenderElement*>& renderQueue, F&& callback)
|
||||||
{
|
{
|
||||||
if (renderQueue.empty())
|
if (renderQueue.empty())
|
||||||
return;
|
return;
|
||||||
|
|
@ -485,8 +542,7 @@ namespace Nz
|
||||||
if (elementType >= m_elementRenderers.size() || !m_elementRenderers[elementType])
|
if (elementType >= m_elementRenderers.size() || !m_elementRenderers[elementType])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ElementRenderer& elementRenderer = *m_elementRenderers[elementType];
|
callback(elementType, first, count);
|
||||||
elementRenderer.Render(builder, first, count);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
// Copyright (C) 2017 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Engine - Graphics module"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#include <Nazara/Graphics/Sprite.hpp>
|
||||||
|
#include <Nazara/Graphics/Material.hpp>
|
||||||
|
#include <Nazara/Graphics/RenderSpriteChain.hpp>
|
||||||
|
#include <Nazara/Graphics/WorldInstance.hpp>
|
||||||
|
#include <Nazara/Graphics/Debug.hpp>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
Sprite::Sprite(std::shared_ptr<Material> material) :
|
||||||
|
InstancedRenderable(Nz::Boxf(-1000.f, -1000.f, -1000.f, 2000.f, 2000.f, 2000.f)),
|
||||||
|
m_material(std::move(material))
|
||||||
|
{
|
||||||
|
m_vertices[0] = VertexStruct_XYZ_Color_UV{ Vector3f(0.f, 0.f, 0.f), Nz::Color::White, Vector2f(0.f, 0.f) };
|
||||||
|
m_vertices[1] = VertexStruct_XYZ_Color_UV{ Vector3f(1.f, 0.f, 0.f), Nz::Color::White, Vector2f(1.f, 0.f) };
|
||||||
|
m_vertices[2] = VertexStruct_XYZ_Color_UV{ Vector3f(0.f, 1.f, 0.f), Nz::Color::White, Vector2f(0.f, 1.f) };
|
||||||
|
m_vertices[3] = VertexStruct_XYZ_Color_UV{ Vector3f(1.f, 1.f, 0.f), Nz::Color::White, Vector2f(1.f, 1.f) };
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sprite::BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, std::vector<std::unique_ptr<RenderElement>>& elements) const
|
||||||
|
{
|
||||||
|
MaterialPass* materialPass = m_material->GetPass(passIndex);
|
||||||
|
if (!materialPass)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const std::shared_ptr<VertexDeclaration>& vertexDeclaration = VertexDeclaration::Get(VertexLayout::XYZ_Color_UV);
|
||||||
|
|
||||||
|
std::vector<RenderPipelineInfo::VertexBufferData> vertexBufferData = {
|
||||||
|
{
|
||||||
|
{
|
||||||
|
0,
|
||||||
|
vertexDeclaration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const auto& renderPipeline = materialPass->GetPipeline()->GetRenderPipeline(vertexBufferData);
|
||||||
|
|
||||||
|
elements.emplace_back(std::make_unique<RenderSpriteChain>(0, renderPipeline, vertexDeclaration, 1, m_vertices.data(), materialPass->GetShaderBinding(), worldInstance.GetShaderBinding()));
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::shared_ptr<Material>& Sprite::GetMaterial(std::size_t i) const
|
||||||
|
{
|
||||||
|
assert(i == 0);
|
||||||
|
NazaraUnused(i);
|
||||||
|
|
||||||
|
return m_material;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t Sprite::GetMaterialCount() const
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,258 @@
|
||||||
|
// Copyright (C) 2017 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Engine - Graphics module"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#include <Nazara/Graphics/SpriteChainRenderer.hpp>
|
||||||
|
#include <Nazara/Graphics/Graphics.hpp>
|
||||||
|
#include <Nazara/Graphics/RenderSpriteChain.hpp>
|
||||||
|
#include <Nazara/Renderer/CommandBufferBuilder.hpp>
|
||||||
|
#include <Nazara/Renderer/RenderFrame.hpp>
|
||||||
|
#include <Nazara/Renderer/UploadPool.hpp>
|
||||||
|
#include <utility>
|
||||||
|
#include <Nazara/Graphics/Debug.hpp>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
SpriteChainRenderer::SpriteChainRenderer(RenderDevice& device, std::size_t maxVertexBufferSize) :
|
||||||
|
m_device(device),
|
||||||
|
m_maxVertexBufferSize(maxVertexBufferSize),
|
||||||
|
m_maxVertexCount(m_maxVertexBufferSize / (2 * sizeof(float))) // Treat vec2 as the minimum declaration possible
|
||||||
|
{
|
||||||
|
std::size_t maxQuadCount = m_maxVertexCount / 4;
|
||||||
|
std::size_t indexCount = 6 * maxQuadCount;
|
||||||
|
|
||||||
|
m_indexBuffer = m_device.InstantiateBuffer(BufferType::Index);
|
||||||
|
if (!m_indexBuffer->Initialize(indexCount * sizeof(UInt16), BufferUsage::DeviceLocal))
|
||||||
|
throw std::runtime_error("failed to initialize index buffer");
|
||||||
|
|
||||||
|
// Generate indices for quad (0, 1, 2, 2, 1, 3, ...)
|
||||||
|
std::vector<UInt16> indices(indexCount);
|
||||||
|
UInt16* indexPtr = indices.data();
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < maxQuadCount; ++i)
|
||||||
|
{
|
||||||
|
*indexPtr++ = i * 4 + 0;
|
||||||
|
*indexPtr++ = i * 4 + 1;
|
||||||
|
*indexPtr++ = i * 4 + 2;
|
||||||
|
|
||||||
|
*indexPtr++ = i * 4 + 2;
|
||||||
|
*indexPtr++ = i * 4 + 1;
|
||||||
|
*indexPtr++ = i * 4 + 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_indexBuffer->Fill(indices.data(), 0, indexCount * sizeof(UInt16));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ElementRendererData> SpriteChainRenderer::InstanciateData()
|
||||||
|
{
|
||||||
|
return std::make_unique<SpriteChainRendererData>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpriteChainRenderer::Prepare(ElementRendererData& rendererData, RenderFrame& currentFrame, const Pointer<const RenderElement>* elements, std::size_t elementCount)
|
||||||
|
{
|
||||||
|
auto& data = static_cast<SpriteChainRendererData&>(rendererData);
|
||||||
|
|
||||||
|
std::vector<std::pair<UploadPool::Allocation*, AbstractBuffer*>> pendingCopies;
|
||||||
|
|
||||||
|
std::size_t firstQuadIndex = 0;
|
||||||
|
SpriteChainRendererData::DrawCall* currentDrawCall = nullptr;
|
||||||
|
UploadPool::Allocation* currentAllocation = nullptr;
|
||||||
|
UInt8* currentAllocationMemPtr = nullptr;
|
||||||
|
const VertexDeclaration* currentVertexDeclaration = nullptr;
|
||||||
|
AbstractBuffer* currentVertexBuffer = nullptr;
|
||||||
|
const RenderPipeline* currentPipeline = nullptr;
|
||||||
|
const ShaderBinding* currentInstanceBinding = nullptr;
|
||||||
|
const ShaderBinding* currentMaterialBinding = nullptr;
|
||||||
|
|
||||||
|
auto FlushDrawCall = [&]()
|
||||||
|
{
|
||||||
|
currentDrawCall = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto Flush = [&]()
|
||||||
|
{
|
||||||
|
// changing vertex buffer always mean we have to switch draw calls
|
||||||
|
FlushDrawCall();
|
||||||
|
|
||||||
|
if (currentAllocation)
|
||||||
|
{
|
||||||
|
pendingCopies.emplace_back(currentAllocation, currentVertexBuffer);
|
||||||
|
|
||||||
|
firstQuadIndex = 0;
|
||||||
|
currentAllocation = nullptr;
|
||||||
|
currentVertexBuffer = nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::size_t oldDrawCallCount = data.drawCalls.size();
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < elementCount; ++i)
|
||||||
|
{
|
||||||
|
assert(elements[i]->GetElementType() == UnderlyingCast(BasicRenderElement::SpriteChain));
|
||||||
|
const RenderSpriteChain& spriteChain = static_cast<const RenderSpriteChain&>(*elements[i]);
|
||||||
|
|
||||||
|
const VertexDeclaration* vertexDeclaration = spriteChain.GetVertexDeclaration();
|
||||||
|
std::size_t stride = vertexDeclaration->GetStride();
|
||||||
|
|
||||||
|
if (currentVertexDeclaration != vertexDeclaration)
|
||||||
|
{
|
||||||
|
// TODO: It's be possible to use another vertex declaration with the same vertex buffer but currently very complicated
|
||||||
|
// Wait until buffer rewrite
|
||||||
|
Flush();
|
||||||
|
currentVertexDeclaration = vertexDeclaration;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentPipeline != spriteChain.GetRenderPipeline())
|
||||||
|
{
|
||||||
|
FlushDrawCall();
|
||||||
|
currentPipeline = spriteChain.GetRenderPipeline();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentMaterialBinding != &spriteChain.GetMaterialBinding())
|
||||||
|
{
|
||||||
|
FlushDrawCall();
|
||||||
|
currentMaterialBinding = &spriteChain.GetMaterialBinding();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentInstanceBinding != &spriteChain.GetInstanceBinding())
|
||||||
|
{
|
||||||
|
// TODO: Flushing draw calls on instance binding means we can have e.g. 1000 sprites rendered using a draw call for each one
|
||||||
|
// which is far from being efficient, using some bindless could help (or at least instancing?)
|
||||||
|
FlushDrawCall();
|
||||||
|
currentInstanceBinding = &spriteChain.GetInstanceBinding();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t remainingQuads = spriteChain.GetSpriteCount();
|
||||||
|
while (remainingQuads > 0)
|
||||||
|
{
|
||||||
|
if (!currentAllocation)
|
||||||
|
{
|
||||||
|
currentAllocation = ¤tFrame.GetUploadPool().Allocate(m_maxVertexBufferSize);
|
||||||
|
currentAllocationMemPtr = static_cast<UInt8*>(currentAllocation->mappedPtr);
|
||||||
|
|
||||||
|
std::shared_ptr<AbstractBuffer> vertexBuffer = m_device.InstantiateBuffer(BufferType::Vertex);
|
||||||
|
vertexBuffer->Initialize(m_maxVertexBufferSize, BufferUsage::DeviceLocal);
|
||||||
|
|
||||||
|
currentVertexBuffer = vertexBuffer.get();
|
||||||
|
|
||||||
|
data.vertexBuffers.emplace_back(std::move(vertexBuffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!currentDrawCall)
|
||||||
|
{
|
||||||
|
data.drawCalls.push_back(SpriteChainRendererData::DrawCall{
|
||||||
|
currentVertexBuffer,
|
||||||
|
currentPipeline,
|
||||||
|
currentInstanceBinding,
|
||||||
|
currentMaterialBinding,
|
||||||
|
6 * firstQuadIndex,
|
||||||
|
0,
|
||||||
|
});
|
||||||
|
|
||||||
|
currentDrawCall = &data.drawCalls.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t remainingSpace = m_maxVertexBufferSize - (currentAllocationMemPtr - currentAllocation->mappedPtr);
|
||||||
|
std::size_t maxQuads = remainingSpace / (4 * stride);
|
||||||
|
if (maxQuads == 0)
|
||||||
|
{
|
||||||
|
Flush();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t copiedQuadCount = std::min(maxQuads, remainingQuads);
|
||||||
|
std::size_t copiedSize = 4 * copiedQuadCount * stride;
|
||||||
|
|
||||||
|
std::memcpy(currentAllocationMemPtr, spriteChain.GetSpriteData(), copiedSize);
|
||||||
|
currentAllocationMemPtr += copiedSize;
|
||||||
|
|
||||||
|
firstQuadIndex += copiedQuadCount;
|
||||||
|
currentDrawCall->quadCount += copiedQuadCount;
|
||||||
|
remainingQuads -= copiedQuadCount;
|
||||||
|
|
||||||
|
// If there's still data to copy, it means buffer is full, flush it
|
||||||
|
if (remainingQuads > 0)
|
||||||
|
Flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Add Finish()/PrepareEnd() call to allow to reuse buffers/draw calls for multiple Prepare calls
|
||||||
|
Flush();
|
||||||
|
|
||||||
|
const RenderSpriteChain* firstSpriteChain = static_cast<const RenderSpriteChain*>(elements[0]);
|
||||||
|
std::size_t drawCallCount = data.drawCalls.size() - oldDrawCallCount;
|
||||||
|
data.drawCallPerElement[firstSpriteChain] = SpriteChainRendererData::DrawCallIndices{ oldDrawCallCount, drawCallCount };
|
||||||
|
|
||||||
|
if (!pendingCopies.empty())
|
||||||
|
{
|
||||||
|
currentFrame.Execute([&](CommandBufferBuilder& builder)
|
||||||
|
{
|
||||||
|
for (auto&& [allocation, buffer] : pendingCopies)
|
||||||
|
builder.CopyBuffer(*allocation, buffer);
|
||||||
|
|
||||||
|
builder.PostTransferBarrier();
|
||||||
|
}, Nz::QueueType::Transfer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpriteChainRenderer::Render(ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, const Pointer<const RenderElement>* elements, std::size_t elementCount)
|
||||||
|
{
|
||||||
|
auto& data = static_cast<SpriteChainRendererData&>(rendererData);
|
||||||
|
|
||||||
|
commandBuffer.BindIndexBuffer(*m_indexBuffer);
|
||||||
|
|
||||||
|
const AbstractBuffer* currentVertexBuffer = nullptr;
|
||||||
|
const RenderPipeline* currentPipeline = nullptr;
|
||||||
|
const ShaderBinding* currentInstanceBinding = nullptr;
|
||||||
|
const ShaderBinding* currentMaterialBinding = nullptr;
|
||||||
|
|
||||||
|
const RenderSpriteChain* firstSpriteChain = static_cast<const RenderSpriteChain*>(elements[0]);
|
||||||
|
auto it = data.drawCallPerElement.find(firstSpriteChain);
|
||||||
|
assert(it != data.drawCallPerElement.end());
|
||||||
|
|
||||||
|
const auto& indices = it->second;
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < indices.count; ++i)
|
||||||
|
{
|
||||||
|
const auto& drawCall = data.drawCalls[indices.start + i];
|
||||||
|
|
||||||
|
if (currentVertexBuffer != drawCall.vertexBuffer)
|
||||||
|
{
|
||||||
|
commandBuffer.BindVertexBuffer(0, *drawCall.vertexBuffer);
|
||||||
|
currentVertexBuffer = drawCall.vertexBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentPipeline != drawCall.renderPipeline)
|
||||||
|
{
|
||||||
|
commandBuffer.BindPipeline(*drawCall.renderPipeline);
|
||||||
|
currentPipeline = drawCall.renderPipeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentMaterialBinding != drawCall.materialBinding)
|
||||||
|
{
|
||||||
|
commandBuffer.BindShaderBinding(Graphics::MaterialBindingSet, *drawCall.materialBinding);
|
||||||
|
currentMaterialBinding = drawCall.materialBinding;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentInstanceBinding != drawCall.instanceBinding)
|
||||||
|
{
|
||||||
|
commandBuffer.BindShaderBinding(Graphics::WorldBindingSet, *drawCall.instanceBinding);
|
||||||
|
currentInstanceBinding = drawCall.instanceBinding;
|
||||||
|
}
|
||||||
|
|
||||||
|
commandBuffer.DrawIndexed(drawCall.quadCount * 6, 1U, drawCall.firstIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpriteChainRenderer::Reset(ElementRendererData& rendererData, RenderFrame& currentFrame)
|
||||||
|
{
|
||||||
|
auto& data = static_cast<SpriteChainRendererData&>(rendererData);
|
||||||
|
|
||||||
|
// TODO: Reuse vertex buffers
|
||||||
|
for (auto& vertexBufferPtr : data.vertexBuffers)
|
||||||
|
currentFrame.PushForRelease(std::move(vertexBufferPtr));
|
||||||
|
|
||||||
|
data.drawCalls.clear();
|
||||||
|
data.vertexBuffers.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,7 +10,12 @@
|
||||||
|
|
||||||
namespace Nz
|
namespace Nz
|
||||||
{
|
{
|
||||||
void SubmeshRenderer::Render(CommandBufferBuilder& commandBuffer, const Pointer<const RenderElement>* elements, std::size_t elementCount)
|
std::unique_ptr<ElementRendererData> SubmeshRenderer::InstanciateData()
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void SubmeshRenderer::Render(ElementRendererData& /*rendererData*/, CommandBufferBuilder& commandBuffer, const Pointer<const RenderElement>* elements, std::size_t elementCount)
|
||||||
{
|
{
|
||||||
const AbstractBuffer* currentIndexBuffer = nullptr;
|
const AbstractBuffer* currentIndexBuffer = nullptr;
|
||||||
const AbstractBuffer* currentVertexBuffer = nullptr;
|
const AbstractBuffer* currentVertexBuffer = nullptr;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue