From ecd1e4389028440d2a3b1ed65f73512caea4e5cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Sat, 13 Nov 2021 20:08:03 +0100 Subject: [PATCH] Graphics: Add support for multi-viewer rendering (a bit hacky) --- examples/DeferredShading/main.cpp | 2 +- examples/PhysicsDemo/main.cpp | 7 ++- .../Nazara/Graphics/ForwardFramePipeline.hpp | 2 + include/Nazara/Graphics/FrameGraph.hpp | 6 +-- include/Nazara/Graphics/FrameGraph.inl | 10 ++--- src/Nazara/Graphics/ForwardFramePipeline.cpp | 34 +++++++++----- src/Nazara/Graphics/FrameGraph.cpp | 45 +++++++++++++------ src/Nazara/Graphics/Graphics.cpp | 10 +++++ 8 files changed, 80 insertions(+), 36 deletions(-) diff --git a/examples/DeferredShading/main.cpp b/examples/DeferredShading/main.cpp index da74d1f93..1127a3e94 100644 --- a/examples/DeferredShading/main.cpp +++ b/examples/DeferredShading/main.cpp @@ -789,7 +789,7 @@ int main() bloomBlendPass.AddInput(bloomTextureB); bloomBlendPass.AddOutput(backbuffer); - graph.SetBackbufferOutput(backbuffer); + graph.AddBackbufferOutput(backbuffer); return graph.Bake(); }(); diff --git a/examples/PhysicsDemo/main.cpp b/examples/PhysicsDemo/main.cpp index d87b9fae0..c54f89caf 100644 --- a/examples/PhysicsDemo/main.cpp +++ b/examples/PhysicsDemo/main.cpp @@ -158,9 +158,12 @@ int main() entt::entity text2D = registry.create(); { + std::shared_ptr sprite2D = std::make_shared(spriteMaterial); + sprite2D->Update(Nz::SimpleTextDrawer::Draw("Voix ambiguë d'un cœur qui, au zéphyr, préfère les jattes de kiwis", 72)); + registry.emplace(text2D).SetPosition(Nz::Vector3f(0.f, 200.f, 0.f)); auto& gfxComponent = registry.emplace(text2D); - gfxComponent.AttachRenderable(sprite, 2); + gfxComponent.AttachRenderable(sprite2D, 2); } entt::entity viewer = registry.create(); @@ -254,7 +257,7 @@ int main() Nz::Clock secondClock; unsigned int fps = 0; - //Nz::Mouse::SetRelativeMouseMode(true); + Nz::Mouse::SetRelativeMouseMode(true); float elapsedTime = 0.f; Nz::UInt64 time = Nz::GetElapsedMicroseconds(); diff --git a/include/Nazara/Graphics/ForwardFramePipeline.hpp b/include/Nazara/Graphics/ForwardFramePipeline.hpp index 0458debf9..8f2639483 100644 --- a/include/Nazara/Graphics/ForwardFramePipeline.hpp +++ b/include/Nazara/Graphics/ForwardFramePipeline.hpp @@ -26,6 +26,7 @@ namespace Nz { class RenderFrame; + class RenderTarget; class NAZARA_GRAPHICS_API ForwardFramePipeline : public FramePipeline { @@ -99,6 +100,7 @@ namespace Nz std::unordered_map m_viewers; std::unordered_map m_materials; std::unordered_map> m_renderables; + std::unordered_map> m_viewerPerTarget; std::unordered_set m_invalidatedViewerInstances; std::unordered_set m_invalidatedMaterials; std::unordered_set m_invalidatedWorldInstances; diff --git a/include/Nazara/Graphics/FrameGraph.hpp b/include/Nazara/Graphics/FrameGraph.hpp index b594414b2..eaa6e0b9f 100644 --- a/include/Nazara/Graphics/FrameGraph.hpp +++ b/include/Nazara/Graphics/FrameGraph.hpp @@ -31,12 +31,11 @@ namespace Nz ~FrameGraph() = default; inline std::size_t AddAttachment(FramePassAttachment attachment); + inline void AddBackbufferOutput(std::size_t backbufferOutput); inline FramePass& AddPass(std::string name); BakedFrameGraph Bake(); - inline void SetBackbufferOutput(std::size_t backbufferOutput); - FrameGraph& operator=(const FrameGraph&) = delete; FrameGraph& operator=(FrameGraph&&) noexcept = default; @@ -86,7 +85,6 @@ namespace Nz struct WorkData { - std::size_t backbufferResourceIndex; std::vector> renderPasses; std::vector physicalPasses; std::vector textures; @@ -109,7 +107,7 @@ namespace Nz void ReorderPasses(); void TraverseGraph(std::size_t passIndex); - std::optional m_backbufferOutput; + std::vector m_backbufferOutputs; std::vector m_framePasses; std::vector m_attachments; WorkData m_pending; diff --git a/include/Nazara/Graphics/FrameGraph.inl b/include/Nazara/Graphics/FrameGraph.inl index 0a4aa3958..08aceacc3 100644 --- a/include/Nazara/Graphics/FrameGraph.inl +++ b/include/Nazara/Graphics/FrameGraph.inl @@ -16,16 +16,16 @@ namespace Nz return id; } + inline void FrameGraph::AddBackbufferOutput(std::size_t backbufferOutput) + { + m_backbufferOutputs.push_back(backbufferOutput); + } + inline FramePass& FrameGraph::AddPass(std::string name) { std::size_t id = m_framePasses.size(); return m_framePasses.emplace_back(*this, id, std::move(name)); } - - inline void FrameGraph::SetBackbufferOutput(std::size_t backbufferOutput) - { - m_backbufferOutput = backbufferOutput; - } } #include diff --git a/src/Nazara/Graphics/ForwardFramePipeline.cpp b/src/Nazara/Graphics/ForwardFramePipeline.cpp index 3abb65f0c..b67076325 100644 --- a/src/Nazara/Graphics/ForwardFramePipeline.cpp +++ b/src/Nazara/Graphics/ForwardFramePipeline.cpp @@ -136,8 +136,6 @@ namespace Nz // Update UBOs and materials UploadPool& uploadPool = renderFrame.GetUploadPool(); - bool prepare = false; - renderFrame.Execute([&](CommandBufferBuilder& builder) { builder.BeginDebugRegion("UBO Update", Color::Yellow); @@ -336,6 +334,7 @@ namespace Nz m_bakedFrameGraph.Execute(renderFrame); m_rebuildFrameGraph = false; + m_viewerPerTarget.clear(); const Vector2ui& frameSize = renderFrame.GetSize(); for (auto&& [viewer, viewerData] : m_viewers) { @@ -344,13 +343,25 @@ namespace Nz viewerData.prepare = false; const RenderTarget& renderTarget = viewer->GetRenderTarget(); + + m_viewerPerTarget[&renderTarget].push_back(&viewerData); + } + + for (auto&& [renderTargetPtr, viewerDataVec] : m_viewerPerTarget) + { Recti renderRegion(0, 0, frameSize.x, frameSize.y); - const ShaderBindingPtr& blitShaderBinding = viewerData.blitShaderBinding; - const std::shared_ptr& sourceTexture = m_bakedFrameGraph.GetAttachmentTexture(viewerData.colorAttachment); + + const RenderTarget& renderTarget = *renderTargetPtr; + const auto& viewers = viewerDataVec; renderFrame.Execute([&](CommandBufferBuilder& builder) { - builder.TextureBarrier(PipelineStage::ColorOutput, PipelineStage::FragmentShader, MemoryAccess::ColorWrite, MemoryAccess::ShaderRead, TextureLayout::ColorOutput, TextureLayout::ColorInput, *sourceTexture); + for (const ViewerData* viewerData : viewers) + { + const std::shared_ptr& sourceTexture = m_bakedFrameGraph.GetAttachmentTexture(viewerData->colorAttachment); + + builder.TextureBarrier(PipelineStage::ColorOutput, PipelineStage::FragmentShader, MemoryAccess::ColorWrite, MemoryAccess::ShaderRead, TextureLayout::ColorOutput, TextureLayout::ColorInput, *sourceTexture); + } std::array clearValues; clearValues[0].color = Color::Black; @@ -363,12 +374,16 @@ namespace Nz { builder.SetScissor(renderRegion); builder.SetViewport(renderRegion); - builder.BindPipeline(*graphics->GetBlitPipeline()); builder.BindVertexBuffer(0, *graphics->GetFullscreenVertexBuffer()); - builder.BindShaderBinding(0, *blitShaderBinding); - builder.Draw(3); + for (const ViewerData* viewerData : viewers) + { + const ShaderBindingPtr& blitShaderBinding = viewerData->blitShaderBinding; + + builder.BindShaderBinding(0, *blitShaderBinding); + builder.Draw(3); + } } builder.EndDebugRegion(); } @@ -503,9 +518,8 @@ namespace Nz }); } - //FIXME: This doesn't handle multiple window viewers for (auto&& [viewer, viewerData] : m_viewers) - frameGraph.SetBackbufferOutput(viewerData.colorAttachment); + frameGraph.AddBackbufferOutput(viewerData.colorAttachment); return frameGraph.Bake(); } diff --git a/src/Nazara/Graphics/FrameGraph.cpp b/src/Nazara/Graphics/FrameGraph.cpp index fa7c45585..8bb73328d 100644 --- a/src/Nazara/Graphics/FrameGraph.cpp +++ b/src/Nazara/Graphics/FrameGraph.cpp @@ -33,7 +33,7 @@ namespace Nz BakedFrameGraph FrameGraph::Bake() { - if (!m_backbufferOutput.has_value()) + if (m_backbufferOutputs.empty()) throw std::runtime_error("no backbuffer output has been set"); m_pending.attachmentReadList.clear(); @@ -46,17 +46,18 @@ namespace Nz m_pending.renderPasses.clear(); m_pending.textures.clear(); - m_pending.backbufferResourceIndex = m_backbufferOutput.value(); - BuildReadWriteList(); - auto it = m_pending.attachmentWriteList.find(m_pending.backbufferResourceIndex); - if (it == m_pending.attachmentWriteList.end()) - throw std::runtime_error("no pass writes to backbuffer"); + for (std::size_t output : m_backbufferOutputs) + { + auto it = m_pending.attachmentWriteList.find(output); + if (it == m_pending.attachmentWriteList.end()) + throw std::runtime_error("no pass writes to backbuffer"); - const std::vector& backbufferPasses = it->second; - for (std::size_t passIndex : backbufferPasses) - TraverseGraph(passIndex); + const std::vector& backbufferPasses = it->second; + for (std::size_t passIndex : backbufferPasses) + TraverseGraph(passIndex); + } std::reverse(m_pending.passList.begin(), m_pending.passList.end()); @@ -88,8 +89,22 @@ namespace Nz bakedSubpass.commandCallback = framePass.GetCommandCallback(); for (const auto& output : framePass.GetOutputs()) + { bakedPass.outputTextureIndices.push_back(Retrieve(m_pending.attachmentToTextures, output.attachmentId)); + auto& clearValues = bakedPass.outputClearValues.emplace_back(); + if (output.clearColor) + clearValues.color = *output.clearColor; + } + + // Add depth-stencil clear values + auto& dsClearValues = bakedPass.outputClearValues.emplace_back(); + if (const auto& depthStencilClear = framePass.GetDepthStencilClear()) + { + dsClearValues.depth = depthStencilClear->depth; + dsClearValues.stencil = depthStencilClear->stencil; + } + std::size_t attachmentId; if (attachmentId = framePass.GetDepthStencilOutput(); attachmentId != FramePass::InvalidAttachmentId) bakedPass.outputTextureIndices.push_back(Retrieve(m_pending.attachmentToTextures, attachmentId)); @@ -228,12 +243,14 @@ namespace Nz } // Add TextureUsage::Sampled to backbuffer output + for (std::size_t output : m_backbufferOutputs) + { + auto it = m_pending.attachmentToTextures.find(output); + assert(it != m_pending.attachmentToTextures.end()); - auto it = m_pending.attachmentToTextures.find(m_pending.backbufferResourceIndex); - assert(it != m_pending.attachmentToTextures.end()); - - auto& backbufferTexture = m_pending.textures[it->second]; - backbufferTexture.usage |= TextureUsage::ShaderSampling; + auto& backbufferTexture = m_pending.textures[it->second]; + backbufferTexture.usage |= TextureUsage::ShaderSampling; + } } void FrameGraph::BuildBarriers() diff --git a/src/Nazara/Graphics/Graphics.cpp b/src/Nazara/Graphics/Graphics.cpp index 507e9c8fd..9d301af60 100644 --- a/src/Nazara/Graphics/Graphics.cpp +++ b/src/Nazara/Graphics/Graphics.cpp @@ -163,6 +163,16 @@ namespace Nz throw std::runtime_error("failed to instantiate blit shader"); RenderPipelineInfo pipelineInfo; + + // Alpha blending + pipelineInfo.blending = true; + pipelineInfo.blend.modeColor = BlendEquation::Add; + pipelineInfo.blend.modeAlpha = BlendEquation::Add; + pipelineInfo.blend.srcColor = BlendFunc::One; + pipelineInfo.blend.dstColor = BlendFunc::One; + pipelineInfo.blend.srcAlpha = BlendFunc::One; + pipelineInfo.blend.dstAlpha = BlendFunc::One; + pipelineInfo.pipelineLayout = m_blitPipelineLayout; pipelineInfo.shaderModules.push_back(std::move(blitShader)); pipelineInfo.vertexBuffers.assign({