From 416441bd3e3caca84dcdadae5ae8cadc66bc51f3 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 15 Sep 2016 14:21:06 +0200 Subject: [PATCH] Sdk/RenderSystem: Regenerate renderqueue only when needed Former-commit-id: 8883c832e1ea34172cf7b21e949f931f188542cf [formerly 3e5d67644e985fd6b5dc0d24bd431e575b9192b7] [formerly 9240e84ee3e77f9b4fa525c5e614ee32c4a59501 [formerly 4f5f4c5d6f366619e888feb8e7fcc8379cf0fabd]] Former-commit-id: ebc0908d6be73e8509e322450bfe6c2cfcc89ae8 [formerly b621f6434040e1c78841d51e905eda23fdad9b62] Former-commit-id: 382e99294b674b9740dc9c9b5f5e6dd39b103c52 --- .../NDK/Components/CameraComponent.hpp | 3 + .../NDK/Components/CameraComponent.inl | 22 +++++ SDK/include/NDK/Systems/RenderSystem.hpp | 1 + SDK/src/NDK/Components/GraphicsComponent.cpp | 3 + SDK/src/NDK/Systems/RenderSystem.cpp | 53 ++++++++---- include/Nazara/Graphics/CullingList.hpp | 8 +- include/Nazara/Graphics/CullingList.inl | 81 ++++++++++++++++--- 7 files changed, 145 insertions(+), 26 deletions(-) diff --git a/SDK/include/NDK/Components/CameraComponent.hpp b/SDK/include/NDK/Components/CameraComponent.hpp index af2245b11..b8bc8a0e7 100644 --- a/SDK/include/NDK/Components/CameraComponent.hpp +++ b/SDK/include/NDK/Components/CameraComponent.hpp @@ -61,6 +61,8 @@ namespace Ndk inline void SetZFar(float zFar); inline void SetZNear(float zNear); + inline bool UpdateVisibility(std::size_t visibilityHash); + static ComponentIndex componentIndex; private: @@ -86,6 +88,7 @@ namespace Ndk NazaraSlot(Nz::RenderTarget, OnRenderTargetRelease, m_targetReleaseSlot); NazaraSlot(Nz::RenderTarget, OnRenderTargetSizeChange, m_targetResizeSlot); + std::size_t m_visibilityHash; Nz::ProjectionType m_projectionType; mutable Nz::Frustumf m_frustum; mutable Nz::Matrix4f m_projectionMatrix; diff --git a/SDK/include/NDK/Components/CameraComponent.inl b/SDK/include/NDK/Components/CameraComponent.inl index d42d0e152..f16fee99a 100644 --- a/SDK/include/NDK/Components/CameraComponent.inl +++ b/SDK/include/NDK/Components/CameraComponent.inl @@ -13,6 +13,7 @@ namespace Ndk */ inline CameraComponent::CameraComponent() : + m_visibilityHash(0U), m_projectionType(Nz::ProjectionType_Perspective), m_targetRegion(0.f, 0.f, 1.f, 1.f), m_target(nullptr), @@ -38,6 +39,7 @@ namespace Ndk inline CameraComponent::CameraComponent(const CameraComponent& camera) : Component(camera), AbstractViewer(camera), + m_visibilityHash(camera.m_visibilityHash), m_projectionType(camera.m_projectionType), m_targetRegion(camera.m_targetRegion), m_target(nullptr), @@ -371,6 +373,26 @@ namespace Ndk InvalidateProjectionMatrix(); } + /*! + * \brief Update the camera component visibility hash + * + * This is used with CullingList (which produce a visibility hash) + * + * \param visibilityHash New visibility hash + * + * \return True if the visibility hash is not the same as before + */ + inline bool CameraComponent::UpdateVisibility(std::size_t visibilityHash) + { + if (m_visibilityHash != visibilityHash) + { + m_visibilityHash = visibilityHash; + return true; + } + + return false; + } + /*! * \brief Invalidates the frustum */ diff --git a/SDK/include/NDK/Systems/RenderSystem.hpp b/SDK/include/NDK/Systems/RenderSystem.hpp index a9f38d950..61ccefe75 100644 --- a/SDK/include/NDK/Systems/RenderSystem.hpp +++ b/SDK/include/NDK/Systems/RenderSystem.hpp @@ -69,6 +69,7 @@ namespace Ndk Nz::Matrix4f m_coordinateSystemMatrix; Nz::RenderTexture m_shadowRT; bool m_coordinateSystemInvalidated; + bool m_forceRenderQueueInvalidation; }; } diff --git a/SDK/src/NDK/Components/GraphicsComponent.cpp b/SDK/src/NDK/Components/GraphicsComponent.cpp index af54d4f8a..a90853d1d 100644 --- a/SDK/src/NDK/Components/GraphicsComponent.cpp +++ b/SDK/src/NDK/Components/GraphicsComponent.cpp @@ -89,6 +89,9 @@ namespace Ndk Renderable& r = m_renderables[index]; r.dataUpdated = false; r.renderable->InvalidateData(&r.data, flags); + + for (VolumeCullingEntry& entry : m_volumeCullingEntries) + entry.listEntry.ForceInvalidation(); } /*! diff --git a/SDK/src/NDK/Systems/RenderSystem.cpp b/SDK/src/NDK/Systems/RenderSystem.cpp index 303caba9d..20fe2ad4b 100644 --- a/SDK/src/NDK/Systems/RenderSystem.cpp +++ b/SDK/src/NDK/Systems/RenderSystem.cpp @@ -30,7 +30,8 @@ namespace Ndk */ RenderSystem::RenderSystem() : m_coordinateSystemMatrix(Nz::Matrix4f::Identity()), - m_coordinateSystemInvalidated(true) + m_coordinateSystemInvalidated(true), + m_forceRenderQueueInvalidation(false) { ChangeRenderTechnique(); SetDefaultBackground(Nz::ColorBackground::New()); @@ -44,6 +45,8 @@ namespace Ndk */ void RenderSystem::OnEntityRemoved(Entity* entity) { + m_forceRenderQueueInvalidation = true; //< Hackfix until lights and particles are handled by culling list + m_cameras.Remove(entity); m_directionalLights.Remove(entity); m_drawables.Remove(entity); @@ -102,6 +105,8 @@ namespace Ndk if (entity->HasComponent() && entity->HasComponent()) { + m_forceRenderQueueInvalidation = true; //< Hackfix until lights and particles are handled by culling list + LightComponent& lightComponent = entity->GetComponent(); if (lightComponent.GetLightType() == Nz::LightType_Directional) { @@ -118,15 +123,25 @@ namespace Ndk } else { + m_forceRenderQueueInvalidation = true; //< Hackfix until lights and particles are handled by culling list + m_directionalLights.Remove(entity); m_lights.Remove(entity); m_pointSpotLights.Remove(entity); } if (entity->HasComponent()) + { + m_forceRenderQueueInvalidation = true; //< Hackfix until lights and particles are handled by culling list + m_particleGroups.Insert(entity); + } else + { + m_forceRenderQueueInvalidation = true; //< Hackfix until lights and particles are handled by culling list + m_particleGroups.Remove(entity); + } } /*! @@ -168,26 +183,32 @@ namespace Ndk graphicsComponent.EnsureBoundingVolumeUpdate(); } - m_drawableCulling.Cull(camComponent.GetFrustum()); + bool forceInvalidation = false; + std::size_t visibilityHash = m_drawableCulling.Cull(camComponent.GetFrustum(), &forceInvalidation); - renderQueue->Clear(); - for (const GraphicsComponent* gfxComponent : m_drawableCulling) - gfxComponent->AddToRenderQueue(renderQueue); - - for (const Ndk::EntityHandle& light : m_lights) + if (camComponent.UpdateVisibility(visibilityHash) || m_forceRenderQueueInvalidation || forceInvalidation) { - LightComponent& lightComponent = light->GetComponent(); - NodeComponent& lightNode = light->GetComponent(); + renderQueue->Clear(); + for (const GraphicsComponent* gfxComponent : m_drawableCulling) + gfxComponent->AddToRenderQueue(renderQueue); - ///TODO: Cache somehow? - lightComponent.AddToRenderQueue(renderQueue, Nz::Matrix4f::ConcatenateAffine(m_coordinateSystemMatrix, lightNode.GetTransformMatrix())); - } + for (const Ndk::EntityHandle& light : m_lights) + { + LightComponent& lightComponent = light->GetComponent(); + NodeComponent& lightNode = light->GetComponent(); - for (const Ndk::EntityHandle& particleGroup : m_particleGroups) - { - ParticleGroupComponent& groupComponent = particleGroup->GetComponent(); + ///TODO: Cache somehow? + lightComponent.AddToRenderQueue(renderQueue, Nz::Matrix4f::ConcatenateAffine(m_coordinateSystemMatrix, lightNode.GetTransformMatrix())); + } - groupComponent.AddToRenderQueue(renderQueue, Nz::Matrix4f::Identity()); //< ParticleGroup doesn't use any transform matrix (yet) + for (const Ndk::EntityHandle& particleGroup : m_particleGroups) + { + ParticleGroupComponent& groupComponent = particleGroup->GetComponent(); + + groupComponent.AddToRenderQueue(renderQueue, Nz::Matrix4f::Identity()); //< ParticleGroup doesn't use any transform matrix (yet) + } + + m_forceRenderQueueInvalidation = false; } camComponent.ApplyView(); diff --git a/include/Nazara/Graphics/CullingList.hpp b/include/Nazara/Graphics/CullingList.hpp index afefa37a8..aee9b61cb 100644 --- a/include/Nazara/Graphics/CullingList.hpp +++ b/include/Nazara/Graphics/CullingList.hpp @@ -39,7 +39,7 @@ namespace Nz CullingList(CullingList&& renderable) = delete; ~CullingList(); - std::size_t Cull(const Frustumf& frustum); + std::size_t Cull(const Frustumf& frustum, bool* forceInvalidation = nullptr); NoTestEntry RegisterNoTest(const T* renderable); SphereEntry RegisterSphereTest(const T* renderable); @@ -73,6 +73,7 @@ namespace Nz NazaraSignal(OnCullingListRelease, CullingList* /*cullingList*/); private: + inline void NotifyForceInvalidation(CullTest type, std::size_t index); inline void NotifyMovement(CullTest type, std::size_t index, void* oldPtr, void* newPtr); inline void NotifyRelease(CullTest type, std::size_t index); inline void NotifySphereUpdate(std::size_t index, const Spheref& sphere); @@ -82,6 +83,7 @@ namespace Nz { NoTestEntry* entry; const T* renderable; + bool forceInvalidation; }; struct SphereVisibilityEntry @@ -89,6 +91,7 @@ namespace Nz Spheref sphere; SphereEntry* entry; const T* renderable; + bool forceInvalidation; }; struct VolumeVisibilityEntry @@ -96,6 +99,7 @@ namespace Nz BoundingVolumef volume; VolumeEntry* entry; const T* renderable; + bool forceInvalidation; }; std::vector m_noTestList; @@ -114,6 +118,8 @@ namespace Nz Entry(Entry&& entry); ~Entry(); + void ForceInvalidation(); + CullingList* GetParent() const; void UpdateIndex(std::size_t index); diff --git a/include/Nazara/Graphics/CullingList.inl b/include/Nazara/Graphics/CullingList.inl index 64650bfa3..617ccfbfc 100644 --- a/include/Nazara/Graphics/CullingList.inl +++ b/include/Nazara/Graphics/CullingList.inl @@ -1,47 +1,72 @@ -#include "CullingList.hpp" // Copyright (C) 2015 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 + namespace Nz { template - inline CullingList::~CullingList() + CullingList::~CullingList() { OnCullingListRelease(this); } template - std::size_t CullingList::Cull(const Frustumf& frustum) + std::size_t CullingList::Cull(const Frustumf& frustum, bool* forceInvalidation) { m_results.clear(); + bool forcedInvalidation = false; + std::size_t visibleHash = 0U; - for (const NoTestVisibilityEntry& entry : m_noTestList) + for (NoTestVisibilityEntry& entry : m_noTestList) { m_results.push_back(entry.renderable); Nz::HashCombine(visibleHash, entry.renderable); + + if (entry.forceInvalidation) + { + forcedInvalidation = true; + entry.forceInvalidation = false; + } } - for (const SphereVisibilityEntry& entry : m_sphereTestList) + for (SphereVisibilityEntry& entry : m_sphereTestList) { if (frustum.Contains(entry.sphere)) { m_results.push_back(entry.renderable); Nz::HashCombine(visibleHash, entry.renderable); + + if (entry.forceInvalidation) + { + forcedInvalidation = true; + entry.forceInvalidation = false; + } } } - for (const VolumeVisibilityEntry& entry : m_volumeTestList) + for (VolumeVisibilityEntry& entry : m_volumeTestList) { if (frustum.Contains(entry.volume)) { m_results.push_back(entry.renderable); Nz::HashCombine(visibleHash, entry.renderable); + + if (entry.forceInvalidation) + { + forcedInvalidation = true; + entry.forceInvalidation = false; + } } } + if (forceInvalidation) + *forceInvalidation = forcedInvalidation; + return visibleHash; } @@ -49,7 +74,7 @@ namespace Nz typename CullingList::NoTestEntry CullingList::RegisterNoTest(const T* renderable) { NoTestEntry entry(this, m_noTestList.size()); - m_noTestList.emplace_back(NoTestVisibilityEntry{&entry, renderable}); //< Address of entry will be updated when moving + m_noTestList.emplace_back(NoTestVisibilityEntry{&entry, renderable, false}); //< Address of entry will be updated when moving return entry; } @@ -58,7 +83,7 @@ namespace Nz typename CullingList::SphereEntry CullingList::RegisterSphereTest(const T* renderable) { SphereEntry entry(this, m_sphereTestList.size()); - m_sphereTestList.emplace_back(SphereVisibilityEntry{Nz::Spheref(), &entry, renderable}); //< Address of entry will be updated when moving + m_sphereTestList.emplace_back(SphereVisibilityEntry{Nz::Spheref(), &entry, renderable, false}); //< Address of entry will be updated when moving return entry; } @@ -67,7 +92,7 @@ namespace Nz typename CullingList::VolumeEntry CullingList::RegisterVolumeTest(const T* renderable) { VolumeEntry entry(this, m_volumeTestList.size()); - m_volumeTestList.emplace_back(VolumeVisibilityEntry{Nz::BoundingVolumef(), &entry, renderable}); //< Address of entry will be updated when moving + m_volumeTestList.emplace_back(VolumeVisibilityEntry{Nz::BoundingVolumef(), &entry, renderable, false}); //< Address of entry will be updated when moving return entry; } @@ -157,6 +182,35 @@ namespace Nz return m_results.size(); } + template + void CullingList::NotifyForceInvalidation(CullTest type, std::size_t index) + { + switch (type) + { + case CullTest::NoTest: + { + m_noTestList[index].forceInvalidation = true; + break; + } + + case CullTest::Sphere: + { + m_sphereTestList[index].forceInvalidation = true; + break; + } + + case CullTest::Volume: + { + m_volumeTestList[index].forceInvalidation = true; + break; + } + + default: + NazaraInternalError("Unhandled culltype"); + break; + } + } + template void CullingList::NotifyMovement(CullTest type, std::size_t index, void* oldPtr, void* newPtr) { @@ -279,6 +333,13 @@ namespace Nz m_parent->NotifyRelease(Type, m_index); } + template + template + void CullingList::Entry::ForceInvalidation() + { + m_parent->NotifyForceInvalidation(Type, m_index); + } + template template CullingList* CullingList::Entry::GetParent() const @@ -361,3 +422,5 @@ namespace Nz m_parent->NotifyVolumeUpdate(m_index, volume); } } + +#include