From b985f0c759e0ad5ae8597496efbe4dcca0b6f57c Mon Sep 17 00:00:00 2001 From: Sylvain Doremus Date: Mon, 29 May 2023 17:03:57 +0200 Subject: [PATCH] Clusters: Added support for scene samples clustering. --- data/vcpkg/ports/ashes/portfile.cmake | 4 +- data/vcpkg/ports/castor3d/portfile.cmake | 6 +- data/vcpkg/ports/rendergraph/portfile.cmake | 8 +- data/vcpkg/ports/shaderwriter/portfile.cmake | 4 +- external/RenderGraph | 2 +- external/vcpkg | 2 +- include/Core/Castor3D/Cache/LightCache.hpp | 16 +- include/Core/Castor3D/Limits.hpp | 6 +- .../Castor3D/Miscellaneous/makeVkType.hpp | 12 +- .../Render/Clustered/ClustersMask.hpp | 20 + .../Render/Clustered/FindUniqueClusters.hpp | 18 + .../Render/Clustered/FrustumClusters.hpp | 62 ++- .../Castor3D/Render/Prepass/DepthPass.hpp | 8 +- .../Core/Castor3D/Render/RenderTechnique.hpp | 1 + include/Core/Castor3D/Scene/Light/Light.hpp | 5 + .../Castor3D/Scene/Light/LightCategory.hpp | 8 +- include/Core/Castor3D/Scene/SceneModule.hpp | 2 +- .../Shader/ShaderBuffers/LightBuffer.hpp | 11 + .../Shader/ShaderBuffers/PassBuffer.hpp | 1 + .../Shader/Shaders/GlslClusteredLights.hpp | 40 ++ include/Core/CastorUtils/Data/Endianness.hpp | 422 +++++++++++++++--- include/Core/CastorUtils/Math/Math.hpp | 59 +++ source/Core/Castor3D/CMakeLists.txt | 4 + source/Core/Castor3D/Cache/LightCache.cpp | 35 +- source/Core/Castor3D/DebugDefines.hpp | 1 + .../Clustered/AssignLightsToClusters.cpp | 52 ++- .../Render/Clustered/BuildLightsBVH.cpp | 12 +- .../Render/Clustered/ClustersMask.cpp | 254 +++++++++++ .../Render/Clustered/FindUniqueClusters.cpp | 145 ++++++ .../Render/Clustered/FrustumClusters.cpp | 95 ++-- .../Render/Clustered/ReduceLightsAABB.cpp | 8 +- .../Render/Clustered/SortLightsMortonCode.cpp | 8 +- .../Castor3D/Render/Prepass/DepthPass.cpp | 11 + .../Render/Prepass/PrepassRendering.cpp | 13 - .../Render/Prepass/VisibilityPass.cpp | 2 + .../Core/Castor3D/Render/RenderTechnique.cpp | 15 +- .../Castor3D/Scene/Light/DirectionalLight.cpp | 2 +- .../Castor3D/Scene/Light/LightCategory.cpp | 3 +- .../Core/Castor3D/Scene/Light/PointLight.cpp | 2 +- .../Core/Castor3D/Scene/Light/SpotLight.cpp | 2 +- source/Core/Castor3D/Scene/Scene.cpp | 6 +- .../Scene/SceneFileParser_Parsers.cpp | 34 ++ .../Shader/ShaderBuffers/LightBuffer.cpp | 102 +++-- .../Shader/ShaderBuffers/PassBuffer.cpp | 36 +- .../Shader/ShaderBuffers/SssProfileBuffer.cpp | 16 +- .../ShaderBuffers/TextureAnimationBuffer.cpp | 10 +- .../TextureConfigurationBuffer.cpp | 23 +- .../SceneExporter/Text/TextTextureUnit.cpp | 3 +- .../AtmosphereBackgroundPass.cpp | 3 +- tools/GuiCommon/System/SceneObjectsList.cpp | 38 +- vcpkg.json | 2 +- 51 files changed, 1362 insertions(+), 292 deletions(-) create mode 100644 include/Core/Castor3D/Render/Clustered/ClustersMask.hpp create mode 100644 include/Core/Castor3D/Render/Clustered/FindUniqueClusters.hpp create mode 100644 source/Core/Castor3D/Render/Clustered/ClustersMask.cpp create mode 100644 source/Core/Castor3D/Render/Clustered/FindUniqueClusters.cpp diff --git a/data/vcpkg/ports/ashes/portfile.cmake b/data/vcpkg/ports/ashes/portfile.cmake index 272af475fd..c8e8bf9f14 100644 --- a/data/vcpkg/ports/ashes/portfile.cmake +++ b/data/vcpkg/ports/ashes/portfile.cmake @@ -11,9 +11,9 @@ vcpkg_from_github( vcpkg_from_github( OUT_SOURCE_PATH CMAKE_SOURCE_PATH REPO DragonJoker/CMakeUtils - REF 89a4c8fd4f0a464403676b6b1f1c5d178f6255b3 + REF 4e0292ed50d76dab5fc8c81840ae0e021dc60c2a HEAD_REF master - SHA512 98c46a563f2e4a28d9c91f4f255c500118dd0c66a4422d42969bdcc16c1493581db45b709fc3167e1ced8fa628d51880cb459df0d6b3dc013b945f66597ec768 + SHA512 c79c6a5ef2e059b56d4de20cc73e74386bf8b6acea2f6b76fd9949a6a2760f82302c90419e4a753f50c30d01cc4f3a039e04b585f5c0d4461cce3464d9fb9c95 ) file(REMOVE_RECURSE "${SOURCE_PATH}/CMake") diff --git a/data/vcpkg/ports/castor3d/portfile.cmake b/data/vcpkg/ports/castor3d/portfile.cmake index 18e2e71760..5a1c6ff357 100644 --- a/data/vcpkg/ports/castor3d/portfile.cmake +++ b/data/vcpkg/ports/castor3d/portfile.cmake @@ -5,14 +5,14 @@ vcpkg_from_github( REPO DragonJoker/Castor3D REF 31c7acf35e4c5e5605df591fee61b989dc4d4d9d HEAD_REF master - SHA512 203dbd28c32e02e714726460cab5a6477bec03f5a63e08001074cd1fc8342b6d64b91369cdf3a6d55d6758991c59bce691c377f3c82aa866cd09ecea8f6a518a + SHA512 0 ) vcpkg_from_github(OUT_SOURCE_PATH CMAKE_SOURCE_PATH REPO DragonJoker/CMakeUtils - REF 7d355194fa795c437ce970cecf00e23ae10fc686 + REF 4e0292ed50d76dab5fc8c81840ae0e021dc60c2a HEAD_REF master - SHA512 ca25b19bdeb3e8fda7abc32f8548731f0ba1cd09889a70f6f287ad76d2fdfa0fedbb7f6f65b26d356ea51543bed8926c6bb463f8e8461b7d51d3b7b33134374c + SHA512 c79c6a5ef2e059b56d4de20cc73e74386bf8b6acea2f6b76fd9949a6a2760f82302c90419e4a753f50c30d01cc4f3a039e04b585f5c0d4461cce3464d9fb9c95 ) file(REMOVE_RECURSE "${SOURCE_PATH}/CMake") diff --git a/data/vcpkg/ports/rendergraph/portfile.cmake b/data/vcpkg/ports/rendergraph/portfile.cmake index 3f722d50a8..988c5bbc45 100644 --- a/data/vcpkg/ports/rendergraph/portfile.cmake +++ b/data/vcpkg/ports/rendergraph/portfile.cmake @@ -1,15 +1,15 @@ vcpkg_from_github(OUT_SOURCE_PATH SOURCE_PATH REPO DragonJoker/RenderGraph - REF e9f6b3243095d832f409e15fbafff4f73af6e401 + REF 1223fb79f141c62cda27406bab53d06cb3dc588a HEAD_REF master - SHA512 3609da52a6f5c5c213fcc56416cfc714403d0bc80742540990cab2973b2ee3e41e9629b04f379db84c2194acff6cecf11c4e86d4167ca78aa8606a85cbcaa433 + SHA512 82503225e44c9bd956b326c0eb42e5983bcb52a879f0aa23eb8bd2ba8cd214ead26e302c294609e0d0b73cc48d2eb4ca896cb806a5ce5146b220f1d208b813f1 ) vcpkg_from_github(OUT_SOURCE_PATH CMAKE_SOURCE_PATH REPO DragonJoker/CMakeUtils - REF 3818effff171f863d0c23e6fbbf79911f03cc6d3 + REF 4e0292ed50d76dab5fc8c81840ae0e021dc60c2a HEAD_REF master - SHA512 3a13b371adf24f530fdef6005d3a9105185eca131c9b8aba68615a593f76d6aac2c3c7f0ecf6ce430e2b854afca4abd99f1400a1e6665478c9daa34a8dac6f5b + SHA512 c79c6a5ef2e059b56d4de20cc73e74386bf8b6acea2f6b76fd9949a6a2760f82302c90419e4a753f50c30d01cc4f3a039e04b585f5c0d4461cce3464d9fb9c95 ) get_filename_component(SRC_PATH "${CMAKE_SOURCE_PATH}" DIRECTORY) diff --git a/data/vcpkg/ports/shaderwriter/portfile.cmake b/data/vcpkg/ports/shaderwriter/portfile.cmake index aaf33ee3cf..370b838a15 100644 --- a/data/vcpkg/ports/shaderwriter/portfile.cmake +++ b/data/vcpkg/ports/shaderwriter/portfile.cmake @@ -7,9 +7,9 @@ vcpkg_from_github(OUT_SOURCE_PATH SOURCE_PATH vcpkg_from_github(OUT_SOURCE_PATH CMAKE_SOURCE_PATH REPO DragonJoker/CMakeUtils - REF 3818effff171f863d0c23e6fbbf79911f03cc6d3 + REF 4e0292ed50d76dab5fc8c81840ae0e021dc60c2a HEAD_REF master - SHA512 3a13b371adf24f530fdef6005d3a9105185eca131c9b8aba68615a593f76d6aac2c3c7f0ecf6ce430e2b854afca4abd99f1400a1e6665478c9daa34a8dac6f5b + SHA512 c79c6a5ef2e059b56d4de20cc73e74386bf8b6acea2f6b76fd9949a6a2760f82302c90419e4a753f50c30d01cc4f3a039e04b585f5c0d4461cce3464d9fb9c95 ) file(REMOVE_RECURSE "${SOURCE_PATH}/CMake") diff --git a/external/RenderGraph b/external/RenderGraph index e9f6b32430..1223fb79f1 160000 --- a/external/RenderGraph +++ b/external/RenderGraph @@ -1 +1 @@ -Subproject commit e9f6b3243095d832f409e15fbafff4f73af6e401 +Subproject commit 1223fb79f141c62cda27406bab53d06cb3dc588a diff --git a/external/vcpkg b/external/vcpkg index 1c5a340f6e..8a2b7de29d 160000 --- a/external/vcpkg +++ b/external/vcpkg @@ -1 +1 @@ -Subproject commit 1c5a340f6e10985e2d92af174a68dbd15c1fa4e1 +Subproject commit 8a2b7de29d42d713e4816d542cd610ee59dff63e diff --git a/include/Core/Castor3D/Cache/LightCache.hpp b/include/Core/Castor3D/Cache/LightCache.hpp index 7f4de26f7a..ff7f348fa0 100644 --- a/include/Core/Castor3D/Cache/LightCache.hpp +++ b/include/Core/Castor3D/Cache/LightCache.hpp @@ -141,17 +141,22 @@ namespace castor3d C3D_API ashes::WriteDescriptorSet getBinding( uint32_t binding , VkDeviceSize offset , VkDeviceSize size )const; + /** + *\~english + *\param[in] type The light type. + *\return The number of light sources of the given type, in the buffer. + *\~french + *\brief Crée le descriptor write pour le buffer de sources lumineuses. + *\param[in] type Le type de lumière. + *\return Le nombre de sources lumineuses du type donné, dans le buffer. + */ + C3D_API uint32_t getLightsBufferCount( LightType type )const noexcept; uint32_t getLightsCount( LightType type )const { return uint32_t( getLights( type ).size() ); } - GpuBufferOffsetT< castor::Point2ui > getLightsIndexOffset()const noexcept - { - return m_lightsIndexOffset; - } - bool isDirty()const noexcept { return m_dirty || !m_dirtyLights.empty(); @@ -171,7 +176,6 @@ namespace castor3d private: LightsRefArray m_dirtyLights; LightBufferUPtr m_lightBuffer; - GpuBufferOffsetT< castor::Point2ui > m_lightsIndexOffset; std::vector< Light * > m_pendingLights; bool m_dirty{ true }; }; diff --git a/include/Core/Castor3D/Limits.hpp b/include/Core/Castor3D/Limits.hpp index e9c01fbc7f..5f3875a4e8 100644 --- a/include/Core/Castor3D/Limits.hpp +++ b/include/Core/Castor3D/Limits.hpp @@ -94,7 +94,7 @@ namespace castor3d * Directional Light Shadows. */ //@{ - static uint32_t constexpr ShadowMapDirectionalTextureSize = 2048u; + static uint32_t constexpr ShadowMapDirectionalTextureSize = 2'048u; static uint32_t constexpr MaxDirectionalCascadesCount = 6u; //@} /** @@ -123,7 +123,6 @@ namespace castor3d // Pass Buffer. static uint32_t constexpr MaxMaterialsCount = 2'048u; static uint32_t constexpr MaxSssProfilesCount = 128u; - static int32_t constexpr MaxMaterialComponentsCount = 8; // Texture Configuration Buffer. static uint32_t constexpr MaxTextureConfigurationCount = 4'096u; // Texture Animation Buffer. @@ -147,12 +146,11 @@ namespace castor3d */ //@{ // The number of vec4s in the random buffer. - static uint32_t constexpr RandomDataCount = 1024u; + static uint32_t constexpr RandomDataCount = 1'024u; // Max overlay count per buffer static uint32_t constexpr MaxOverlaysPerBuffer = 65'536u; // Max counts for text overlays static uint32_t constexpr MaxCharsPerOverlay = 1'024u; - static uint32_t constexpr MaxLinesPerOverlay = 1'024u; // Max counts for text overlays text buffer static uint32_t constexpr MaxCharsPerBuffer = 65'536u; static uint32_t constexpr MaxWordsPerBuffer = 16'384u; diff --git a/include/Core/Castor3D/Miscellaneous/makeVkType.hpp b/include/Core/Castor3D/Miscellaneous/makeVkType.hpp index f497b095c7..bbe26b4b37 100644 --- a/include/Core/Castor3D/Miscellaneous/makeVkType.hpp +++ b/include/Core/Castor3D/Miscellaneous/makeVkType.hpp @@ -6,6 +6,9 @@ See LICENSE file in root folder #include "MiscellaneousModule.hpp" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" + namespace castor3d { template< typename AshesType > @@ -884,11 +887,14 @@ namespace castor3d template<> struct VkStructTraits< VkVideoEncodeRateControlInfoKHR >{ static VkStructureType constexpr value = VK_STRUCTURE_TYPE_VIDEO_ENCODE_RATE_CONTROL_INFO_KHR; }; #endif + template< typename VkStructT > + static VkStructureType constexpr vkStructureTypeV = VkStructTraits< VkStructT >::value; + template< typename VkStructT, typename ... ParamsT > inline VkStructT makeVkStructPNext( void * next , ParamsT && ... params ) { - return VkStructT{ VkStructTraits< VkStructT >::value + return VkStructT{ vkStructureTypeV< VkStructT > , next , std::forward< ParamsT >( params )... }; } @@ -896,10 +902,12 @@ namespace castor3d template< typename VkStructT, typename ... ParamsT > inline VkStructT makeVkStruct( ParamsT && ... params ) { - return VkStructT{ VkStructTraits< VkStructT >::value + return VkStructT{ vkStructureTypeV< VkStructT > , nullptr , std::forward< ParamsT >( params )... }; } } +#pragma GCC diagnostic pop + #endif diff --git a/include/Core/Castor3D/Render/Clustered/ClustersMask.hpp b/include/Core/Castor3D/Render/Clustered/ClustersMask.hpp new file mode 100644 index 0000000000..e0e951a175 --- /dev/null +++ b/include/Core/Castor3D/Render/Clustered/ClustersMask.hpp @@ -0,0 +1,20 @@ +/* +See LICENSE file in root folder +*/ +#ifndef ___C3D_ClustersMask_H___ +#define ___C3D_ClustersMask_H___ + +#include "ClusteredModule.hpp" + +namespace castor3d +{ + crg::FramePass const & createClustersMaskPass( crg::FramePassGroup & graph + , crg::FramePass const & previousPass + , RenderDevice const & device + , CameraUbo const & cameraUbo + , FrustumClusters & clusters + , RenderTechnique & technique + , RenderNodesPass *& nodesPass ); +} + +#endif diff --git a/include/Core/Castor3D/Render/Clustered/FindUniqueClusters.hpp b/include/Core/Castor3D/Render/Clustered/FindUniqueClusters.hpp new file mode 100644 index 0000000000..3ad8a75208 --- /dev/null +++ b/include/Core/Castor3D/Render/Clustered/FindUniqueClusters.hpp @@ -0,0 +1,18 @@ +/* +See LICENSE file in root folder +*/ +#ifndef ___C3D_FindUniqueClusters_H___ +#define ___C3D_FindUniqueClusters_H___ + +#include "ClusteredModule.hpp" + +namespace castor3d +{ + C3D_API crg::FramePass const & createFindUniqueClustersPass( crg::FramePassGroup & graph + , crg::FramePass const & previousPass + , RenderDevice const & device + , CameraUbo const & cameraUbo + , FrustumClusters & clusters ); +} + +#endif diff --git a/include/Core/Castor3D/Render/Clustered/FrustumClusters.hpp b/include/Core/Castor3D/Render/Clustered/FrustumClusters.hpp index abea8aed90..91f8e68238 100644 --- a/include/Core/Castor3D/Render/Clustered/FrustumClusters.hpp +++ b/include/Core/Castor3D/Render/Clustered/FrustumClusters.hpp @@ -43,7 +43,9 @@ namespace castor3d */ C3D_API crg::FramePass const & createFramePasses( crg::FramePassGroup & graph , crg::FramePass const * previousPass - , CameraUbo const & cameraUbo ); + , RenderTechnique & technique + , CameraUbo const & cameraUbo + , RenderNodesPass *& nodesPass ); /** *\~english *\brief Compute the number of nodes for given BVH level. @@ -124,20 +126,17 @@ namespace castor3d auto & getLightsAABBBuffer()const noexcept { - CU_Require( m_lightsAABBBuffer ); - return *m_lightsAABBBuffer; + return m_lightsAABBBuffer->getBuffer(); } auto & getPointLightBVHBuffer()const noexcept { - CU_Require( m_pointBVHBuffer ); - return *m_pointBVHBuffer; + return m_pointBVHBuffer->getBuffer(); } auto & getSpotLightBVHBuffer()const noexcept { - CU_Require( m_spotBVHBuffer ); - return *m_spotBVHBuffer; + return m_spotBVHBuffer->getBuffer(); } void initPointLightMortonIndicesIO()noexcept @@ -162,22 +161,22 @@ namespace castor3d ashes::BufferBase & getPointLightIndicesBuffer( uint32_t index )const noexcept { - return *m_pointIndicesBuffers[index]; + return m_pointIndicesBuffers[index]->getBuffer(); } ashes::BufferBase & getSpotLightIndicesBuffer( uint32_t index )const noexcept { - return *m_spotIndicesBuffers[index]; + return m_spotIndicesBuffers[index]->getBuffer(); } ashes::BufferBase & getPointLightMortonCodesBuffer( uint32_t index )const noexcept { - return *m_pointMortonCodesBuffers[index]; + return m_pointMortonCodesBuffers[index]->getBuffer(); } ashes::BufferBase & getSpotLightMortonCodesBuffer( uint32_t index )const noexcept { - return *m_spotMortonCodesBuffers[index]; + return m_spotMortonCodesBuffers[index]->getBuffer(); } ashes::BufferBase & getInputPointLightIndicesBuffer()const noexcept @@ -222,7 +221,22 @@ namespace castor3d ashes::BufferBase & getMergePathPartitionsBuffer()const noexcept { - return *m_mergePathPartitionsBuffer; + return m_mergePathPartitionsBuffer->getBuffer(); + } + + ashes::BufferBase & getClusterFlagsBuffer()const noexcept + { + return *m_clusterFlags; + } + + ashes::BufferBase & getUniqueClustersBuffer()const noexcept + { + return *m_uniqueClusters; + } + + ashes::BufferBase & getClustersIndirectBuffer()const noexcept + { + return m_clustersIndirect->getBuffer(); } auto & getCamera()const noexcept @@ -237,7 +251,6 @@ namespace castor3d { castor::Point4f min; castor::Point4f max; - castor::Point4f sphere; }; private: @@ -257,19 +270,26 @@ namespace castor3d castor::GroupChangeTracked< castor::Matrix4x4f > m_cameraView; castor::GroupChangeTracked< float > m_nearK; ClustersUbo m_clustersUbo; + ashes::BufferPtr< VkDispatchIndirectCommand > m_clustersIndirect; + + // Fixed size buffers, related to lights + ashes::BufferPtr< AABB > m_lightsAABBBuffer; + std::array< ashes::BufferPtr< u32 >, 2u > m_pointMortonCodesBuffers; + std::array< ashes::BufferPtr< u32 >, 2u > m_spotMortonCodesBuffers; + std::array< ashes::BufferPtr< u32 >, 2u > m_pointIndicesBuffers; + std::array< ashes::BufferPtr< u32 >, 2u > m_spotIndicesBuffers; + ashes::BufferPtr< AABB > m_pointBVHBuffer; + ashes::BufferPtr< AABB > m_spotBVHBuffer; + ashes::BufferPtr< s32 > m_mergePathPartitionsBuffer; + + // Variable size buffers, related to frustum dimensions ashes::BufferBasePtr m_aabbBuffer; ashes::BufferBasePtr m_pointLightClusterGridBuffer; ashes::BufferBasePtr m_spotLightClusterGridBuffer; ashes::BufferBasePtr m_pointLightClusterIndexBuffer; ashes::BufferBasePtr m_spotLightClusterIndexBuffer; - ashes::BufferBasePtr m_lightsAABBBuffer; - ashes::BufferBasePtr m_mergePathPartitionsBuffer; - std::array< ashes::BufferBasePtr, 2u > m_pointMortonCodesBuffers; - std::array< ashes::BufferBasePtr, 2u > m_spotMortonCodesBuffers; - std::array< ashes::BufferBasePtr, 2u > m_pointIndicesBuffers; - std::array< ashes::BufferBasePtr, 2u > m_spotIndicesBuffers; - ashes::BufferBasePtr m_pointBVHBuffer; - ashes::BufferBasePtr m_spotBVHBuffer; + ashes::BufferBasePtr m_clusterFlags; + ashes::BufferBasePtr m_uniqueClusters; std::vector< ashes::BufferBasePtr > m_toDelete; }; } diff --git a/include/Core/Castor3D/Render/Prepass/DepthPass.hpp b/include/Core/Castor3D/Render/Prepass/DepthPass.hpp index 8cdaa75804..d1cb5f6bb2 100644 --- a/include/Core/Castor3D/Render/Prepass/DepthPass.hpp +++ b/include/Core/Castor3D/Render/Prepass/DepthPass.hpp @@ -56,14 +56,10 @@ namespace castor3d ProgramFlags doAdjustProgramFlags( ProgramFlags flags )const override; SceneFlags doAdjustSceneFlags( SceneFlags flags )const override; void doFillAdditionalBindings( PipelineFlags const & flags - , ashes::VkDescriptorSetLayoutBindingArray & bindings )const override - { - } + , ashes::VkDescriptorSetLayoutBindingArray & bindings )const override; void doFillAdditionalDescriptor( PipelineFlags const & flags , ashes::WriteDescriptorSetArray & descriptorWrites - , ShadowMapLightTypeArray const & shadowMaps )override - { - } + , ShadowMapLightTypeArray const & shadowMaps )override; ashes::PipelineDepthStencilStateCreateInfo doCreateDepthStencilState( PipelineFlags const & flags )const override; ashes::PipelineColorBlendStateCreateInfo doCreateBlendState( PipelineFlags const & flags )const override; ShaderPtr doGetGeometryShaderSource( PipelineFlags const & flags )const override; diff --git a/include/Core/Castor3D/Render/RenderTechnique.hpp b/include/Core/Castor3D/Render/RenderTechnique.hpp index 55bd6b9cd8..7faf3b2813 100644 --- a/include/Core/Castor3D/Render/RenderTechnique.hpp +++ b/include/Core/Castor3D/Render/RenderTechnique.hpp @@ -419,6 +419,7 @@ namespace castor3d PrepassRendering m_prepass; crg::FramePass const * m_lastDepthPass{}; crg::FramePass const * m_depthRangePass{}; + RenderNodesPass * m_clustersFlagsPass{}; crg::FramePass const * m_clustersLastPass{}; BackgroundRendererUPtr m_background{}; OpaqueRendering m_opaque; diff --git a/include/Core/Castor3D/Scene/Light/Light.hpp b/include/Core/Castor3D/Scene/Light/Light.hpp index 84161e91ca..26da094def 100644 --- a/include/Core/Castor3D/Scene/Light/Light.hpp +++ b/include/Core/Castor3D/Scene/Light/Light.hpp @@ -89,6 +89,11 @@ namespace castor3d return m_category->getLightType(); } + uint32_t getComponentCount()const + { + return m_category->getComponentCount(); + } + bool isEnabled()const { return m_enabled; diff --git a/include/Core/Castor3D/Scene/Light/LightCategory.hpp b/include/Core/Castor3D/Scene/Light/LightCategory.hpp index 7640033fa9..fcdac5256e 100644 --- a/include/Core/Castor3D/Scene/Light/LightCategory.hpp +++ b/include/Core/Castor3D/Scene/Light/LightCategory.hpp @@ -29,7 +29,7 @@ namespace castor3d *\param[in] lightType Le type de catégorie de lumière. *\param[in] light La Light parente. */ - C3D_API explicit LightCategory( LightType lightType, Light & light ); + C3D_API explicit LightCategory( LightType lightType, Light & light, uint32_t componentCount ); public: struct ShadowData @@ -107,6 +107,11 @@ namespace castor3d return m_lightType; } + uint32_t getComponentCount()const + { + return m_componentCount; + } + float getDiffuseIntensity()const { return m_intensity[0]; @@ -204,6 +209,7 @@ namespace castor3d private: LightType m_lightType; Light & m_light; + uint32_t m_componentCount{}; castor::Point3f m_colour{ 1.0, 1.0, 1.0 }; castor::Point2f m_intensity{ 1.0, 1.0 }; }; diff --git a/include/Core/Castor3D/Scene/SceneModule.hpp b/include/Core/Castor3D/Scene/SceneModule.hpp index 343318c426..823deffba3 100644 --- a/include/Core/Castor3D/Scene/SceneModule.hpp +++ b/include/Core/Castor3D/Scene/SceneModule.hpp @@ -464,7 +464,7 @@ namespace castor3d using ElementKeyT = KeyT; using ElementPtrT = castor::UniquePtr< ElementT >; using ElementObsT = ElementT *; - using ElementContT = std::unordered_map< KeyT, ElementPtrT >; + using ElementContT = std::map< KeyT, ElementPtrT >; using ElementCacheT = ObjectCacheBaseT< ElementT, KeyT >; using ElementInitialiserT = std::function< void( ElementT & ) >; diff --git a/include/Core/Castor3D/Shader/ShaderBuffers/LightBuffer.hpp b/include/Core/Castor3D/Shader/ShaderBuffers/LightBuffer.hpp index 512a257c67..73eb28c32f 100644 --- a/include/Core/Castor3D/Shader/ShaderBuffers/LightBuffer.hpp +++ b/include/Core/Castor3D/Shader/ShaderBuffers/LightBuffer.hpp @@ -119,6 +119,16 @@ namespace castor3d */ C3D_API void createBinding( ashes::DescriptorSet & descriptorSet , VkDescriptorSetLayoutBinding const & binding )const; + /** + *\~english + *\param[in] type The light type. + *\return The number of light sources of the given type, in the buffer. + *\~french + *\brief Crée le descriptor write pour le buffer de sources lumineuses. + *\param[in] type Le type de lumière. + *\return Le nombre de sources lumineuses du type donné, dans le buffer. + */ + C3D_API uint32_t getLightsBufferCount( LightType type )const noexcept; uint8_t * getPtr() { @@ -134,6 +144,7 @@ namespace castor3d std::pair< uint32_t, uint32_t > doGetOffsetIndex( Light const & light )const; void doMarkNextDirty( LightType type , uint32_t index ); + uint32_t doGetBufferEnd( LightType type )const noexcept; private: ShaderBuffer m_buffer; diff --git a/include/Core/Castor3D/Shader/ShaderBuffers/PassBuffer.hpp b/include/Core/Castor3D/Shader/ShaderBuffers/PassBuffer.hpp index 8fe1b09223..5c0d20daec 100644 --- a/include/Core/Castor3D/Shader/ShaderBuffers/PassBuffer.hpp +++ b/include/Core/Castor3D/Shader/ShaderBuffers/PassBuffer.hpp @@ -317,6 +317,7 @@ namespace castor3d private: uint32_t m_stride; + uint32_t m_maxCount; ShaderBuffer m_buffer; std::vector< Pass * > m_passes; std::vector< Pass const * > m_dirty; diff --git a/include/Core/Castor3D/Shader/Shaders/GlslClusteredLights.hpp b/include/Core/Castor3D/Shader/Shaders/GlslClusteredLights.hpp index 2ebe5b32d7..610b4cebef 100644 --- a/include/Core/Castor3D/Shader/Shaders/GlslClusteredLights.hpp +++ b/include/Core/Castor3D/Shader/Shaders/GlslClusteredLights.hpp @@ -191,6 +191,46 @@ namespace castor3d::shader #define C3D_SpotLightMortonCodes( writer, binding, set ) \ C3D_SpotLightMortonCodesEx( writer, binding, set, true ) + + + +#define C3D_ClusterFlagsEx( writer, binding, set, enabled ) \ + auto c3d_clusterFlagsBuffer = writer.declStorageBuffer( "c3d_clusterFlagsBuffer" \ + , ( enabled ? uint32_t( binding ) : 0u ) \ + , set \ + , sdw::type::MemoryLayout::eStd430 \ + , enabled ); \ + auto c3d_clusterFlags = c3d_clusterFlagsBuffer.declMemberArray< sdw::UInt >( "cf", enabled ); \ + c3d_clusterFlagsBuffer.end() + +#define C3D_ClusterFlags( writer, binding, set ) \ + C3D_ClusterFlagsEx( writer, binding, set, true ) + +#define C3D_UniqueClustersEx( writer, binding, set, enabled ) \ + auto c3d_uniqueClustersBuffer = writer.declStorageBuffer( "c3d_uniqueClustersBuffer" \ + , ( enabled ? uint32_t( binding ) : 0u ) \ + , set \ + , sdw::type::MemoryLayout::eStd430 \ + , enabled ); \ + auto c3d_uniqueClusters = c3d_uniqueClustersBuffer.declMemberArray< sdw::UInt >( "uc", enabled ); \ + c3d_uniqueClustersBuffer.end() + +#define C3D_UniqueClusters( writer, binding, set ) \ + C3D_UniqueClustersEx( writer, binding, set, true ) + +#define C3D_ClustersIndirectEx( writer, binding, set, enabled ) \ + auto c3d_clustersIndirectBuffer = writer.declStorageBuffer( "c3d_clustersIndirectBuffer" \ + , ( enabled ? uint32_t( binding ) : 0u ) \ + , set \ + , sdw::type::MemoryLayout::eStd430 \ + , enabled ); \ + auto c3d_clustersCountX = c3d_clustersIndirectBuffer.declMember< sdw::UInt >( "ccx" , enabled ); \ + auto c3d_clustersCountY = c3d_clustersIndirectBuffer.declMember< sdw::UInt >( "ccy" , enabled ); \ + auto c3d_clustersCountZ = c3d_clustersIndirectBuffer.declMember< sdw::UInt >( "ccz" , enabled ); \ + c3d_clustersIndirectBuffer.end() + +#define C3D_ClustersIndirect( writer, binding, set ) \ + C3D_ClustersIndirectEx( writer, binding, set, true ) } #endif diff --git a/include/Core/CastorUtils/Data/Endianness.hpp b/include/Core/CastorUtils/Data/Endianness.hpp index a9443ab82d..cb14f5de40 100644 --- a/include/Core/CastorUtils/Data/Endianness.hpp +++ b/include/Core/CastorUtils/Data/Endianness.hpp @@ -6,25 +6,29 @@ See LICENSE file in root folder #include "CastorUtils/Data/DataModule.hpp" +#include + namespace castor { - namespace details - { - static union - { - uint32_t i; - char c[4]; - } BigInt = { 0x01020304 }; - } /** *\~english *\brief Detects if the current system is big endian. *\~french *\brief Détecte si le système courant est big endian. */ - inline bool isBigEndian()noexcept + inline constexpr bool isBigEndian()noexcept + { + return std::endian::native == std::endian::big; + } + /** + *\~english + *\brief Detects if the current system is little endian. + *\~french + *\brief Détecte si le système courant est little endian. + */ + inline constexpr bool isLittleEndian()noexcept { - return details::BigInt.c[0] == 1; + return std::endian::native == std::endian::little; } /** *\~english @@ -35,7 +39,7 @@ namespace castor *\param[in,out] value La valeur à convertir. */ template< typename T > - inline T & switchEndianness( T & value )noexcept + inline constexpr T & switchEndianness( T & value )noexcept { uint8_t * p = reinterpret_cast< uint8_t * >( &value ); size_t lo, hi; @@ -56,7 +60,7 @@ namespace castor *\param[in,out] value La valeur à convertir. */ template< typename T > - inline T switchEndianness( T const & value ) + inline constexpr T switchEndianness( T const & value ) { T result{ value }; switchEndianness( result ); @@ -71,14 +75,16 @@ namespace castor *\param[in,out] value La valeur à convertir. */ template< typename T > - inline T & systemEndianToBigEndian( T & value )noexcept + inline constexpr T & systemEndianToBigEndian( T & value )noexcept { - if ( !isBigEndian() ) + if constexpr ( !isBigEndian() ) { - switchEndianness( value ); + return switchEndianness( value ); + } + else + { + return value; } - - return value; } /** *\~english @@ -89,7 +95,7 @@ namespace castor *\param[in,out] value La valeur à convertir. */ template< typename T > - inline T systemEndianToBigEndian( T const & value ) + inline constexpr T systemEndianToBigEndian( T const & value ) { T result{ value }; switchEndianness( result ); @@ -104,17 +110,21 @@ namespace castor *\param[in,out] value La valeur à convertir. */ template< typename T, size_t N > - inline std::array< T, N > & systemEndianToBigEndian( std::array< T, N > & value )noexcept + inline constexpr std::array< T, N > & systemEndianToBigEndian( std::array< T, N > & value )noexcept { - if ( !isBigEndian() ) + if constexpr ( !isBigEndian() ) { for ( auto & element : value ) { switchEndianness( element ); } - } - return value; + return value; + } + else + { + return value; + } } /** *\~english @@ -125,19 +135,23 @@ namespace castor *\param[in,out] value La valeur à convertir. */ template< typename T, size_t N > - inline std::array< T, N > systemEndianToBigEndian( std::array< T, N > const & value ) + inline constexpr std::array< T, N > systemEndianToBigEndian( std::array< T, N > const & value ) { std::array< T, N > result{ value }; - if ( !isBigEndian() ) + if constexpr ( !isBigEndian() ) { for ( auto & element : result ) { switchEndianness( element ); } - } - return result; + return result; + } + else + { + return result; + } } /** *\~english @@ -148,17 +162,21 @@ namespace castor *\param[in,out] value La valeur à convertir. */ template< typename T > - inline std::vector< T > & systemEndianToBigEndian( std::vector< T > & value )noexcept + inline constexpr std::vector< T > & systemEndianToBigEndian( std::vector< T > & value )noexcept { - if ( !isBigEndian() ) + if constexpr ( !isBigEndian() ) { for ( auto & element : value ) { switchEndianness( element ); } - } - return value; + return value; + } + else + { + return value; + } } /** *\~english @@ -169,20 +187,163 @@ namespace castor *\param[in,out] value La valeur à convertir. */ template< typename T > - inline std::vector< T > systemEndianToBigEndian( std::vector< T > const & value ) + inline constexpr std::vector< T > systemEndianToBigEndian( std::vector< T > const & value ) { std::vector< T > result{ value }; - if ( !isBigEndian() ) + if constexpr ( !isBigEndian() ) { for ( auto & element : result ) { switchEndianness( element ); } - } + return result; + } + else + { + return result; + } + } + /** + *\~english + *\brief Convert the given value to little endian if needed. + *\param[in,out] value Value to be converted. + *\~french + *\brief Convertit la valeur donnée en little endian si nécessaire. + *\param[in,out] value La valeur à convertir. + */ + template< typename T > + inline constexpr T & systemEndianToLittleEndian( T & value )noexcept + { + if constexpr ( !isLittleEndian() ) + { + return switchEndianness( value ); + } + else + { + return value; + } + } + /** + *\~english + *\brief Convert the given value to little endian if needed. + *\param[in,out] value Value to be converted. + *\~french + *\brief Convertit la valeur donnée en little endian si nécessaire. + *\param[in,out] value La valeur à convertir. + */ + template< typename T > + inline constexpr T systemEndianToLittleEndian( T const & value ) + { + T result{ value }; + switchEndianness( result ); return result; } + /** + *\~english + *\brief Convert the given value to little endian if needed. + *\param[in,out] value Value to be converted. + *\~french + *\brief Convertit la valeur donnée en little endian si nécessaire. + *\param[in,out] value La valeur à convertir. + */ + template< typename T, size_t N > + inline constexpr std::array< T, N > & systemEndianToLittleEndian( std::array< T, N > & value )noexcept + { + if constexpr ( !isLittleEndian() ) + { + for ( auto & element : value ) + { + switchEndianness( element ); + } + + return value; + } + else + { + return value; + } + } + /** + *\~english + *\brief Convert the given value to little endian if needed. + *\param[in,out] value Value to be converted. + *\~french + *\brief Convertit la valeur donnée en little endian si nécessaire. + *\param[in,out] value La valeur à convertir. + */ + template< typename T, size_t N > + inline constexpr std::array< T, N > systemEndianToLittleEndian( std::array< T, N > const & value ) + { + std::array< T, N > result{ value }; + + if constexpr ( !isLittleEndian() ) + { + for ( auto & element : result ) + { + switchEndianness( element ); + } + + return result; + } + else + { + return result; + } + } + /** + *\~english + *\brief Convert the given value to little endian if needed. + *\param[in,out] value Value to be converted. + *\~french + *\brief Convertit la valeur donnée en little endian si nécessaire. + *\param[in,out] value La valeur à convertir. + */ + template< typename T > + inline std::vector< T > & systemEndianToLittleEndian( std::vector< T > & value )noexcept + { + if constexpr ( !isLittleEndian() ) + { + for ( auto & element : value ) + { + switchEndianness( element ); + } + + return value; + } + else + { + return value; + } + } + /** + *\~english + *\brief Convert the given value to little endian if needed. + *\param[in,out] value Value to be converted. + *\~french + *\brief Convertit la valeur donnée en little endian si nécessaire. + *\param[in,out] value La valeur à convertir. + */ + template< typename T > + inline std::vector< T > systemEndianToLittleEndian( std::vector< T > const & value ) + { + std::vector< T > result{ value }; + + if constexpr ( !isLittleEndian() ) + { + for ( auto & element : result ) + { + switchEndianness( element ); + } + + return result; + } + else + { + return result; + } + } /** *\~english *\brief Convert the given big endian value to system endian if needed. @@ -192,14 +353,16 @@ namespace castor *\param[in,out] value La valeur à convertir. */ template< typename T > - inline T & bigEndianToSystemEndian( T & value )noexcept + inline constexpr T & bigEndianToSystemEndian( T & value )noexcept { - if ( !isBigEndian() ) + if constexpr ( !isBigEndian() ) { - switchEndianness( value ); + return switchEndianness( value ); + } + else + { + return value; } - - return value; } /** *\~english @@ -210,7 +373,7 @@ namespace castor *\param[in,out] value La valeur à convertir. */ template< typename T > - inline T bigEndianToSystemEndian( T const & value ) + inline constexpr T bigEndianToSystemEndian( T const & value ) { T result{ value }; switchEndianness( result ); @@ -225,17 +388,21 @@ namespace castor *\param[in,out] value La valeur à convertir. */ template< typename T, size_t N > - inline std::array< T, N > & bigEndianToSystemEndian( std::array< T, N > & value )noexcept + inline constexpr std::array< T, N > & bigEndianToSystemEndian( std::array< T, N > & value )noexcept { - if ( !isBigEndian() ) + if constexpr ( !isBigEndian() ) { for ( auto & element : value ) { switchEndianness( element ); } - } - return value; + return value; + } + else + { + return value; + } } /** *\~english @@ -246,19 +413,23 @@ namespace castor *\param[in,out] value La valeur à convertir. */ template< typename T, size_t N > - inline std::array< T, N > bigEndianToSystemEndian( std::array< T, N > const & value ) + inline constexpr std::array< T, N > bigEndianToSystemEndian( std::array< T, N > const & value ) { std::array< T, N > result{ value }; - if ( !isBigEndian() ) + if constexpr ( !isBigEndian() ) { for ( auto & element : result ) { switchEndianness( element ); } - } - return result; + return result; + } + else + { + return result; + } } /** *\~english @@ -271,15 +442,19 @@ namespace castor template< typename T > inline std::vector< T > & bigEndianToSystemEndian( std::vector< T > & value )noexcept { - if ( !isBigEndian() ) + if constexpr ( !isBigEndian() ) { for ( auto & element : value ) { switchEndianness( element ); } - } - return value; + return value; + } + else + { + return value; + } } /** *\~english @@ -294,16 +469,159 @@ namespace castor { std::vector< T > result{ value }; - if ( !isBigEndian() ) + if constexpr ( !isBigEndian() ) { for ( auto & element : result ) { switchEndianness( element ); } - } + return result; + } + else + { + return result; + } + } + /** + *\~english + *\brief Convert the given little endian value to system endian if needed. + *\param[in,out] value Value to be converted. + *\~french + *\brief Convertit la valeur donnée de little endian à l'endianness du système si nécessaire. + *\param[in,out] value La valeur à convertir. + */ + template< typename T > + inline constexpr T & littleEndianToSystemEndian( T & value )noexcept + { + if constexpr ( !isLittleEndian() ) + { + return switchEndianness( value ); + } + else + { + return value; + } + } + /** + *\~english + *\brief Convert the given little endian value to system endian if needed. + *\param[in,out] value Value to be converted. + *\~french + *\brief Convertit la valeur donnée de little endian à l'endianness du système si nécessaire. + *\param[in,out] value La valeur à convertir. + */ + template< typename T > + inline constexpr T littleEndianToSystemEndian( T const & value ) + { + T result{ value }; + switchEndianness( result ); return result; } + /** + *\~english + *\brief Convert the given value to little endian if needed. + *\param[in,out] value Value to be converted. + *\~french + *\brief Convertit la valeur donnée en little endian si nécessaire. + *\param[in,out] value La valeur à convertir. + */ + template< typename T, size_t N > + inline constexpr std::array< T, N > & littleEndianToSystemEndian( std::array< T, N > & value )noexcept + { + if constexpr ( !isLittleEndian() ) + { + for ( auto & element : value ) + { + switchEndianness( element ); + } + + return value; + } + else + { + return value; + } + } + /** + *\~english + *\brief Convert the given value to little endian if needed. + *\param[in,out] value Value to be converted. + *\~french + *\brief Convertit la valeur donnée en little endian si nécessaire. + *\param[in,out] value La valeur à convertir. + */ + template< typename T, size_t N > + inline constexpr std::array< T, N > littleEndianToSystemEndian( std::array< T, N > const & value ) + { + std::array< T, N > result{ value }; + + if constexpr ( !isLittleEndian() ) + { + for ( auto & element : result ) + { + switchEndianness( element ); + } + + return result; + } + else + { + return result; + } + } + /** + *\~english + *\brief Convert the given value to little endian if needed. + *\param[in,out] value Value to be converted. + *\~french + *\brief Convertit la valeur donnée en little endian si nécessaire. + *\param[in,out] value La valeur à convertir. + */ + template< typename T > + inline std::vector< T > & littleEndianToSystemEndian( std::vector< T > & value )noexcept + { + if constexpr ( !isLittleEndian() ) + { + for ( auto & element : value ) + { + switchEndianness( element ); + } + + return value; + } + else + { + return value; + } + } + /** + *\~english + *\brief Convert the given value to little endian if needed. + *\param[in,out] value Value to be converted. + *\~french + *\brief Convertit la valeur donnée en little endian si nécessaire. + *\param[in,out] value La valeur à convertir. + */ + template< typename T > + inline std::vector< T > littleEndianToSystemEndian( std::vector< T > const & value ) + { + std::vector< T > result{ value }; + + if constexpr ( !isLittleEndian() ) + { + for ( auto & element : result ) + { + switchEndianness( element ); + } + + return result; + } + else + { + return result; + } + } } #endif diff --git a/include/Core/CastorUtils/Math/Math.hpp b/include/Core/CastorUtils/Math/Math.hpp index c1b16a8b01..a3b7461fc6 100644 --- a/include/Core/CastorUtils/Math/Math.hpp +++ b/include/Core/CastorUtils/Math/Math.hpp @@ -122,6 +122,65 @@ namespace castor //************************************************************************************************ + namespace details + { + template< typename DataT > + concept ValueTypeT = std::is_floating_point_v< DataT > + || std::is_integral_v< DataT >; + + + template< ValueTypeT DataT, DataT ... ValuesT > + struct MinRecT; + + template< ValueTypeT DataT, DataT ValueT > + struct MinRecT< DataT, ValueT > + { + static constexpr DataT value = ValueT; + }; + + template< ValueTypeT DataT, DataT LhsT, DataT RhsT > + struct MinRecT< DataT, LhsT, RhsT > + { + static constexpr DataT value = std::min( LhsT, RhsT ); + }; + + template< ValueTypeT DataT, DataT LhsT, DataT RhsT, DataT ... ValuesT > + struct MinRecT< DataT, LhsT, RhsT, ValuesT... > + { + static constexpr DataT value = MinRecT< DataT, std::max( LhsT, RhsT ), ValuesT... >::value; + }; + + + template< ValueTypeT DataT, DataT ... ValuesT > + struct MaxRecT; + + template< ValueTypeT DataT, DataT ValueT > + struct MaxRecT< DataT, ValueT > + { + static constexpr DataT value = ValueT; + }; + + template< ValueTypeT DataT, DataT LhsT, DataT RhsT > + struct MaxRecT< DataT, LhsT, RhsT > + { + static constexpr DataT value = std::max( LhsT, RhsT ); + }; + + template< ValueTypeT DataT, DataT LhsT, DataT RhsT, DataT ... ValuesT > + struct MaxRecT< DataT, LhsT, RhsT, ValuesT... > + { + static constexpr DataT value = MaxRecT< DataT, std::max( LhsT, RhsT ), ValuesT... >::value; + }; + } + + template< details::ValueTypeT DataT, DataT ... ValuesT > + static DataT minValueT = details::MinRecT< DataT, ValuesT... >::value; + + template< details::ValueTypeT DataT, DataT ... ValuesT > + static DataT maxValueT = details::MaxRecT< DataT, ValuesT... >::value; + + //************************************************************************************************ + /** *\~english *\brief Tests if a double is a number diff --git a/source/Core/Castor3D/CMakeLists.txt b/source/Core/Castor3D/CMakeLists.txt index 07585c20ae..3f44e82f8b 100644 --- a/source/Core/Castor3D/CMakeLists.txt +++ b/source/Core/Castor3D/CMakeLists.txt @@ -1134,8 +1134,10 @@ set( ${PROJECT_NAME}_FOLDER_SRC_FILES ${CASTOR_SOURCE_DIR}/source/Core/${PROJECT_NAME}/Render/Clustered/AssignLightsToClusters.cpp ${CASTOR_SOURCE_DIR}/source/Core/${PROJECT_NAME}/Render/Clustered/BuildLightsBVH.cpp ${CASTOR_SOURCE_DIR}/source/Core/${PROJECT_NAME}/Render/Clustered/ClusteredModule.cpp + ${CASTOR_SOURCE_DIR}/source/Core/${PROJECT_NAME}/Render/Clustered/ClustersMask.cpp ${CASTOR_SOURCE_DIR}/source/Core/${PROJECT_NAME}/Render/Clustered/ComputeClustersAABB.cpp ${CASTOR_SOURCE_DIR}/source/Core/${PROJECT_NAME}/Render/Clustered/ComputeLightsMortonCode.cpp + ${CASTOR_SOURCE_DIR}/source/Core/${PROJECT_NAME}/Render/Clustered/FindUniqueClusters.cpp ${CASTOR_SOURCE_DIR}/source/Core/${PROJECT_NAME}/Render/Clustered/FrustumClusters.cpp ${CASTOR_SOURCE_DIR}/source/Core/${PROJECT_NAME}/Render/Clustered/ReduceLightsAABB.cpp ${CASTOR_SOURCE_DIR}/source/Core/${PROJECT_NAME}/Render/Clustered/SortLightsMortonCode.cpp @@ -1144,8 +1146,10 @@ set( ${PROJECT_NAME}_FOLDER_HDR_FILES ${CASTOR_SOURCE_DIR}/include/Core/${PROJECT_NAME}/Render/Clustered/AssignLightsToClusters.hpp ${CASTOR_SOURCE_DIR}/include/Core/${PROJECT_NAME}/Render/Clustered/BuildLightsBVH.hpp ${CASTOR_SOURCE_DIR}/include/Core/${PROJECT_NAME}/Render/Clustered/ClusteredModule.hpp + ${CASTOR_SOURCE_DIR}/include/Core/${PROJECT_NAME}/Render/Clustered/ClustersMask.hpp ${CASTOR_SOURCE_DIR}/include/Core/${PROJECT_NAME}/Render/Clustered/ComputeClustersAABB.hpp ${CASTOR_SOURCE_DIR}/include/Core/${PROJECT_NAME}/Render/Clustered/ComputeLightsMortonCode.hpp + ${CASTOR_SOURCE_DIR}/include/Core/${PROJECT_NAME}/Render/Clustered/FindUniqueClusters.hpp ${CASTOR_SOURCE_DIR}/include/Core/${PROJECT_NAME}/Render/Clustered/FrustumClusters.hpp ${CASTOR_SOURCE_DIR}/include/Core/${PROJECT_NAME}/Render/Clustered/ReduceLightsAABB.hpp ${CASTOR_SOURCE_DIR}/include/Core/${PROJECT_NAME}/Render/Clustered/SortLightsMortonCode.hpp diff --git a/source/Core/Castor3D/Cache/LightCache.cpp b/source/Core/Castor3D/Cache/LightCache.cpp index 2c0601e266..643ea5f07f 100644 --- a/source/Core/Castor3D/Cache/LightCache.cpp +++ b/source/Core/Castor3D/Cache/LightCache.cpp @@ -62,16 +62,14 @@ namespace castor3d m_lightBuffer = castor::makeUnique< LightBuffer >( m_engine , device , MaxLightsCount ); - m_lightsIndexOffset = device.bufferPool->getBuffer< castor::Point2ui >( VK_BUFFER_USAGE_STORAGE_BUFFER_BIT - , MaxLightsCount - , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ); + std::vector< Light * > pending; + std::swap( pending, m_pendingLights ); - for ( auto light : m_pendingLights ) + for ( auto light : pending ) { doRegisterLight( *light ); } - m_pendingLights.clear(); } } @@ -90,7 +88,6 @@ namespace castor3d void ObjectCacheT< Light, castor::String, LightCacheTraits >::update( CpuUpdater & updater ) { - m_dirty = false; auto lock( castor::makeUniqueLock( *this ) ); auto & sceneObjs = updater.dirtyScenes[getScene()]; LightsRefArray dirty; @@ -101,6 +98,7 @@ namespace castor3d if ( !dirty.empty() ) { + m_dirty = true; auto end = std::unique( dirty.begin(), dirty.end() ); dirty.erase( end, dirty.end() ); @@ -114,19 +112,6 @@ namespace castor3d { m_lightBuffer->update( updater ); m_dirty = !dirty.empty(); - - if ( m_dirty ) - { - auto lightsData = m_lightsIndexOffset.getData(); - - for ( auto light : dirty ) - { - lightsData[light->getBufferIndex()] = { uint32_t( light->getLightType() ), uint32_t( light->getBufferOffset() ) }; - } - - m_lightsIndexOffset.markDirty( VK_ACCESS_SHADER_READ_BIT - , VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT ); - } } } @@ -172,10 +157,20 @@ namespace castor3d return m_lightBuffer->getSingleBinding( binding, offset, size ); } + uint32_t ObjectCacheT< Light, castor::String, LightCacheTraits >::getLightsBufferCount( LightType type )const noexcept + { + if ( m_lightBuffer ) + { + return m_lightBuffer->getLightsBufferCount( type ); + } + + return 0u; + } + bool ObjectCacheT< Light, castor::String, LightCacheTraits >::doCheckUniqueDirectionalLight( LightType toAdd ) { bool result = toAdd != LightType::eDirectional - || getLightsCount( LightType::eDirectional ) == 0u; + || getLightsBufferCount( LightType::eDirectional ) == 0u; if ( !result ) { diff --git a/source/Core/Castor3D/DebugDefines.hpp b/source/Core/Castor3D/DebugDefines.hpp index a222885256..247c16b484 100644 --- a/source/Core/Castor3D/DebugDefines.hpp +++ b/source/Core/Castor3D/DebugDefines.hpp @@ -17,5 +17,6 @@ See LICENSE file in root folder #define C3D_DebugUseLightsBVH 1 #define C3D_DebugSortLightsMortonCode 1 +#define C3D_DebugUseDepthClusteredSamples 1 #endif diff --git a/source/Core/Castor3D/Render/Clustered/AssignLightsToClusters.cpp b/source/Core/Castor3D/Render/Clustered/AssignLightsToClusters.cpp index 7c945b8118..9cb1c5c89d 100644 --- a/source/Core/Castor3D/Render/Clustered/AssignLightsToClusters.cpp +++ b/source/Core/Castor3D/Render/Clustered/AssignLightsToClusters.cpp @@ -46,6 +46,7 @@ namespace castor3d eSpotLightBVH, ePointLightIndices, eSpotLightIndices, + eUniqueClusters, }; #if C3D_DebugUseLightsBVH @@ -107,6 +108,10 @@ namespace castor3d , eSpotLightIndices , 0u , useLightBVH ); + C3D_UniqueClustersEx( writer + , eUniqueClusters + , 0u + , C3D_DebugUseDepthClusteredSamples != 0 ); // Using a stack of node IDs to traverse the BVH was inspired by: // Source: https://devblogs.nvidia.com/parallelforall/thinking-parallel-part-ii-tree-traversal-gpu/ @@ -124,7 +129,6 @@ namespace castor3d auto gsSpotLights = writer.declSharedVariable< shader::AppendArrayT< sdw::UInt > >( "gsSpotLights" , true, "U32", MaxLightsPerCluster ); - auto gsClusterIndex3D = writer.declSharedVariable< sdw::U32Vec3 >( "gsClusterIndex3D" ); auto gsClusterIndex1D = writer.declSharedVariable< sdw::UInt32 >( "gsClusterIndex1D" ); auto gsClusterAABB = writer.declSharedVariable< shader::AABB >( "gsClusterAABB" ); auto gsClusterSphere = writer.declSharedVariable< sdw::Vec4 >( "gsClusterSphere" ); @@ -286,8 +290,11 @@ namespace castor3d gsStackPtr = 0_i; gsParentIndex = 0_u; +#if C3D_DebugUseDepthClusteredSamples + gsClusterIndex1D = c3d_uniqueClusters[in.workGroupID.x()]; +#else gsClusterIndex1D = in.workGroupID.x(); - gsClusterIndex3D = c3d_clustersData.computeClusterIndex3D( gsClusterIndex1D ); +#endif gsClusterAABB = c3D_clustersAABB[gsClusterIndex1D]; auto aabbCenter = writer.declLocale( "aabbCenter" , gsClusterAABB.min().xyz() + ( gsClusterAABB.max().xyz() - gsClusterAABB.min().xyz() ) / 2.0_f ); @@ -544,22 +551,26 @@ namespace castor3d , crg::ru::Config{ 1u } #endif , config - .getPassIndex( RunnablePass::GetPassIndexCallback( [this](){ return doGetPassIndex(); } ) ) + .getPassIndex( RunnablePass::GetPassIndexCallback( [this, &clusters](){ return doGetPassIndex( clusters ); } ) ) .program( ashes::makeVkArray< VkPipelineShaderStageCreateInfo >( CreateInfoHolder::getData() ) ) +#if C3D_DebugUseDepthClusteredSamples + .recordInto( RunnablePass::RecordCallback( [this, &clusters]( crg::RecordContext & ctx, VkCommandBuffer cmd, uint32_t idx ){ doSubRecordInto( ctx, cmd, idx, clusters ); } ) ) +#else .enabled( &clusters.needsLightsUpdate() ) +#endif .end( RecordCallback{ [this]( crg::RecordContext & ctx, VkCommandBuffer cb, uint32_t idx ) { doPostRecord( ctx, cb, idx ); } } ) } - , m_lightCache{ clusters.getCamera().getScene()->getLightCache() } { } private: - uint32_t doGetPassIndex() + uint32_t doGetPassIndex( FrustumClusters const & clusters ) { #if C3D_DebugUseLightsBVH && C3D_DebugSortLightsMortonCode u32 result = {}; + auto & lightCache = clusters.getCamera().getScene()->getLightCache(); - auto pointLightsCount = m_lightCache.getLightsCount( LightType::ePoint ); - auto spoLightsCount = m_lightCache.getLightsCount( LightType::eSpot ); + auto pointLightsCount = lightCache.getLightsBufferCount( LightType::ePoint ); + auto spoLightsCount = lightCache.getLightsBufferCount( LightType::eSpot ); auto totalValues = std::max( pointLightsCount, spoLightsCount ); auto numChunks = getLightsMortonCodeChunkCount( totalValues ); @@ -574,6 +585,20 @@ namespace castor3d #endif } + void doSubRecordInto( crg::RecordContext & context + , VkCommandBuffer commandBuffer + , uint32_t index + , FrustumClusters const & clusters ) + { + auto & buffer = clusters.getClustersIndirectBuffer(); + context.memoryBarrier( commandBuffer + , VkBuffer( buffer ) + , crg::BufferSubresourceRange{ 0u, ashes::WholeSize } + , VkAccessFlags( VK_ACCESS_INDIRECT_COMMAND_READ_BIT ) + , VkPipelineStageFlags( VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT ) + , crg::AccessState{ VK_ACCESS_INDIRECT_COMMAND_READ_BIT, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT } ); + } + void doPostRecord( crg::RecordContext & context , VkCommandBuffer commandBuffer , uint32_t index ) @@ -597,9 +622,6 @@ namespace castor3d } } } - - private: - LightCache const & m_lightCache; }; } @@ -622,7 +644,12 @@ namespace castor3d , device , clusters , crg::cp::Config{} - .groupCountX( clusters.getDimensions()->x * clusters.getDimensions()->y * clusters.getDimensions()->z ) ); +#if C3D_DebugUseDepthClusteredSamples + .indirectBuffer( crg::IndirectBuffer{ { clusters.getClustersIndirectBuffer(), "C3D_ClustersIndirect" }, uint32_t( sizeof( VkDispatchIndirectCommand ) ) } ) +#else + .groupCountX( clusters.getDimensions()->x * clusters.getDimensions()->y * clusters.getDimensions()->z ) +#endif + ); device.renderSystem.getEngine()->registerTimer( framePass.getFullName() , result->getTimer() ); return result; @@ -647,6 +674,9 @@ namespace castor3d createInputStoragePassBinding( pass, uint32_t( dspclst::ePointLightIndices ), "C3D_PointLightIndices", clusters.getInputPointLightIndicesBuffer(), 0u, ashes::WholeSize ); createInputStoragePassBinding( pass, uint32_t( dspclst::eSpotLightIndices ), "C3D_SpotLightIndices", clusters.getInputSpotLightIndicesBuffer(), 0u, ashes::WholeSize ); # endif +#endif +#if C3D_DebugUseDepthClusteredSamples + createInputStoragePassBinding( pass, uint32_t( dspclst::eUniqueClusters ), "C3D_UniqueClusters", clusters.getUniqueClustersBuffer(), 0u, ashes::WholeSize ); #endif return pass; } diff --git a/source/Core/Castor3D/Render/Clustered/BuildLightsBVH.cpp b/source/Core/Castor3D/Render/Clustered/BuildLightsBVH.cpp index 59142c1f6f..c330f31b00 100644 --- a/source/Core/Castor3D/Render/Clustered/BuildLightsBVH.cpp +++ b/source/Core/Castor3D/Render/Clustered/BuildLightsBVH.cpp @@ -384,8 +384,8 @@ namespace castor3d : shader{ VK_SHADER_STAGE_COMPUTE_BIT, "BuildLightsBVH", createShader( bottomLevel ) } , createInfo{ ashes::PipelineShaderStageCreateInfoArray{ makeShaderState( device, shader ) } } , cpConfig{ crg::getDefaultV< InitialiseCallback >() - , &parent->m_clusters.needsLightsUpdate() - , crg::getDefaultV< IsEnabledCallback >() + , nullptr + , IsEnabledCallback( [parent]() { return parent->m_clusters.needsLightsUpdate(); } ) , GetPassIndexCallback( [parent]() { return parent->doGetPassIndex(); } ) , crg::getDefaultV< RecordCallback >() , crg::getDefaultV< RecordCallback >() @@ -428,8 +428,8 @@ namespace castor3d #if C3D_DebugSortLightsMortonCode u32 result = {}; - auto pointLightsCount = m_lightCache.getLightsCount( LightType::ePoint ); - auto spoLightsCount = m_lightCache.getLightsCount( LightType::eSpot ); + auto pointLightsCount = m_lightCache.getLightsBufferCount( LightType::ePoint ); + auto spoLightsCount = m_lightCache.getLightsBufferCount( LightType::eSpot ); auto totalValues = std::max( pointLightsCount, spoLightsCount ); auto numChunks = getLightsMortonCodeChunkCount( totalValues ); @@ -455,8 +455,8 @@ namespace castor3d , uint32_t index ) { // Build bottom level of the BVH. - auto pointLightsCount = m_lightCache.getLightsCount( LightType::ePoint ); - auto spoLightsCount = m_lightCache.getLightsCount( LightType::eSpot ); + auto pointLightsCount = m_lightCache.getLightsBufferCount( LightType::ePoint ); + auto spoLightsCount = m_lightCache.getLightsBufferCount( LightType::eSpot ); auto maxLeaves = std::max( pointLightsCount, spoLightsCount ); auto numThreadGroups = uint32_t( std::ceil( float( maxLeaves ) / float( NumThreads ) ) ); m_bottom.pipeline.recordInto( context, commandBuffer, index ); diff --git a/source/Core/Castor3D/Render/Clustered/ClustersMask.cpp b/source/Core/Castor3D/Render/Clustered/ClustersMask.cpp new file mode 100644 index 0000000000..b9d5fbc15a --- /dev/null +++ b/source/Core/Castor3D/Render/Clustered/ClustersMask.cpp @@ -0,0 +1,254 @@ +#include "Castor3D/Render/Clustered/ClustersMask.hpp" + +#include "Castor3D/DebugDefines.hpp" +#include "Castor3D/Engine.hpp" +#include "Castor3D/Cache/LightCache.hpp" +#include "Castor3D/Render/RenderDevice.hpp" +#include "Castor3D/Render/RenderPipeline.hpp" +#include "Castor3D/Render/RenderSystem.hpp" +#include "Castor3D/Render/RenderTarget.hpp" +#include "Castor3D/Render/RenderTechnique.hpp" +#include "Castor3D/Render/RenderTechniquePass.hpp" +#include "Castor3D/Render/Clustered/FrustumClusters.hpp" +#include "Castor3D/Render/Prepass/DepthPass.hpp" +#include "Castor3D/Scene/Camera.hpp" +#include "Castor3D/Scene/Scene.hpp" +#include "Castor3D/Scene/Light/PointLight.hpp" +#include "Castor3D/Scene/Light/SpotLight.hpp" +#include "Castor3D/Shader/Program.hpp" +#include "Castor3D/Shader/Shaders/GlslBlendComponents.hpp" +#include "Castor3D/Shader/Shaders/GlslClusteredLights.hpp" +#include "Castor3D/Shader/Shaders/GlslMaterial.hpp" +#include "Castor3D/Shader/Shaders/GlslTextureAnimation.hpp" +#include "Castor3D/Shader/Shaders/GlslTextureConfiguration.hpp" +#include "Castor3D/Shader/Shaders/GlslPassShaders.hpp" +#include "Castor3D/Shader/Shaders/GlslUtils.hpp" +#include "Castor3D/Shader/Ubos/CameraUbo.hpp" +#include "Castor3D/Shader/Ubos/BillboardUbo.hpp" +#include "Castor3D/Shader/Ubos/CameraUbo.hpp" +#include "Castor3D/Shader/Ubos/ClustersUbo.hpp" +#include "Castor3D/Shader/Ubos/ModelDataUbo.hpp" + +#include + +#include + +#include +#include + +#include + +namespace castor3d +{ + //********************************************************************************************* + + namespace clsmsk + { + class NodesPass + : public RenderTechniqueNodesPass + { + public: + NodesPass( RenderTechnique * parent + , crg::FramePass const & pass + , crg::GraphContext & context + , crg::RunnableGraph & graph + , RenderDevice const & device + , crg::ImageViewIdArray targetDepth + , SsaoConfig const & ssaoConfig + , RenderNodesPassDesc const & renderPassDesc ) + : RenderTechniqueNodesPass{ parent + , pass + , context + , graph + , device + , cuT( "c3d.clusters_mask" ) + , {} + , std::move( targetDepth ) + , renderPassDesc + , { false, ssaoConfig } } + { + } + + ShaderFlags getShaderFlags()const override + { + return ( ShaderFlag::eOpacity + | ShaderFlag::eViewSpace + | ShaderFlag::eDepth ); + } + + private: + ProgramFlags doAdjustProgramFlags( ProgramFlags flags )const override + { + return flags; + } + + SceneFlags doAdjustSceneFlags( SceneFlags flags )const override + { + return SceneFlag::eNone; + } + + void doFillAdditionalBindings( PipelineFlags const & flags + , ashes::VkDescriptorSetLayoutBindingArray & bindings )const override + { + auto index = uint32_t( GlobalBuffersIdx::eCount ); + auto & frustumClusters = getTechnique().getRenderTarget().getFrustumClusters(); + bindings.emplace_back( frustumClusters.getClustersUbo().createLayoutBinding( index++ // ClustersUbo + , VK_SHADER_STAGE_FRAGMENT_BIT ) ); + bindings.emplace_back( makeDescriptorSetLayoutBinding( index++ // ClustersFlags + , VK_DESCRIPTOR_TYPE_STORAGE_BUFFER + , VK_SHADER_STAGE_FRAGMENT_BIT ) ); + } + + void doFillAdditionalDescriptor( PipelineFlags const & flags + , ashes::WriteDescriptorSetArray & descriptorWrites + , ShadowMapLightTypeArray const & shadowMaps )override + { + auto index = uint32_t( GlobalBuffersIdx::eCount ); + auto & frustumClusters = getTechnique().getRenderTarget().getFrustumClusters(); + descriptorWrites.emplace_back( frustumClusters.getClustersUbo().getDescriptorWrite( index++ ) ); + bindBuffer( frustumClusters.getClusterFlagsBuffer(), descriptorWrites, index ); + } + + ashes::PipelineDepthStencilStateCreateInfo doCreateDepthStencilState( PipelineFlags const & flags )const override + { + return ashes::PipelineDepthStencilStateCreateInfo{ 0u, VK_TRUE, VK_FALSE, VK_COMPARE_OP_GREATER_OR_EQUAL }; + } + + ashes::PipelineColorBlendStateCreateInfo doCreateBlendState( PipelineFlags const & flags )const override + { + return ashes::PipelineColorBlendStateCreateInfo{ 0u + , VK_FALSE + , VK_LOGIC_OP_COPY + , ashes::VkPipelineColorBlendAttachmentStateArray{} }; + } + + ShaderPtr doGetGeometryShaderSource( PipelineFlags const & flags )const override + { + return ShaderPtr{}; + } + + ShaderPtr doGetPixelShaderSource( PipelineFlags const & flags )const override + { + using namespace sdw; + FragmentWriter writer; + bool enableTextures = flags.enableTextures(); + + shader::Utils utils{ writer }; + shader::PassShaders passShaders{ getEngine()->getPassComponentsRegister() + , flags + , getComponentsMask() + , utils }; + + C3D_ModelsData( writer + , GlobalBuffersIdx::eModelsData + , RenderPipeline::eBuffers ); + shader::Materials materials{ writer + , passShaders + , uint32_t( GlobalBuffersIdx::eMaterials ) + , RenderPipeline::eBuffers }; + shader::TextureConfigurations textureConfigs{ writer + , uint32_t( GlobalBuffersIdx::eTexConfigs ) + , RenderPipeline::eBuffers + , enableTextures }; + shader::TextureAnimations textureAnims{ writer + , uint32_t( GlobalBuffersIdx::eTexAnims ) + , RenderPipeline::eBuffers + , enableTextures }; + + C3D_Clusters( writer + , GlobalBuffersIdx::eCount + , RenderPipeline::eBuffers ); + C3D_ClusterFlags( writer + , uint32_t( GlobalBuffersIdx::eCount ) + 1u + , RenderPipeline::eBuffers ); + + auto c3d_maps( writer.declCombinedImgArray< FImg2DRgba32 >( "c3d_maps" + , 0u + , RenderPipeline::eTextures + , enableTextures ) ); + + sdw::PushConstantBuffer pcb{ writer, "C3D_DrawData", "c3d_drawData" }; + auto pipelineID = pcb.declMember< sdw::UInt >( "pipelineID" ); + pcb.end(); + + writer.implementMainT< shader::FragmentSurfaceT, VoidT >( sdw::FragmentInT< shader::FragmentSurfaceT >{ writer + , passShaders + , flags } + , FragmentOut{ writer } + , [&]( FragmentInT< shader::FragmentSurfaceT > in + , FragmentOut out ) + { + auto modelData = writer.declLocale( "modelData" + , c3d_modelsData[in.nodeId - 1u] ); + auto material = writer.declLocale( "material" + , materials.getMaterial( modelData.getMaterialId() ) ); + auto components = writer.declLocale( "components" + , shader::BlendComponents{ materials + , material + , in } ); + materials.blendMaterials( flags + , textureConfigs + , textureAnims + , c3d_maps + , material + , modelData.getMaterialId() + , in.passMultipliers + , components ); + auto clusterIndex3D = writer.declLocale( "clusterIndex3D" + , c3d_clustersData.computeClusterIndex3D( in.fragCoord.xy(), in.viewPosition.z() ) ); + auto clusterIndex1D = writer.declLocale( "clusterIndex1D" + , c3d_clustersData.computeClusterIndex1D( clusterIndex3D ) ); + c3d_clusterFlags[clusterIndex1D] = 1_u; + } ); + + return std::make_unique< ast::Shader >( std::move( writer.getShader() ) );} + }; + } + + //********************************************************************************************* + + crg::FramePass const & createClustersMaskPass( crg::FramePassGroup & graph + , crg::FramePass const & previousPass + , RenderDevice const & device + , CameraUbo const & cameraUbo + , FrustumClusters & clusters + , RenderTechnique & technique + , RenderNodesPass *& nodesPass ) + { + auto & result = graph.createPass( "NodesPass" + , [&nodesPass, &device, &technique]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runnableGraph ) + { + auto res = std::make_unique< clsmsk::NodesPass >( &technique + , framePass + , context + , runnableGraph + , device + , technique.getTargetDepth() + , technique.getSsaoConfig() + , RenderNodesPassDesc{ technique.getTargetExtent() + , technique.getCameraUbo() + , technique.getSceneUbo() + , technique.getRenderTarget().getCuller() + , RenderFilter::eNone + , false /* isOit */ + , true /* forceTwoSided */ } + .safeBand( true ) + .meshShading( true ) + .allowClusteredLighting() + .componentModeFlags( ComponentModeFlag::eOpacity + | ComponentModeFlag::eGeometry ) ); + nodesPass = res.get(); + nodesPass->getEngine()->registerTimer( framePass.getFullName() + , res->getTimer() ); + return res; + } ); + result.addDependency( previousPass ); + result.addInOutDepthStencilView( technique.getTargetDepth() ); + + return result; + } + + //********************************************************************************************* +} diff --git a/source/Core/Castor3D/Render/Clustered/FindUniqueClusters.cpp b/source/Core/Castor3D/Render/Clustered/FindUniqueClusters.cpp new file mode 100644 index 0000000000..19fa43131d --- /dev/null +++ b/source/Core/Castor3D/Render/Clustered/FindUniqueClusters.cpp @@ -0,0 +1,145 @@ +#include "Castor3D/Render/Clustered/FindUniqueClusters.hpp" + +#include "Castor3D/DebugDefines.hpp" +#include "Castor3D/Engine.hpp" +#include "Castor3D/Cache/LightCache.hpp" +#include "Castor3D/Render/RenderDevice.hpp" +#include "Castor3D/Render/RenderSystem.hpp" +#include "Castor3D/Render/Clustered/FrustumClusters.hpp" +#include "Castor3D/Scene/Camera.hpp" +#include "Castor3D/Scene/Scene.hpp" +#include "Castor3D/Scene/Light/PointLight.hpp" +#include "Castor3D/Scene/Light/SpotLight.hpp" +#include "Castor3D/Shader/Program.hpp" +#include "Castor3D/Shader/Shaders/GlslAABB.hpp" +#include "Castor3D/Shader/Shaders/GlslAppendBuffer.hpp" +#include "Castor3D/Shader/Shaders/GlslClusteredLights.hpp" +#include "Castor3D/Shader/Shaders/GlslLight.hpp" +#include "Castor3D/Shader/Ubos/CameraUbo.hpp" +#include "Castor3D/Shader/Ubos/ClustersUbo.hpp" + +#include + +#include + +#include +#include + +#include + +namespace castor3d +{ + //********************************************************************************************* + + namespace fndunq + { + enum BindingPoints + { + eClustersFlags, + eUniqueClusters, + eClustersIndirect, + }; + + static uint32_t constexpr NumThreads = 1024u; + + static ShaderPtr createShader() + { + sdw::ComputeWriter writer; + + // Inputs + C3D_ClusterFlags( writer + , eClustersFlags + , 0u ); + C3D_UniqueClusters( writer + , eUniqueClusters + , 0u ); + C3D_ClustersIndirect( writer + , eClustersIndirect + , 0u ); + + writer.implementMainT< sdw::VoidT >(NumThreads + , [&](sdw::ComputeIn in) + { + auto clusterID = writer.declLocale( "clusterID" + , in.globalInvocationID.x() ); + + IF( writer, clusterID == 0_u ) + { + c3d_clustersCountY = 1_u; + c3d_clustersCountZ = 1_u; + } + FI; + + IF( writer, c3d_clusterFlags[clusterID] != 0_u ) + { + auto i = writer.declLocale ("i" + , atomicAdd( c3d_clustersCountX, 1_u ) ); + c3d_uniqueClusters[i] = clusterID; + } + FI; + } ); + return std::make_unique< ast::Shader >( std::move( writer.getShader() ) ); + } + + class FramePass + : private castor::DataHolderT< ShaderModule > + , private castor::DataHolderT< ashes::PipelineShaderStageCreateInfoArray > + , private castor::DataHolderT< bool > + , public crg::ComputePass + { + using ShaderHolder = DataHolderT< ShaderModule >; + using CreateInfoHolder = DataHolderT< ashes::PipelineShaderStageCreateInfoArray >; + using EnabledHolder = DataHolderT< bool >; + + public: + FramePass( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & graph + , RenderDevice const & device + , FrustumClusters const & clusters ) + : ShaderHolder{ ShaderModule{ VK_SHADER_STAGE_COMPUTE_BIT, "FindUniqueClusters", createShader() } } + , CreateInfoHolder{ ashes::PipelineShaderStageCreateInfoArray{ makeShaderState( device, ShaderHolder::getData() ) } } + , EnabledHolder{ true } + , crg::ComputePass{framePass + , context + , graph + , crg::ru::Config{} + , crg::cp::Config{} + .groupCountX( uint32_t( std::ceil( float( clusters.getDimensions()->x * clusters.getDimensions()->y * clusters.getDimensions()->z ) / float( NumThreads ) ) ) ) + .program( ashes::makeVkArray< VkPipelineShaderStageCreateInfo >( CreateInfoHolder::getData() ) ) } + { + } + }; + } + + //********************************************************************************************* + + crg::FramePass const & createFindUniqueClustersPass( crg::FramePassGroup & graph + , crg::FramePass const & previousPass + , RenderDevice const & device + , CameraUbo const & cameraUbo + , FrustumClusters & clusters ) + { + auto & pass = graph.createPass( "FindUniqueClusters" + , [&clusters, &device]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & graph ) + { + auto result = std::make_unique< fndunq::FramePass >( framePass + , context + , graph + , device + , clusters ); + device.renderSystem.getEngine()->registerTimer( framePass.getFullName() + , result->getTimer() ); + return result; + } ); + pass.addDependency( previousPass ); + createInputStoragePassBinding( pass, uint32_t( fndunq::eClustersFlags ), "C3D_ClustersFlags", clusters.getClusterFlagsBuffer(), 0u, ashes::WholeSize ); + createClearableOutputStorageBinding( pass, uint32_t( fndunq::eUniqueClusters ), "C3D_UniqueClusters", clusters.getUniqueClustersBuffer(), 0u, ashes::WholeSize ); + createClearableOutputStorageBinding( pass, uint32_t( fndunq::eClustersIndirect ), "C3D_ClustersIndirect", clusters.getClustersIndirectBuffer(), 0u, ashes::WholeSize ); + return pass; + } + + //********************************************************************************************* +} diff --git a/source/Core/Castor3D/Render/Clustered/FrustumClusters.cpp b/source/Core/Castor3D/Render/Clustered/FrustumClusters.cpp index e78c23a43e..dd04b73dbb 100644 --- a/source/Core/Castor3D/Render/Clustered/FrustumClusters.cpp +++ b/source/Core/Castor3D/Render/Clustered/FrustumClusters.cpp @@ -7,8 +7,10 @@ #include "Castor3D/Render/RenderDevice.hpp" #include "Castor3D/Render/Clustered/AssignLightsToClusters.hpp" #include "Castor3D/Render/Clustered/BuildLightsBVH.hpp" +#include "Castor3D/Render/Clustered/ClustersMask.hpp" #include "Castor3D/Render/Clustered/ComputeClustersAABB.hpp" #include "Castor3D/Render/Clustered/ComputeLightsMortonCode.hpp" +#include "Castor3D/Render/Clustered/FindUniqueClusters.hpp" #include "Castor3D/Render/Clustered/ReduceLightsAABB.hpp" #include "Castor3D/Render/Clustered/SortLightsMortonCode.hpp" #include "Castor3D/Scene/Camera.hpp" @@ -33,7 +35,8 @@ namespace castor3d , VkDeviceSize elementCount , std::string const & debugName , ashes::BufferBasePtr & buffer - , std::vector< ashes::BufferBasePtr > & toDelete ) + , std::vector< ashes::BufferBasePtr > & toDelete + , VkBufferUsageFlags usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT ) { if ( buffer ) { @@ -42,11 +45,10 @@ namespace castor3d buffer = makeBufferBase( device , elementCount * sizeof( DataT ) - , VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT + , usage , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT , "C3D_" + debugName ); } - } //********************************************************************************************* @@ -61,59 +63,66 @@ namespace castor3d , m_cameraView{ m_clustersDirty, {} } , m_nearK{ m_clustersDirty, 0.0f } , m_clustersUbo{ m_device } +#if C3D_DebugUseDepthClusteredSamples + , m_clustersIndirect{ makeBuffer< VkDispatchIndirectCommand >( m_device + , getNumNodes( MaxLightsCount ) + , VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT + , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT + , "C3D_ClustersIndirect" ) } +#endif #if C3D_DebugUseLightsBVH - , m_lightsAABBBuffer{ makeBufferBase( m_device - , sizeof( AABB ) * MaxLightsCount + , m_lightsAABBBuffer{ makeBuffer< AABB >( m_device + , MaxLightsCount , VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT , "C3D_LightsAABB" ) } - , m_pointMortonCodesBuffers{ { makeBufferBase( m_device - , MaxLightsCount * sizeof( u32 ) + , m_pointMortonCodesBuffers{ { makeBuffer< u32 >( m_device + , MaxLightsCount , VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT , "C3D_PointLightMortonCodesA" ) - , makeBufferBase( m_device - , MaxLightsCount * sizeof( u32 ) + , makeBuffer< u32 >( m_device + , MaxLightsCount , VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT , "C3D_PointLightMortonCodesB" ) } } - , m_spotMortonCodesBuffers{ { makeBufferBase( m_device - , MaxLightsCount * sizeof( u32 ) + , m_spotMortonCodesBuffers{ { makeBuffer< u32 >( m_device + , MaxLightsCount , VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT , "C3D_SpotLightMortonCodesA" ) - , makeBufferBase( m_device - , MaxLightsCount * sizeof( u32 ) + , makeBuffer< u32 >( m_device + , MaxLightsCount , VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT , "C3D_SpotLightMortonCodesB" ) } } - , m_pointIndicesBuffers{ { makeBufferBase( m_device - , MaxLightsCount * sizeof( u32 ) + , m_pointIndicesBuffers{ { makeBuffer< u32 >( m_device + , MaxLightsCount , VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT , "C3D_PointLightIndicesA" ) - , makeBufferBase( m_device - , MaxLightsCount * sizeof( u32 ) + , makeBuffer< u32 >( m_device + , MaxLightsCount , VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT , "C3D_PointLightIndicesB" ) } } - , m_spotIndicesBuffers{ { makeBufferBase( m_device - , MaxLightsCount * sizeof( u32 ) + , m_spotIndicesBuffers{ { makeBuffer< u32 >( m_device + , MaxLightsCount , VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT , "C3D_SpotLightIndicesA" ) - , makeBufferBase( m_device - , MaxLightsCount * sizeof( u32 ) + , makeBuffer< u32 >( m_device + , MaxLightsCount , VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT , "C3D_SpotLightIndicesB" ) } } - , m_pointBVHBuffer{ makeBufferBase( m_device - , sizeof( AABB ) * getNumNodes( MaxLightsCount ) + , m_pointBVHBuffer{ makeBuffer< AABB >( m_device + , getNumNodes( MaxLightsCount ) , VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT , "C3D_PointLightBVH" ) } - , m_spotBVHBuffer{ makeBufferBase( m_device - , sizeof( AABB ) * getNumNodes( MaxLightsCount ) + , m_spotBVHBuffer{ makeBuffer< AABB >( m_device + , getNumNodes( MaxLightsCount ) , VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT , "C3D_SpotLightBVH" ) } @@ -145,8 +154,8 @@ namespace castor3d // needed by a single sort group multiplied by the maximum number of sort groups. uint32_t maxMergePathPartitions = numMergePathPartitionsPerSortGroup * maxSortGroups; - m_mergePathPartitionsBuffer = makeBufferBase( m_device - , sizeof( u32 ) * maxMergePathPartitions + m_mergePathPartitionsBuffer = makeBuffer< s32 >( m_device + , maxMergePathPartitions , VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT , "C3D_MergePathPartitions" ); @@ -158,7 +167,8 @@ namespace castor3d void FrustumClusters::update( CpuUpdater & updater ) { - auto & lightCache = m_camera.getScene()->getLightCache(); + auto scene = m_camera.getScene(); + auto & lightCache = scene->getLightCache(); m_clustersDirty = lightCache.hasClusteredLights() && m_first; doUpdate(); @@ -166,10 +176,13 @@ namespace castor3d , m_camera.getNear() , m_clusterSize.value() , m_nearK.value() - , lightCache.getLightsCount( LightType::ePoint ) - , lightCache.getLightsCount( LightType::eSpot ) ); + , lightCache.getLightsBufferCount( LightType::ePoint ) + , lightCache.getLightsBufferCount( LightType::eSpot ) ); + auto it = updater.dirtyScenes.find( scene ); m_lightsDirty = lightCache.hasClusteredLights() - && ( m_clustersDirty || lightCache.isDirty() ); + && ( m_clustersDirty + || lightCache.isDirty() + || ( it != updater.dirtyScenes.end() && !it->second.isEmpty() ) ); m_first = m_camera.getEngine()->areUpdateOptimisationsEnabled() ? false : true; @@ -177,10 +190,20 @@ namespace castor3d crg::FramePass const & FrustumClusters::createFramePasses( crg::FramePassGroup & parentGraph , crg::FramePass const * previousPass - , CameraUbo const & cameraUbo ) + , RenderTechnique & technique + , CameraUbo const & cameraUbo + , RenderNodesPass *& nodesPass ) { auto & graph = parentGraph.createPassGroup( "Clusters" ); - crg::FramePassArray lastPasses = { &createComputeClustersAABBPass( graph, previousPass + crg::FramePassArray lastPasses{ 1u, previousPass }; +#if C3D_DebugUseDepthClusteredSamples + lastPasses = { &createClustersMaskPass( graph, *lastPasses.front() + , m_device, cameraUbo, *this + , technique, nodesPass ) }; + lastPasses = { &createFindUniqueClustersPass( graph, *lastPasses.front() + , m_device, cameraUbo, *this ) }; +#endif + lastPasses = { &createComputeClustersAABBPass( graph, lastPasses.front() , m_device, cameraUbo, *this ) }; #if C3D_DebugUseLightsBVH lastPasses = { &createReduceLightsAABBPass( graph, lastPasses.front() @@ -287,7 +310,11 @@ namespace castor3d frscls::updateBuffer< castor::Point2ui >( m_device, cellCount, "PointLightClusterGrid", m_pointLightClusterGridBuffer, m_toDelete ); frscls::updateBuffer< castor::Point2ui >( m_device, cellCount, "SpotLightClusterGrid", m_spotLightClusterGridBuffer, m_toDelete ); frscls::updateBuffer< u32 >( m_device, indexCount, "PointLightClusterIndex", m_pointLightClusterIndexBuffer, m_toDelete ); - frscls::updateBuffer< u32 >( m_device, indexCount, "SpottLightClusterIndex", m_spotLightClusterIndexBuffer, m_toDelete ); + frscls::updateBuffer< u32 >( m_device, indexCount, "SpotLightClusterIndex", m_spotLightClusterIndexBuffer, m_toDelete ); +#if C3D_DebugUseDepthClusteredSamples + frscls::updateBuffer< u32 >( m_device, cellCount, "ClusterFlags", m_clusterFlags, m_toDelete ); + frscls::updateBuffer< u32 >( m_device, cellCount, "UniqueClusters", m_uniqueClusters, m_toDelete ); +#endif onClusterBuffersChanged( *this ); } } diff --git a/source/Core/Castor3D/Render/Clustered/ReduceLightsAABB.cpp b/source/Core/Castor3D/Render/Clustered/ReduceLightsAABB.cpp index af7e6be5cd..3349658766 100644 --- a/source/Core/Castor3D/Render/Clustered/ReduceLightsAABB.cpp +++ b/source/Core/Castor3D/Render/Clustered/ReduceLightsAABB.cpp @@ -281,8 +281,8 @@ namespace castor3d : shader{ VK_SHADER_STAGE_COMPUTE_BIT, "ReduceLightsAABB" + ( first ? std::string{ "/First" } : std::string{ "/Second" } ), createShader( first ) } , createInfo{ ashes::PipelineShaderStageCreateInfoArray{ makeShaderState( device, shader ) } } , cpConfig{ crg::getDefaultV< InitialiseCallback >() - , &clusters.needsLightsUpdate() - , crg::getDefaultV< IsEnabledCallback >() + , nullptr + , IsEnabledCallback( [&clusters]() { return clusters.needsLightsUpdate(); } ) , crg::getDefaultV< GetPassIndexCallback >() , crg::getDefaultV< RecordCallback >() , crg::getDefaultV< RecordCallback >() @@ -331,8 +331,8 @@ namespace castor3d uint32_t reduceNumElements{}; } dispatchData; - auto pointLightsCount = m_lightCache.getLightsCount( LightType::ePoint ); - auto spoLightsCount = m_lightCache.getLightsCount( LightType::eSpot ); + auto pointLightsCount = m_lightCache.getLightsBufferCount( LightType::ePoint ); + auto spoLightsCount = m_lightCache.getLightsBufferCount( LightType::eSpot ); auto maxLightsCount = std::max( pointLightsCount, spoLightsCount ); // Don't dispatch more than 512 thread groups. The reduction algorithm depends on the diff --git a/source/Core/Castor3D/Render/Clustered/SortLightsMortonCode.cpp b/source/Core/Castor3D/Render/Clustered/SortLightsMortonCode.cpp index 470c8e21d0..4c7b51b5ed 100644 --- a/source/Core/Castor3D/Render/Clustered/SortLightsMortonCode.cpp +++ b/source/Core/Castor3D/Render/Clustered/SortLightsMortonCode.cpp @@ -324,7 +324,7 @@ namespace castor3d bool doIsEnabled()const { return m_clusters.needsLightsUpdate() - && m_lightCache.getLightsCount( m_lightData.lightType ) > 0; + && m_lightCache.getLightsBufferCount( m_lightData.lightType ) > 0; } void doRecordInto( crg::RecordContext & context @@ -332,7 +332,7 @@ namespace castor3d , uint32_t index ) { // Build bottom level of the BVH. - auto lightsCount = m_lightCache.getLightsCount( m_lightData.lightType ); + auto lightsCount = m_lightCache.getLightsBufferCount( m_lightData.lightType ); auto numThreadGroups = uint32_t( std::ceil( float( lightsCount ) / float( NumThreadsPerThreadGroup ) ) ); DispatchData data{ lightsCount, 0u }; m_pipeline.pipeline.recordInto( context, commandBuffer, index ); @@ -747,14 +747,14 @@ namespace castor3d bool doIsEnabled()const { return m_clusters.needsLightsUpdate() - && m_lightCache.getLightsCount( m_lightData.lightType ) > 0; + && m_lightCache.getLightsBufferCount( m_lightData.lightType ) > 0; } void doRecordInto( crg::RecordContext & context , VkCommandBuffer commandBuffer , uint32_t index ) { - auto totalValues = m_lightCache.getLightsCount( m_lightData.lightType ); + auto totalValues = m_lightCache.getLightsBufferCount( m_lightData.lightType ); auto chunkSize = NumThreadsPerThreadGroup; // The total number of complete chunks to sort. diff --git a/source/Core/Castor3D/Render/Prepass/DepthPass.cpp b/source/Core/Castor3D/Render/Prepass/DepthPass.cpp index b1d82ecd62..c7f723f96b 100644 --- a/source/Core/Castor3D/Render/Prepass/DepthPass.cpp +++ b/source/Core/Castor3D/Render/Prepass/DepthPass.cpp @@ -100,6 +100,17 @@ namespace castor3d , m_deferred ? 2u : 3u ); } + void DepthPass::doFillAdditionalBindings( PipelineFlags const & flags + , ashes::VkDescriptorSetLayoutBindingArray & bindings )const + { + } + + void DepthPass::doFillAdditionalDescriptor( PipelineFlags const & flags + , ashes::WriteDescriptorSetArray & descriptorWrites + , ShadowMapLightTypeArray const & shadowMaps ) + { + } + ShaderPtr DepthPass::doGetGeometryShaderSource( PipelineFlags const & flags )const { return ShaderPtr{}; diff --git a/source/Core/Castor3D/Render/Prepass/PrepassRendering.cpp b/source/Core/Castor3D/Render/Prepass/PrepassRendering.cpp index 00a45e2650..61290d4ca1 100644 --- a/source/Core/Castor3D/Render/Prepass/PrepassRendering.cpp +++ b/source/Core/Castor3D/Render/Prepass/PrepassRendering.cpp @@ -88,19 +88,6 @@ namespace castor3d void PrepassRendering::update( GpuUpdater & updater ) { - if ( !m_depthPass && !m_visibilityPass ) - { - return; - } - - if ( hasVisibility() ) - { - m_visibilityPass->countNodes( updater.info ); - } - else - { - m_depthPass->countNodes( updater.info ); - } } void PrepassRendering::accept( RenderTechniqueVisitor & visitor ) diff --git a/source/Core/Castor3D/Render/Prepass/VisibilityPass.cpp b/source/Core/Castor3D/Render/Prepass/VisibilityPass.cpp index 076678c494..d663af113d 100644 --- a/source/Core/Castor3D/Render/Prepass/VisibilityPass.cpp +++ b/source/Core/Castor3D/Render/Prepass/VisibilityPass.cpp @@ -7,6 +7,7 @@ #include "Castor3D/Render/RenderPipeline.hpp" #include "Castor3D/Render/RenderSystem.hpp" #include "Castor3D/Render/RenderTarget.hpp" +#include "Castor3D/Render/RenderTechnique.hpp" #include "Castor3D/Render/Opaque/VisibilityResolvePass.hpp" #include "Castor3D/Scene/Scene.hpp" #include "Castor3D/Shader/Program.hpp" @@ -21,6 +22,7 @@ #include "Castor3D/Shader/Shaders/GlslSurface.hpp" #include "Castor3D/Shader/Ubos/BillboardUbo.hpp" #include "Castor3D/Shader/Ubos/CameraUbo.hpp" +#include "Castor3D/Shader/Ubos/ClustersUbo.hpp" #include "Castor3D/Shader/Ubos/ModelDataUbo.hpp" #include diff --git a/source/Core/Castor3D/Render/RenderTechnique.cpp b/source/Core/Castor3D/Render/RenderTechnique.cpp index 2d52bbd66b..ae082e6848 100644 --- a/source/Core/Castor3D/Render/RenderTechnique.cpp +++ b/source/Core/Castor3D/Render/RenderTechnique.cpp @@ -67,9 +67,9 @@ namespace castor3d auto lock( castor::makeUniqueLock( cache ) ); std::map< double, LightRPtr > lights; - if ( cache.getLightsCount( LightType::eDirectional ) <= 1u - && cache.getLightsCount( LightType::ePoint ) <= MaxPointShadowMapCount - && cache.getLightsCount( LightType::eSpot ) <= MaxSpotShadowMapCount ) + if ( cache.getLightsBufferCount( LightType::eDirectional ) <= 1u + && cache.getLightsBufferCount( LightType::ePoint ) <= MaxPointShadowMapCount + && cache.getLightsBufferCount( LightType::eSpot ) <= MaxSpotShadowMapCount ) { double index{}; @@ -389,7 +389,9 @@ namespace castor3d , m_clustersLastPass{ ( C3D_UseClusteredRendering ? &m_renderTarget.getFrustumClusters().createFramePasses( m_graph , m_depthRangePass - , m_cameraUbo ) + , *this + , m_cameraUbo + , m_clustersFlagsPass ) : nullptr ) } , m_background{ doCreateBackgroundPass( progress ) } , m_opaque{ *this @@ -497,6 +499,11 @@ namespace castor3d } ); m_prepass.update( updater ); + if ( m_clustersFlagsPass ) + { + m_clustersFlagsPass->update( updater ); + } + rendtech::applyAction( m_renderPasses[size_t( TechniquePassEvent::eBeforeBackground )] , [&updater]( RenderTechniquePass & renderPass ) { diff --git a/source/Core/Castor3D/Scene/Light/DirectionalLight.cpp b/source/Core/Castor3D/Scene/Light/DirectionalLight.cpp index 9521a9d331..bdb22f71ad 100644 --- a/source/Core/Castor3D/Scene/Light/DirectionalLight.cpp +++ b/source/Core/Castor3D/Scene/Light/DirectionalLight.cpp @@ -164,7 +164,7 @@ namespace castor3d //************************************************************************************************* DirectionalLight::DirectionalLight( Light & light ) - : LightCategory{ LightType::eDirectional, light } + : LightCategory{ LightType::eDirectional, light, LightDataComponents } , m_cascades( light.getScene()->getDirectionalShadowCascades() ) , m_prvCascades( light.getScene()->getDirectionalShadowCascades() ) { diff --git a/source/Core/Castor3D/Scene/Light/LightCategory.cpp b/source/Core/Castor3D/Scene/Light/LightCategory.cpp index c60977cc66..5e96014b38 100644 --- a/source/Core/Castor3D/Scene/Light/LightCategory.cpp +++ b/source/Core/Castor3D/Scene/Light/LightCategory.cpp @@ -11,9 +11,10 @@ CU_ImplementSmartPtr( castor3d, LightCategory ) namespace castor3d { - LightCategory::LightCategory( LightType lightType, Light & light ) + LightCategory::LightCategory( LightType lightType, Light & light, uint32_t componentCount ) : m_lightType{ lightType } , m_light{ light } + , m_componentCount{ componentCount } { } diff --git a/source/Core/Castor3D/Scene/Light/PointLight.cpp b/source/Core/Castor3D/Scene/Light/PointLight.cpp index eb674205f2..567f98fb96 100644 --- a/source/Core/Castor3D/Scene/Light/PointLight.cpp +++ b/source/Core/Castor3D/Scene/Light/PointLight.cpp @@ -32,7 +32,7 @@ namespace castor3d //************************************************************************************************* PointLight::PointLight( Light & light ) - : LightCategory{ LightType::ePoint, light } + : LightCategory{ LightType::ePoint, light, LightDataComponents } { } diff --git a/source/Core/Castor3D/Scene/Light/SpotLight.cpp b/source/Core/Castor3D/Scene/Light/SpotLight.cpp index 7f339edc35..afb1239755 100644 --- a/source/Core/Castor3D/Scene/Light/SpotLight.cpp +++ b/source/Core/Castor3D/Scene/Light/SpotLight.cpp @@ -43,7 +43,7 @@ namespace castor3d //************************************************************************************************* SpotLight::SpotLight( Light & light ) - : LightCategory{ LightType::eSpot, light } + : LightCategory{ LightType::eSpot, light, LightDataComponents } , m_attenuation{ m_dirtyData, castor::Point3f{ 1, 0, 0 } } , m_exponent{ m_dirtyData, 1.0f } , m_innerCutOff{ m_dirtyData, 22.5_degrees } diff --git a/source/Core/Castor3D/Scene/Scene.cpp b/source/Core/Castor3D/Scene/Scene.cpp index 7b6e8776bb..1357dce924 100644 --- a/source/Core/Castor3D/Scene/Scene.cpp +++ b/source/Core/Castor3D/Scene/Scene.cpp @@ -452,9 +452,9 @@ namespace castor3d auto block( m_timerGpuUpdate->start() ); #endif updater.scene = this; - updater.info.totalLightsCount += getLightCache().getLightsCount( LightType::eDirectional ); - updater.info.totalLightsCount += getLightCache().getLightsCount( LightType::eSpot ); - updater.info.totalLightsCount += getLightCache().getLightsCount( LightType::ePoint ); + updater.info.totalLightsCount += getLightCache().getLightsBufferCount( LightType::eDirectional ); + updater.info.totalLightsCount += getLightCache().getLightsBufferCount( LightType::eSpot ); + updater.info.totalLightsCount += getLightCache().getLightsBufferCount( LightType::ePoint ); doUpdateParticles( updater ); m_renderNodes->update( updater ); m_meshCache->forEach( []( Mesh & mesh ) diff --git a/source/Core/Castor3D/Scene/SceneFileParser_Parsers.cpp b/source/Core/Castor3D/Scene/SceneFileParser_Parsers.cpp index 55a9d4e538..a6306be6a4 100644 --- a/source/Core/Castor3D/Scene/SceneFileParser_Parsers.cpp +++ b/source/Core/Castor3D/Scene/SceneFileParser_Parsers.cpp @@ -64,6 +64,8 @@ #include #include +using castor::operator<<; + namespace castor3d { namespace scnprs @@ -575,6 +577,10 @@ namespace castor3d { auto & parsingContext = getParserContext( context ); parsingContext.inWindow = false; + log::info << "Loaded RenderWindow [" << parsingContext.window.name + << ", HDR(" << parsingContext.window.allowHdr << ")" + << ", VSYNC(" << parsingContext.window.enableVSync << ")" + << ", FS" << parsingContext.window.fullscreen << ")]" << std::endl; } CU_EndAttributePop() @@ -784,6 +790,11 @@ namespace castor3d } else { + auto target = parsingContext.renderTarget; + log::info << "Loaded RenderTarget [" << target->getName() + << ", FMT(" << ashes::getName( VkFormat( target->getPixelFormat() ) ) << ")" + << ", VSYNC(" << target->getSize() << ")]" << std::endl; + if ( parsingContext.inWindow ) { parsingContext.window.renderTarget = std::move( parsingContext.renderTarget ); @@ -1070,6 +1081,8 @@ namespace castor3d } else { + log::info << "Loaded Sampler [" << parsingContext.sampler->getName() << "]" << std::endl; + if ( parsingContext.ownSampler ) { parsingContext.parser->getEngine()->addSampler( parsingContext.ownSampler->getName() @@ -1468,6 +1481,8 @@ namespace castor3d } else { + log::info << "Loaded Scene [" << parsingContext.scene->getName() << "]" << std::endl; + if ( parsingContext.scene->getName() == LoadingScreen::SceneName ) { parsingContext.parser->getEngine()->setLoadingScene( std::move( parsingContext.ownScene ) ); @@ -1911,6 +1926,7 @@ namespace castor3d else { parsingContext.parentNode = nullptr; + log::info << "Loaded Sampler [" << parsingContext.particleSystem->getName() << "]" << std::endl; if ( parsingContext.ownParticleSystem ) { @@ -2025,6 +2041,7 @@ namespace castor3d } else { + log::info << "Loaded Light [" << parsingContext.light->getName() << "]" << std::endl; parsingContext.parentNode = nullptr; if ( parsingContext.ownLight ) @@ -2831,6 +2848,8 @@ namespace castor3d } } } + + log::info << "Loaded SceneNode [" << name << "]" << std::endl; } CU_EndAttributePop() @@ -2976,6 +2995,7 @@ namespace castor3d { auto & parsingContext = getParserContext( context ); parsingContext.parentNode = nullptr; + log::info << "Loaded Geometry [" << parsingContext.geometry->getName() << "]" << std::endl; if ( parsingContext.ownGeometry ) { @@ -3145,6 +3165,7 @@ namespace castor3d } else { + log::info << "Loaded Skeleton [" << parsingContext.skeleton->getName() << "]" << std::endl; parsingContext.importer.reset(); parsingContext.skeleton = nullptr; } @@ -3603,6 +3624,7 @@ namespace castor3d } else if ( auto mesh = parsingContext.mesh ) { + log::info << "Loaded MorpAnimation [" << parsingContext.morphAnimation->getName() << "]" << std::endl; mesh->addAnimation( castor::ptrRefCast< Animation >( parsingContext.morphAnimation ) ); } else @@ -4132,6 +4154,8 @@ namespace castor3d } else if ( parsingContext.ownMaterial ) { + log::info << "Loaded Material [" << parsingContext.material->getName() << "]" << std::endl; + if ( parsingContext.scene ) { parsingContext.scene->addMaterial( parsingContext.material->getName() @@ -4209,6 +4233,8 @@ namespace castor3d else { parsingContext.pass->prepareTextures(); + log::info << "Loaded Pass [" << parsingContext.material->getName() + << ", " << parsingContext.pass->getIndex() << "]" << std::endl; parsingContext.pass = {}; parsingContext.passComponent = nullptr; } @@ -4894,6 +4920,8 @@ namespace castor3d , uint32_t( parsingContext.fontHeight ) , context.file.getPath() / parsingContext.path ); } + + log::info << "Loaded Font [" << parsingContext.strName << "]" << std::endl; } } CU_EndAttributePop() @@ -5058,6 +5086,7 @@ namespace castor3d CU_ImplementAttributeParser( parserOverlayEnd ) { auto & parsingContext = getParserContext( context ); + log::info << "Loaded Overlay [" << parsingContext.overlay.rptr->getName() << "]" << std::endl; if ( parsingContext.overlay.rptr->getType() == OverlayType::eText ) { @@ -5464,6 +5493,7 @@ namespace castor3d , std::move( *parsingContext.viewport.release() ) ); camera->setGamma( parsingContext.point2f[0] ); camera->setExposure( parsingContext.point2f[1] ); + log::info << "Loaded Camera [" << camera->getName() << "]" << std::endl; } } CU_EndAttributePop() @@ -5677,6 +5707,7 @@ namespace castor3d { auto & parsingContext = getParserContext( context ); parsingContext.parentNode = nullptr; + log::info << "Loaded Billboards [" << parsingContext.billboards->getName() << "]" << std::endl; if ( parsingContext.ownBillboards ) { @@ -5927,6 +5958,7 @@ namespace castor3d CU_ParsingError( cuT( "No animated object group initialised" ) ); } + log::info << "Loaded AnimatedObjectGroup [" << parsingContext.animGroup->getName() << "]" << std::endl; parsingContext.animGroup = {}; } CU_EndAttributePop() @@ -6281,6 +6313,7 @@ namespace castor3d if ( parsingContext.skybox ) { + log::info << "Loaded Skybox" << std::endl; parsingContext.scene->setBackground( castor::ptrRefCast< SceneBackground >( parsingContext.skybox ) ); } else @@ -6632,6 +6665,7 @@ namespace castor3d if ( parsingContext.renderTarget ) { + log::info << "Loaded SSAO Configuration" << std::endl; parsingContext.renderTarget->setSsaoConfig( parsingContext.ssaoConfig ); parsingContext.ssaoConfig = {}; } diff --git a/source/Core/Castor3D/Shader/ShaderBuffers/LightBuffer.cpp b/source/Core/Castor3D/Shader/ShaderBuffers/LightBuffer.cpp index 10f71223ec..56c5d1db22 100644 --- a/source/Core/Castor3D/Shader/ShaderBuffers/LightBuffer.cpp +++ b/source/Core/Castor3D/Shader/ShaderBuffers/LightBuffer.cpp @@ -1,12 +1,15 @@ #include "Castor3D/Shader/ShaderBuffers/LightBuffer.hpp" #include "Castor3D/Engine.hpp" +#include "Castor3D/Miscellaneous/Logger.hpp" #include "Castor3D/Scene/Light/DirectionalLight.hpp" #include "Castor3D/Scene/Light/Light.hpp" #include "Castor3D/Scene/Light/PointLight.hpp" #include "Castor3D/Scene/Light/SpotLight.hpp" #include "Castor3D/Shader/Shaders/SdwModule.hpp" +#include + CU_ImplementSmartPtr( castor3d, LightBuffer ) namespace castor3d @@ -15,12 +18,10 @@ namespace castor3d namespace lgtbuf { - static LightBuffer::LightsData doBindData( uint8_t * buffer - , uint32_t count ) - { - return castor::makeArrayView( reinterpret_cast< castor::Point4f * >( buffer ) - , reinterpret_cast< castor::Point4f * >( buffer ) + count ); - } + static VkDeviceSize MaxLightComponentsCount = castor::maxValueT< uint32_t + , DirectionalLight::LightDataComponents + , PointLight::LightDataComponents + , SpotLight::LightDataComponents >; } //********************************************************************************************* @@ -28,11 +29,15 @@ namespace castor3d LightBuffer::LightBuffer( Engine & engine , RenderDevice const & device , uint32_t count ) - : m_buffer{ engine, device, count * 32u * sizeof( castor::Point4f ), cuT( "LightBuffer" ) } + : m_buffer{ engine + , device + , VkDeviceSize( count ) * lgtbuf::MaxLightComponentsCount * sizeof( castor::Point4f ) + , cuT( "C3D_LightBuffer" ) } , m_lightSizes{ DirectionalLight::LightDataComponents , PointLight::LightDataComponents , SpotLight::LightDataComponents } - , m_data{ lgtbuf::doBindData( m_buffer.getPtr(), count * 32u ) } + , m_data{ castor::makeArrayView( reinterpret_cast< castor::Point4f * >( m_buffer.getPtr() ) + , VkDeviceSize( count ) * lgtbuf::MaxLightComponentsCount ) } { } @@ -40,19 +45,20 @@ namespace castor3d { auto lock( castor::makeUniqueLock( m_mutex ) ); auto index = size_t( light.getLightType() ); - auto it = std::find( m_typeSortedLights[index].begin() - , m_typeSortedLights[index].end() + auto & lights = m_typeSortedLights[index]; + auto it = std::find( lights.begin() + , lights.end() , &light ); - if ( it == m_typeSortedLights[index].end() ) + if ( it == lights.end() ) { - m_typeSortedLights[index].push_back( &light ); + lights.push_back( &light ); m_dirty.emplace_back( &light ); m_connections.emplace( &light , light.onGPUChanged.connect( [this]( Light & plight ) - { - m_dirty.emplace_back( &plight ); - } ) ); + { + m_dirty.emplace_back( &plight ); + } ) ); // Mark next lights as dirty (due to sorted container) doMarkNextDirty( LightType( index + 1u ), 0u ); @@ -63,14 +69,15 @@ namespace castor3d { auto lock( castor::makeUniqueLock( m_mutex ) ); auto index = size_t( light.getLightType() ); - auto it = std::find( m_typeSortedLights[index].begin() - , m_typeSortedLights[index].end() + auto & lights = m_typeSortedLights[index]; + auto it = std::find( lights.begin() + , lights.end() , &light ); - if ( it != m_typeSortedLights[index].end() ) + if ( it != lights.end() ) { - auto dist = uint32_t( std::distance( m_typeSortedLights[index].begin(), it ) ); - m_typeSortedLights[index].erase( it ); + auto dist = uint32_t( std::distance( lights.begin(), it ) ); + lights.erase( it ); m_connections.erase( &light ); // Mark next lights as dirty (due to sorted container) @@ -90,15 +97,16 @@ namespace castor3d for ( auto light : castor::makeArrayView( dirty.begin(), std::unique( dirty.begin(), dirty.end() ) ) ) { auto [index, offset] = doGetOffsetIndex( *light ); - light->fillBuffer( index, offset, &m_data[offset] ); + + if ( index <= MaxLightsCount ) + { + light->fillBuffer( index, offset, &m_data[offset] ); + } } - auto dirEnd = uint32_t( m_typeSortedLights[0].size() * DirectionalLight::LightDataComponents ); - auto pntEnd = uint32_t( dirEnd + m_typeSortedLights[1].size() * PointLight::LightDataComponents ); - auto sptEnd = uint32_t( pntEnd + m_typeSortedLights[2].size() * SpotLight::LightDataComponents ); - m_buffer.setFirstCount( dirEnd ); - m_buffer.setSecondCount( pntEnd ); - m_buffer.setThirdCount( sptEnd ); + m_buffer.setFirstCount( std::min( uint32_t( m_data.size() ), doGetBufferEnd( LightType::eDirectional ) ) ); + m_buffer.setSecondCount( std::min( uint32_t( m_data.size() ), doGetBufferEnd( LightType::ePoint ) ) ); + m_buffer.setThirdCount( std::min( uint32_t( m_data.size() ), doGetBufferEnd( LightType::eSpot ) ) ); m_wasDirty = true; } } @@ -140,17 +148,33 @@ namespace castor3d return m_buffer.getSingleBinding( binding, offset, size ); } + uint32_t LightBuffer::getLightsBufferCount( LightType lightType )const noexcept + { + uint32_t result{}; + auto type = uint32_t( lightType ); + + for ( uint32_t i = 0u; i < type; ++i ) + { + result += getLightsBufferCount( LightType( i ) ); + } + + auto count = uint32_t( m_typeSortedLights[type].size() ); + return ( ( result + count <= MaxLightsCount ) + ? count + : ( MaxLightsCount - result ) ); + } + std::pair< uint32_t, uint32_t > LightBuffer::doGetOffsetIndex( Light const & light )const { + uint32_t index{}; uint32_t result{}; uint32_t type = uint32_t( light.getLightType() ); - uint32_t index{}; for ( uint32_t i = 0u; i < type; ++i ) { - auto count = m_typeSortedLights[i].size(); - index += uint32_t( count ); - result += uint32_t( count * m_lightSizes[i] ); + auto count = getLightsBufferCount( LightType( i ) ); + index += count; + result += count * m_lightSizes[i]; } auto typeSortedLights = m_typeSortedLights[type]; @@ -181,4 +205,20 @@ namespace castor3d } } } + + uint32_t LightBuffer::doGetBufferEnd( LightType lightType )const noexcept + { + uint32_t bufferEnd{}; + auto type = uint32_t( lightType ); + + for ( uint32_t i = 0u; i < type; ++i ) + { + auto count = getLightsBufferCount( LightType( i ) ); + bufferEnd += count * m_lightSizes[i]; + } + + auto count = getLightsBufferCount( lightType ); + bufferEnd += count * m_lightSizes[type]; + return bufferEnd; + } } diff --git a/source/Core/Castor3D/Shader/ShaderBuffers/PassBuffer.cpp b/source/Core/Castor3D/Shader/ShaderBuffers/PassBuffer.cpp index ebdb3511e6..3ebf51a77a 100644 --- a/source/Core/Castor3D/Shader/ShaderBuffers/PassBuffer.cpp +++ b/source/Core/Castor3D/Shader/ShaderBuffers/PassBuffer.cpp @@ -88,7 +88,8 @@ namespace castor3d , RenderDevice const & device , uint32_t count ) : m_stride{ uint32_t( engine.getPassComponentsRegister().getPassBufferStride() ) } - , m_buffer{ engine, device, count * m_stride, cuT( "PassBuffer" ) } + , m_maxCount{ count } + , m_buffer{ engine, device, count * VkDeviceSize( m_stride ), cuT( "PassBuffer" ) } , m_data{ castor::makeArrayView( m_buffer.getPtr(), count * m_stride ) } { } @@ -99,7 +100,7 @@ namespace castor3d { auto lock( castor::makeUniqueLock( m_mutex ) ); - CU_Require( m_passes.size() < MaxMaterialsCount ); + CU_Require( m_passes.size() < m_maxCount ); m_passes.emplace_back( &pass ); pass.setId( m_passID++ ); m_connections.emplace_back( pass.onChanged.connect( [this]( Pass const & ppass @@ -153,8 +154,15 @@ namespace castor3d , PassTypeData{ uint16_t( m_passTypeIndices.size() ) , pass->getComponentCombineID() , pass->getTextureCombineID() } ).first; - - pass->fillBuffer( *this, it->second.index ); + + if ( it->second.index * VkDeviceSize( m_stride ) > m_data.size() ) + { + log::warn << "Material pass [" << pass->getOwner()->getName() << ", " << pass->getIndex() <<"] is out of buffer boundaries, ignoring it." << std::endl; + } + else + { + pass->fillBuffer( *this, it->second.index ); + } for ( auto & buffer : specifics ) { @@ -164,7 +172,8 @@ namespace castor3d pass->reset(); } - m_buffer.setCount( uint32_t( m_passes.size() ) ); + auto passCount = std::min( m_maxCount, uint32_t( m_passes.size() ) ); + m_buffer.setCount( passCount ); m_buffer.setSecondCount( uint32_t( m_passTypeIndices.size() ) ); m_buffer.upload( commandBuffer ); @@ -172,7 +181,7 @@ namespace castor3d { if ( auto & buf = buffer.second.second ) { - buf->setCount( uint32_t( m_passes.size() ) ); + buf->setCount( passCount ); buf->upload( commandBuffer ); } } @@ -211,7 +220,20 @@ namespace castor3d { CU_Require( passID > 0 ); auto index = passID - 1; - return PassBuffer::PassDataPtr{ castor::makeArrayView( m_data.data() + m_stride * index, m_stride ) }; + + if ( index < m_maxCount ) + { + return PassBuffer::PassDataPtr{ castor::makeArrayView( m_data.data() + ptrdiff_t( m_stride ) * index, m_stride ) }; + } + + CU_Failure( "Pass ID is out of buffer bounds." ); + static castor::ByteArray dummy{ [this]() + { + castor::ByteArray result; + result.resize( m_stride ); + return result; + }() }; + return PassBuffer::PassDataPtr{ castor::makeArrayView( dummy.data(), m_stride ) }; } uint32_t PassBuffer::getMaxPassTypeCount()const diff --git a/source/Core/Castor3D/Shader/ShaderBuffers/SssProfileBuffer.cpp b/source/Core/Castor3D/Shader/ShaderBuffers/SssProfileBuffer.cpp index 0c0bfed075..6406366944 100644 --- a/source/Core/Castor3D/Shader/ShaderBuffers/SssProfileBuffer.cpp +++ b/source/Core/Castor3D/Shader/ShaderBuffers/SssProfileBuffer.cpp @@ -81,13 +81,23 @@ namespace castor3d std::vector< SubsurfaceScatteringComponent const * > dirty; std::swap( m_dirty, dirty ); auto end = std::unique( dirty.begin(), dirty.end() ); + uint32_t index{}; - std::for_each( dirty.begin(), end, [this]( SubsurfaceScatteringComponent const * component ) + for ( auto component : castor::makeArrayView( dirty.begin(), end ) ) { + if ( index * VkDeviceSize( DataSize ) > m_data.size() ) + { + log::warn << "SssProfile [" << component->getSssProfileId() << "] is out of buffer boundaries, ignoring it." << std::endl; + } + else + { component->fillProfileBuffer( *this ); - } ); + } + + ++index; + } - m_buffer.setCount( uint32_t( m_components.size() ) ); + m_buffer.setCount( uint32_t( std::min( m_data.size() * DataSize, m_components.size() ) ) ); m_buffer.upload( commandBuffer ); } } diff --git a/source/Core/Castor3D/Shader/ShaderBuffers/TextureAnimationBuffer.cpp b/source/Core/Castor3D/Shader/ShaderBuffers/TextureAnimationBuffer.cpp index e3e3ef850f..79df7e5a96 100644 --- a/source/Core/Castor3D/Shader/ShaderBuffers/TextureAnimationBuffer.cpp +++ b/source/Core/Castor3D/Shader/ShaderBuffers/TextureAnimationBuffer.cpp @@ -64,10 +64,16 @@ namespace castor3d if ( m_count ) { auto lock( castor::makeUniqueLock( m_mutex ) ); - auto buffer = m_data.data(); + auto buffer = m_data.begin(); for ( auto anim : castor::makeArrayView( std::next( m_animations.begin() ), m_animations.end() ) ) { + if ( buffer == m_data.end() ) + { + log::warn << "TextureAnimation [" << anim->getName() << "] is out of buffer boundaries, ignoring it." << std::endl; + break; + } + if ( anim ) { anim->fillBuffer( buffer ); @@ -76,7 +82,7 @@ namespace castor3d ++buffer; } - m_buffer.setCount( uint32_t( m_animations.size() ) ); + m_buffer.setCount( uint32_t( std::min( m_data.size(), m_animations.size() ) ) ); m_buffer.upload( commandBuffer ); } } diff --git a/source/Core/Castor3D/Shader/ShaderBuffers/TextureConfigurationBuffer.cpp b/source/Core/Castor3D/Shader/ShaderBuffers/TextureConfigurationBuffer.cpp index ec91396f36..e67c05c499 100644 --- a/source/Core/Castor3D/Shader/ShaderBuffers/TextureConfigurationBuffer.cpp +++ b/source/Core/Castor3D/Shader/ShaderBuffers/TextureConfigurationBuffer.cpp @@ -109,14 +109,18 @@ namespace castor3d std::swap( m_dirty, dirty ); auto end = std::unique( dirty.begin(), dirty.end() ); - std::for_each( dirty.begin() - , end - , [this]( TextureUnit const * unit ) - { - CU_Require( unit->getId() > 0 ); - auto & config = unit->getConfiguration(); - auto index = unit->getId() - 1u; + for ( auto unit : castor::makeArrayView( dirty.begin(), end ) ) + { + CU_Require( unit->getId() > 0 ); + auto & config = unit->getConfiguration(); + auto index = unit->getId() - 1u; + if ( index * DataSize > m_data.size() ) + { + log::warn << "TextureUnit [" << unit->getId() << "] is out of buffer boundaries, ignoring it." << std::endl; + } + else + { auto & data = m_data[index]; data.translate = config.transform.translate; data.rotateU = config.transform.rotate.cos(); @@ -139,9 +143,10 @@ namespace castor3d { data.components[i] = texcfgbuf::writeFlags( config.components[i] ); } - } ); + } + } - m_buffer.setCount( uint32_t( m_configurations.size() ) ); + m_buffer.setCount( uint32_t( std::min( m_data.size() * DataSize, m_configurations.size() ) ) ); m_buffer.upload( commandBuffer ); } } diff --git a/source/Core/SceneExporter/Text/TextTextureUnit.cpp b/source/Core/SceneExporter/Text/TextTextureUnit.cpp index 48c26d1098..5dfd358546 100644 --- a/source/Core/SceneExporter/Text/TextTextureUnit.cpp +++ b/source/Core/SceneExporter/Text/TextTextureUnit.cpp @@ -63,10 +63,11 @@ namespace castor } auto dimensions = unit.getTexture()->getDimensions(); + auto format = unit.getTexture()->getPixelFormat(); if ( result && unit.getTexture()->getMipmapCount() > 1 - && unit.getTexture()->getMipmapCount() != ashes::getMaxMipCount( dimensions ) ) + && unit.getTexture()->getMipmapCount() != castor::getMipLevels( dimensions, format ) ) { result = write( file, cuT( "levels_count" ), unit.getTexture()->getMipmapCount() ); } diff --git a/source/Plugins/Generic/AtmosphereScattering/AtmosphereBackgroundPass.cpp b/source/Plugins/Generic/AtmosphereScattering/AtmosphereBackgroundPass.cpp index 71903ee091..b806711d1c 100644 --- a/source/Plugins/Generic/AtmosphereScattering/AtmosphereBackgroundPass.cpp +++ b/source/Plugins/Generic/AtmosphereScattering/AtmosphereBackgroundPass.cpp @@ -3,6 +3,7 @@ #include "AtmosphereScattering/AtmosphereBackground.hpp" #include +#include #include #include #include @@ -96,7 +97,7 @@ namespace atmosphere_scattering , crg::rq::Config{} .isEnabled( IsEnabledCallback( [this](){ return castor3d::BackgroundPassBase::doIsEnabled(); } ) ) .renderSize( size ) - .depthStencilState( ashes::PipelineDepthStencilStateCreateInfo{ 0u, VK_TRUE, VK_FALSE, VK_COMPARE_OP_GREATER_OR_EQUAL } ) + .depthStencilState( castor3d::makeVkStruct< VkPipelineDepthStencilStateCreateInfo >( 0u, VK_TRUE, VK_FALSE, VK_COMPARE_OP_GREATER_OR_EQUAL ) ) .passIndex( &background.getPassIndex( forceVisible ) ) .programCreator( { 2u , [size, this, &background, &device]( uint32_t programIndex ) diff --git a/tools/GuiCommon/System/SceneObjectsList.cpp b/tools/GuiCommon/System/SceneObjectsList.cpp index a84ca795f4..13eae5147d 100644 --- a/tools/GuiCommon/System/SceneObjectsList.cpp +++ b/tools/GuiCommon/System/SceneObjectsList.cpp @@ -241,34 +241,16 @@ namespace GuiCommon , elem ); } ); - catId = AppendItem( sceneId - , _( "Cameras" ) - , eBMP_CAMERA - , eBMP_CAMERA_SEL ); - scene->getCameraCache().forEach( [this, catId]( castor3d::Camera & elem ) - { - doAddCamera( catId, elem ); - } ); - - catId = AppendItem( sceneId - , _( "Light Sources" ) - , eBMP_DIRECTIONAL_LIGHT - , eBMP_DIRECTIONAL_LIGHT_SEL ); - scene->getLightCache().forEach( [this, catId]( castor3d::Light & elem ) - { - doAddLight( catId, elem ); - } ); - - catId = AppendItem( sceneId - , _( "Scene Nodes" ) - , eBMP_NODE - , eBMP_NODE_SEL ); - auto rootNode = scene->getRootNode(); - - if ( rootNode ) - { - doAddNode( catId, *rootNode ); - } + //catId = AppendItem( sceneId + // , _( "Scene Nodes" ) + // , eBMP_NODE + // , eBMP_NODE_SEL ); + //auto rootNode = scene->getRootNode(); + + //if ( rootNode ) + //{ + // doAddNode( catId, *rootNode ); + //} catId = AppendItem( sceneId , _( "Materials" ) diff --git a/vcpkg.json b/vcpkg.json index 30fe633775..11c0911528 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -2,7 +2,7 @@ "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json", "name": "castor3d", "version": "0.15.0", - "builtin-baseline": "1c5a340f6e10985e2d92af174a68dbd15c1fa4e1", + "builtin-baseline": "8a2b7de29d42d713e4816d542cd610ee59dff63e", "dependencies": [ "convectionkernels", "freetype",