Merge branch 'master' into automatic-file-fix
This commit is contained in:
@@ -5,41 +5,48 @@
|
||||
#include <Nazara/Graphics/SubmeshRenderer.hpp>
|
||||
#include <Nazara/Graphics/Graphics.hpp>
|
||||
#include <Nazara/Graphics/RenderSubmesh.hpp>
|
||||
#include <Nazara/Graphics/ViewerInstance.hpp>
|
||||
#include <Nazara/Renderer/CommandBufferBuilder.hpp>
|
||||
#include <Nazara/Renderer/RenderFrame.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
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 {};
|
||||
return std::make_unique<SubmeshRendererData>();
|
||||
}
|
||||
|
||||
void SubmeshRenderer::Render(ElementRendererData& /*rendererData*/, CommandBufferBuilder& commandBuffer, const Pointer<const RenderElement>* elements, std::size_t elementCount)
|
||||
void SubmeshRenderer::Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& /*currentFrame*/, const Pointer<const RenderElement>* elements, std::size_t elementCount)
|
||||
{
|
||||
Graphics* graphics = Graphics::Instance();
|
||||
|
||||
auto& data = static_cast<SubmeshRendererData&>(rendererData);
|
||||
|
||||
const AbstractBuffer* currentIndexBuffer = nullptr;
|
||||
const AbstractBuffer* currentVertexBuffer = nullptr;
|
||||
const RenderPipeline* currentPipeline = nullptr;
|
||||
const ShaderBinding* currentMaterialBinding = nullptr;
|
||||
const ShaderBinding* currentShaderBinding = nullptr;
|
||||
const WorldInstance* currentWorldInstance = nullptr;
|
||||
|
||||
commandBuffer.BindShaderBinding(Graphics::DrawDataBindingSet, *m_renderDataBinding);
|
||||
auto FlushDrawCall = [&]()
|
||||
{
|
||||
// Does nothing for now (but will serve once instancing is implemented)
|
||||
};
|
||||
|
||||
auto FlushDrawData = [&]()
|
||||
{
|
||||
FlushDrawCall();
|
||||
|
||||
currentShaderBinding = nullptr;
|
||||
};
|
||||
|
||||
const auto& whiteTexture = Graphics::Instance()->GetDefaultTextures().whiteTextures[UnderlyingCast(ImageType::E2D)];
|
||||
const auto& defaultSampler = graphics->GetSamplerCache().Get({});
|
||||
|
||||
for (std::size_t i = 0; i < elementCount; ++i)
|
||||
{
|
||||
@@ -48,34 +55,139 @@ namespace Nz
|
||||
|
||||
if (const RenderPipeline* pipeline = submesh.GetRenderPipeline(); currentPipeline != pipeline)
|
||||
{
|
||||
commandBuffer.BindPipeline(*pipeline);
|
||||
FlushDrawCall();
|
||||
currentPipeline = pipeline;
|
||||
}
|
||||
|
||||
if (const ShaderBinding* materialBinding = &submesh.GetMaterialBinding(); currentMaterialBinding != materialBinding)
|
||||
{
|
||||
commandBuffer.BindShaderBinding(Graphics::MaterialBindingSet, *materialBinding);
|
||||
currentMaterialBinding = materialBinding;
|
||||
}
|
||||
|
||||
if (const AbstractBuffer* indexBuffer = submesh.GetIndexBuffer(); currentIndexBuffer != indexBuffer)
|
||||
{
|
||||
commandBuffer.BindIndexBuffer(*indexBuffer);
|
||||
FlushDrawCall();
|
||||
currentIndexBuffer = indexBuffer;
|
||||
}
|
||||
|
||||
if (const AbstractBuffer* vertexBuffer = submesh.GetVertexBuffer(); currentVertexBuffer != vertexBuffer)
|
||||
{
|
||||
commandBuffer.BindVertexBuffer(0, *vertexBuffer);
|
||||
FlushDrawCall();
|
||||
currentVertexBuffer = vertexBuffer;
|
||||
}
|
||||
|
||||
commandBuffer.BindShaderBinding(Graphics::WorldBindingSet, submesh.GetInstanceBinding());
|
||||
if (currentWorldInstance != &submesh.GetWorldInstance())
|
||||
{
|
||||
// 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?)
|
||||
FlushDrawData();
|
||||
currentWorldInstance = &submesh.GetWorldInstance();
|
||||
}
|
||||
|
||||
if (currentIndexBuffer)
|
||||
commandBuffer.DrawIndexed(submesh.GetIndexCount());
|
||||
else
|
||||
commandBuffer.Draw(submesh.GetIndexCount());
|
||||
if (!currentShaderBinding)
|
||||
{
|
||||
m_bindingCache.clear();
|
||||
|
||||
const MaterialPass& materialPass = submesh.GetMaterialPass();
|
||||
materialPass.FillShaderBinding(m_bindingCache);
|
||||
|
||||
// Predefined shader bindings
|
||||
const auto& matSettings = materialPass.GetSettings();
|
||||
if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::InstanceDataUbo); bindingIndex != MaterialSettings::InvalidIndex)
|
||||
{
|
||||
const auto& instanceBuffer = currentWorldInstance->GetInstanceBuffer();
|
||||
|
||||
auto& bindingEntry = m_bindingCache.emplace_back();
|
||||
bindingEntry.bindingIndex = bindingIndex;
|
||||
bindingEntry.content = ShaderBinding::UniformBufferBinding{
|
||||
instanceBuffer.get(),
|
||||
0, instanceBuffer->GetSize()
|
||||
};
|
||||
}
|
||||
|
||||
if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::ViewerDataUbo); bindingIndex != MaterialSettings::InvalidIndex)
|
||||
{
|
||||
const auto& viewerBuffer = viewerInstance.GetViewerBuffer();
|
||||
|
||||
auto& bindingEntry = m_bindingCache.emplace_back();
|
||||
bindingEntry.bindingIndex = bindingIndex;
|
||||
bindingEntry.content = ShaderBinding::UniformBufferBinding{
|
||||
viewerBuffer.get(),
|
||||
0, viewerBuffer->GetSize()
|
||||
};
|
||||
}
|
||||
|
||||
if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::OverlayTexture); bindingIndex != MaterialSettings::InvalidIndex)
|
||||
{
|
||||
auto& bindingEntry = m_bindingCache.emplace_back();
|
||||
bindingEntry.bindingIndex = bindingIndex;
|
||||
bindingEntry.content = ShaderBinding::TextureBinding{
|
||||
whiteTexture.get(), defaultSampler.get()
|
||||
};
|
||||
}
|
||||
|
||||
ShaderBindingPtr drawDataBinding = currentPipeline->GetPipelineInfo().pipelineLayout->AllocateShaderBinding(0);
|
||||
drawDataBinding->Update(m_bindingCache.data(), m_bindingCache.size());
|
||||
|
||||
currentShaderBinding = drawDataBinding.get();
|
||||
|
||||
data.shaderBindings.emplace_back(std::move(drawDataBinding));
|
||||
}
|
||||
|
||||
auto& drawCall = data.drawCalls.emplace_back();
|
||||
drawCall.indexBuffer = currentIndexBuffer;
|
||||
drawCall.indexCount = submesh.GetIndexCount();
|
||||
drawCall.renderPipeline = currentPipeline;
|
||||
drawCall.shaderBinding = currentShaderBinding;
|
||||
drawCall.vertexBuffer = currentVertexBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
void SubmeshRenderer::Render(const ViewerInstance& /*viewerInstance*/, ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, const Pointer<const RenderElement>* /*elements*/, std::size_t /*elementCount*/)
|
||||
{
|
||||
auto& data = static_cast<SubmeshRendererData&>(rendererData);
|
||||
|
||||
const AbstractBuffer* currentIndexBuffer = nullptr;
|
||||
const AbstractBuffer* currentVertexBuffer = nullptr;
|
||||
const RenderPipeline* currentPipeline = nullptr;
|
||||
const ShaderBinding* currentShaderBinding = nullptr;
|
||||
|
||||
for (const auto& drawData : data.drawCalls)
|
||||
{
|
||||
if (currentPipeline != drawData.renderPipeline)
|
||||
{
|
||||
commandBuffer.BindPipeline(*drawData.renderPipeline);
|
||||
currentPipeline = drawData.renderPipeline;
|
||||
}
|
||||
|
||||
if (currentShaderBinding != drawData.shaderBinding)
|
||||
{
|
||||
commandBuffer.BindShaderBinding(0, *drawData.shaderBinding);
|
||||
currentShaderBinding = drawData.shaderBinding;
|
||||
}
|
||||
|
||||
if (currentIndexBuffer != drawData.indexBuffer)
|
||||
{
|
||||
commandBuffer.BindIndexBuffer(*drawData.indexBuffer);
|
||||
currentIndexBuffer = drawData.indexBuffer;
|
||||
}
|
||||
|
||||
if (currentVertexBuffer != drawData.vertexBuffer)
|
||||
{
|
||||
commandBuffer.BindVertexBuffer(0, *drawData.vertexBuffer);
|
||||
currentVertexBuffer = drawData.vertexBuffer;
|
||||
}
|
||||
|
||||
if (currentIndexBuffer)
|
||||
commandBuffer.DrawIndexed(drawData.indexCount);
|
||||
else
|
||||
commandBuffer.Draw(drawData.indexCount);
|
||||
}
|
||||
}
|
||||
|
||||
void SubmeshRenderer::Reset(ElementRendererData& rendererData, RenderFrame& currentFrame)
|
||||
{
|
||||
auto& data = static_cast<SubmeshRendererData&>(rendererData);
|
||||
|
||||
for (auto& shaderBinding : data.shaderBindings)
|
||||
currentFrame.PushForRelease(std::move(shaderBinding));
|
||||
data.shaderBindings.clear();
|
||||
|
||||
data.drawCalls.clear();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user