diff --git a/include/Nazara/Graphics/ForwardFramePipeline.hpp b/include/Nazara/Graphics/ForwardFramePipeline.hpp index 1325169fc..9e2f9e333 100644 --- a/include/Nazara/Graphics/ForwardFramePipeline.hpp +++ b/include/Nazara/Graphics/ForwardFramePipeline.hpp @@ -54,12 +54,6 @@ namespace Nz void ProcessRenderQueue(CommandBufferBuilder& builder, const RenderQueue& renderQueue); void UnregisterMaterialPass(MaterialPass* material); - struct ElementAABB - { - Boxf aabb; - std::size_t count; - }; - struct MaterialData { std::size_t usedCount = 0; @@ -72,14 +66,17 @@ namespace Nz NazaraSlot(InstancedRenderable, OnMaterialInvalidated, onMaterialInvalidated); }; + struct VisibleRenderable + { + const InstancedRenderable* instancedRenderable; + const WorldInstance* worldInstance; + }; + struct ViewerData { std::size_t colorAttachment; std::size_t depthStencilAttachment; - std::size_t depthPrepassVisibilityHash = 0; - std::size_t forwardVisibilityHash = 0; - std::vector depthPrepassAABB; - std::vector forwardAABB; + std::size_t visibilityHash = 0; std::vector> depthPrepassRenderElements; std::vector> forwardRenderElements; RenderQueueRegistry depthPrepassRegistry; @@ -101,6 +98,7 @@ namespace Nz std::unordered_set m_invalidatedWorldInstances; std::unordered_set m_removedWorldInstances; std::vector> m_elementRenderers; + std::vector m_visibleRenderables; BakedFrameGraph m_bakedFrameGraph; bool m_rebuildFrameGraph; }; diff --git a/include/Nazara/Graphics/InstancedRenderable.hpp b/include/Nazara/Graphics/InstancedRenderable.hpp index 7189d847a..975acb005 100644 --- a/include/Nazara/Graphics/InstancedRenderable.hpp +++ b/include/Nazara/Graphics/InstancedRenderable.hpp @@ -28,7 +28,7 @@ namespace Nz InstancedRenderable(InstancedRenderable&&) noexcept = default; ~InstancedRenderable(); - virtual void BuildElement(std::size_t passIndex, WorldInstance& worldInstance, std::vector>& elements) const = 0; + virtual void BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, std::vector>& elements) const = 0; inline const Boxf& GetAABB() const; virtual const std::shared_ptr& GetMaterial(std::size_t i) const = 0; diff --git a/include/Nazara/Graphics/Model.hpp b/include/Nazara/Graphics/Model.hpp index dde892dd5..99028a26d 100644 --- a/include/Nazara/Graphics/Model.hpp +++ b/include/Nazara/Graphics/Model.hpp @@ -28,7 +28,7 @@ namespace Nz Model(Model&&) noexcept = default; ~Model() = default; - void BuildElement(std::size_t passIndex, WorldInstance& worldInstance, std::vector>& elements) const override; + void BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, std::vector>& elements) const override; const std::shared_ptr& GetIndexBuffer(std::size_t subMeshIndex) const; std::size_t GetIndexCount(std::size_t subMeshIndex) const; diff --git a/src/Nazara/Graphics/ForwardFramePipeline.cpp b/src/Nazara/Graphics/ForwardFramePipeline.cpp index 5b4b9c112..1e74ce40d 100644 --- a/src/Nazara/Graphics/ForwardFramePipeline.cpp +++ b/src/Nazara/Graphics/ForwardFramePipeline.cpp @@ -1,548 +1,504 @@ -// 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Nz -{ - ForwardFramePipeline::ForwardFramePipeline() : - m_rebuildFrameGraph(true) - { - auto& passRegistry = Graphics::Instance()->GetMaterialPassRegistry(); - m_depthPassIndex = passRegistry.GetPassIndex("DepthPass"); - m_forwardPassIndex = passRegistry.GetPassIndex("ForwardPass"); - - m_elementRenderers.resize(1); - m_elementRenderers[UnderlyingCast(BasicRenderElement::Submesh)] = std::make_unique(); - } - - void ForwardFramePipeline::InvalidateViewer(AbstractViewer* viewerInstance) - { - m_invalidatedViewerInstances.insert(viewerInstance); - } - - void ForwardFramePipeline::InvalidateWorldInstance(WorldInstance* worldInstance) - { - m_invalidatedWorldInstances.insert(worldInstance); - } - - void ForwardFramePipeline::RegisterInstancedDrawable(WorldInstancePtr worldInstance, const InstancedRenderable* instancedRenderable) - { - m_removedWorldInstances.erase(worldInstance); - - auto& renderableMap = m_renderables[worldInstance]; - if (renderableMap.empty()) - InvalidateWorldInstance(worldInstance.get()); - - if (auto it = renderableMap.find(instancedRenderable); it == renderableMap.end()) - { - auto& renderableData = renderableMap.emplace(instancedRenderable, RenderableData{}).first->second; - renderableData.onMaterialInvalidated.Connect(instancedRenderable->OnMaterialInvalidated, [this](InstancedRenderable* instancedRenderable, std::size_t materialIndex, const std::shared_ptr& newMaterial) - { - if (newMaterial) - { - if (MaterialPass* pass = newMaterial->GetPass(m_depthPassIndex)) - RegisterMaterialPass(pass); - - if (MaterialPass* pass = newMaterial->GetPass(m_forwardPassIndex)) - RegisterMaterialPass(pass); - } - - const auto& prevMaterial = instancedRenderable->GetMaterial(materialIndex); - if (prevMaterial) - { - if (MaterialPass* pass = prevMaterial->GetPass(m_depthPassIndex)) - UnregisterMaterialPass(pass); - - if (MaterialPass* pass = prevMaterial->GetPass(m_forwardPassIndex)) - UnregisterMaterialPass(pass); - } +// 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 - for (auto&& [viewer, viewerData] : m_viewers) - { - viewerData.rebuildDepthPrepass = true; - viewerData.rebuildForwardPass = true; - } - }); - - std::size_t matCount = instancedRenderable->GetMaterialCount(); - for (std::size_t i = 0; i < matCount; ++i) - { - if (Material* mat = instancedRenderable->GetMaterial(i).get()) - { - if (MaterialPass* pass = mat->GetPass(m_depthPassIndex)) - RegisterMaterialPass(pass); - - if (MaterialPass* pass = mat->GetPass(m_forwardPassIndex)) - RegisterMaterialPass(pass); - } - } +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include - for (auto&& [viewer, viewerData] : m_viewers) - { - viewerData.rebuildDepthPrepass = true; - viewerData.rebuildForwardPass = true; - } - } - } - - void ForwardFramePipeline::RegisterViewer(AbstractViewer* viewerInstance) - { - m_viewers.emplace(viewerInstance, ViewerData{}); +namespace Nz +{ + ForwardFramePipeline::ForwardFramePipeline() : + m_rebuildFrameGraph(true) + { + auto& passRegistry = Graphics::Instance()->GetMaterialPassRegistry(); + m_depthPassIndex = passRegistry.GetPassIndex("DepthPass"); + m_forwardPassIndex = passRegistry.GetPassIndex("ForwardPass"); + + m_elementRenderers.resize(1); + m_elementRenderers[UnderlyingCast(BasicRenderElement::Submesh)] = std::make_unique(); + } + + void ForwardFramePipeline::InvalidateViewer(AbstractViewer* viewerInstance) + { m_invalidatedViewerInstances.insert(viewerInstance); - m_rebuildFrameGraph = true; - } - - void ForwardFramePipeline::Render(RenderFrame& renderFrame) - { - Graphics* graphics = Graphics::Instance(); - - renderFrame.PushForRelease(std::move(m_removedWorldInstances)); - m_removedWorldInstances.clear(); - - if (m_rebuildFrameGraph) - { - renderFrame.PushForRelease(std::move(m_bakedFrameGraph)); - m_bakedFrameGraph = BuildFrameGraph(); - } - - // Update UBOs and materials - UploadPool& uploadPool = renderFrame.GetUploadPool(); - - renderFrame.Execute([&](CommandBufferBuilder& builder) - { - builder.BeginDebugRegion("UBO Update", Color::Yellow); - { - builder.PreTransferBarrier(); - - for (AbstractViewer* viewer : m_invalidatedViewerInstances) - viewer->GetViewerInstance().UpdateBuffers(uploadPool, builder); - - m_invalidatedViewerInstances.clear(); - - for (WorldInstance* worldInstance : m_invalidatedWorldInstances) - worldInstance->UpdateBuffers(uploadPool, builder); - - m_invalidatedWorldInstances.clear(); - - for (MaterialPass* material : m_invalidatedMaterials) - { - if (material->Update(renderFrame, builder)) + } + + void ForwardFramePipeline::InvalidateWorldInstance(WorldInstance* worldInstance) + { + m_invalidatedWorldInstances.insert(worldInstance); + } + + void ForwardFramePipeline::RegisterInstancedDrawable(WorldInstancePtr worldInstance, const InstancedRenderable* instancedRenderable) + { + m_removedWorldInstances.erase(worldInstance); + + auto& renderableMap = m_renderables[worldInstance]; + if (renderableMap.empty()) + InvalidateWorldInstance(worldInstance.get()); + + if (auto it = renderableMap.find(instancedRenderable); it == renderableMap.end()) + { + auto& renderableData = renderableMap.emplace(instancedRenderable, RenderableData{}).first->second; + renderableData.onMaterialInvalidated.Connect(instancedRenderable->OnMaterialInvalidated, [this](InstancedRenderable* instancedRenderable, std::size_t materialIndex, const std::shared_ptr& newMaterial) + { + if (newMaterial) + { + if (MaterialPass* pass = newMaterial->GetPass(m_depthPassIndex)) + RegisterMaterialPass(pass); + + if (MaterialPass* pass = newMaterial->GetPass(m_forwardPassIndex)) + RegisterMaterialPass(pass); + } + + const auto& prevMaterial = instancedRenderable->GetMaterial(materialIndex); + if (prevMaterial) + { + if (MaterialPass* pass = prevMaterial->GetPass(m_depthPassIndex)) + UnregisterMaterialPass(pass); + + if (MaterialPass* pass = prevMaterial->GetPass(m_forwardPassIndex)) + UnregisterMaterialPass(pass); + } + + for (auto&& [viewer, viewerData] : m_viewers) + { + viewerData.rebuildDepthPrepass = true; + viewerData.rebuildForwardPass = true; + } + }); + + std::size_t matCount = instancedRenderable->GetMaterialCount(); + for (std::size_t i = 0; i < matCount; ++i) + { + if (Material* mat = instancedRenderable->GetMaterial(i).get()) + { + if (MaterialPass* pass = mat->GetPass(m_depthPassIndex)) + RegisterMaterialPass(pass); + + if (MaterialPass* pass = mat->GetPass(m_forwardPassIndex)) + RegisterMaterialPass(pass); + } + } + + for (auto&& [viewer, viewerData] : m_viewers) + { + viewerData.rebuildDepthPrepass = true; + viewerData.rebuildForwardPass = true; + } + } + } + + void ForwardFramePipeline::RegisterViewer(AbstractViewer* viewerInstance) + { + m_viewers.emplace(viewerInstance, ViewerData{}); + m_invalidatedViewerInstances.insert(viewerInstance); + m_rebuildFrameGraph = true; + } + + void ForwardFramePipeline::Render(RenderFrame& renderFrame) + { + Graphics* graphics = Graphics::Instance(); + + renderFrame.PushForRelease(std::move(m_removedWorldInstances)); + m_removedWorldInstances.clear(); + + if (m_rebuildFrameGraph) + { + renderFrame.PushForRelease(std::move(m_bakedFrameGraph)); + m_bakedFrameGraph = BuildFrameGraph(); + } + + // Update UBOs and materials + UploadPool& uploadPool = renderFrame.GetUploadPool(); + + renderFrame.Execute([&](CommandBufferBuilder& builder) + { + builder.BeginDebugRegion("UBO Update", Color::Yellow); + { + builder.PreTransferBarrier(); + + for (AbstractViewer* viewer : m_invalidatedViewerInstances) + viewer->GetViewerInstance().UpdateBuffers(uploadPool, builder); + + m_invalidatedViewerInstances.clear(); + + for (WorldInstance* worldInstance : m_invalidatedWorldInstances) + worldInstance->UpdateBuffers(uploadPool, builder); + + m_invalidatedWorldInstances.clear(); + + for (MaterialPass* material : m_invalidatedMaterials) + { + if (material->Update(renderFrame, builder)) { - for (auto&& [viewer, viewerData] : m_viewers) - { - viewerData.rebuildDepthPrepass = true; + for (auto&& [viewer, viewerData] : m_viewers) + { + viewerData.rebuildDepthPrepass = true; viewerData.rebuildForwardPass = true; - } - } - } - m_invalidatedMaterials.clear(); - - builder.PostTransferBarrier(); - } - builder.EndDebugRegion(); - }, QueueType::Transfer); + } + } + } + m_invalidatedMaterials.clear(); + + builder.PostTransferBarrier(); + } + builder.EndDebugRegion(); + }, QueueType::Transfer); auto CombineHash = [](std::size_t currentHash, std::size_t newHash) { return currentHash * 23 + newHash; - }; - + }; + // Render queues handling for (auto&& [viewer, data] : m_viewers) { auto& viewerData = data; - - //if (viewerData.rebuildDepthPrepass) - { - viewerData.depthPrepassAABB.clear(); - viewerData.depthPrepassRenderElements.clear(); - - for (const auto& [worldInstance, renderables] : m_renderables) - { - for (const auto& [renderable, renderableData] : renderables) - { - std::size_t prevCount = viewerData.depthPrepassRenderElements.size(); - renderable->BuildElement(m_depthPassIndex, *worldInstance, viewerData.depthPrepassRenderElements); - std::size_t currentCount = viewerData.depthPrepassRenderElements.size(); - - if (currentCount > prevCount) - { - BoundingVolumef boundingVolume(renderable->GetAABB()); - boundingVolume.Update(worldInstance->GetWorldMatrix()); - - auto& aabbData = viewerData.depthPrepassAABB.emplace_back(); - aabbData.aabb = boundingVolume.aabb; - aabbData.count = currentCount - prevCount; - } - } - } - } - - //if (viewerData.rebuildForwardPass) - { - viewerData.forwardAABB.clear(); - viewerData.forwardRenderElements.clear(); - - for (const auto& [worldInstance, renderables] : m_renderables) - { - for (const auto& [renderable, renderableData] : renderables) - { - std::size_t prevCount = viewerData.forwardRenderElements.size(); - renderable->BuildElement(m_forwardPassIndex, *worldInstance, viewerData.forwardRenderElements); - std::size_t currentCount = viewerData.forwardRenderElements.size(); - - if (currentCount > prevCount) - { - BoundingVolumef boundingVolume(renderable->GetAABB()); - boundingVolume.Update(worldInstance->GetWorldMatrix()); - - auto& aabbData = viewerData.forwardAABB.emplace_back(); - aabbData.aabb = boundingVolume.aabb; - aabbData.count = currentCount - prevCount; - } - } - } - } + // Frustum culling const Matrix4f& viewProjMatrix = viewer->GetViewerInstance().GetViewProjMatrix(); Frustumf frustum; frustum.Extract(viewProjMatrix); - - viewerData.depthPrepassRegistry.Clear(); - viewerData.depthPrepassRenderQueue.Clear(); + + std::size_t visibilityHash = 5U; + + m_visibleRenderables.clear(); + for (const auto& [worldInstance, renderables] : m_renderables) { - std::size_t visibilityHash = 5U; + bool isInstanceVisible = false; - auto elementIt = viewerData.depthPrepassRenderElements.begin(); - for (auto&& [aabb, elementCount] : viewerData.depthPrepassAABB) + for (const auto& [renderable, renderableData] : renderables) { - if (!frustum.Contains(aabb)) - { - std::advance(elementIt, elementCount); + // Get global AABB + BoundingVolumef boundingVolume(renderable->GetAABB()); + boundingVolume.Update(worldInstance->GetWorldMatrix()); + + if (!frustum.Contains(boundingVolume.aabb)) continue; - } - for (std::size_t i = 0; i < elementCount; ++i) - { - auto& renderElement = *elementIt++; - renderElement->Register(viewerData.depthPrepassRegistry); - viewerData.depthPrepassRenderQueue.Insert(renderElement.get()); + auto& renderableData = m_visibleRenderables.emplace_back(); + renderableData.instancedRenderable = renderable; + renderableData.worldInstance = worldInstance.get(); - visibilityHash = CombineHash(visibilityHash, std::hash()(renderElement.get())); - } - } - - viewerData.depthPrepassRenderQueue.Sort([&](const RenderElement* element) - { - return element->ComputeSortingScore(viewerData.depthPrepassRegistry); - }); + isInstanceVisible = true; + visibilityHash = CombineHash(visibilityHash, std::hash()(renderable)); + } - if (viewerData.depthPrepassVisibilityHash != visibilityHash) + if (isInstanceVisible) + visibilityHash = CombineHash(visibilityHash, std::hash()(worldInstance.get())); + } + + if (viewerData.visibilityHash != visibilityHash) + { + viewerData.rebuildDepthPrepass = true; + viewerData.rebuildForwardPass = true; + + viewerData.visibilityHash = visibilityHash; + } + + if (viewerData.rebuildDepthPrepass) + { + viewerData.depthPrepassRenderElements.clear(); + + for (const auto& renderableData : m_visibleRenderables) + renderableData.instancedRenderable->BuildElement(m_depthPassIndex, *renderableData.worldInstance, viewerData.depthPrepassRenderElements); + + viewerData.depthPrepassRegistry.Clear(); + viewerData.depthPrepassRenderQueue.Clear(); + + for (const auto& renderElement : viewerData.depthPrepassRenderElements) { - viewerData.rebuildDepthPrepass = true; - viewerData.depthPrepassVisibilityHash = visibilityHash; + renderElement->Register(viewerData.depthPrepassRegistry); + viewerData.depthPrepassRenderQueue.Insert(renderElement.get()); } } - - viewerData.forwardRegistry.Clear(); - viewerData.forwardRenderQueue.Clear(); + + viewerData.depthPrepassRenderQueue.Sort([&](const RenderElement* element) { - std::size_t visibilityHash = 5U; - - auto elementIt = viewerData.forwardRenderElements.begin(); - for (auto&& [aabb, elementCount] : viewerData.forwardAABB) - { - if (!frustum.Contains(aabb)) - { - std::advance(elementIt, elementCount); - continue; - } - - for (std::size_t i = 0; i < elementCount; ++i) - { - auto& renderElement = *elementIt++; - renderElement->Register(viewerData.forwardRegistry); - viewerData.forwardRenderQueue.Insert(renderElement.get()); + return element->ComputeSortingScore(viewerData.depthPrepassRegistry); + }); - visibilityHash = CombineHash(visibilityHash, std::hash()(renderElement.get())); - } - } - - viewerData.forwardRenderQueue.Sort([&](const RenderElement* element) - { - return element->ComputeSortingScore(viewerData.forwardRegistry); - }); + if (viewerData.rebuildForwardPass) + { + viewerData.forwardRenderElements.clear(); - if (viewerData.forwardVisibilityHash != visibilityHash) + for (const auto& renderableData : m_visibleRenderables) + renderableData.instancedRenderable->BuildElement(m_forwardPassIndex, *renderableData.worldInstance, viewerData.forwardRenderElements); + + viewerData.forwardRegistry.Clear(); + viewerData.forwardRenderQueue.Clear(); + for (const auto& renderElement : viewerData.forwardRenderElements) { - viewerData.rebuildForwardPass = true; - viewerData.forwardVisibilityHash = visibilityHash; - } - } - } - - if (m_bakedFrameGraph.Resize(renderFrame)) - { - const std::shared_ptr& sampler = graphics->GetSamplerCache().Get({}); - for (auto&& [_, viewerData] : m_viewers) - { - if (viewerData.blitShaderBinding) - renderFrame.PushForRelease(std::move(viewerData.blitShaderBinding)); - - viewerData.blitShaderBinding = graphics->GetBlitPipelineLayout()->AllocateShaderBinding(0); - viewerData.blitShaderBinding->Update({ - { - 0, - ShaderBinding::TextureBinding { - m_bakedFrameGraph.GetAttachmentTexture(viewerData.colorAttachment).get(), - sampler.get() - } - } - }); - } - } - - m_bakedFrameGraph.Execute(renderFrame); - m_rebuildFrameGraph = false; - - const Vector2ui& frameSize = renderFrame.GetSize(); - for (auto&& [viewer, viewerData] : m_viewers) + renderElement->Register(viewerData.forwardRegistry); + viewerData.forwardRenderQueue.Insert(renderElement.get()); + } + } + + viewerData.forwardRenderQueue.Sort([&](const RenderElement* element) + { + return element->ComputeSortingScore(viewerData.forwardRegistry); + }); + } + + if (m_bakedFrameGraph.Resize(renderFrame)) { - viewerData.rebuildForwardPass = false; - viewerData.rebuildDepthPrepass = false; - - const RenderTarget& renderTarget = viewer->GetRenderTarget(); - Recti renderRegion(0, 0, frameSize.x, frameSize.y); - const ShaderBindingPtr& blitShaderBinding = viewerData.blitShaderBinding; - const std::shared_ptr& sourceTexture = m_bakedFrameGraph.GetAttachmentTexture(viewerData.colorAttachment); - - renderFrame.Execute([&](CommandBufferBuilder& builder) - { - builder.TextureBarrier(PipelineStage::ColorOutput, PipelineStage::FragmentShader, MemoryAccess::ColorWrite, MemoryAccess::ShaderRead, TextureLayout::ColorOutput, TextureLayout::ColorInput, *sourceTexture); - - std::array clearValues; - clearValues[0].color = Color::Black; - clearValues[1].depth = 1.f; - clearValues[1].stencil = 0; - - builder.BeginDebugRegion("Main window rendering", Color::Green); - { - builder.BeginRenderPass(renderTarget.GetFramebuffer(renderFrame.GetFramebufferIndex()), renderTarget.GetRenderPass(), renderRegion, { clearValues[0], clearValues[1] }); - { - builder.SetScissor(renderRegion); - builder.SetViewport(renderRegion); - - builder.BindPipeline(*graphics->GetBlitPipeline()); - builder.BindVertexBuffer(0, *graphics->GetFullscreenVertexBuffer()); - builder.BindShaderBinding(0, *blitShaderBinding); - - builder.Draw(3); - } - builder.EndRenderPass(); - } - builder.EndDebugRegion(); - - }, QueueType::Graphics); - } - } - - void ForwardFramePipeline::UnregisterInstancedDrawable(const WorldInstancePtr& worldInstance, const InstancedRenderable* instancedRenderable) - { - auto instanceIt = m_renderables.find(worldInstance); - if (instanceIt == m_renderables.end()) - return; - - auto& instancedRenderables = instanceIt->second; - - auto renderableIt = instancedRenderables.find(instancedRenderable); - if (renderableIt == instancedRenderables.end()) - return; - - if (instancedRenderables.size() > 1) - instancedRenderables.erase(renderableIt); - else - { - m_removedWorldInstances.insert(worldInstance); - m_renderables.erase(instanceIt);; - } - - std::size_t matCount = instancedRenderable->GetMaterialCount(); - for (std::size_t i = 0; i < matCount; ++i) - { - if (MaterialPass* pass = instancedRenderable->GetMaterial(i)->GetPass(m_depthPassIndex)) - UnregisterMaterialPass(pass); - - if (MaterialPass* pass = instancedRenderable->GetMaterial(i)->GetPass(m_forwardPassIndex)) - UnregisterMaterialPass(pass); - } - - for (auto&& [viewer, viewerData] : m_viewers) + const std::shared_ptr& sampler = graphics->GetSamplerCache().Get({}); + for (auto&& [_, viewerData] : m_viewers) + { + if (viewerData.blitShaderBinding) + renderFrame.PushForRelease(std::move(viewerData.blitShaderBinding)); + + viewerData.blitShaderBinding = graphics->GetBlitPipelineLayout()->AllocateShaderBinding(0); + viewerData.blitShaderBinding->Update({ + { + 0, + ShaderBinding::TextureBinding { + m_bakedFrameGraph.GetAttachmentTexture(viewerData.colorAttachment).get(), + sampler.get() + } + } + }); + } + } + + m_bakedFrameGraph.Execute(renderFrame); + m_rebuildFrameGraph = false; + + const Vector2ui& frameSize = renderFrame.GetSize(); + for (auto&& [viewer, viewerData] : m_viewers) { - viewerData.rebuildDepthPrepass = true; + viewerData.rebuildForwardPass = false; + viewerData.rebuildDepthPrepass = false; + + const RenderTarget& renderTarget = viewer->GetRenderTarget(); + Recti renderRegion(0, 0, frameSize.x, frameSize.y); + const ShaderBindingPtr& blitShaderBinding = viewerData.blitShaderBinding; + const std::shared_ptr& sourceTexture = m_bakedFrameGraph.GetAttachmentTexture(viewerData.colorAttachment); + + renderFrame.Execute([&](CommandBufferBuilder& builder) + { + builder.TextureBarrier(PipelineStage::ColorOutput, PipelineStage::FragmentShader, MemoryAccess::ColorWrite, MemoryAccess::ShaderRead, TextureLayout::ColorOutput, TextureLayout::ColorInput, *sourceTexture); + + std::array clearValues; + clearValues[0].color = Color::Black; + clearValues[1].depth = 1.f; + clearValues[1].stencil = 0; + + builder.BeginDebugRegion("Main window rendering", Color::Green); + { + builder.BeginRenderPass(renderTarget.GetFramebuffer(renderFrame.GetFramebufferIndex()), renderTarget.GetRenderPass(), renderRegion, { clearValues[0], clearValues[1] }); + { + builder.SetScissor(renderRegion); + builder.SetViewport(renderRegion); + + builder.BindPipeline(*graphics->GetBlitPipeline()); + builder.BindVertexBuffer(0, *graphics->GetFullscreenVertexBuffer()); + builder.BindShaderBinding(0, *blitShaderBinding); + + builder.Draw(3); + } + builder.EndRenderPass(); + } + builder.EndDebugRegion(); + + }, QueueType::Graphics); + } + } + + void ForwardFramePipeline::UnregisterInstancedDrawable(const WorldInstancePtr& worldInstance, const InstancedRenderable* instancedRenderable) + { + auto instanceIt = m_renderables.find(worldInstance); + if (instanceIt == m_renderables.end()) + return; + + auto& instancedRenderables = instanceIt->second; + + auto renderableIt = instancedRenderables.find(instancedRenderable); + if (renderableIt == instancedRenderables.end()) + return; + + if (instancedRenderables.size() > 1) + instancedRenderables.erase(renderableIt); + else + { + m_removedWorldInstances.insert(worldInstance); + m_renderables.erase(instanceIt);; + } + + std::size_t matCount = instancedRenderable->GetMaterialCount(); + for (std::size_t i = 0; i < matCount; ++i) + { + if (MaterialPass* pass = instancedRenderable->GetMaterial(i)->GetPass(m_depthPassIndex)) + UnregisterMaterialPass(pass); + + if (MaterialPass* pass = instancedRenderable->GetMaterial(i)->GetPass(m_forwardPassIndex)) + UnregisterMaterialPass(pass); + } + + for (auto&& [viewer, viewerData] : m_viewers) + { + viewerData.rebuildDepthPrepass = true; viewerData.rebuildForwardPass = true; - } - } - - void ForwardFramePipeline::UnregisterViewer(AbstractViewer* viewerInstance) - { - m_viewers.erase(viewerInstance); - m_rebuildFrameGraph = true; - } - - BakedFrameGraph ForwardFramePipeline::BuildFrameGraph() - { - FrameGraph frameGraph; - - for (auto&& [viewer, viewerData] : m_viewers) - { - viewerData.colorAttachment = frameGraph.AddAttachment({ - "Color", - PixelFormat::RGBA8 - }); - - viewerData.depthStencilAttachment = frameGraph.AddAttachment({ - "Depth-stencil buffer", - Graphics::Instance()->GetPreferredDepthStencilFormat() - }); - } - - for (auto&& [viewer, data] : m_viewers) + } + } + + void ForwardFramePipeline::UnregisterViewer(AbstractViewer* viewerInstance) + { + m_viewers.erase(viewerInstance); + m_rebuildFrameGraph = true; + } + + BakedFrameGraph ForwardFramePipeline::BuildFrameGraph() + { + FrameGraph frameGraph; + + for (auto&& [viewer, viewerData] : m_viewers) + { + viewerData.colorAttachment = frameGraph.AddAttachment({ + "Color", + PixelFormat::RGBA8 + }); + + viewerData.depthStencilAttachment = frameGraph.AddAttachment({ + "Depth-stencil buffer", + Graphics::Instance()->GetPreferredDepthStencilFormat() + }); + } + + for (auto&& [viewer, data] : m_viewers) { auto& viewerData = data; - - FramePass& depthPrepass = frameGraph.AddPass("Depth pre-pass"); - depthPrepass.SetDepthStencilOutput(viewerData.depthStencilAttachment); - depthPrepass.SetDepthStencilClear(1.f, 0); - - depthPrepass.SetExecutionCallback([&]() - { - if (viewerData.rebuildDepthPrepass) - return FramePassExecution::UpdateAndExecute; - else - return FramePassExecution::Execute; - }); - - depthPrepass.SetCommandCallback([this, viewer = viewer, &viewerData](CommandBufferBuilder& builder, const Recti& /*renderRect*/) - { - Recti viewport = viewer->GetViewport(); - - builder.SetScissor(viewport); - builder.SetViewport(viewport); - - builder.BindShaderBinding(Graphics::ViewerBindingSet, viewer->GetViewerInstance().GetShaderBinding()); - - ProcessRenderQueue(builder, viewerData.depthPrepassRenderQueue); - }); - - FramePass& forwardPass = frameGraph.AddPass("Forward pass"); - forwardPass.AddOutput(viewerData.colorAttachment); - forwardPass.SetDepthStencilInput(viewerData.depthStencilAttachment); - //forwardPass.SetDepthStencilOutput(viewerData.depthStencilAttachment); - - forwardPass.SetClearColor(0, Color::Black); - forwardPass.SetDepthStencilClear(1.f, 0); - - forwardPass.SetExecutionCallback([&]() - { - if (viewerData.rebuildForwardPass) - return FramePassExecution::UpdateAndExecute; - else - return FramePassExecution::Execute; - }); - - forwardPass.SetCommandCallback([this, viewer = viewer, &viewerData](CommandBufferBuilder& builder, const Recti& /*renderRect*/) - { - Recti viewport = viewer->GetViewport(); - - builder.SetScissor(viewport); - builder.SetViewport(viewport); - - builder.BindShaderBinding(Graphics::ViewerBindingSet, viewer->GetViewerInstance().GetShaderBinding()); - - ProcessRenderQueue(builder, viewerData.forwardRenderQueue); - }); - } - - //FIXME: This doesn't handle multiple window viewers - for (auto&& [viewer, viewerData] : m_viewers) - frameGraph.SetBackbufferOutput(viewerData.colorAttachment); - - return frameGraph.Bake(); - } - - void ForwardFramePipeline::RegisterMaterialPass(MaterialPass* material) - { - auto it = m_materials.find(material); - if (it == m_materials.end()) - { - it = m_materials.emplace(material, MaterialData{}).first; - it->second.onMaterialInvalided.Connect(material->OnMaterialInvalidated, [this, material](const MaterialPass* /*material*/) - { - m_invalidatedMaterials.insert(material); - }); - - m_invalidatedMaterials.insert(material); - } - - it->second.usedCount++; - } - - void ForwardFramePipeline::ProcessRenderQueue(CommandBufferBuilder& builder, const RenderQueue& renderQueue) - { - if (renderQueue.empty()) - return; - - auto it = renderQueue.begin(); - auto itEnd = renderQueue.end(); - while (it != itEnd) - { - const RenderElement* element = *it; - UInt8 elementType = element->GetElementType(); - - const Pointer* first = it; - - ++it; - while (it != itEnd && (*it)->GetElementType() == elementType) - ++it; - - std::size_t count = it - first; - - if (elementType >= m_elementRenderers.size() || !m_elementRenderers[elementType]) - continue; - - ElementRenderer& elementRenderer = *m_elementRenderers[elementType]; - elementRenderer.Render(builder, first, count); - } - } - - void ForwardFramePipeline::UnregisterMaterialPass(MaterialPass* material) - { - auto it = m_materials.find(material); - assert(it != m_materials.end()); - - MaterialData& materialData = it->second; - assert(materialData.usedCount > 0); - if (--materialData.usedCount == 0) - m_materials.erase(material); - } -} + + FramePass& depthPrepass = frameGraph.AddPass("Depth pre-pass"); + depthPrepass.SetDepthStencilOutput(viewerData.depthStencilAttachment); + depthPrepass.SetDepthStencilClear(1.f, 0); + + depthPrepass.SetExecutionCallback([&]() + { + if (viewerData.rebuildDepthPrepass) + return FramePassExecution::UpdateAndExecute; + else + return FramePassExecution::Execute; + }); + + depthPrepass.SetCommandCallback([this, viewer = viewer, &viewerData](CommandBufferBuilder& builder, const Recti& /*renderRect*/) + { + Recti viewport = viewer->GetViewport(); + + builder.SetScissor(viewport); + builder.SetViewport(viewport); + + builder.BindShaderBinding(Graphics::ViewerBindingSet, viewer->GetViewerInstance().GetShaderBinding()); + + ProcessRenderQueue(builder, viewerData.depthPrepassRenderQueue); + }); + + FramePass& forwardPass = frameGraph.AddPass("Forward pass"); + forwardPass.AddOutput(viewerData.colorAttachment); + forwardPass.SetDepthStencilInput(viewerData.depthStencilAttachment); + //forwardPass.SetDepthStencilOutput(viewerData.depthStencilAttachment); + + forwardPass.SetClearColor(0, Color::Black); + forwardPass.SetDepthStencilClear(1.f, 0); + + forwardPass.SetExecutionCallback([&]() + { + if (viewerData.rebuildForwardPass) + return FramePassExecution::UpdateAndExecute; + else + return FramePassExecution::Execute; + }); + + forwardPass.SetCommandCallback([this, viewer = viewer, &viewerData](CommandBufferBuilder& builder, const Recti& /*renderRect*/) + { + Recti viewport = viewer->GetViewport(); + + builder.SetScissor(viewport); + builder.SetViewport(viewport); + + builder.BindShaderBinding(Graphics::ViewerBindingSet, viewer->GetViewerInstance().GetShaderBinding()); + + ProcessRenderQueue(builder, viewerData.forwardRenderQueue); + }); + } + + //FIXME: This doesn't handle multiple window viewers + for (auto&& [viewer, viewerData] : m_viewers) + frameGraph.SetBackbufferOutput(viewerData.colorAttachment); + + return frameGraph.Bake(); + } + + void ForwardFramePipeline::RegisterMaterialPass(MaterialPass* material) + { + auto it = m_materials.find(material); + if (it == m_materials.end()) + { + it = m_materials.emplace(material, MaterialData{}).first; + it->second.onMaterialInvalided.Connect(material->OnMaterialInvalidated, [this, material](const MaterialPass* /*material*/) + { + m_invalidatedMaterials.insert(material); + }); + + m_invalidatedMaterials.insert(material); + } + + it->second.usedCount++; + } + + void ForwardFramePipeline::ProcessRenderQueue(CommandBufferBuilder& builder, const RenderQueue& renderQueue) + { + if (renderQueue.empty()) + return; + + auto it = renderQueue.begin(); + auto itEnd = renderQueue.end(); + while (it != itEnd) + { + const RenderElement* element = *it; + UInt8 elementType = element->GetElementType(); + + const Pointer* first = it; + + ++it; + while (it != itEnd && (*it)->GetElementType() == elementType) + ++it; + + std::size_t count = it - first; + + if (elementType >= m_elementRenderers.size() || !m_elementRenderers[elementType]) + continue; + + ElementRenderer& elementRenderer = *m_elementRenderers[elementType]; + elementRenderer.Render(builder, first, count); + } + } + + void ForwardFramePipeline::UnregisterMaterialPass(MaterialPass* material) + { + auto it = m_materials.find(material); + assert(it != m_materials.end()); + + MaterialData& materialData = it->second; + assert(materialData.usedCount > 0); + if (--materialData.usedCount == 0) + m_materials.erase(material); + } +} diff --git a/src/Nazara/Graphics/Model.cpp b/src/Nazara/Graphics/Model.cpp index 9e49d774b..fb967da38 100644 --- a/src/Nazara/Graphics/Model.cpp +++ b/src/Nazara/Graphics/Model.cpp @@ -31,7 +31,7 @@ namespace Nz } } - void Model::BuildElement(std::size_t passIndex, WorldInstance& worldInstance, std::vector>& elements) const + void Model::BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, std::vector>& elements) const { for (std::size_t i = 0; i < m_submeshes.size(); ++i) {