Graphics: Add support for draw call data (texture overlay)

This commit is contained in:
Jérôme Leclercq 2021-09-05 18:26:12 +02:00
parent 26e5a41dce
commit abdcd63058
16 changed files with 160 additions and 18 deletions

View File

@ -29,12 +29,14 @@ namespace Nz
using Dependencies = TypeList<Renderer>;
struct Config;
struct DefaultTextures;
Graphics(Config config);
~Graphics();
inline const std::shared_ptr<RenderPipeline>& GetBlitPipeline() const;
inline const std::shared_ptr<RenderPipelineLayout>& GetBlitPipelineLayout() const;
inline const DefaultTextures& GetDefaultTextures() const;
inline const std::shared_ptr<AbstractBuffer>& GetFullscreenVertexBuffer() const;
inline const std::shared_ptr<VertexDeclaration>& GetFullscreenVertexDeclaration() const;
inline MaterialPassRegistry& GetMaterialPassRegistry();
@ -51,15 +53,23 @@ namespace Nz
bool useDedicatedRenderDevice = true;
};
static constexpr UInt32 MaterialBindingSet = 2;
struct DefaultTextures
{
std::shared_ptr<Texture> whiteTexture2d;
};
static constexpr UInt32 DrawDataBindingSet = 2;
static constexpr UInt32 MaterialBindingSet = 3;
static constexpr UInt32 ViewerBindingSet = 0;
static constexpr UInt32 WorldBindingSet = 1;
static void FillDrawDataPipelineLayout(RenderPipelineLayoutInfo& layoutInfo, UInt32 set = DrawDataBindingSet);
static void FillViewerPipelineLayout(RenderPipelineLayoutInfo& layoutInfo, UInt32 set = ViewerBindingSet);
static void FillWorldPipelineLayout(RenderPipelineLayoutInfo& layoutInfo, UInt32 set = WorldBindingSet);
private:
void BuildBlitPipeline();
void BuildDefaultTextures();
void BuildFullscreenVertexBuffer();
void RegisterMaterialPasses();
void SelectDepthStencilFormats();
@ -72,6 +82,7 @@ namespace Nz
std::shared_ptr<RenderPipelineLayout> m_blitPipelineLayout;
std::shared_ptr<RenderPipelineLayout> m_referencePipelineLayout;
std::shared_ptr<VertexDeclaration> m_fullscreenVertexDeclaration;
DefaultTextures m_defaultTextures;
MaterialPassRegistry m_materialPassRegistry;
PixelFormat m_preferredDepthStencilFormat;

View File

@ -17,6 +17,11 @@ namespace Nz
return m_blitPipelineLayout;
}
inline auto Graphics::GetDefaultTextures() const -> const DefaultTextures&
{
return m_defaultTextures;
}
inline const std::shared_ptr<AbstractBuffer>& Graphics::GetFullscreenVertexBuffer() const
{
return m_fullscreenVertexBuffer;

View File

@ -18,6 +18,7 @@ namespace Nz
m_data(std::move(data))
{
RenderPipelineLayoutInfo info;
Graphics::FillDrawDataPipelineLayout(info);
Graphics::FillViewerPipelineLayout(info);
Graphics::FillWorldPipelineLayout(info);

View File

@ -23,7 +23,7 @@ namespace Nz
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);
inline RenderSpriteChain(int renderLayer, std::shared_ptr<RenderPipeline> renderPipeline, std::shared_ptr<VertexDeclaration> vertexDeclaration, std::shared_ptr<Texture> textureOverlay, std::size_t spriteCount, const void* spriteData, const ShaderBinding& materialBinding, const ShaderBinding& instanceBinding);
~RenderSpriteChain() = default;
inline UInt64 ComputeSortingScore(const RenderQueueRegistry& registry) const override;
@ -33,6 +33,7 @@ namespace Nz
inline const RenderPipeline* GetRenderPipeline() const;
inline std::size_t GetSpriteCount() const;
inline const void* GetSpriteData() const;
inline const Texture* GetTextureOverlay() const;
inline const VertexDeclaration* GetVertexDeclaration() const;
inline void Register(RenderQueueRegistry& registry) const override;
@ -40,6 +41,7 @@ namespace Nz
private:
std::shared_ptr<RenderPipeline> m_renderPipeline;
std::shared_ptr<VertexDeclaration> m_vertexDeclaration;
std::shared_ptr<Texture> m_textureOverlay;
std::size_t m_spriteCount;
const void* m_spriteData;
const ShaderBinding& m_instanceBinding;

View File

@ -7,10 +7,11 @@
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) :
inline RenderSpriteChain::RenderSpriteChain(int renderLayer, std::shared_ptr<RenderPipeline> renderPipeline, std::shared_ptr<VertexDeclaration> vertexDeclaration, std::shared_ptr<Texture> textureOverlay, 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_textureOverlay(std::move(textureOverlay)),
m_spriteCount(spriteCount),
m_spriteData(spriteData),
m_instanceBinding(instanceBinding),
@ -64,6 +65,11 @@ namespace Nz
return m_spriteData;
}
inline const Texture* RenderSpriteChain::GetTextureOverlay() const
{
return m_textureOverlay.get();
}
inline const VertexDeclaration* RenderSpriteChain::GetVertexDeclaration() const
{
return m_vertexDeclaration.get();

View File

@ -9,6 +9,7 @@
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Graphics/ElementRenderer.hpp>
#include <Nazara/Renderer/ShaderBinding.hpp>
#include <Nazara/Renderer/UploadPool.hpp>
#include <memory>
#include <unordered_map>
@ -53,6 +54,7 @@ namespace Nz
{
const AbstractBuffer* vertexBuffer;
const RenderPipeline* renderPipeline;
const ShaderBinding* drawDataBinding;
const ShaderBinding* instanceBinding;
const ShaderBinding* materialBinding;
std::size_t firstIndex;
@ -68,6 +70,7 @@ namespace Nz
std::unordered_map<const RenderSpriteChain*, DrawCallIndices> drawCallPerElement;
std::vector<DrawCall> drawCalls;
std::vector<std::shared_ptr<AbstractBuffer>> vertexBuffers;
std::vector<ShaderBindingPtr> shaderBindings;
};
}

View File

@ -9,17 +9,21 @@
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Graphics/ElementRenderer.hpp>
#include <Nazara/Renderer/ShaderBinding.hpp>
namespace Nz
{
class NAZARA_GRAPHICS_API SubmeshRenderer : public ElementRenderer
{
public:
SubmeshRenderer() = default;
SubmeshRenderer();
~SubmeshRenderer() = default;
std::unique_ptr<ElementRendererData> InstanciateData();
void Render(ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, const Pointer<const RenderElement>* elements, std::size_t elementCount) override;
private:
ShaderBindingPtr m_renderDataBinding;
};
}

View File

@ -42,8 +42,8 @@ namespace Nz
struct TextureBinding
{
Texture* texture;
TextureSampler* sampler;
const Texture* texture;
const TextureSampler* sampler;
};
struct UniformBufferBinding

View File

@ -66,11 +66,13 @@ namespace Nz
MaterialPipeline::Initialize();
RenderPipelineLayoutInfo referenceLayoutInfo;
FillDrawDataPipelineLayout(referenceLayoutInfo);
FillViewerPipelineLayout(referenceLayoutInfo);
FillWorldPipelineLayout(referenceLayoutInfo);
m_referencePipelineLayout = m_renderDevice->InstantiateRenderPipelineLayout(std::move(referenceLayoutInfo));
BuildDefaultTextures();
BuildFullscreenVertexBuffer();
BuildBlitPipeline();
RegisterMaterialPasses();
@ -86,10 +88,22 @@ namespace Nz
m_fullscreenVertexDeclaration.reset();
m_blitPipeline.reset();
m_blitPipelineLayout.reset();
m_defaultTextures.whiteTexture2d.reset();
}
void Graphics::FillDrawDataPipelineLayout(RenderPipelineLayoutInfo& layoutInfo, UInt32 set)
{
// TextureOverlay
layoutInfo.bindings.push_back({
set, 0,
ShaderBindingType::Texture,
ShaderStageType_All
});
}
void Graphics::FillViewerPipelineLayout(RenderPipelineLayoutInfo& layoutInfo, UInt32 set)
{
// ViewerData
layoutInfo.bindings.push_back({
set, 0,
ShaderBindingType::UniformBuffer,
@ -99,6 +113,7 @@ namespace Nz
void Graphics::FillWorldPipelineLayout(RenderPipelineLayoutInfo& layoutInfo, UInt32 set)
{
// InstanceData
layoutInfo.bindings.push_back({
set, 0,
ShaderBindingType::UniformBuffer,
@ -138,6 +153,22 @@ namespace Nz
m_blitPipeline = m_renderDevice->InstantiateRenderPipeline(std::move(pipelineInfo));
}
void Graphics::BuildDefaultTextures()
{
// White texture 2D
{
Nz::TextureInfo texInfo;
texInfo.width = texInfo.height = texInfo.depth = texInfo.mipmapLevel = 1;
texInfo.pixelFormat = PixelFormat::BGRA8;
texInfo.type = ImageType::E2D;
std::array<UInt8, 4> texData = { 0xFF, 0xFF, 0xFF, 0xFF };
m_defaultTextures.whiteTexture2d = m_renderDevice->InstantiateTexture(texInfo);
m_defaultTextures.whiteTexture2d->Update(texData.data());
}
}
void Graphics::BuildFullscreenVertexBuffer()
{
m_fullscreenVertexDeclaration = VertexDeclaration::Get(VertexLayout::XY_UV);

View File

@ -8,7 +8,7 @@ option ColorLocation: i32 = -1;
option UvLocation: i32 = -1;
const HasVertexColor = (ColorLocation >= 0);
const HasUV = (UvLocation >= 0) && (HasDiffuseTexture || HasAlphaTexture);
const HasUV = (UvLocation >= 0);
[layout(std140)]
struct BasicSettings
@ -42,9 +42,10 @@ external
{
[set(0), binding(0)] viewerData: uniform<ViewerData>,
[set(1), binding(0)] instanceData: uniform<InstanceData>,
[set(2), binding(0)] settings: uniform<BasicSettings>,
[set(2), binding(2)] MaterialAlphaMap: sampler2D<f32>,
[set(2), binding(1)] MaterialDiffuseMap: sampler2D<f32>
[set(2), binding(0)] TextureOverlay: sampler2D<f32>,
[set(3), binding(0)] settings: uniform<BasicSettings>,
[set(3), binding(2)] MaterialAlphaMap: sampler2D<f32>,
[set(3), binding(1)] MaterialDiffuseMap: sampler2D<f32>
}
// Fragment stage
@ -64,6 +65,10 @@ fn main(input: FragIn) -> FragOut
{
let diffuseColor = settings.DiffuseColor;
const if (HasUV)
//TODO: diffuseColor *= TextureOverlay.Sample(input.uv);
diffuseColor = diffuseColor * TextureOverlay.Sample(input.uv);
const if (HasVertexColor)
//TODO: diffuseColor *= input.color;
diffuseColor = diffuseColor * input.color;

View File

@ -36,9 +36,10 @@ external
{
[set(0), binding(0)] viewerData: uniform<ViewerData>,
[set(1), binding(0)] instanceData: uniform<InstanceData>,
[set(2), binding(0)] settings: uniform<BasicSettings>,
[set(2), binding(2)] MaterialAlphaMap: sampler2D<f32>,
[set(2), binding(1)] MaterialDiffuseMap: sampler2D<f32>
[set(2), binding(0)] TextureOverlay: sampler2D<f32>,
[set(3), binding(0)] settings: uniform<BasicSettings>,
[set(3), binding(2)] MaterialAlphaMap: sampler2D<f32>,
[set(3), binding(1)] MaterialDiffuseMap: sampler2D<f32>
}
// Fragment stage
@ -51,6 +52,11 @@ struct FragIn
fn main(input: FragIn)
{
let alpha = settings.DiffuseColor.a;
const if (HasUV)
//TODO: diffuseColor *= TextureOverlay.Sample(input.uv);
alpha = alpha * TextureOverlay.Sample(input.uv).a;
const if (HasDiffuseTexture)
// TODO: alpha *= MaterialDiffuseMap.Sample(input.uv).a;
alpha = alpha * MaterialDiffuseMap.Sample(input.uv).a;

View File

@ -38,7 +38,9 @@ namespace Nz
};
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 auto& whiteTexture = Graphics::Instance()->GetDefaultTextures().whiteTexture2d;
elements.emplace_back(std::make_unique<RenderSpriteChain>(0, renderPipeline, vertexDeclaration, whiteTexture, 1, m_vertices.data(), materialPass->GetShaderBinding(), worldInstance.GetShaderBinding()));
}
const std::shared_ptr<Material>& Sprite::GetMaterial(std::size_t i) const

View File

@ -52,6 +52,8 @@ namespace Nz
void SpriteChainRenderer::Prepare(ElementRendererData& rendererData, RenderFrame& currentFrame, const Pointer<const RenderElement>* elements, std::size_t elementCount)
{
Graphics* graphics = Graphics::Instance();
auto& data = static_cast<SpriteChainRendererData&>(rendererData);
std::size_t firstQuadIndex = 0;
@ -61,14 +63,23 @@ namespace Nz
const VertexDeclaration* currentVertexDeclaration = nullptr;
AbstractBuffer* currentVertexBuffer = nullptr;
const RenderPipeline* currentPipeline = nullptr;
const ShaderBinding* currentDrawDataBinding = nullptr;
const ShaderBinding* currentInstanceBinding = nullptr;
const ShaderBinding* currentMaterialBinding = nullptr;
const Texture* currentTextureOverlay = nullptr;
auto FlushDrawCall = [&]()
{
currentDrawCall = nullptr;
};
auto FlushDrawData = [&]()
{
FlushDrawCall();
currentDrawDataBinding = nullptr;
};
auto Flush = [&]()
{
// changing vertex buffer always mean we have to switch draw calls
@ -85,6 +96,7 @@ namespace Nz
};
std::size_t oldDrawCallCount = data.drawCalls.size();
const auto& defaultSampler = graphics->GetSamplerCache().Get({});
for (std::size_t i = 0; i < elementCount; ++i)
{
@ -122,6 +134,12 @@ namespace Nz
currentInstanceBinding = &spriteChain.GetInstanceBinding();
}
if (currentTextureOverlay != spriteChain.GetTextureOverlay())
{
FlushDrawData();
currentTextureOverlay = spriteChain.GetTextureOverlay();
}
std::size_t remainingQuads = spriteChain.GetSpriteCount();
while (remainingQuads > 0)
{
@ -149,11 +167,29 @@ namespace Nz
data.vertexBuffers.emplace_back(std::move(vertexBuffer));
}
if (!currentDrawDataBinding)
{
ShaderBindingPtr drawDataBinding = Graphics::Instance()->GetReferencePipelineLayout()->AllocateShaderBinding(Graphics::DrawDataBindingSet);
drawDataBinding->Update({
{
0,
ShaderBinding::TextureBinding {
currentTextureOverlay, defaultSampler.get()
}
}
});
currentDrawDataBinding = drawDataBinding.get();
data.shaderBindings.emplace_back(std::move(drawDataBinding));
}
if (!currentDrawCall)
{
data.drawCalls.push_back(SpriteChainRendererData::DrawCall{
currentVertexBuffer,
currentPipeline,
currentDrawDataBinding,
currentInstanceBinding,
currentMaterialBinding,
6 * firstQuadIndex,
@ -216,6 +252,7 @@ namespace Nz
const AbstractBuffer* currentVertexBuffer = nullptr;
const RenderPipeline* currentPipeline = nullptr;
const ShaderBinding* currentDrawDataBinding = nullptr;
const ShaderBinding* currentInstanceBinding = nullptr;
const ShaderBinding* currentMaterialBinding = nullptr;
@ -241,6 +278,12 @@ namespace Nz
currentPipeline = drawCall.renderPipeline;
}
if (currentDrawDataBinding != drawCall.drawDataBinding)
{
commandBuffer.BindShaderBinding(Graphics::DrawDataBindingSet, *drawCall.drawDataBinding);
currentDrawDataBinding = drawCall.drawDataBinding;
}
if (currentMaterialBinding != drawCall.materialBinding)
{
commandBuffer.BindShaderBinding(Graphics::MaterialBindingSet, *drawCall.materialBinding);
@ -270,6 +313,10 @@ namespace Nz
}
data.vertexBuffers.clear();
for (auto& shaderBinding : data.shaderBindings)
currentFrame.PushForRelease(std::move(shaderBinding));
data.shaderBindings.clear();
data.drawCalls.clear();
}
}

View File

@ -10,6 +10,23 @@
namespace Nz
{
SubmeshRenderer::SubmeshRenderer()
{
Graphics* graphics = Graphics::Instance();
const auto& whiteTexture = graphics->GetDefaultTextures().whiteTexture2d;
const auto& defaultSampler = graphics->GetSamplerCache().Get({});
m_renderDataBinding = graphics->GetReferencePipelineLayout()->AllocateShaderBinding(Graphics::DrawDataBindingSet);
m_renderDataBinding->Update({
{
0,
ShaderBinding::TextureBinding {
whiteTexture.get(), defaultSampler.get()
}
}
});
}
std::unique_ptr<ElementRendererData> SubmeshRenderer::InstanciateData()
{
return {};
@ -22,6 +39,8 @@ namespace Nz
const RenderPipeline* currentPipeline = nullptr;
const ShaderBinding* currentMaterialBinding = nullptr;
commandBuffer.BindShaderBinding(Graphics::DrawDataBindingSet, *m_renderDataBinding);
for (std::size_t i = 0; i < elementCount; ++i)
{
assert(elements[i]->GetElementType() == UnderlyingCast(BasicRenderElement::Submesh));

View File

@ -68,11 +68,11 @@ namespace Nz
{
auto& textureDescriptor = m_owner.GetTextureDescriptor(m_poolIndex, m_bindingIndex, binding.bindingIndex);
if (OpenGLTexture* glTexture = static_cast<OpenGLTexture*>(arg.texture))
if (const OpenGLTexture* glTexture = static_cast<const OpenGLTexture*>(arg.texture))
{
textureDescriptor.texture = glTexture->GetTexture().GetObjectId();
if (OpenGLTextureSampler* glSampler = static_cast<OpenGLTextureSampler*>(arg.sampler))
if (const OpenGLTextureSampler* glSampler = static_cast<const OpenGLTextureSampler*>(arg.sampler))
textureDescriptor.sampler = glSampler->GetSampler(glTexture->GetLevelCount() > 1).GetObjectId();
else
textureDescriptor.sampler = 0;

View File

@ -34,8 +34,8 @@ namespace Nz
if constexpr (std::is_same_v<T, TextureBinding>)
{
VulkanTexture* vkTexture = static_cast<VulkanTexture*>(arg.texture);
VulkanTextureSampler* vkSampler = static_cast<VulkanTextureSampler*>(arg.sampler);
const VulkanTexture* vkTexture = static_cast<const VulkanTexture*>(arg.texture);
const VulkanTextureSampler* vkSampler = static_cast<const VulkanTextureSampler*>(arg.sampler);
VkDescriptorImageInfo& imageInfo = imageBinding.emplace_back();
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;