From dc41722b4ab0da664239f1157a9606a6c6ada868 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Mon, 28 Apr 2025 19:59:15 +0700 Subject: [PATCH 01/64] Implement mutable shader spec info --- include/nbl/asset/ICPUComputePipeline.h | 48 +++++++--- include/nbl/asset/ICPUGraphicsPipeline.h | 106 ++++++++++++++++------- include/nbl/asset/ICPUPipeline.h | 102 +--------------------- include/nbl/asset/IGraphicsPipeline.h | 4 +- include/nbl/asset/IPipeline.h | 26 ++++-- 5 files changed, 135 insertions(+), 151 deletions(-) diff --git a/include/nbl/asset/ICPUComputePipeline.h b/include/nbl/asset/ICPUComputePipeline.h index b9b707d9fc..704c4c05fc 100644 --- a/include/nbl/asset/ICPUComputePipeline.h +++ b/include/nbl/asset/ICPUComputePipeline.h @@ -12,20 +12,21 @@ namespace nbl::asset { //! CPU Version of Compute Pipeline -class ICPUComputePipeline : public ICPUPipeline,1> +class ICPUComputePipeline : public ICPUPipeline> { - using base_t = ICPUPipeline,1>; + using base_t = ICPUPipeline>; public: struct SCreationParams final : IPipeline::SCreationParams { - SShaderSpecInfo shader; + IPipelineBase::SShaderSpecInfo shader; }; static core::smart_refctd_ptr create(const SCreationParams& params) { if (!params.layout) return nullptr; auto retval = new ICPUComputePipeline(core::smart_refctd_ptr(params.layout)); + if (!retval->setSpecInfo(params.shader)) { retval->drop(); @@ -34,35 +35,54 @@ class ICPUComputePipeline : public ICPUPipeline,1> return core::smart_refctd_ptr(retval,core::dont_grab); } + inline core::smart_refctd_ptr clone(uint32_t _depth = ~0u) const override final + { + core::smart_refctd_ptr layout; + if (_depth>0u && m_layout) + layout = core::smart_refctd_ptr_static_cast(m_layout->clone(_depth-1u)); + + auto cp = new ICPUComputePipeline(std::move(layout)); + if (m_specInfo.shader) + { + SShaderSpecInfo specInfo = m_specInfo; + if (_depth > 0u) + { + specInfo.shader = core::smart_refctd_ptr_static_cast(m_specInfo.shader->clone(_depth - 1u)); + } + cp->setSpecInfo(specInfo); + } + return core::smart_refctd_ptr(cp,core::dont_grab); + } + constexpr static inline auto AssetType = ET_COMPUTE_PIPELINE; inline E_TYPE getAssetType() const override { return AssetType; } //! inline size_t getDependantCount() const override {return 2;} - // provide default arg - inline IPipelineBase::SShaderSpecInfo getSpecInfo() const {return base_t::getSpecInfo(hlsl::ShaderStage::ESS_COMPUTE);} - protected: using base_t::base_t; virtual ~ICPUComputePipeline() = default; - base_t* clone_impl(core::smart_refctd_ptr&& layout) const override - { - return new ICPUComputePipeline(std::move(layout)); - } - inline IAsset* getDependant_impl(const size_t ix) override { if (ix!=0) - return m_stages[0].shader.get(); + return m_specInfo.shader.get(); return const_cast(m_layout.get()); } - inline int8_t stageToIndex(const hlsl::ShaderStage stage) const override + inline bool setSpecInfo(const IPipelineBase::SShaderSpecInfo& info) { - return stage!=hlsl::ShaderStage::ESS_COMPUTE ? (-1):0; + const auto specSize = info.valid(); + if (specSize < 0) return false; + if (info.stage != hlsl::ESS_COMPUTE) return false; + m_specInfo = info; + return true; } + + private: + SShaderSpecInfo m_specInfo; + }; } diff --git a/include/nbl/asset/ICPUGraphicsPipeline.h b/include/nbl/asset/ICPUGraphicsPipeline.h index 2643db7550..b624d53aa9 100644 --- a/include/nbl/asset/ICPUGraphicsPipeline.h +++ b/include/nbl/asset/ICPUGraphicsPipeline.h @@ -13,10 +13,10 @@ namespace nbl::asset { -class ICPUGraphicsPipeline final : public ICPUPipeline,5u> +class ICPUGraphicsPipeline final : public ICPUPipeline, ICPUPipelineLayout,ICPURenderpass>> { - using pipeline_base_t = IGraphicsPipeline; - using base_t = ICPUPipeline; + using pipeline_base_t = IGraphicsPipeline,ICPUPipelineLayout, ICPURenderpass>; + using base_t = ICPUPipeline; public: struct SCreationParams final : pipeline_base_t::SCreationParams @@ -29,27 +29,65 @@ class ICPUGraphicsPipeline final : public ICPUPipeline create(const SCreationParams& params) { // we'll validate the specialization info later when attempting to set it - if (!params.impl_valid([](const IPipelineBase::SShaderSpecInfo& info)->bool{return true;})) - return nullptr; - auto retval = new ICPUGraphicsPipeline(params); - for (const auto spec : params.shaders) - if (spec.shader) - retval->setSpecInfo(spec); - return core::smart_refctd_ptr(retval,core::dont_grab); + if (!params.impl_valid([](const SShaderSpecInfo& info)->bool{return true;})) + return nullptr; + auto retval = new ICPUGraphicsPipeline(params); + for (const auto spec : params.shaders) + { + if (spec.shader) retval->setSpecInfo(spec); + } + return core::smart_refctd_ptr(retval,core::dont_grab); } + inline core::smart_refctd_ptr clone(uint32_t _depth = ~0u) const override final + { + core::smart_refctd_ptr layout; + if (_depth>0u && m_layout) + layout = core::smart_refctd_ptr_static_cast(m_layout->clone(_depth-1u)); + + auto* cp = [&] { + std::array, GRAPHICS_SHADER_STAGE_COUNT> _shaders; + for (auto i = 0; i < GRAPHICS_SHADER_STAGE_COUNT; i++) + _shaders[i] = m_specInfos[i]; + const SCreationParams params = { { + .shaders = _shaders, + .cached = m_params, + .renderpass = m_renderpass.get() + } }; + return new ICPUGraphicsPipeline(params); + }(); + for (auto specInfo : m_specInfos) + { + if (specInfo.shader) + { + auto newSpecInfo = specInfo; + if (_depth>0u) + { + newSpecInfo.shader = core::smart_refctd_ptr_static_cast(specInfo.shader->clone(_depth-1u)); + } + cp->setSpecInfo(newSpecInfo); + } + } + + return core::smart_refctd_ptr(cp,core::dont_grab); + } + + constexpr static inline auto AssetType = ET_GRAPHICS_PIPELINE; inline E_TYPE getAssetType() const override { return AssetType; } inline size_t getDependantCount() const override { auto stageCount = 2; // the layout and renderpass - for (const auto& stage : m_stages) - if (stage.shader) - stageCount++; + for (const auto& info : m_specInfos) + { + if (info.shader) + stageCount++; + } return stageCount; } @@ -65,18 +103,6 @@ class ICPUGraphicsPipeline final : public ICPUPipeline&& layout) const override - { - std::array _shaders; - for (auto i=0; i=GRAPHICS_SHADER_STAGE_COUNT || hlsl::bitCount(stage)!=1) + if (stageIx<0 || stageIx>= GRAPHICS_SHADER_STAGE_COUNT || hlsl::bitCount(stage)!=1) return -1; return stageIx; } + + inline bool setSpecInfo(const SShaderSpecInfo& info) + { + assert(isMutable()); + const auto specSize = info.valid(); + if (specSize<0) return false; + const auto stage = info.stage; + const auto stageIx = stageToIndex(stage); + if (stageIx<0) return false; + m_specInfos[stageIx] = info; + return true; + } + + SShaderSpecInfo m_specInfos[GRAPHICS_SHADER_STAGE_COUNT]; }; } diff --git a/include/nbl/asset/ICPUPipeline.h b/include/nbl/asset/ICPUPipeline.h index d1693f18eb..eb634d3f12 100644 --- a/include/nbl/asset/ICPUPipeline.h +++ b/include/nbl/asset/ICPUPipeline.h @@ -14,37 +14,13 @@ namespace nbl::asset { // Common Base class for pipelines -template +template class ICPUPipeline : public IAsset, public PipelineNonAssetBase { - using this_t = ICPUPipeline; + using this_t = ICPUPipeline; + using shader_info_spec_t = IPipelineBase::SShaderSpecInfo; public: - inline core::smart_refctd_ptr clone(uint32_t _depth = ~0u) const override final - { - core::smart_refctd_ptr layout; - if (_depth>0u && PipelineNonAssetBase::m_layout) - layout = core::smart_refctd_ptr_static_cast(PipelineNonAssetBase::m_layout->clone(_depth-1u)); - - auto cp = clone_impl(std::move(layout)); - for (auto i=0; i newShader; - if (_depth>0u) - { - newShader = core::smart_refctd_ptr_static_cast(shader->clone(_depth-1u)); - stageInfo.shader = newShader.get(); - } - cp->setSpecInfo(stageInfo); - } - } - - return core::smart_refctd_ptr(cp,core::dont_grab); - } // extras for this class ICPUPipelineLayout* getLayout() @@ -60,82 +36,10 @@ class ICPUPipeline : public IAsset, public PipelineNonAssetBase PipelineNonAssetBase::m_layout = std::move(_layout); } - // The getters are weird because the shader pointer, spec constant map and entry point needs patching - inline IShader* getShader(const hlsl::ShaderStage stage) - { - assert(isMutable()); - return const_cast(getSpecInfo(stage).shader); - } - inline std::string* getEntryPoint(const hlsl::ShaderStage stage) - { - const auto stageIx = stageToIndex(stage); - if (stageIx<0) - return {}; - return &m_stages[stageIx].entryPoint; - } - inline IPipelineBase::SShaderSpecInfo::spec_constant_map_t* getSpecConstantMap(const hlsl::ShaderStage stage) - { - assert(isMutable()); - return const_cast(getSpecInfo(stage).entries); - } - // - inline IPipelineBase::SShaderSpecInfo getSpecInfo(const hlsl::ShaderStage stage) const - { - const auto stageIx = stageToIndex(stage); - if (stageIx<0) - return {}; - return m_stages[stageIx].info; - } - inline bool setSpecInfo(const IPipelineBase::SShaderSpecInfo& info) - { - assert(isMutable()); - const int64_t specSize = info.valid(); - if (specSize<0) - return false; - const auto stageIx = stageToIndex(info.stage); - if (stageIx<0) - return false; - auto& outStage = m_stages[stageIx]; - outStage.info = info; - outStage.entryPoint = info.entryPoint; - outStage.shader = core::smart_refctd_ptr(const_cast(info.shader)); - outStage.info.shader = outStage.shader.get(); - auto& outEntries = outStage.entries; - if (specSize>0) - { - outEntries = std::make_unique(); - outEntries->reserve(info.entries->size()); - std::copy(info.entries->begin(),info.entries->end(),std::insert_iterator(*outEntries,outEntries->begin())); - } - else - outEntries = nullptr; - outStage.info.entries = outEntries.get(); - return true; - } - inline bool clearStage(const hlsl::ShaderStage stage) - { - assert(isMutable()); - const auto stageIx = stageToIndex(stage); - if (stageIx<0) - return false; - m_stages[stageIx] = {}; - return true; - } - protected: using PipelineNonAssetBase::PipelineNonAssetBase; virtual ~ICPUPipeline() = default; - virtual this_t* clone_impl(core::smart_refctd_ptr&& layout) const = 0; - virtual int8_t stageToIndex(const hlsl::ShaderStage stage) const = 0; - - struct ShaderStage - { - std::string entryPoint = {}; - core::smart_refctd_ptr shader = {}; - std::unique_ptr entries = {}; - IPipelineBase::SShaderSpecInfo info = {}; - } m_stages[MaxShaderStageCount] = {}; }; } diff --git a/include/nbl/asset/IGraphicsPipeline.h b/include/nbl/asset/IGraphicsPipeline.h index c59ad51ca9..1f3bec79a1 100644 --- a/include/nbl/asset/IGraphicsPipeline.h +++ b/include/nbl/asset/IGraphicsPipeline.h @@ -81,7 +81,7 @@ class IGraphicsPipelineBase : public virtual core::IReferenceCounted }; }; -template +template class IGraphicsPipeline : public IPipeline, public IGraphicsPipelineBase { protected: @@ -91,7 +91,7 @@ class IGraphicsPipeline : public IPipeline, public IGraphics struct SCreationParams : IPipeline::SCreationParams { protected: - using SpecInfo = IPipelineBase::SShaderSpecInfo; + using SpecInfo = SpecInfoType; template inline bool impl_valid(ExtraLambda&& extra) const { diff --git a/include/nbl/asset/IPipeline.h b/include/nbl/asset/IPipeline.h index 036a684729..8ecb2f0fb3 100644 --- a/include/nbl/asset/IPipeline.h +++ b/include/nbl/asset/IPipeline.h @@ -132,8 +132,10 @@ class IPipelineBase Without Specialization Constants, you would have to commit to a final value before the SPIR-V compilation */ + template struct SShaderSpecInfo final { + //! Structure specifying a specialization map entry /* Note that if specialization constant ID is used @@ -146,7 +148,7 @@ class IPipelineBase */ //!< The ID of the specialization constant in SPIR-V. If it isn't used in the shader, the map entry does not affect the behavior of the pipeline. using spec_constant_id_t = uint32_t; - struct SSpecConstantValue + struct SSpecConstantValueImmutable { const void* data = nullptr; //!< The byte size of the specialization constant value within the supplied data buffer. @@ -154,8 +156,18 @@ class IPipelineBase inline operator bool() const {return data&&size;} - auto operator<=>(const SSpecConstantValue&) const = default; + auto operator<=>(const SSpecConstantValueImmutable&) const = default; + }; + + struct SSPecConstantValueMutable + { + core::vector data; + inline operator bool() const { return data.size(); } + auto operator<=>(const SSPecConstantValueMutable&) const = default; }; + + using SSpecConstantValue = std::conditional_t; + inline SSpecConstantValue getSpecializationByteValue(const spec_constant_id_t _specConstID) const { if (!entries) @@ -231,11 +243,14 @@ class IPipelineBase return static_cast(specData); } + using shader_ptr_t = std::conditional_t, const IShader*>; + using entry_point_t = std::conditional_t; using spec_constant_map_t = core::unordered_map; + using entries_t = std::conditional_t; - const IShader* shader = nullptr; + shader_ptr_t shader = nullptr; // A name of the function where the entry point of an shader executable begins. It's often "main" function. - std::string_view entryPoint = {}; + entry_point_t entryPoint = {}; // stage must be set hlsl::ShaderStage stage = hlsl::ShaderStage::ESS_UNKNOWN; // there's some padding here @@ -244,12 +259,13 @@ class IPipelineBase uint8_t requireFullSubgroups : 1 = false; // Container choice implicitly satisfies: // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkSpecializationInfo.html#VUID-VkSpecializationInfo-constantID-04911 - const spec_constant_map_t* entries = nullptr; + entries_t entries = nullptr; // By requiring Nabla Core Profile features we implicitly satisfy: // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-flags-02784 // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-flags-02785 // Also because our API is sane, it satisfies the following by construction: // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-pNext-02754 + }; }; template From 7fe3431366e436dc63fa1795afd324ba99cf473d Mon Sep 17 00:00:00 2001 From: kevyuu Date: Mon, 28 Apr 2025 20:14:37 +0700 Subject: [PATCH 02/64] Rework IGPUGraphicsPipeline --- include/nbl/asset/IGraphicsPipeline.h | 6 +++--- include/nbl/video/IGPUGraphicsPipeline.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/nbl/asset/IGraphicsPipeline.h b/include/nbl/asset/IGraphicsPipeline.h index 1f3bec79a1..77f220aa78 100644 --- a/include/nbl/asset/IGraphicsPipeline.h +++ b/include/nbl/asset/IGraphicsPipeline.h @@ -86,12 +86,12 @@ class IGraphicsPipeline : public IPipeline, public IGraphics { protected: using renderpass_t = RenderpassType; + using spec_info_t = SpecInfoType; public: struct SCreationParams : IPipeline::SCreationParams { protected: - using SpecInfo = SpecInfoType; template inline bool impl_valid(ExtraLambda&& extra) const { @@ -136,7 +136,7 @@ class IGraphicsPipeline : public IPipeline, public IGraphics public: inline bool valid() const { - return impl_valid([](const SpecInfo& info)->bool + return impl_valid([](const spec_info_t& info)->bool { if (!info.valid()) return false; @@ -144,7 +144,7 @@ class IGraphicsPipeline : public IPipeline, public IGraphics }); } - std::span shaders = {}; + std::span shaders = {}; SCachedCreationParams cached = {}; renderpass_t* renderpass = nullptr; }; diff --git a/include/nbl/video/IGPUGraphicsPipeline.h b/include/nbl/video/IGPUGraphicsPipeline.h index 8240bcea94..4838d7f4d3 100644 --- a/include/nbl/video/IGPUGraphicsPipeline.h +++ b/include/nbl/video/IGPUGraphicsPipeline.h @@ -11,9 +11,9 @@ namespace nbl::video { -class IGPUGraphicsPipeline : public IBackendObject, public asset::IGraphicsPipeline +class IGPUGraphicsPipeline : public IBackendObject, public asset::IGraphicsPipeline, const IGPUPipelineLayout,const IGPURenderpass> { - using pipeline_t = asset::IGraphicsPipeline; + using pipeline_t = asset::IGraphicsPipeline, const IGPUPipelineLayout,const IGPURenderpass>; public: struct SCreationParams final : pipeline_t::SCreationParams, SPipelineCreationParams @@ -36,7 +36,7 @@ class IGPUGraphicsPipeline : public IBackendObject, public asset::IGraphicsPipel if (!layout) return {}; SSpecializationValidationResult retval = {.count=0,.dataSize=0}; - const bool valid = pipeline_t::SCreationParams::impl_valid([&retval](const IPipelineBase::SShaderSpecInfo& info)->bool + const bool valid = pipeline_t::SCreationParams::impl_valid([&retval](const spec_info_t& info)->bool { const auto dataSize = info.valid(); if (dataSize<0) From 8dbe9c782ef1f0ac7f154d9c04598f740c061d8f Mon Sep 17 00:00:00 2001 From: kevyuu Date: Mon, 28 Apr 2025 20:14:51 +0700 Subject: [PATCH 03/64] Rework IGPUComputePipeline.h --- include/nbl/video/IGPUComputePipeline.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/nbl/video/IGPUComputePipeline.h b/include/nbl/video/IGPUComputePipeline.h index 49e44dfcc1..ba29cc58e2 100644 --- a/include/nbl/video/IGPUComputePipeline.h +++ b/include/nbl/video/IGPUComputePipeline.h @@ -17,6 +17,7 @@ namespace nbl::video class IGPUComputePipeline : public IBackendObject, public asset::IPipeline { using pipeline_t = asset::IPipeline; + using spec_info_t = SShaderSpecInfo; public: struct SCreationParams final : pipeline_t::SCreationParams, SPipelineCreationParams @@ -63,11 +64,11 @@ class IGPUComputePipeline : public IBackendObject, public asset::IPipeline(dataSize)}; } - inline std::span getShaders() const {return {&shader,1}; } + inline std::span getShaders() const {return {&shader,1}; } // TODO: Could guess the required flags from SPIR-V introspection of declared caps core::bitflag flags = FLAGS::NONE; - IPipelineBase::SShaderSpecInfo shader = {}; + spec_info_t shader = {}; }; inline core::bitflag getCreationFlags() const {return m_flags;} From 436e6e16e51f1abf19c2c599834ed9a7fa1f0d38 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Tue, 29 Apr 2025 15:09:19 +0700 Subject: [PATCH 04/64] Remove default value for mutable template parameter --- include/nbl/asset/IPipeline.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/nbl/asset/IPipeline.h b/include/nbl/asset/IPipeline.h index 8ecb2f0fb3..97d7ab9c94 100644 --- a/include/nbl/asset/IPipeline.h +++ b/include/nbl/asset/IPipeline.h @@ -132,7 +132,7 @@ class IPipelineBase Without Specialization Constants, you would have to commit to a final value before the SPIR-V compilation */ - template + template struct SShaderSpecInfo final { From 2e367d12519c473135785b689700b7ce62457104 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Mon, 5 May 2025 17:00:39 +0700 Subject: [PATCH 05/64] Implement IGPUPipeline and refactor SCreationParams --- include/nbl/asset/ICPUComputePipeline.h | 67 ++-- include/nbl/asset/ICPUGraphicsPipeline.h | 183 +++++----- include/nbl/asset/ICPUPipeline.h | 111 ++++++- include/nbl/asset/IGraphicsPipeline.h | 74 +---- include/nbl/asset/IPipeline.h | 349 ++++++-------------- include/nbl/video/IGPUComputePipeline.h | 20 +- include/nbl/video/IGPUGraphicsPipeline.h | 68 +++- include/nbl/video/IGPUPipeline.h | 110 ++++++ include/nbl/video/IGPURayTracingPipeline.h | 32 +- include/nbl/video/SPipelineCreationParams.h | 2 +- 10 files changed, 518 insertions(+), 498 deletions(-) create mode 100644 include/nbl/video/IGPUPipeline.h diff --git a/include/nbl/asset/ICPUComputePipeline.h b/include/nbl/asset/ICPUComputePipeline.h index 704c4c05fc..d9bc8dd646 100644 --- a/include/nbl/asset/ICPUComputePipeline.h +++ b/include/nbl/asset/ICPUComputePipeline.h @@ -17,68 +17,53 @@ class ICPUComputePipeline : public ICPUPipeline> using base_t = ICPUPipeline>; public: - struct SCreationParams final : IPipeline::SCreationParams - { - IPipelineBase::SShaderSpecInfo shader; - }; - static core::smart_refctd_ptr create(const SCreationParams& params) + explicit ICPUComputePipeline(const ICPUPipelineLayout* layout): + base_t(core::smart_refctd_ptr(layout)) + {} + + static core::smart_refctd_ptr create(const ICPUPipelineLayout* layout) { - if (!params.layout) - return nullptr; - auto retval = new ICPUComputePipeline(core::smart_refctd_ptr(params.layout)); - - if (!retval->setSpecInfo(params.shader)) - { - retval->drop(); - return nullptr; - } + auto retval = new ICPUComputePipeline(layout); return core::smart_refctd_ptr(retval,core::dont_grab); } - inline core::smart_refctd_ptr clone(uint32_t _depth = ~0u) const override final + inline base_t* clone_impl(core::smart_refctd_ptr&& layout, uint32_t depth) const override final { - core::smart_refctd_ptr layout; - if (_depth>0u && m_layout) - layout = core::smart_refctd_ptr_static_cast(m_layout->clone(_depth-1u)); - - auto cp = new ICPUComputePipeline(std::move(layout)); - if (m_specInfo.shader) - { - SShaderSpecInfo specInfo = m_specInfo; - if (_depth > 0u) - { - specInfo.shader = core::smart_refctd_ptr_static_cast(m_specInfo.shader->clone(_depth - 1u)); - } - cp->setSpecInfo(specInfo); - } - return core::smart_refctd_ptr(cp,core::dont_grab); + auto newPipeline = new ICPUComputePipeline(std::move(layout)); + newPipeline->m_specInfo = newPipeline->cloneSpecInfo(m_specInfo, depth); + return newPipeline; } constexpr static inline auto AssetType = ET_COMPUTE_PIPELINE; inline E_TYPE getAssetType() const override { return AssetType; } - //! - inline size_t getDependantCount() const override {return 2;} + //! + inline size_t getDependantCount() const override { return 2; } + + inline virtual std::span getSpecInfo(hlsl::ShaderStage stage) override final + { + if (stage==hlsl::ShaderStage::ESS_COMPUTE && isMutable()) + return {m_specInfo,1}; + return {}; + } + + inline virtual bool valid() const override final + { + // TODO(kevinyu): Fix this temporary dummy code + return true; + } protected: using base_t::base_t; virtual ~ICPUComputePipeline() = default; - inline IAsset* getDependant_impl(const size_t ix) override + inline IAsset* getDependant_impl(const size_t ix) override { if (ix!=0) return m_specInfo.shader.get(); return const_cast(m_layout.get()); } - inline bool setSpecInfo(const IPipelineBase::SShaderSpecInfo& info) - { - const auto specSize = info.valid(); - if (specSize < 0) return false; - if (info.stage != hlsl::ESS_COMPUTE) return false; - m_specInfo = info; - return true; - } private: SShaderSpecInfo m_specInfo; diff --git a/include/nbl/asset/ICPUGraphicsPipeline.h b/include/nbl/asset/ICPUGraphicsPipeline.h index b624d53aa9..b93b8165aa 100644 --- a/include/nbl/asset/ICPUGraphicsPipeline.h +++ b/include/nbl/asset/ICPUGraphicsPipeline.h @@ -13,135 +13,102 @@ namespace nbl::asset { -class ICPUGraphicsPipeline final : public ICPUPipeline, ICPUPipelineLayout,ICPURenderpass>> +class ICPUGraphicsPipeline final : public ICPUPipeline> { - using pipeline_base_t = IGraphicsPipeline,ICPUPipelineLayout, ICPURenderpass>; + using pipeline_base_t = IGraphicsPipeline; using base_t = ICPUPipeline; public: - struct SCreationParams final : pipeline_base_t::SCreationParams - { - private: - friend class ICPUGraphicsPipeline; - template - inline bool impl_valid(ExtraLambda&& extra) const - { - return pipeline_base_t::SCreationParams::impl_valid(std::move(extra)); - } - }; - - static core::smart_refctd_ptr create(const SCreationParams& params) - { - // we'll validate the specialization info later when attempting to set it - if (!params.impl_valid([](const SShaderSpecInfo& info)->bool{return true;})) - return nullptr; - auto retval = new ICPUGraphicsPipeline(params); - for (const auto spec : params.shaders) + explicit ICPUGraphicsPipeline(const ICPUPipelineLayout* layout) + : base_t(layout, {}, {}) + {} + + static core::smart_refctd_ptr create(const ICPUPipelineLayout* layout) { - if (spec.shader) retval->setSpecInfo(spec); + auto retval = new ICPUGraphicsPipeline(layout); + return core::smart_refctd_ptr(retval,core::dont_grab); } - return core::smart_refctd_ptr(retval,core::dont_grab); - } - - inline core::smart_refctd_ptr clone(uint32_t _depth = ~0u) const override final - { - core::smart_refctd_ptr layout; - if (_depth>0u && m_layout) - layout = core::smart_refctd_ptr_static_cast(m_layout->clone(_depth-1u)); - auto* cp = [&] { - std::array, GRAPHICS_SHADER_STAGE_COUNT> _shaders; + inline base_t* clone_impl(core::smart_refctd_ptr&& layout, uint32_t depth) const override final + { + auto* newPipeline = new ICPUGraphicsPipeline(layout.get()); for (auto i = 0; i < GRAPHICS_SHADER_STAGE_COUNT; i++) - _shaders[i] = m_specInfos[i]; - const SCreationParams params = { { - .shaders = _shaders, - .cached = m_params, - .renderpass = m_renderpass.get() - } }; - return new ICPUGraphicsPipeline(params); - }(); - for (auto specInfo : m_specInfos) - { - if (specInfo.shader) + newPipeline->m_specInfos[i] = m_specInfos[i]; + newPipeline->m_params = m_params; + newPipeline->m_renderpass = m_renderpass; + + for (auto specInfo_i = 0u; specInfo_i < m_specInfos.size(); specInfo_i++) { - auto newSpecInfo = specInfo; - if (_depth>0u) - { - newSpecInfo.shader = core::smart_refctd_ptr_static_cast(specInfo.shader->clone(_depth-1u)); - } - cp->setSpecInfo(newSpecInfo); + newPipeline->m_specInfos[specInfo_i] = newPipeline->cloneSpecInfo(m_specInfos[specInfo_i], depth); } - } - - return core::smart_refctd_ptr(cp,core::dont_grab); - } - - - constexpr static inline auto AssetType = ET_GRAPHICS_PIPELINE; - inline E_TYPE getAssetType() const override { return AssetType; } - - inline size_t getDependantCount() const override - { - auto stageCount = 2; // the layout and renderpass - for (const auto& info : m_specInfos) - { - if (info.shader) - stageCount++; - } - return stageCount; - } - - // extras for this class - inline const SCachedCreationParams& getCachedCreationParams() const {return base_t::getCachedCreationParams();} + + return newPipeline; + } + + constexpr static inline auto AssetType = ET_GRAPHICS_PIPELINE; + inline E_TYPE getAssetType() const override { return AssetType; } + + inline size_t getDependantCount() const override + { + auto stageCount = 2; // the layout and renderpass + for (const auto& info : m_specInfos) + { + if (info.shader) + stageCount++; + } + return stageCount; + } + inline SCachedCreationParams& getCachedCreationParams() { assert(isMutable()); return m_params; } + inline virtual std::span getSpecInfo(hlsl::ShaderStage stage) override final + { + const auto stageIndex = stageToIndex(stage); + if (isMutable() && stageIndex != -1) + { + return { &m_specInfos[stageIndex], 1 }; + } + return {}; + } + + inline virtual bool valid() const override final + { + // TODO(kevinyu): Fix this temporary stub code + return true; + } + protected: - using base_t::base_t; + using base_t::base_t; ~ICPUGraphicsPipeline() = default; - inline IAsset* getDependant_impl(const size_t ix) override - { - if (ix==0) - return const_cast(m_layout.get()); - if (ix==1) - return m_renderpass.get(); - size_t stageCount = 0; - for (auto& specInfo : m_specInfos) - { - if (specInfo.shader) + inline IAsset* getDependant_impl(const size_t ix) override { - if ((stageCount++)==ix-2) - return specInfo.shader.get(); + if (ix==0) + return const_cast(m_layout.get()); + if (ix==1) + return m_renderpass.get(); + size_t stageCount = 0; + for (auto& specInfo : m_specInfos) + { + if (specInfo.shader) + if ((stageCount++)==ix-2) return specInfo.shader.get(); + } + return nullptr; + } + + inline int8_t stageToIndex(const hlsl::ShaderStage stage) const + { + const auto stageIx = hlsl::findLSB(stage); + if (stageIx<0 || stageIx>= GRAPHICS_SHADER_STAGE_COUNT || hlsl::bitCount(stage)!=1) + return -1; + return stageIx; } - } - return nullptr; - } - - inline int8_t stageToIndex(const hlsl::ShaderStage stage) const - { - const auto stageIx = hlsl::findLSB(stage); - if (stageIx<0 || stageIx>= GRAPHICS_SHADER_STAGE_COUNT || hlsl::bitCount(stage)!=1) - return -1; - return stageIx; - } - - inline bool setSpecInfo(const SShaderSpecInfo& info) - { - assert(isMutable()); - const auto specSize = info.valid(); - if (specSize<0) return false; - const auto stage = info.stage; - const auto stageIx = stageToIndex(stage); - if (stageIx<0) return false; - m_specInfos[stageIx] = info; - return true; - } - - SShaderSpecInfo m_specInfos[GRAPHICS_SHADER_STAGE_COUNT]; + + std::array m_specInfos; }; } diff --git a/include/nbl/asset/ICPUPipeline.h b/include/nbl/asset/ICPUPipeline.h index eb634d3f12..623d5ae2df 100644 --- a/include/nbl/asset/ICPUPipeline.h +++ b/include/nbl/asset/ICPUPipeline.h @@ -13,12 +13,95 @@ namespace nbl::asset { +class ICPUPipelineBase +{ + public: + struct SShaderSpecInfo + { + //! Structure specifying a specialization map entry + /* + Note that if specialization constant ID is used + in a shader, \bsize\b and \boffset'b must match + to \isuch an ID\i accordingly. + + By design the API satisfies: + https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkSpecializationInfo.html#VUID-VkSpecializationInfo-offset-00773 + https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkSpecializationInfo.html#VUID-VkSpecializationInfo-pMapEntries-00774 + */ + //!< The ID of the specialization constant in SPIR-V. If it isn't used in the shader, the map entry does not affect the behavior of the pipeline. + using spec_constant_id_t = uint32_t; + + struct SSpecConstantValue + { + core::vector data; + inline operator bool() const { return data.size(); } + inline size_t size() const { return data.size(); } + }; + + inline SSpecConstantValue* getSpecializationByteValue(const spec_constant_id_t _specConstID) + { + const auto found = entries.find(_specConstID); + if (found != entries.end() && bool(found->second)) return &found->second; + else return nullptr; + } + + static constexpr int32_t INVALID_SPEC_INFO = -1; + inline int32_t valid() const + { + if (!shader) return INVALID_SPEC_INFO; + + // Impossible to check: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-pName-00707 + if (entryPoint.empty()) return INVALID_SPEC_INFO; + + // Impossible to efficiently check anything from: + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-maxClipDistances-00708 + // to: + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-stage-06686 + // and from: + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-pNext-02756 + // to: + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-module-08987 + + int64_t specData = 0; + for (const auto& entry : entries) + { + if (!entry.second) return INVALID_SPEC_INFO; + specData += entry.second.size(); + } + if (specData > 0x7fffffff) return INVALID_SPEC_INFO; + return static_cast(specData); + } + + core::smart_refctd_ptr shader = nullptr; + std::string entryPoint = ""; + IPipelineBase::SUBGROUP_SIZE requiredSubgroupSize : 3 = IPipelineBase::SUBGROUP_SIZE::UNKNOWN; //!< Default value of 8 means no requirement + uint8_t requireFullSubgroups : 1 = false; + + // Container choice implicitly satisfies: + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkSpecializationInfo.html#VUID-VkSpecializationInfo-constantID-04911 + core::unordered_map entries; + // By requiring Nabla Core Profile features we implicitly satisfy: + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-flags-02784 + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-flags-02785 + // Also because our API is sane, it satisfies the following by construction: + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-pNext-02754 + + }; + + virtual std::span getSpecInfo(const hlsl::ShaderStage stage) = 0; + inline std::span getSpecInfo(const hlsl::ShaderStage stage) const + { + return getSpecInfo(stage); + } + + virtual bool valid() const = 0; +}; + // Common Base class for pipelines template -class ICPUPipeline : public IAsset, public PipelineNonAssetBase +class ICPUPipeline : public IAsset, public PipelineNonAssetBase, public ICPUPipelineBase { using this_t = ICPUPipeline; - using shader_info_spec_t = IPipelineBase::SShaderSpecInfo; public: @@ -36,9 +119,33 @@ class ICPUPipeline : public IAsset, public PipelineNonAssetBase PipelineNonAssetBase::m_layout = std::move(_layout); } + inline core::smart_refctd_ptr clone(uint32_t _depth = ~0u) const override final + { + core::smart_refctd_ptr layout; + if (_depth>0u && getLayout()) + layout = core::smart_refctd_ptr_static_cast(getLayout->clone(_depth-1u)); + + auto* newPipeline = clone_impl(std::move(layout), _depth); + + return core::smart_refctd_ptr(newPipeline,core::dont_grab); + } + + SShaderSpecInfo cloneSpecInfo(const SShaderSpecInfo& specInfo, uint32_t depth) + { + auto newSpecInfo = specInfo; + if (depth>0u) + { + newSpecInfo.shader = core::smart_refctd_ptr_static_cast(specInfo.shader->clone(depth - 1u)); + } + return newSpecInfo; + } + protected: + using PipelineNonAssetBase::PipelineNonAssetBase; virtual ~ICPUPipeline() = default; + + virtual this_t* clone_impl(core::smart_refctd_ptr&& layout, uint32_t depth) const = 0; }; diff --git a/include/nbl/asset/IGraphicsPipeline.h b/include/nbl/asset/IGraphicsPipeline.h index 77f220aa78..3e029e76b2 100644 --- a/include/nbl/asset/IGraphicsPipeline.h +++ b/include/nbl/asset/IGraphicsPipeline.h @@ -81,85 +81,23 @@ class IGraphicsPipelineBase : public virtual core::IReferenceCounted }; }; -template +template class IGraphicsPipeline : public IPipeline, public IGraphicsPipelineBase { protected: using renderpass_t = RenderpassType; - using spec_info_t = SpecInfoType; public: - struct SCreationParams : IPipeline::SCreationParams - { - protected: - template - inline bool impl_valid(ExtraLambda&& extra) const - { - if (!IPipeline::SCreationParams::layout) - return false; - - // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-dynamicRendering-06576 - if (!renderpass || cached.subpassIx>=renderpass->getSubpassCount()) - return false; - - // TODO: check rasterization samples, etc. - //rp->getCreationParameters().subpasses[i] - - core::bitflag stagePresence = {}; - for (const auto info : shaders) - if (info.shader) - { - if (!extra(info)) - return false; - const auto stage = info.stage; - if (stage>hlsl::ShaderStage::ESS_FRAGMENT) - return false; - if (stagePresence.hasFlags(stage)) - return false; - stagePresence |= stage; - } - // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-stage-02096 - if (!stagePresence.hasFlags(hlsl::ShaderStage::ESS_VERTEX)) - return false; - // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-pStages-00729 - // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-pStages-00730 - if (stagePresence.hasFlags(hlsl::ShaderStage::ESS_TESSELLATION_CONTROL)!=stagePresence.hasFlags(hlsl::ShaderStage::ESS_TESSELLATION_EVALUATION)) - return false; - // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-pStages-08888 - // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-topology-08889 - if (stagePresence.hasFlags(hlsl::ShaderStage::ESS_TESSELLATION_EVALUATION)!=(cached.primitiveAssembly.primitiveType==EPT_PATCH_LIST)) - return false; - - return true; - } - - public: - inline bool valid() const - { - return impl_valid([](const spec_info_t& info)->bool - { - if (!info.valid()) - return false; - return false; - }); - } - - std::span shaders = {}; - SCachedCreationParams cached = {}; - renderpass_t* renderpass = nullptr; - }; - inline const SCachedCreationParams& getCachedCreationParams() const {return m_params;} - inline const renderpass_t* getRenderpass() const {return m_renderpass.get();} protected: - explicit IGraphicsPipeline(const SCreationParams& _params) : - IPipeline(core::smart_refctd_ptr(_params.layout)), - m_params(_params.cached), m_renderpass(core::smart_refctd_ptr(_params.renderpass)) {} + explicit IGraphicsPipeline(const PipelineLayoutType* layout, const SCachedCreationParams& cachedParams, const renderpass_t* renderpass) : + IPipeline(core::smart_refctd_ptr(layout)), m_renderpass(core::smart_refctd_ptr(renderpass)) + {} - SCachedCreationParams m_params; - core::smart_refctd_ptr m_renderpass; + SCachedCreationParams m_params = {}; + core::smart_refctd_ptr m_renderpass = nullptr; }; } diff --git a/include/nbl/asset/IPipeline.h b/include/nbl/asset/IPipeline.h index 97d7ab9c94..98f1671cca 100644 --- a/include/nbl/asset/IPipeline.h +++ b/include/nbl/asset/IPipeline.h @@ -27,265 +27,112 @@ namespace nbl::asset */ class IPipelineBase { - public: - struct SCreationParams - { - protected: - // This is not public to make sure that different pipelines only get the enums they support - enum class FLAGS : uint64_t - { - NONE = 0, // disallowed in maintanance5 - DISABLE_OPTIMIZATIONS = 1<<0, - ALLOW_DERIVATIVES = 1<<1, - - // I can just derive this - //DERIVATIVE = 1<<2, + public: + enum class CreationFlags : uint64_t + { + NONE = 0, // disallowed in maintanance5 + DISABLE_OPTIMIZATIONS = 1 << 0, + ALLOW_DERIVATIVES = 1 << 1, + + // I can just derive this + //DERIVATIVE = 1<<2, + + // Graphics Pipelines only + //VIEW_INDEX_FROM_DEVICE_INDEX = 1<<3, + + // Compute Pipelines only + //DISPATCH_BASE = 1<<4, + + // This is for NV-raytracing extension. Now this is done via IDeferredOperation + //DEFER_COMPILE_NV = 1<<5, + + // We use Renderdoc to take care of this for us, + // we won't be parsing the statistics and internal representation ourselves. + //CAPTURE_STATISTICS = 1<<6, + //CAPTURE_INTERNAL_REPRESENTATIONS = 1<<7, + + // Will soon be deprecated due to + // https://github.com/Devsh-Graphics-Programming/Nabla/issues/854 + FAIL_ON_PIPELINE_COMPILE_REQUIRED = 1 << 8, + EARLY_RETURN_ON_FAILURE = 1 << 9, + + // Will be exposed later with the IPipelineLibrary asset implementation + // https://github.com/Devsh-Graphics-Programming/Nabla/issues/853 + //LINK_TIME_OPTIMIZATION = 1<<10, + + // Won't be exposed because we'll introduce Libraries as a separate object/asset-type + // https://github.com/Devsh-Graphics-Programming/Nabla/issues/853 + //CREATE_LIBRARY = 1<<11, + + // Ray Tracing Pipelines only + //SKIP_BUILT_IN_PRIMITIVES = 1<<12, + //SKIP_AABBS = 1<<13, + //NO_NULL_ANY_HIT_SHADERS = 1<<14, + //NO_NULL_CLOSEST_HIT_SHADERS = 1<<15, + //NO_NULL_MISS_SHADERS = 1<<16, + //NO_NULL_INTERSECTION_SHADERS = 1<<17, + + // There is a new Device Generated Commands extension with its own flag that will deprecate this + //INDIRECT_BINDABLE_NV = 1<<18, + + // Ray Tracing Pipelines only + // For debug tools + //RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_BIT_KHR = 1<<19, + + // Ray Tracing Pipelines only + //ALLOW_MOTION = 1<<20, + + // Graphics Pipelineonly (we don't support subpass shading) + //RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 1<<21, + //RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT = 1<<22, + + // Will be exposed later with the IPipelineLibrary asset implementation + // https://github.com/Devsh-Graphics-Programming/Nabla/issues/853 + //RETAIN_LINK_TIME_OPTIMIZATION_INFO = 1<<23, + + // Ray Tracing Pipelines only + //RAY_TRACING_OPACITY_MICROMAP_BIT_EXT = 1<<24, + + // Not supported yet, and we will move to dynamic rendering, so this might never be supported + //COLOR_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 1<<25, + //DEPTH_STENCIL_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 1<<26, + + // Not Supported Yet + //NO_PROTECTED_ACCESS=1<<27, + //RAY_TRACING_DISPLACEMENT_MICROMAP_BIT_NV = 1<<28, + //DESCRIPTOR_VUFFER_BIT=1<<29, + //PROTECTED_ACCESS_ONLY=1<<30, + }; + + // Nabla requires device's reported subgroup size to be between 4 and 128 + enum class SUBGROUP_SIZE : uint8_t + { + // No constraint but probably means `gl_SubgroupSize` is Dynamically Uniform + UNKNOWN = 0, + // Allows the Subgroup Uniform `gl_SubgroupSize` to be non-Dynamically Uniform and vary between Device's min and max + VARYING = 1, + // The rest we encode as log2(x) of the required value + REQUIRE_4 = 2, + REQUIRE_8 = 3, + REQUIRE_16 = 4, + REQUIRE_32 = 5, + REQUIRE_64 = 6, + REQUIRE_128 = 7 + }; - // Graphics Pipelines only - //VIEW_INDEX_FROM_DEVICE_INDEX = 1<<3, - - // Compute Pipelines only - //DISPATCH_BASE = 1<<4, - - // This is for NV-raytracing extension. Now this is done via IDeferredOperation - //DEFER_COMPILE_NV = 1<<5, - - // We use Renderdoc to take care of this for us, - // we won't be parsing the statistics and internal representation ourselves. - //CAPTURE_STATISTICS = 1<<6, - //CAPTURE_INTERNAL_REPRESENTATIONS = 1<<7, - - // Will soon be deprecated due to - // https://github.com/Devsh-Graphics-Programming/Nabla/issues/854 - FAIL_ON_PIPELINE_COMPILE_REQUIRED = 1<<8, - EARLY_RETURN_ON_FAILURE = 1<<9, - - // Will be exposed later with the IPipelineLibrary asset implementation - // https://github.com/Devsh-Graphics-Programming/Nabla/issues/853 - //LINK_TIME_OPTIMIZATION = 1<<10, - - // Won't be exposed because we'll introduce Libraries as a separate object/asset-type - // https://github.com/Devsh-Graphics-Programming/Nabla/issues/853 - //CREATE_LIBRARY = 1<<11, - - // Ray Tracing Pipelines only - //SKIP_BUILT_IN_PRIMITIVES = 1<<12, - //SKIP_AABBS = 1<<13, - //NO_NULL_ANY_HIT_SHADERS = 1<<14, - //NO_NULL_CLOSEST_HIT_SHADERS = 1<<15, - //NO_NULL_MISS_SHADERS = 1<<16, - //NO_NULL_INTERSECTION_SHADERS = 1<<17, - - // There is a new Device Generated Commands extension with its own flag that will deprecate this - //INDIRECT_BINDABLE_NV = 1<<18, - - // Ray Tracing Pipelines only - // For debug tools - //RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_BIT_KHR = 1<<19, - - // Ray Tracing Pipelines only - //ALLOW_MOTION = 1<<20, - - // Graphics Pipelineonly (we don't support subpass shading) - //RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 1<<21, - //RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT = 1<<22, - - // Will be exposed later with the IPipelineLibrary asset implementation - // https://github.com/Devsh-Graphics-Programming/Nabla/issues/853 - //RETAIN_LINK_TIME_OPTIMIZATION_INFO = 1<<23, - - // Ray Tracing Pipelines only - //RAY_TRACING_OPACITY_MICROMAP_BIT_EXT = 1<<24, - - // Not supported yet, and we will move to dynamic rendering, so this might never be supported - //COLOR_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 1<<25, - //DEPTH_STENCIL_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 1<<26, - - // Not Supported Yet - //NO_PROTECTED_ACCESS=1<<27, - //RAY_TRACING_DISPLACEMENT_MICROMAP_BIT_NV = 1<<28, - //DESCRIPTOR_VUFFER_BIT=1<<29, - //PROTECTED_ACCESS_ONLY=1<<30, - }; - }; - - /* - Specialization info contains things such as entry point to a shader, - specialization map entry, required subgroup size, etc. for a blob of SPIR-V - - It also handles Specialization Constants. - - In Vulkan, all shaders get halfway-compiled into SPIR-V and - then then lowered (compiled) into the HW ISA by the Vulkan driver. - Normally, the half-way compile folds all constant values - and optimizes the code that uses them. - - But, it would be nice every so often to have your Vulkan - program sneak into the halfway-compiled SPIR-V binary and - manipulate some constants at runtime. This is what - Specialization Constants are for. - - So A Specialization Constant is a way of injecting an integer - constant into a halfway-compiled version of a shader right - before the lowering and linking when creating a pipeline. - - Without Specialization Constants, you would have to commit - to a final value before the SPIR-V compilation - */ - template - struct SShaderSpecInfo final - { - - //! Structure specifying a specialization map entry - /* - Note that if specialization constant ID is used - in a shader, \bsize\b and \boffset'b must match - to \isuch an ID\i accordingly. - - By design the API satisfies: - https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkSpecializationInfo.html#VUID-VkSpecializationInfo-offset-00773 - https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkSpecializationInfo.html#VUID-VkSpecializationInfo-pMapEntries-00774 - */ - //!< The ID of the specialization constant in SPIR-V. If it isn't used in the shader, the map entry does not affect the behavior of the pipeline. - using spec_constant_id_t = uint32_t; - struct SSpecConstantValueImmutable - { - const void* data = nullptr; - //!< The byte size of the specialization constant value within the supplied data buffer. - uint32_t size = 0; - - inline operator bool() const {return data&&size;} - - auto operator<=>(const SSpecConstantValueImmutable&) const = default; - }; - - struct SSPecConstantValueMutable - { - core::vector data; - inline operator bool() const { return data.size(); } - auto operator<=>(const SSPecConstantValueMutable&) const = default; - }; - - using SSpecConstantValue = std::conditional_t; - - inline SSpecConstantValue getSpecializationByteValue(const spec_constant_id_t _specConstID) const - { - if (!entries) - return { nullptr,0u }; - - const auto found = entries->find(_specConstID); - if (found != entries->end() && bool(found->second)) - return found->second; - else - return { nullptr,0u }; - } - - // Nabla requires device's reported subgroup size to be between 4 and 128 - enum class SUBGROUP_SIZE : uint8_t - { - // No constraint but probably means `gl_SubgroupSize` is Dynamically Uniform - UNKNOWN = 0, - // Allows the Subgroup Uniform `gl_SubgroupSize` to be non-Dynamically Uniform and vary between Device's min and max - VARYING = 1, - // The rest we encode as log2(x) of the required value - REQUIRE_4 = 2, - REQUIRE_8 = 3, - REQUIRE_16 = 4, - REQUIRE_32 = 5, - REQUIRE_64 = 6, - REQUIRE_128 = 7 - }; - - // - static constexpr int32_t INVALID_SPEC_INFO = -1; - // Returns negative on failure, otherwise the size of the buffer required to reserve for the spec constant data - inline int32_t valid() const - { - if (!shader || hlsl::bitCount(stage)!=1) - return INVALID_SPEC_INFO; - - // Impossible to check: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-pName-00707 - if (entryPoint.empty()) - return INVALID_SPEC_INFO; - - // Shader stages already checked for validity w.r.t. features enabled, during unspec shader creation, only check: - // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-flags-08988 - if (requireFullSubgroups) - switch (stage) - { - case hlsl::ShaderStage::ESS_COMPUTE: [[fallthrough]]; - case hlsl::ShaderStage::ESS_TASK: [[fallthrough]]; - case hlsl::ShaderStage::ESS_MESH: - break; - default: - return INVALID_SPEC_INFO; - break; - } - // Impossible to efficiently check anything from: - // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-maxClipDistances-00708 - // to: - // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-stage-06686 - // and from: - // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-pNext-02756 - // to: - // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-module-08987 - - int64_t specData = 0; - if (entries) - for (const auto& entry : *entries) - { - if (!entry.second) - return INVALID_SPEC_INFO; - specData += entry.second.size; - } - if (specData>0x7fffffff) - return INVALID_SPEC_INFO; - return static_cast(specData); - } - - using shader_ptr_t = std::conditional_t, const IShader*>; - using entry_point_t = std::conditional_t; - using spec_constant_map_t = core::unordered_map; - using entries_t = std::conditional_t; - - shader_ptr_t shader = nullptr; - // A name of the function where the entry point of an shader executable begins. It's often "main" function. - entry_point_t entryPoint = {}; - // stage must be set - hlsl::ShaderStage stage = hlsl::ShaderStage::ESS_UNKNOWN; - // there's some padding here - SUBGROUP_SIZE requiredSubgroupSize : 3 = SUBGROUP_SIZE::UNKNOWN; //!< Default value of 8 means no requirement - // Valid only for Compute, Mesh and Task shaders - uint8_t requireFullSubgroups : 1 = false; - // Container choice implicitly satisfies: - // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkSpecializationInfo.html#VUID-VkSpecializationInfo-constantID-04911 - entries_t entries = nullptr; - // By requiring Nabla Core Profile features we implicitly satisfy: - // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-flags-02784 - // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-flags-02785 - // Also because our API is sane, it satisfies the following by construction: - // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-pNext-02754 - - }; }; template class IPipeline : public IPipelineBase { - public: - // For now, due to API design we implicitly satisfy a bunch of VUIDs - struct SCreationParams : protected IPipelineBase::SCreationParams - { - public: - const PipelineLayout* layout = nullptr; - }; + public: + inline const PipelineLayout* getLayout() const {return m_layout.get();} - inline const PipelineLayout* getLayout() const {return m_layout.get();} + protected: - protected: - inline IPipeline(core::smart_refctd_ptr&& _layout) - : m_layout(std::move(_layout)) {} + inline IPipeline(core::smart_refctd_ptr&& _layout) + : m_layout(std::move(_layout)) {} - core::smart_refctd_ptr m_layout; + core::smart_refctd_ptr m_layout; }; } diff --git a/include/nbl/video/IGPUComputePipeline.h b/include/nbl/video/IGPUComputePipeline.h index ba29cc58e2..8c5fc017d9 100644 --- a/include/nbl/video/IGPUComputePipeline.h +++ b/include/nbl/video/IGPUComputePipeline.h @@ -7,20 +7,19 @@ #include "nbl/asset/IPipeline.h" -#include "nbl/video/SPipelineCreationParams.h" +#include "nbl/video/IGPUPipeline.h" #include "nbl/video/SPipelineCreationParams.h" namespace nbl::video { -class IGPUComputePipeline : public IBackendObject, public asset::IPipeline +class IGPUComputePipeline : public IGPUPipeline> { using pipeline_t = asset::IPipeline; - using spec_info_t = SShaderSpecInfo; public: - struct SCreationParams final : pipeline_t::SCreationParams, SPipelineCreationParams + struct SCreationParams final : SPipelineCreationParams { // By construction we satisfy from: // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkComputePipelineCreateInfo.html#VUID-VkComputePipelineCreateInfo-flags-03365 @@ -29,7 +28,7 @@ class IGPUComputePipeline : public IBackendObject, public asset::IPipeline(pipeline_t::SCreationParams::FLAGS::F) + #define base_flag(F) static_cast(pipeline_t::CreationFlags::F) enum class FLAGS : uint64_t { NONE = base_flag(NONE), @@ -51,7 +50,7 @@ class IGPUComputePipeline : public IBackendObject, public asset::IPipeline(dataSize)}; } - inline std::span getShaders() const {return {&shader,1}; } + inline std::span getShaders() const {return {&shader,1}; } // TODO: Could guess the required flags from SPIR-V introspection of declared caps core::bitflag flags = FLAGS::NONE; - spec_info_t shader = {}; + SShaderSpecInfo shader = {}; }; inline core::bitflag getCreationFlags() const {return m_flags;} @@ -78,9 +77,8 @@ class IGPUComputePipeline : public IBackendObject, public asset::IPipeline&& _layout, const core::bitflag _flags) : - IBackendObject(core::smart_refctd_ptr(_layout->getOriginDevice())), - pipeline_t(std::move(_layout)), - m_flags(_flags) {} + IGPUPipeline(core::smart_refctd_ptr(_layout->getOriginDevice()), std::move(_layout)), m_flags(_flags) + {} virtual ~IGPUComputePipeline() = default; const core::bitflag m_flags; diff --git a/include/nbl/video/IGPUGraphicsPipeline.h b/include/nbl/video/IGPUGraphicsPipeline.h index 4838d7f4d3..9fba0c4a4a 100644 --- a/include/nbl/video/IGPUGraphicsPipeline.h +++ b/include/nbl/video/IGPUGraphicsPipeline.h @@ -6,20 +6,21 @@ #include "nbl/video/IGPUPipelineLayout.h" #include "nbl/video/IGPURenderpass.h" +#include "nbl/video/IGPUPipeline.h" namespace nbl::video { -class IGPUGraphicsPipeline : public IBackendObject, public asset::IGraphicsPipeline, const IGPUPipelineLayout,const IGPURenderpass> +class IGPUGraphicsPipeline : public IGPUPipeline> { - using pipeline_t = asset::IGraphicsPipeline, const IGPUPipelineLayout,const IGPURenderpass>; + using pipeline_t = asset::IGraphicsPipeline; public: - struct SCreationParams final : pipeline_t::SCreationParams, SPipelineCreationParams - { + struct SCreationParams final : public SPipelineCreationParams + { public: - #define base_flag(F) static_cast(pipeline_t::SCreationParams::FLAGS::F) + #define base_flag(F) static_cast(pipeline_t::CreationFlags::F) enum class FLAGS : uint64_t { NONE = base_flag(NONE), @@ -31,12 +32,53 @@ class IGPUGraphicsPipeline : public IBackendObject, public asset::IGraphicsPipel }; #undef base_flag + template + inline bool impl_valid(ExtraLambda&& extra) const + { + if (!layout) + return false; + + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-dynamicRendering-06576 + if (!renderpass || cached.subpassIx>=renderpass->getSubpassCount()) + return false; + + // TODO: check rasterization samples, etc. + //rp->getCreationParameters().subpasses[i] + + core::bitflag stagePresence = {}; + for (const auto info : shaders) + if (info.shader) + { + if (!extra(info)) + return false; + const auto stage = info.stage; + if (stage>hlsl::ShaderStage::ESS_FRAGMENT) + return false; + if (stagePresence.hasFlags(stage)) + return false; + stagePresence |= stage; + } + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-stage-02096 + if (!stagePresence.hasFlags(hlsl::ShaderStage::ESS_VERTEX)) + return false; + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-pStages-00729 + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-pStages-00730 + if (stagePresence.hasFlags(hlsl::ShaderStage::ESS_TESSELLATION_CONTROL)!=stagePresence.hasFlags(hlsl::ShaderStage::ESS_TESSELLATION_EVALUATION)) + return false; + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-pStages-08888 + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-topology-08889 + if (stagePresence.hasFlags(hlsl::ShaderStage::ESS_TESSELLATION_EVALUATION)!=(cached.primitiveAssembly.primitiveType==asset::EPT_PATCH_LIST)) + return false; + + return true; + } + inline SSpecializationValidationResult valid() const { if (!layout) return {}; SSpecializationValidationResult retval = {.count=0,.dataSize=0}; - const bool valid = pipeline_t::SCreationParams::impl_valid([&retval](const spec_info_t& info)->bool + const bool valid = impl_valid([&retval](const SShaderSpecInfo& info)->bool { const auto dataSize = info.valid(); if (dataSize<0) @@ -55,11 +97,16 @@ class IGPUGraphicsPipeline : public IBackendObject, public asset::IGraphicsPipel return retval; } - inline std::span getShaders() const {return shaders;} + inline std::span getShaders() const {return shaders;} + + IGPUPipelineLayout* layout = nullptr; + std::span shaders = {}; + SCachedCreationParams cached = {}; + renderpass_t* renderpass = nullptr; // TODO: Could guess the required flags from SPIR-V introspection of declared caps core::bitflag flags = FLAGS::NONE; - }; + }; inline core::bitflag getCreationFlags() const {return m_flags;} @@ -67,8 +114,9 @@ class IGPUGraphicsPipeline : public IBackendObject, public asset::IGraphicsPipel virtual const void* getNativeHandle() const = 0; protected: - IGPUGraphicsPipeline(const SCreationParams& params) : IBackendObject(core::smart_refctd_ptr(params.layout->getOriginDevice())), - pipeline_t(params), m_flags(params.flags) {} + IGPUGraphicsPipeline(const SCreationParams& params) : + IGPUPipeline(core::smart_refctd_ptr(params.layout->getOriginDevice()), params.layout, params.cached, params.renderpass), m_flags(params.flags) + {} virtual ~IGPUGraphicsPipeline() = default; const core::bitflag m_flags; diff --git a/include/nbl/video/IGPUPipeline.h b/include/nbl/video/IGPUPipeline.h new file mode 100644 index 0000000000..0761d5d020 --- /dev/null +++ b/include/nbl/video/IGPUPipeline.h @@ -0,0 +1,110 @@ + + +// Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. +// This file is part of the "Nabla Engine". +// For conditions of distribution and use, see copyright notice in nabla.h +#ifndef _NBL_VIDEO_I_GPU_PIPELINE_H_INCLUDED_ +#define _NBL_VIDEO_I_GPU_PIPELINE_H_INCLUDED_ + +#include "nbl/asset/IPipeline.h" + +namespace nbl::video +{ + +class IGPUPipelineBase { + public: + struct SShaderSpecInfo + { + //! Structure specifying a specialization map entry + /* + Note that if specialization constant ID is used + in a shader, \bsize\b and \boffset'b must match + to \isuch an ID\i accordingly. + + By design the API satisfies: + https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkSpecializationInfo.html#VUID-VkSpecializationInfo-offset-00773 + https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkSpecializationInfo.html#VUID-VkSpecializationInfo-pMapEntries-00774 + */ + //!< The ID of the specialization constant in SPIR-V. If it isn't used in the shader, the map entry does not affect the behavior of the pipeline. + using spec_constant_id_t = uint32_t; + + struct SSpecConstantValue + { + std::span data; + inline operator bool() const { return data.size(); } + inline size_t size() const { return data.size(); } + }; + + inline SSpecConstantValue getSpecializationByteValue(const spec_constant_id_t _specConstID) const + { + if (!entries) return {}; + + const auto found = entries->find(_specConstID); + if (found != entries->end() && bool(found->second)) return found->second; + else return {}; + } + + static constexpr int32_t INVALID_SPEC_INFO = -1; + inline int32_t valid() const + { + if (!shader) return INVALID_SPEC_INFO; + + // Impossible to check: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-pName-00707 + if (entryPoint.empty()) return INVALID_SPEC_INFO; + + // Impossible to efficiently check anything from: + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-maxClipDistances-00708 + // to: + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-stage-06686 + // and from: + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-pNext-02756 + // to: + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-module-08987 + + int64_t specData = 0; + for (const auto& entry : *entries) + { + if (!entry.second) + return INVALID_SPEC_INFO; + specData += entry.second.size(); + } + if (specData>0x7fffffff) + return INVALID_SPEC_INFO; + return static_cast(specData); + } + + const asset::IShader* shader = nullptr; + std::string_view entryPoint = ""; + asset::IPipelineBase::SUBGROUP_SIZE requiredSubgroupSize : 3 = asset::IPipelineBase::SUBGROUP_SIZE::UNKNOWN; //!< Default value of 8 means no requirement + uint8_t requireFullSubgroups : 1 = false; + + // Container choice implicitly satisfies: + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkSpecializationInfo.html#VUID-VkSpecializationInfo-constantID-04911 + const core::unordered_map* entries; + // By requiring Nabla Core Profile features we implicitly satisfy: + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-flags-02784 + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-flags-02785 + // Also because our API is sane, it satisfies the following by construction: + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-pNext-02754 + + }; + +}; + +// Common Base class for pipelines +template +class IGPUPipeline : public IBackendObject, public PipelineNonAssetBase, public IGPUPipelineBase +{ + protected: + + template + explicit IGPUPipeline(core::smart_refctd_ptr&& device, Args&&... args) : + PipelineNonAssetBase(std::forward(args...)), IBackendObject(std::move(device)) + {} + virtual ~IGPUPipeline() = default; + +}; + +} + +#endif diff --git a/include/nbl/video/IGPURayTracingPipeline.h b/include/nbl/video/IGPURayTracingPipeline.h index fb8c371193..c41ed333a1 100644 --- a/include/nbl/video/IGPURayTracingPipeline.h +++ b/include/nbl/video/IGPURayTracingPipeline.h @@ -10,7 +10,7 @@ namespace nbl::video { -class IGPURayTracingPipeline : public IBackendObject, public asset::IRayTracingPipeline +class IGPURayTracingPipeline : public IGPUPipeline> { using pipeline_t = asset::IRayTracingPipeline; @@ -30,8 +30,28 @@ class IGPURayTracingPipeline : public IBackendObject, public asset::IRayTracingP uint16_t intersection; }; - struct SCreationParams final : pipeline_t::SCreationParams, SPipelineCreationParams + using SGeneralShaderGroupContainer = core::smart_refctd_dynamic_array; + using SHitShaderGroupContainer = core::smart_refctd_dynamic_array; + + struct SCreationParams final : SPipelineCreationParams { + #define base_flag(F) static_cast(IPipelineBase::CreationFlags::F) + enum class FLAGS : uint64_t + { + NONE = base_flag(NONE), + DISABLE_OPTIMIZATIONS = base_flag(DISABLE_OPTIMIZATIONS), + ALLOW_DERIVATIVES = base_flag(ALLOW_DERIVATIVES), + FAIL_ON_PIPELINE_COMPILE_REQUIRED = base_flag(FAIL_ON_PIPELINE_COMPILE_REQUIRED), + EARLY_RETURN_ON_FAILURE = base_flag(EARLY_RETURN_ON_FAILURE), + SKIP_BUILT_IN_PRIMITIVES = 1<<12, + SKIP_AABBS = 1<<13, + NO_NULL_ANY_HIT_SHADERS = 1<<14, + NO_NULL_CLOSEST_HIT_SHADERS = 1<<15, + NO_NULL_MISS_SHADERS = 1<<16, + NO_NULL_INTERSECTION_SHADERS = 1<<17, + ALLOW_MOTION = 1<<20, + }; + #undef base_flag inline SSpecializationValidationResult valid() const { @@ -42,7 +62,7 @@ class IGPURayTracingPipeline : public IBackendObject, public asset::IRayTracingP .count=0, .dataSize=0, }; - const bool valid = pipeline_t::SCreationParams::impl_valid([&retval](const asset::IPipelineBase::SShaderSpecInfo& info)->bool + const bool valid = pipeline_t::SCreationParams::impl_valid([&retval](const spec_info_t& info)->bool { const auto dataSize = info.valid(); if (dataSize<0) @@ -61,8 +81,9 @@ class IGPURayTracingPipeline : public IBackendObject, public asset::IRayTracingP return retval; } - inline std::span getShaders() const { return shaders; } + inline std::span getShaders() const { return shaders; } + IGPUPipelineLayout* layout = nullptr; }; inline core::bitflag getCreationFlags() const { return m_flags; } @@ -82,8 +103,7 @@ class IGPURayTracingPipeline : public IBackendObject, public asset::IRayTracingP virtual uint16_t getDefaultStackSize() const = 0; protected: - IGPURayTracingPipeline(const SCreationParams& params) : IBackendObject(core::smart_refctd_ptr(params.layout->getOriginDevice())), - pipeline_t(params), + IGPURayTracingPipeline(const SCreationParams& params) : IGPUPipeline(core::smart_refctd_ptr(params.layout->getOriginDevice()), params), m_flags(params.flags) {} diff --git a/include/nbl/video/SPipelineCreationParams.h b/include/nbl/video/SPipelineCreationParams.h index 489bff4343..969559d941 100644 --- a/include/nbl/video/SPipelineCreationParams.h +++ b/include/nbl/video/SPipelineCreationParams.h @@ -49,7 +49,7 @@ struct SPipelineCreationParams return basePipelineIndex!=NotDerivingFromPreviousPipeline || basePipeline; } - // If you set this, then we don't take `basePipelineIndex` into account, the pointer takes precedence + const PipelineType* basePipeline = nullptr; int32_t basePipelineIndex = NotDerivingFromPreviousPipeline; }; From a9d5aafcf6188116acb92d3177cb27f1236e9951 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Mon, 5 May 2025 17:15:56 +0700 Subject: [PATCH 06/64] Fix gpu graphics pipeline stage validation --- include/nbl/asset/ICPUGraphicsPipeline.h | 8 -------- include/nbl/asset/IGraphicsPipeline.h | 15 +++++++++++++++ include/nbl/video/IGPUGraphicsPipeline.h | 13 +++++-------- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/include/nbl/asset/ICPUGraphicsPipeline.h b/include/nbl/asset/ICPUGraphicsPipeline.h index b93b8165aa..0f90f1213d 100644 --- a/include/nbl/asset/ICPUGraphicsPipeline.h +++ b/include/nbl/asset/ICPUGraphicsPipeline.h @@ -100,14 +100,6 @@ class ICPUGraphicsPipeline final : public ICPUPipeline= GRAPHICS_SHADER_STAGE_COUNT || hlsl::bitCount(stage)!=1) - return -1; - return stageIx; - } - std::array m_specInfos; }; diff --git a/include/nbl/asset/IGraphicsPipeline.h b/include/nbl/asset/IGraphicsPipeline.h index 3e029e76b2..d7ccf598ed 100644 --- a/include/nbl/asset/IGraphicsPipeline.h +++ b/include/nbl/asset/IGraphicsPipeline.h @@ -91,6 +91,21 @@ class IGraphicsPipeline : public IPipeline, public IGraphics inline const SCachedCreationParams& getCachedCreationParams() const {return m_params;} inline const renderpass_t* getRenderpass() const {return m_renderpass.get();} + static inline int8_t stageToIndex(const hlsl::ShaderStage stage) + { + const auto stageIx = hlsl::findLSB(stage); + if (stageIx < 0 || stageIx >= GRAPHICS_SHADER_STAGE_COUNT || hlsl::bitCount(stage)!=1) + return -1; + return stageIx; + } + + static inline hlsl::ShaderStage indexToStage(const int8_t index) + { + if (index < 0 || index > GRAPHICS_SHADER_STAGE_COUNT) + return hlsl::ShaderStage::ESS_UNKNOWN; + return static_cast(hlsl::ShaderStage::ESS_VERTEX + index); + } + protected: explicit IGraphicsPipeline(const PipelineLayoutType* layout, const SCachedCreationParams& cachedParams, const renderpass_t* renderpass) : IPipeline(core::smart_refctd_ptr(layout)), m_renderpass(core::smart_refctd_ptr(renderpass)) diff --git a/include/nbl/video/IGPUGraphicsPipeline.h b/include/nbl/video/IGPUGraphicsPipeline.h index 9fba0c4a4a..50c09123cb 100644 --- a/include/nbl/video/IGPUGraphicsPipeline.h +++ b/include/nbl/video/IGPUGraphicsPipeline.h @@ -46,18 +46,15 @@ class IGPUGraphicsPipeline : public IGPUPipelinegetCreationParameters().subpasses[i] core::bitflag stagePresence = {}; - for (const auto info : shaders) - if (info.shader) + for (auto shader_i = 0u; shader_i < shaders.size(); shader_i++) { + const auto& info = shaders[shader_i]; if (!extra(info)) return false; - const auto stage = info.stage; - if (stage>hlsl::ShaderStage::ESS_FRAGMENT) - return false; - if (stagePresence.hasFlags(stage)) - return false; - stagePresence |= stage; + if (info.shader) + stagePresence |= indexToStage(shader_i); } + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-stage-02096 if (!stagePresence.hasFlags(hlsl::ShaderStage::ESS_VERTEX)) return false; From 51b69c1574e89b6b8ff1ac67b748cb7b6f200e77 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Mon, 5 May 2025 17:35:42 +0700 Subject: [PATCH 07/64] Fix compute pipeline --- include/nbl/video/IGPUComputePipeline.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/nbl/video/IGPUComputePipeline.h b/include/nbl/video/IGPUComputePipeline.h index 8c5fc017d9..66eb1dba96 100644 --- a/include/nbl/video/IGPUComputePipeline.h +++ b/include/nbl/video/IGPUComputePipeline.h @@ -50,7 +50,7 @@ class IGPUComputePipeline : public IGPUPipeline getShaders() const {return {&shader,1}; } + IGPUPipelineLayout* layout = nullptr; // TODO: Could guess the required flags from SPIR-V introspection of declared caps core::bitflag flags = FLAGS::NONE; SShaderSpecInfo shader = {}; @@ -76,8 +77,8 @@ class IGPUComputePipeline : public IGPUPipeline&& _layout, const core::bitflag _flags) : - IGPUPipeline(core::smart_refctd_ptr(_layout->getOriginDevice()), std::move(_layout)), m_flags(_flags) + inline IGPUComputePipeline(const SCreationParams& params) : + IGPUPipeline(core::smart_refctd_ptr(params.layout->getOriginDevice()), core::smart_refctd_ptr(params.layout)), m_flags(params.flags) {} virtual ~IGPUComputePipeline() = default; From fa759beec86b44dbcf317502870b5d4d713f8e5d Mon Sep 17 00:00:00 2001 From: kevyuu Date: Mon, 5 May 2025 17:55:00 +0700 Subject: [PATCH 08/64] Implement cpu graphics pipeline validation --- include/nbl/asset/ICPUGraphicsPipeline.h | 15 +++++++++++++-- include/nbl/asset/IGraphicsPipeline.h | 16 ++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/include/nbl/asset/ICPUGraphicsPipeline.h b/include/nbl/asset/ICPUGraphicsPipeline.h index 0f90f1213d..c477d42834 100644 --- a/include/nbl/asset/ICPUGraphicsPipeline.h +++ b/include/nbl/asset/ICPUGraphicsPipeline.h @@ -77,8 +77,19 @@ class ICPUGraphicsPipeline final : public ICPUPipeline= m_renderpass->getSubpassCount()) return false; + + core::bitflag stagePresence = {}; + for (auto shader_i = 0u; shader_i < m_specInfos.size(); shader_i++) + { + const auto& info = m_specInfos[shader_i]; + if (info.shader) + stagePresence |= indexToStage(shader_i); + } + return isValidStagePresence(stagePresence, m_params.primitiveAssembly.primitiveType); } protected: diff --git a/include/nbl/asset/IGraphicsPipeline.h b/include/nbl/asset/IGraphicsPipeline.h index d7ccf598ed..f47cee0fa2 100644 --- a/include/nbl/asset/IGraphicsPipeline.h +++ b/include/nbl/asset/IGraphicsPipeline.h @@ -106,6 +106,22 @@ class IGraphicsPipeline : public IPipeline, public IGraphics return static_cast(hlsl::ShaderStage::ESS_VERTEX + index); } + static inline bool isValidStagePresence(const core::bitflag& stagePresence, E_PRIMITIVE_TOPOLOGY primitiveType) + { + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-stage-02096 + if (!stagePresence.hasFlags(hlsl::ShaderStage::ESS_VERTEX)) + return false; + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-pStages-00729 + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-pStages-00730 + if (stagePresence.hasFlags(hlsl::ShaderStage::ESS_TESSELLATION_CONTROL)!=stagePresence.hasFlags(hlsl::ShaderStage::ESS_TESSELLATION_EVALUATION)) + return false; + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-pStages-08888 + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-topology-08889 + if (stagePresence.hasFlags(hlsl::ShaderStage::ESS_TESSELLATION_EVALUATION)!=(primitiveType==asset::EPT_PATCH_LIST)) + return false; + return true; + } + protected: explicit IGraphicsPipeline(const PipelineLayoutType* layout, const SCachedCreationParams& cachedParams, const renderpass_t* renderpass) : IPipeline(core::smart_refctd_ptr(layout)), m_renderpass(core::smart_refctd_ptr(renderpass)) From de8813feca93e7afdb4a78b37df24987e7c59f48 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Mon, 5 May 2025 18:10:14 +0700 Subject: [PATCH 09/64] Implement compute pipeline validation --- include/nbl/asset/ICPUComputePipeline.h | 7 +++---- include/nbl/asset/ICPUGraphicsPipeline.h | 2 +- include/nbl/video/IGPUGraphicsPipeline.h | 15 ++------------- 3 files changed, 6 insertions(+), 18 deletions(-) diff --git a/include/nbl/asset/ICPUComputePipeline.h b/include/nbl/asset/ICPUComputePipeline.h index d9bc8dd646..480f601fc0 100644 --- a/include/nbl/asset/ICPUComputePipeline.h +++ b/include/nbl/asset/ICPUComputePipeline.h @@ -43,14 +43,13 @@ class ICPUComputePipeline : public ICPUPipeline> inline virtual std::span getSpecInfo(hlsl::ShaderStage stage) override final { if (stage==hlsl::ShaderStage::ESS_COMPUTE && isMutable()) - return {m_specInfo,1}; + return {&m_specInfo,1}; return {}; } inline virtual bool valid() const override final { - // TODO(kevinyu): Fix this temporary dummy code - return true; + return m_specInfo.valid(); } protected: @@ -66,7 +65,7 @@ class ICPUComputePipeline : public ICPUPipeline> private: - SShaderSpecInfo m_specInfo; + SShaderSpecInfo m_specInfo; }; diff --git a/include/nbl/asset/ICPUGraphicsPipeline.h b/include/nbl/asset/ICPUGraphicsPipeline.h index c477d42834..7d139d6fe9 100644 --- a/include/nbl/asset/ICPUGraphicsPipeline.h +++ b/include/nbl/asset/ICPUGraphicsPipeline.h @@ -94,7 +94,7 @@ class ICPUGraphicsPipeline final : public ICPUPipeline(params.layout->getOriginDevice()), params.layout, params.cached, params.renderpass), m_flags(params.flags) {} - virtual ~IGPUGraphicsPipeline() = default; + virtual ~IGPUGraphicsPipeline() override = default; const core::bitflag m_flags; }; From 37ab1ce1b34a82b495581e6f01c0f4c5f6329301 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Wed, 7 May 2025 17:53:26 +0700 Subject: [PATCH 10/64] Add FLAGS alias --- include/nbl/asset/IPipeline.h | 1 + include/nbl/video/IGPUComputePipeline.h | 2 +- include/nbl/video/IGPUGraphicsPipeline.h | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/nbl/asset/IPipeline.h b/include/nbl/asset/IPipeline.h index 98f1671cca..c458c34afe 100644 --- a/include/nbl/asset/IPipeline.h +++ b/include/nbl/asset/IPipeline.h @@ -103,6 +103,7 @@ class IPipelineBase //DESCRIPTOR_VUFFER_BIT=1<<29, //PROTECTED_ACCESS_ONLY=1<<30, }; + using FLAGS = CreationFlags; // Nabla requires device's reported subgroup size to be between 4 and 128 enum class SUBGROUP_SIZE : uint8_t diff --git a/include/nbl/video/IGPUComputePipeline.h b/include/nbl/video/IGPUComputePipeline.h index 66eb1dba96..6e825d749b 100644 --- a/include/nbl/video/IGPUComputePipeline.h +++ b/include/nbl/video/IGPUComputePipeline.h @@ -28,7 +28,7 @@ class IGPUComputePipeline : public IGPUPipeline(pipeline_t::CreationFlags::F) + #define base_flag(F) static_cast(pipeline_t::FLAGS::F) enum class FLAGS : uint64_t { NONE = base_flag(NONE), diff --git a/include/nbl/video/IGPUGraphicsPipeline.h b/include/nbl/video/IGPUGraphicsPipeline.h index 53ec20244f..fc596a54e1 100644 --- a/include/nbl/video/IGPUGraphicsPipeline.h +++ b/include/nbl/video/IGPUGraphicsPipeline.h @@ -20,7 +20,7 @@ class IGPUGraphicsPipeline : public IGPUPipeline { public: - #define base_flag(F) static_cast(pipeline_t::CreationFlags::F) + #define base_flag(F) static_cast(pipeline_t::FLAGS::F) enum class FLAGS : uint64_t { NONE = base_flag(NONE), From a0ecd505814f71309de538a994f141397d9e0bcd Mon Sep 17 00:00:00 2001 From: kevyuu Date: Wed, 7 May 2025 17:55:00 +0700 Subject: [PATCH 11/64] Fix clone_impl to return smart pointer --- include/nbl/asset/ICPUComputePipeline.h | 6 +++--- include/nbl/asset/ICPUGraphicsPipeline.h | 6 +++--- include/nbl/asset/ICPUPipeline.h | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/nbl/asset/ICPUComputePipeline.h b/include/nbl/asset/ICPUComputePipeline.h index 480f601fc0..656e8faf6f 100644 --- a/include/nbl/asset/ICPUComputePipeline.h +++ b/include/nbl/asset/ICPUComputePipeline.h @@ -27,11 +27,11 @@ class ICPUComputePipeline : public ICPUPipeline> return core::smart_refctd_ptr(retval,core::dont_grab); } - inline base_t* clone_impl(core::smart_refctd_ptr&& layout, uint32_t depth) const override final + inline core::smart_refctd_ptr clone_impl(core::smart_refctd_ptr&& layout, uint32_t depth) const override final { auto newPipeline = new ICPUComputePipeline(std::move(layout)); - newPipeline->m_specInfo = newPipeline->cloneSpecInfo(m_specInfo, depth); - return newPipeline; + newPipeline->m_specInfo = m_specInfo.clone(depth); + return core::smart_refctd_ptr(newPipeline, core::dont_grab); } constexpr static inline auto AssetType = ET_COMPUTE_PIPELINE; diff --git a/include/nbl/asset/ICPUGraphicsPipeline.h b/include/nbl/asset/ICPUGraphicsPipeline.h index 7d139d6fe9..915a4a43c2 100644 --- a/include/nbl/asset/ICPUGraphicsPipeline.h +++ b/include/nbl/asset/ICPUGraphicsPipeline.h @@ -29,7 +29,7 @@ class ICPUGraphicsPipeline final : public ICPUPipeline(retval,core::dont_grab); } - inline base_t* clone_impl(core::smart_refctd_ptr&& layout, uint32_t depth) const override final + inline core::smart_refctd_ptr clone_impl(core::smart_refctd_ptr&& layout, uint32_t depth) const override final { auto* newPipeline = new ICPUGraphicsPipeline(layout.get()); for (auto i = 0; i < GRAPHICS_SHADER_STAGE_COUNT; i++) @@ -39,10 +39,10 @@ class ICPUGraphicsPipeline final : public ICPUPipelinem_specInfos[specInfo_i] = newPipeline->cloneSpecInfo(m_specInfos[specInfo_i], depth); + newPipeline->m_specInfos[specInfo_i] = m_specInfos[specInfo_i].clone(depth); } - return newPipeline; + return core::smart_refctd_ptr(newPipeline, core::dont_grab); } constexpr static inline auto AssetType = ET_GRAPHICS_PIPELINE; diff --git a/include/nbl/asset/ICPUPipeline.h b/include/nbl/asset/ICPUPipeline.h index 623d5ae2df..3b48ea43f7 100644 --- a/include/nbl/asset/ICPUPipeline.h +++ b/include/nbl/asset/ICPUPipeline.h @@ -121,13 +121,13 @@ class ICPUPipeline : public IAsset, public PipelineNonAssetBase, public ICPUPipe inline core::smart_refctd_ptr clone(uint32_t _depth = ~0u) const override final { + if (!getLayout()) return nullptr; + core::smart_refctd_ptr layout; - if (_depth>0u && getLayout()) + if (_depth > 0u) layout = core::smart_refctd_ptr_static_cast(getLayout->clone(_depth-1u)); - auto* newPipeline = clone_impl(std::move(layout), _depth); - - return core::smart_refctd_ptr(newPipeline,core::dont_grab); + return clone_impl(std::move(layout), _depth); } SShaderSpecInfo cloneSpecInfo(const SShaderSpecInfo& specInfo, uint32_t depth) @@ -145,7 +145,7 @@ class ICPUPipeline : public IAsset, public PipelineNonAssetBase, public ICPUPipe using PipelineNonAssetBase::PipelineNonAssetBase; virtual ~ICPUPipeline() = default; - virtual this_t* clone_impl(core::smart_refctd_ptr&& layout, uint32_t depth) const = 0; + virtual core::smart_refctd_ptr clone_impl(core::smart_refctd_ptr&& layout, uint32_t depth) const = 0; }; From 7890981b72e366e62d6a0e0f9d364e3cf82bb5d4 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Wed, 7 May 2025 17:57:40 +0700 Subject: [PATCH 12/64] Add final decoration to ICPUComputePipeline --- include/nbl/asset/ICPUComputePipeline.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/nbl/asset/ICPUComputePipeline.h b/include/nbl/asset/ICPUComputePipeline.h index 656e8faf6f..0869277911 100644 --- a/include/nbl/asset/ICPUComputePipeline.h +++ b/include/nbl/asset/ICPUComputePipeline.h @@ -12,7 +12,7 @@ namespace nbl::asset { //! CPU Version of Compute Pipeline -class ICPUComputePipeline : public ICPUPipeline> +class ICPUComputePipeline final : public ICPUPipeline> { using base_t = ICPUPipeline>; From 9a14aa175333af1170e80aa2811ba8df6e684111 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Wed, 7 May 2025 17:58:15 +0700 Subject: [PATCH 13/64] Make cpu pipeline constructor private --- include/nbl/asset/ICPUComputePipeline.h | 7 ++++--- include/nbl/asset/ICPUGraphicsPipeline.h | 8 +++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/include/nbl/asset/ICPUComputePipeline.h b/include/nbl/asset/ICPUComputePipeline.h index 0869277911..78dc324b50 100644 --- a/include/nbl/asset/ICPUComputePipeline.h +++ b/include/nbl/asset/ICPUComputePipeline.h @@ -17,9 +17,6 @@ class ICPUComputePipeline final : public ICPUPipeline>; public: - explicit ICPUComputePipeline(const ICPUPipelineLayout* layout): - base_t(core::smart_refctd_ptr(layout)) - {} static core::smart_refctd_ptr create(const ICPUPipelineLayout* layout) { @@ -67,6 +64,10 @@ class ICPUComputePipeline final : public ICPUPipeline(layout)) + {} + }; } diff --git a/include/nbl/asset/ICPUGraphicsPipeline.h b/include/nbl/asset/ICPUGraphicsPipeline.h index 915a4a43c2..2492329a63 100644 --- a/include/nbl/asset/ICPUGraphicsPipeline.h +++ b/include/nbl/asset/ICPUGraphicsPipeline.h @@ -19,9 +19,6 @@ class ICPUGraphicsPipeline final : public ICPUPipeline; public: - explicit ICPUGraphicsPipeline(const ICPUPipelineLayout* layout) - : base_t(layout, {}, {}) - {} static core::smart_refctd_ptr create(const ICPUPipelineLayout* layout) { @@ -112,6 +109,11 @@ class ICPUGraphicsPipeline final : public ICPUPipeline m_specInfos; + + private: + explicit ICPUGraphicsPipeline(const ICPUPipelineLayout* layout) + : base_t(layout, {}, {}) + {} }; } From 9bb9d1411780cfa708609a031f3ecbc13cb276d8 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Wed, 7 May 2025 18:00:14 +0700 Subject: [PATCH 14/64] Add layout validation to compute pipeline validation --- include/nbl/asset/ICPUComputePipeline.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/nbl/asset/ICPUComputePipeline.h b/include/nbl/asset/ICPUComputePipeline.h index 78dc324b50..9db06dbde1 100644 --- a/include/nbl/asset/ICPUComputePipeline.h +++ b/include/nbl/asset/ICPUComputePipeline.h @@ -44,8 +44,11 @@ class ICPUComputePipeline final : public ICPUPipelinevalid()) return false; return m_specInfo.valid(); } From bcb096f97dfad9c69b21c50988ab5da1f4c50456 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Wed, 7 May 2025 18:03:28 +0700 Subject: [PATCH 15/64] Refactor getSpecInfo --- include/nbl/asset/ICPUComputePipeline.h | 2 +- include/nbl/asset/ICPUGraphicsPipeline.h | 7 +++---- include/nbl/asset/ICPUPipeline.h | 16 +++++----------- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/include/nbl/asset/ICPUComputePipeline.h b/include/nbl/asset/ICPUComputePipeline.h index 9db06dbde1..5f933878b4 100644 --- a/include/nbl/asset/ICPUComputePipeline.h +++ b/include/nbl/asset/ICPUComputePipeline.h @@ -37,7 +37,7 @@ class ICPUComputePipeline final : public ICPUPipeline getSpecInfo(hlsl::ShaderStage stage) override final + inline virtual std::span getSpecInfo(hlsl::ShaderStage stage) const override final { if (stage==hlsl::ShaderStage::ESS_COMPUTE && isMutable()) return {&m_specInfo,1}; diff --git a/include/nbl/asset/ICPUGraphicsPipeline.h b/include/nbl/asset/ICPUGraphicsPipeline.h index 2492329a63..fb82bd5608 100644 --- a/include/nbl/asset/ICPUGraphicsPipeline.h +++ b/include/nbl/asset/ICPUGraphicsPipeline.h @@ -62,16 +62,15 @@ class ICPUGraphicsPipeline final : public ICPUPipeline getSpecInfo(hlsl::ShaderStage stage) override final + inline virtual std::span getSpecInfo(hlsl::ShaderStage stage) const override final { const auto stageIndex = stageToIndex(stage); - if (isMutable() && stageIndex != -1) - { + if (stageIndex != -1) return { &m_specInfos[stageIndex], 1 }; - } return {}; } + inline virtual bool valid() const override final { if (!m_layout) return false; diff --git a/include/nbl/asset/ICPUPipeline.h b/include/nbl/asset/ICPUPipeline.h index 3b48ea43f7..fa77c40b7e 100644 --- a/include/nbl/asset/ICPUPipeline.h +++ b/include/nbl/asset/ICPUPipeline.h @@ -88,11 +88,7 @@ class ICPUPipelineBase }; - virtual std::span getSpecInfo(const hlsl::ShaderStage stage) = 0; - inline std::span getSpecInfo(const hlsl::ShaderStage stage) const - { - return getSpecInfo(stage); - } + virtual std::span getSpecInfo(const hlsl::ShaderStage stage) const = 0; virtual bool valid() const = 0; }; @@ -131,13 +127,11 @@ class ICPUPipeline : public IAsset, public PipelineNonAssetBase, public ICPUPipe } SShaderSpecInfo cloneSpecInfo(const SShaderSpecInfo& specInfo, uint32_t depth) + inline std::span getSpecInfo(hlsl::ShaderStage stage) { - auto newSpecInfo = specInfo; - if (depth>0u) - { - newSpecInfo.shader = core::smart_refctd_ptr_static_cast(specInfo.shader->clone(depth - 1u)); - } - return newSpecInfo; + if (!isMutable()) return {}; + const auto specInfo = static_cast(this)->getSpecInfo(stage); + return { const_cast(specInfo.data()), specInfo.size() }; } protected: From 278eb715bcd2e25168f36f30626213a8561ef4f7 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Wed, 7 May 2025 18:04:31 +0700 Subject: [PATCH 16/64] Move stageToIndex and indexToStage --- include/nbl/asset/ICPUGraphicsPipeline.h | 15 +++++++++++++++ include/nbl/asset/IGraphicsPipeline.h | 14 -------------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/include/nbl/asset/ICPUGraphicsPipeline.h b/include/nbl/asset/ICPUGraphicsPipeline.h index fb82bd5608..926ee0ca6c 100644 --- a/include/nbl/asset/ICPUGraphicsPipeline.h +++ b/include/nbl/asset/ICPUGraphicsPipeline.h @@ -113,6 +113,21 @@ class ICPUGraphicsPipeline final : public ICPUPipeline= GRAPHICS_SHADER_STAGE_COUNT || hlsl::bitCount(stage)!=1) + return -1; + return stageIx; + } + + static inline hlsl::ShaderStage indexToStage(const int8_t index) + { + if (index < 0 || index > GRAPHICS_SHADER_STAGE_COUNT) + return hlsl::ShaderStage::ESS_UNKNOWN; + return static_cast(hlsl::ShaderStage::ESS_VERTEX + index); + } }; } diff --git a/include/nbl/asset/IGraphicsPipeline.h b/include/nbl/asset/IGraphicsPipeline.h index f47cee0fa2..859c80b0b7 100644 --- a/include/nbl/asset/IGraphicsPipeline.h +++ b/include/nbl/asset/IGraphicsPipeline.h @@ -91,20 +91,6 @@ class IGraphicsPipeline : public IPipeline, public IGraphics inline const SCachedCreationParams& getCachedCreationParams() const {return m_params;} inline const renderpass_t* getRenderpass() const {return m_renderpass.get();} - static inline int8_t stageToIndex(const hlsl::ShaderStage stage) - { - const auto stageIx = hlsl::findLSB(stage); - if (stageIx < 0 || stageIx >= GRAPHICS_SHADER_STAGE_COUNT || hlsl::bitCount(stage)!=1) - return -1; - return stageIx; - } - - static inline hlsl::ShaderStage indexToStage(const int8_t index) - { - if (index < 0 || index > GRAPHICS_SHADER_STAGE_COUNT) - return hlsl::ShaderStage::ESS_UNKNOWN; - return static_cast(hlsl::ShaderStage::ESS_VERTEX + index); - } static inline bool isValidStagePresence(const core::bitflag& stagePresence, E_PRIMITIVE_TOPOLOGY primitiveType) { From 68bbcff2d77b6635ed8e1e2cbfc154cda8e12029 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Wed, 7 May 2025 18:08:34 +0700 Subject: [PATCH 17/64] Add constraint to template parameter of ICPUPipeline and IGPUPipeline --- include/nbl/asset/ICPUPipeline.h | 1 + include/nbl/video/IGPUPipeline.h | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/nbl/asset/ICPUPipeline.h b/include/nbl/asset/ICPUPipeline.h index fa77c40b7e..8f41de59ec 100644 --- a/include/nbl/asset/ICPUPipeline.h +++ b/include/nbl/asset/ICPUPipeline.h @@ -95,6 +95,7 @@ class ICPUPipelineBase // Common Base class for pipelines template + requires (std::is_base_of_v, PipelineNonAssetBase> && !std::is_base_of_v) class ICPUPipeline : public IAsset, public PipelineNonAssetBase, public ICPUPipelineBase { using this_t = ICPUPipeline; diff --git a/include/nbl/video/IGPUPipeline.h b/include/nbl/video/IGPUPipeline.h index 0761d5d020..4a96c9e01f 100644 --- a/include/nbl/video/IGPUPipeline.h +++ b/include/nbl/video/IGPUPipeline.h @@ -92,14 +92,15 @@ class IGPUPipelineBase { }; // Common Base class for pipelines -template -class IGPUPipeline : public IBackendObject, public PipelineNonAssetBase, public IGPUPipelineBase +template + requires (std::is_base_of_v, PipelineNonBackendObjectBase> && !std::is_base_of_v) +class IGPUPipeline : public IBackendObject, public PipelineNonBackendObjectBase, public IGPUPipelineBase { protected: template explicit IGPUPipeline(core::smart_refctd_ptr&& device, Args&&... args) : - PipelineNonAssetBase(std::forward(args...)), IBackendObject(std::move(device)) + PipelineNonBackendObjectBase(std::forward(args...)), IBackendObject(std::move(device)) {} virtual ~IGPUPipeline() = default; From 8ec04157beeed8ff19aee04e69ccf9ffeeaa6f17 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Wed, 7 May 2025 18:50:06 +0700 Subject: [PATCH 18/64] Rework IGPUPipeline SSpecConstantValue --- include/nbl/video/IGPUPipeline.h | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/include/nbl/video/IGPUPipeline.h b/include/nbl/video/IGPUPipeline.h index 4a96c9e01f..2a93895b9d 100644 --- a/include/nbl/video/IGPUPipeline.h +++ b/include/nbl/video/IGPUPipeline.h @@ -28,19 +28,14 @@ class IGPUPipelineBase { //!< The ID of the specialization constant in SPIR-V. If it isn't used in the shader, the map entry does not affect the behavior of the pipeline. using spec_constant_id_t = uint32_t; - struct SSpecConstantValue - { - std::span data; - inline operator bool() const { return data.size(); } - inline size_t size() const { return data.size(); } - }; + using SSpecConstantValue = std::span; inline SSpecConstantValue getSpecializationByteValue(const spec_constant_id_t _specConstID) const { if (!entries) return {}; const auto found = entries->find(_specConstID); - if (found != entries->end() && bool(found->second)) return found->second; + if (found != entries->end() && found->second.size()) return found->second; else return {}; } @@ -64,7 +59,7 @@ class IGPUPipelineBase { int64_t specData = 0; for (const auto& entry : *entries) { - if (!entry.second) + if (!entry.second.size()) return INVALID_SPEC_INFO; specData += entry.second.size(); } From 57136e8cb8bd148a18286859ac8d79def85b9039 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Wed, 7 May 2025 19:16:58 +0700 Subject: [PATCH 19/64] Rework SShaderSpecInfo for ICPUPIpeline --- include/nbl/asset/ICPUGraphicsPipeline.h | 2 +- include/nbl/asset/ICPUPipeline.h | 11 +++-------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/include/nbl/asset/ICPUGraphicsPipeline.h b/include/nbl/asset/ICPUGraphicsPipeline.h index 926ee0ca6c..62b25443cc 100644 --- a/include/nbl/asset/ICPUGraphicsPipeline.h +++ b/include/nbl/asset/ICPUGraphicsPipeline.h @@ -85,7 +85,7 @@ class ICPUGraphicsPipeline final : public ICPUPipeline data; - inline operator bool() const { return data.size(); } - inline size_t size() const { return data.size(); } - }; + using SSpecConstantValue = core::vector; inline SSpecConstantValue* getSpecializationByteValue(const spec_constant_id_t _specConstID) { const auto found = entries.find(_specConstID); - if (found != entries.end() && bool(found->second)) return &found->second; + if (found != entries.end() && found->second.size()) return &found->second; else return nullptr; } @@ -65,7 +60,7 @@ class ICPUPipelineBase int64_t specData = 0; for (const auto& entry : entries) { - if (!entry.second) return INVALID_SPEC_INFO; + if (!entry.second.size()) return INVALID_SPEC_INFO; specData += entry.second.size(); } if (specData > 0x7fffffff) return INVALID_SPEC_INFO; From 7983e62a27f29c906d64a2152d4033dd9a28a185 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Wed, 7 May 2025 19:17:15 +0700 Subject: [PATCH 20/64] Move cloneSpecInfo into SShaderSpecInfo --- include/nbl/asset/ICPUPipeline.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/include/nbl/asset/ICPUPipeline.h b/include/nbl/asset/ICPUPipeline.h index ddfb4628c8..69d709d1d0 100644 --- a/include/nbl/asset/ICPUPipeline.h +++ b/include/nbl/asset/ICPUPipeline.h @@ -81,6 +81,15 @@ class ICPUPipelineBase // Also because our API is sane, it satisfies the following by construction: // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-pNext-02754 + SShaderSpecInfo clone(uint32_t depth) const + { + auto newSpecInfo = *this; + if (depth > 0u) + { + newSpecInfo.shader = core::smart_refctd_ptr_static_cast(this->shader->clone(depth - 1u)); + } + return newSpecInfo; + } }; virtual std::span getSpecInfo(const hlsl::ShaderStage stage) const = 0; @@ -122,7 +131,6 @@ class ICPUPipeline : public IAsset, public PipelineNonAssetBase, public ICPUPipe return clone_impl(std::move(layout), _depth); } - SShaderSpecInfo cloneSpecInfo(const SShaderSpecInfo& specInfo, uint32_t depth) inline std::span getSpecInfo(hlsl::ShaderStage stage) { if (!isMutable()) return {}; From 071f1ebbb0da7090d097233248b15e25092580b6 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Wed, 7 May 2025 19:17:45 +0700 Subject: [PATCH 21/64] Remove valid virtual function from ICPUPipeline to IAsset --- include/nbl/asset/IAsset.h | 2 ++ include/nbl/asset/ICPUPipeline.h | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/nbl/asset/IAsset.h b/include/nbl/asset/IAsset.h index fdb41ed298..3b8b123ce3 100644 --- a/include/nbl/asset/IAsset.h +++ b/include/nbl/asset/IAsset.h @@ -169,6 +169,8 @@ class IAsset : virtual public core::IReferenceCounted return retval; } + virtual bool valid() const = 0; + protected: inline IAsset() = default; //! Pure virtual destructor to ensure no instantiation diff --git a/include/nbl/asset/ICPUPipeline.h b/include/nbl/asset/ICPUPipeline.h index 69d709d1d0..8b90458f21 100644 --- a/include/nbl/asset/ICPUPipeline.h +++ b/include/nbl/asset/ICPUPipeline.h @@ -94,7 +94,6 @@ class ICPUPipelineBase virtual std::span getSpecInfo(const hlsl::ShaderStage stage) const = 0; - virtual bool valid() const = 0; }; // Common Base class for pipelines From b8f8ba04db3e44aa30e1c265bd108367a2707b19 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Wed, 7 May 2025 19:18:33 +0700 Subject: [PATCH 22/64] Remove getShaders from SShaderSpecInfo --- include/nbl/video/IGPUComputePipeline.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/nbl/video/IGPUComputePipeline.h b/include/nbl/video/IGPUComputePipeline.h index 6e825d749b..42503e1f12 100644 --- a/include/nbl/video/IGPUComputePipeline.h +++ b/include/nbl/video/IGPUComputePipeline.h @@ -63,8 +63,6 @@ class IGPUComputePipeline : public IGPUPipeline(dataSize)}; } - inline std::span getShaders() const {return {&shader,1}; } - IGPUPipelineLayout* layout = nullptr; // TODO: Could guess the required flags from SPIR-V introspection of declared caps core::bitflag flags = FLAGS::NONE; From f661366d6a35cc83fe578436ce0b168f99d381de Mon Sep 17 00:00:00 2001 From: kevyuu Date: Wed, 7 May 2025 19:21:20 +0700 Subject: [PATCH 23/64] Rename isValidStagePresence to hasRequiredStages --- include/nbl/asset/IGraphicsPipeline.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/nbl/asset/IGraphicsPipeline.h b/include/nbl/asset/IGraphicsPipeline.h index 859c80b0b7..ef49e4c03a 100644 --- a/include/nbl/asset/IGraphicsPipeline.h +++ b/include/nbl/asset/IGraphicsPipeline.h @@ -92,7 +92,7 @@ class IGraphicsPipeline : public IPipeline, public IGraphics inline const renderpass_t* getRenderpass() const {return m_renderpass.get();} - static inline bool isValidStagePresence(const core::bitflag& stagePresence, E_PRIMITIVE_TOPOLOGY primitiveType) + static inline bool hasRequiredStages(const core::bitflag& stagePresence, E_PRIMITIVE_TOPOLOGY primitiveType) { // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-stage-02096 if (!stagePresence.hasFlags(hlsl::ShaderStage::ESS_VERTEX)) From 8c10cbdaba40e8fa0eb569ef8e00f39f181d065d Mon Sep 17 00:00:00 2001 From: kevyuu Date: Wed, 7 May 2025 19:25:01 +0700 Subject: [PATCH 24/64] Rework IGPUGraphicsPipeline to have individual shaderSpecInfo per stages --- include/nbl/video/IGPUGraphicsPipeline.h | 31 +++++++++++++++--------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/include/nbl/video/IGPUGraphicsPipeline.h b/include/nbl/video/IGPUGraphicsPipeline.h index fc596a54e1..f5d6e40275 100644 --- a/include/nbl/video/IGPUGraphicsPipeline.h +++ b/include/nbl/video/IGPUGraphicsPipeline.h @@ -46,16 +46,21 @@ class IGPUGraphicsPipeline : public IGPUPipelinegetCreationParameters().subpasses[i] core::bitflag stagePresence = {}; - for (auto shader_i = 0u; shader_i < shaders.size(); shader_i++) - { - const auto& info = shaders[shader_i]; - if (!extra(info)) - return false; - if (info.shader) - stagePresence |= indexToStage(shader_i); - } - return isValidStagePresence(stagePresence, cached.primitiveAssembly.primitiveType); + auto processSpecInfo = [&](const SShaderSpecInfo& specInfo, hlsl::ShaderStage stage) + { + if (!extra(specInfo)) return false; + if (!specInfo.shader) return false; + stagePresence != stage; + return true; + }; + if (!processSpecInfo(vertexShader)) return false; + if (!processSpecInfo(tesselationControlShader)) return false; + if (!processSpecInfo(tesselationEvaluationShader)) return false; + if (!processSpecInfo(geometryShader)) return false; + if (!processSpecInfo(fragmentShader)) return false; + + return hasRequiredStages(stagePresence, cached.primitiveAssembly.primitiveType); } @@ -83,10 +88,12 @@ class IGPUGraphicsPipeline : public IGPUPipeline getShaders() const {return shaders;} - IGPUPipelineLayout* layout = nullptr; - std::span shaders = {}; + SShaderSpecInfo vertexShader; + SShaderSpecInfo tesselationControlShader; + SShaderSpecInfo tesselationEvaluationShader; + SShaderSpecInfo geometryShader; + SShaderSpecInfo fragmentShader; SCachedCreationParams cached = {}; renderpass_t* renderpass = nullptr; From 71056f2274b118a0ed6c22aff5b1f5ff5d96e133 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Wed, 7 May 2025 19:25:24 +0700 Subject: [PATCH 25/64] Add IGPUPipelineLayout to IGPUPipeline --- include/nbl/video/IGPUPipeline.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/nbl/video/IGPUPipeline.h b/include/nbl/video/IGPUPipeline.h index 2a93895b9d..826026d9aa 100644 --- a/include/nbl/video/IGPUPipeline.h +++ b/include/nbl/video/IGPUPipeline.h @@ -6,6 +6,7 @@ #ifndef _NBL_VIDEO_I_GPU_PIPELINE_H_INCLUDED_ #define _NBL_VIDEO_I_GPU_PIPELINE_H_INCLUDED_ +#include "nbl/video/IGPUPipelineLayout.h" #include "nbl/asset/IPipeline.h" namespace nbl::video From 11255d4f7d99279851f41ae5f025912f437b73f6 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Thu, 8 May 2025 20:24:27 +0700 Subject: [PATCH 26/64] Implement ICPURayTracingPipeline --- include/nbl/asset/ICPURayTracingPipeline.h | 122 +++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 include/nbl/asset/ICPURayTracingPipeline.h diff --git a/include/nbl/asset/ICPURayTracingPipeline.h b/include/nbl/asset/ICPURayTracingPipeline.h new file mode 100644 index 0000000000..23a1d82225 --- /dev/null +++ b/include/nbl/asset/ICPURayTracingPipeline.h @@ -0,0 +1,122 @@ + +// Copyright (C) 2018-2024 - DevSH Graphics Programming Sp. z O.O. +// This file is part of the "Nabla Engine". +// For conditions of distribution and use, see copyright notice in nabla.h +#ifndef _NBL_ASSET_I_CPU_RAY_TRACING_PIPELINE_H_INCLUDED_ +#define _NBL_ASSET_I_CPU_RAY_TRACING_PIPELINE_H_INCLUDED_ + +#include "nbl/asset/IRayTracingPipeline.h" +#include "nbl/asset/ICPUPipeline.h" + + +namespace nbl::asset +{ + +//! CPU Version of RayTracing Pipeline +class ICPURayTracingPipeline final : public ICPUPipeline> +{ + using pipeline_base_t = IRayTracingPipeline; + using base_t = ICPUPipeline; + + public: + struct SHitGroupSpecInfo { + SShaderSpecInfo closestHit; + SShaderSpecInfo anyHit; + SShaderSpecInfo intersection; + + SHitGroupSpecInfo clone(uint32_t depth) const + { + auto newSpecInfo = *this; + if (depth > 0u) + { + newSpecInfo.closestHit.shader = core::smart_refctd_ptr_static_cast(this->closestHit.shader->clone(depth - 1u)); + newSpecInfo.anyHit.shader = core::smart_refctd_ptr_static_cast(this->anyHit.shader->clone(depth - 1u)); + newSpecInfo.intersection.shader = core::smart_refctd_ptr_static_cast(this->intersection.shader->clone(depth - 1u)); + } + return newSpecInfo; + } + }; + + static core::smart_refctd_ptr create(const ICPUPipelineLayout* layout) + { + auto retval = new ICPURayTracingPipeline(layout); + return core::smart_refctd_ptr(retval,core::dont_grab); + } + + inline core::smart_refctd_ptr clone_impl(core::smart_refctd_ptr&& layout, uint32_t depth) const override final + { + auto newPipeline = new ICPURayTracingPipeline(layout.get()); + newPipeline->m_raygen = m_raygen.clone(depth); + + newPipeline->m_misses.resize(m_misses.size()); + for (auto specInfo_i = 0u; specInfo_i < m_misses.size(); specInfo_i++) + { + newPipeline->m_misses[specInfo_i] = m_misses[specInfo_i].clone(depth); + } + + newPipeline->m_hitGroups.resize(m_hitGroups.size()); + for (auto specInfo_i = 0u; specInfo_i < m_misses.size(); specInfo_i++) + { + newPipeline->m_hitGroups[specInfo_i] = m_hitGroups[specInfo_i].clone(depth); + } + + newPipeline->m_callables.resize(m_callables.size()); + for (auto specInfo_i = 0u; specInfo_i < m_callables.size(); specInfo_i++) + { + newPipeline->m_callables[specInfo_i] = m_callables[specInfo_i].clone(depth); + } + + newPipeline->m_params = m_params; + return core::smart_refctd_ptr(newPipeline); + } + + constexpr static inline auto AssetType = ET_RAYTRACING_PIPELINE; + inline E_TYPE getAssetType() const override { return AssetType; } + + //! + inline size_t getDependantCount() const override { + //TODO(kevinyu): Implement or refactor the api design to something else + return 0; + } + + inline virtual std::span getSpecInfo(hlsl::ShaderStage stage) const override final + { + switch (stage) + { + case hlsl::ShaderStage::ESS_RAYGEN: + return { &m_raygen, 1 }; + } + return {}; + } + + inline virtual bool valid() const override final + { + // TODO(kevinyu): Fix this temporary dummy code + return true; + } + + protected: + virtual ~ICPURayTracingPipeline() = default; + + inline IAsset* getDependant_impl(const size_t ix) override + { + //TODO(kevinyu): remove this function, since this is expensive + return nullptr; + } + + + private: + + SShaderSpecInfo m_raygen; + core::vector m_misses; + core::vector m_hitGroups; + core::vector m_callables; + + explicit ICPURayTracingPipeline(const ICPUPipelineLayout* layout) + : base_t(layout, {}) + {} + +}; + +} +#endif From 8c549fb7105637649b6b71ae2bb481b8729daa4a Mon Sep 17 00:00:00 2001 From: kevyuu Date: Mon, 12 May 2025 17:40:48 +0700 Subject: [PATCH 27/64] Add computeDependants virtual function to IAsset --- include/nbl/asset/IAsset.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/nbl/asset/IAsset.h b/include/nbl/asset/IAsset.h index 3b8b123ce3..3802536029 100644 --- a/include/nbl/asset/IAsset.h +++ b/include/nbl/asset/IAsset.h @@ -169,6 +169,8 @@ class IAsset : virtual public core::IReferenceCounted return retval; } + virtual core::unordered_set computeDependants() const = 0; + virtual bool valid() const = 0; protected: From 01c4ac66ad760c843853eb1dfb9bc18fbf6a4bd0 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Mon, 12 May 2025 17:41:22 +0700 Subject: [PATCH 28/64] Implement computeDependants for ICPUComputePipeline --- include/nbl/asset/ICPUComputePipeline.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/nbl/asset/ICPUComputePipeline.h b/include/nbl/asset/ICPUComputePipeline.h index 5f933878b4..aa7656af86 100644 --- a/include/nbl/asset/ICPUComputePipeline.h +++ b/include/nbl/asset/ICPUComputePipeline.h @@ -37,6 +37,11 @@ class ICPUComputePipeline final : public ICPUPipeline computeDependants() const override + { + return {m_layout.get(), m_specInfo.shader.get()}; + } + inline virtual std::span getSpecInfo(hlsl::ShaderStage stage) const override final { if (stage==hlsl::ShaderStage::ESS_COMPUTE && isMutable()) From d9efa1a60e17995271a966ffdc20d93f4490fa53 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Mon, 12 May 2025 17:41:56 +0700 Subject: [PATCH 29/64] Implement compute pipeline base --- include/nbl/asset/ICPUComputePipeline.h | 9 ++-- include/nbl/asset/IComputePipeline.h | 56 +++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 include/nbl/asset/IComputePipeline.h diff --git a/include/nbl/asset/ICPUComputePipeline.h b/include/nbl/asset/ICPUComputePipeline.h index aa7656af86..01859e0c3f 100644 --- a/include/nbl/asset/ICPUComputePipeline.h +++ b/include/nbl/asset/ICPUComputePipeline.h @@ -6,15 +6,16 @@ #include "nbl/asset/ICPUPipeline.h" +#include "nbl/asset/IComputePipeline.h" namespace nbl::asset { //! CPU Version of Compute Pipeline -class ICPUComputePipeline final : public ICPUPipeline> +class ICPUComputePipeline final : public ICPUPipeline> { - using base_t = ICPUPipeline>; + using base_t = ICPUPipeline>; public: @@ -26,7 +27,7 @@ class ICPUComputePipeline final : public ICPUPipeline clone_impl(core::smart_refctd_ptr&& layout, uint32_t depth) const override final { - auto newPipeline = new ICPUComputePipeline(std::move(layout)); + auto newPipeline = new ICPUComputePipeline(layout.get()); newPipeline->m_specInfo = m_specInfo.clone(depth); return core::smart_refctd_ptr(newPipeline, core::dont_grab); } @@ -73,7 +74,7 @@ class ICPUComputePipeline final : public ICPUPipeline(layout)) + base_t(layout, {}) {} }; diff --git a/include/nbl/asset/IComputePipeline.h b/include/nbl/asset/IComputePipeline.h new file mode 100644 index 0000000000..4f439d7100 --- /dev/null +++ b/include/nbl/asset/IComputePipeline.h @@ -0,0 +1,56 @@ +#ifndef _NBL_ASSET_I_COMPUTE_PIPELINE_H_INCLUDED_ +#define _NBL_ASSET_I_COMPUTE_PIPELINE_H_INCLUDED_ + +#include "nbl/asset/IPipeline.h" + +namespace nbl::asset +{ + +class IComputePipelineBase : public virtual core::IReferenceCounted +{ + public: + // Nabla requires device's reported subgroup size to be between 4 and 128 + enum class SUBGROUP_SIZE : uint8_t + { + // No constraint but probably means `gl_SubgroupSize` is Dynamically Uniform + UNKNOWN = 0, + // Allows the Subgroup Uniform `gl_SubgroupSize` to be non-Dynamically Uniform and vary between Device's min and max + VARYING = 1, + // The rest we encode as log2(x) of the required value + REQUIRE_4 = 2, + REQUIRE_8 = 3, + REQUIRE_16 = 4, + REQUIRE_32 = 5, + REQUIRE_64 = 6, + REQUIRE_128 = 7 + }; + + struct SCachedCreationParams final + { + SUBGROUP_SIZE requiredSubgroupSize : 3 = SUBGROUP_SIZE::UNKNOWN; //!< Default value of 8 means no requirement + uint8_t requireFullSubgroups : 1 = false; + }; +}; + +template +class IComputePipeline : public IPipeline, public IComputePipelineBase +{ + using base_creation_params_t = IPipeline; + + public: + + inline const SCachedCreationParams& getCachedCreationParams() const { return m_params; } + + protected: + explicit IComputePipeline(const PipelineLayoutType* layout, const SCachedCreationParams& cachedParams) : + IPipeline(core::smart_refctd_ptr(layout)), + m_params(cachedParams) + {} + + SCachedCreationParams m_params; + +}; + +} + +#endif From 0b791b545b40734c17c240dca92837ebcf8cb5c5 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Tue, 13 May 2025 15:26:59 +0700 Subject: [PATCH 30/64] Fix discardDependantsContents and anyDependantDiscardedContents to use computeDependants --- include/nbl/asset/IPreHashed.h | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/include/nbl/asset/IPreHashed.h b/include/nbl/asset/IPreHashed.h index 4bc5ca5dcd..4ffda209df 100644 --- a/include/nbl/asset/IPreHashed.h +++ b/include/nbl/asset/IPreHashed.h @@ -43,28 +43,28 @@ class IPreHashed : public IAsset { struct stack_entry_t { - IAsset* asset; - size_t childCount = 0; - size_t childrenVisited = 0; + const IAsset* asset; + core::unordered_set unvisitedChilds; }; core::stack stack; core::unordered_set alreadyVisited; - auto push = [&stack,&alreadyVisited](IAsset* node) -> void + auto push = [&stack,&alreadyVisited](const IAsset* node) -> void { if (!node) return; const auto [dummy,inserted] = alreadyVisited.insert(node); if (inserted) - stack.push({.asset=node,.childCount=node->getDependantCount()}); + stack.push({ .asset = node, .unvisitedChilds = node->computeDependants()}); }; for (const auto& root : roots) push(root); while (!stack.empty()) { auto& entry = stack.top(); - if (entry.childrenVisited 0) { - const auto dep = entry.asset->getDependant(entry.childrenVisited++); + auto dep = *entry.unvisitedChilds.begin(); + entry.unvisitedChilds.erase(entry.unvisitedChilds.begin()); push(dep); } else @@ -82,8 +82,7 @@ class IPreHashed : public IAsset struct stack_entry_t { const IAsset* asset; - size_t childCount = 0; - size_t childrenVisited = 0; + core::unordered_set unvisitedChilds; }; core::stack stack; core::unordered_set alreadyVisited; @@ -97,7 +96,7 @@ class IPreHashed : public IAsset auto* isPrehashed = dynamic_cast(node); if (isPrehashed && isPrehashed->missingContent()) return true; - stack.push({.asset=node,.childCount=node->getDependantCount()}); + stack.push({ .asset = node, .unvisitedChilds = node->computeDependants() }); } return false; }; @@ -106,9 +105,11 @@ class IPreHashed : public IAsset while (!stack.empty()) { auto& entry = stack.top(); - if (entry.childrenVisited 0) { - const auto dep = entry.asset->getDependant(entry.childrenVisited++); + auto dep = *unvisitedChilds.begin(); + unvisitedChilds.erase(unvisitedChilds.begin()); if (push(dep)) return true; } From e8e43b1fe68f981f8b583941e0b90c359f51fbde Mon Sep 17 00:00:00 2001 From: kevyuu Date: Tue, 13 May 2025 15:30:56 +0700 Subject: [PATCH 31/64] Add Ray Tracing Pipeline Asset to IAsset --- include/nbl/asset/IAsset.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/nbl/asset/IAsset.h b/include/nbl/asset/IAsset.h index 3802536029..a1689daa63 100644 --- a/include/nbl/asset/IAsset.h +++ b/include/nbl/asset/IAsset.h @@ -94,6 +94,7 @@ class IAsset : virtual public core::IReferenceCounted ET_COMPUTE_PIPELINE = 1ull<<20, //!< asset::ICPUComputePipeline ET_PIPELINE_CACHE = 1ull<<21, //!< asset::ICPUPipelineCache ET_SCENE = 1ull<<22, //!< reserved, to implement later + ET_RAYTRACING_PIPELINE = 1ull << 23, //!< asset::ICPURayTracingPipeline ET_IMPLEMENTATION_SPECIFIC_METADATA = 1ull<<31u, //!< lights, etc. //! Reserved special value used for things like terminating lists of this enum From b9db6aa2e1b8a2297c621daab047b757e3b47c36 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Tue, 13 May 2025 15:32:52 +0700 Subject: [PATCH 32/64] Remove unnecessary specInfo assignment in clone method --- include/nbl/asset/ICPUGraphicsPipeline.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/nbl/asset/ICPUGraphicsPipeline.h b/include/nbl/asset/ICPUGraphicsPipeline.h index 62b25443cc..e376300121 100644 --- a/include/nbl/asset/ICPUGraphicsPipeline.h +++ b/include/nbl/asset/ICPUGraphicsPipeline.h @@ -29,8 +29,6 @@ class ICPUGraphicsPipeline final : public ICPUPipeline clone_impl(core::smart_refctd_ptr&& layout, uint32_t depth) const override final { auto* newPipeline = new ICPUGraphicsPipeline(layout.get()); - for (auto i = 0; i < GRAPHICS_SHADER_STAGE_COUNT; i++) - newPipeline->m_specInfos[i] = m_specInfos[i]; newPipeline->m_params = m_params; newPipeline->m_renderpass = m_renderpass; From 2ae6f7818428562f73ead04408a3ffa55e32066a Mon Sep 17 00:00:00 2001 From: kevyuu Date: Tue, 13 May 2025 15:40:42 +0700 Subject: [PATCH 33/64] Move subgroup argument to computePipelineBase --- include/nbl/asset/ICPUPipeline.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/nbl/asset/ICPUPipeline.h b/include/nbl/asset/ICPUPipeline.h index 8b90458f21..ae2c64372d 100644 --- a/include/nbl/asset/ICPUPipeline.h +++ b/include/nbl/asset/ICPUPipeline.h @@ -69,8 +69,6 @@ class ICPUPipelineBase core::smart_refctd_ptr shader = nullptr; std::string entryPoint = ""; - IPipelineBase::SUBGROUP_SIZE requiredSubgroupSize : 3 = IPipelineBase::SUBGROUP_SIZE::UNKNOWN; //!< Default value of 8 means no requirement - uint8_t requireFullSubgroups : 1 = false; // Container choice implicitly satisfies: // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkSpecializationInfo.html#VUID-VkSpecializationInfo-constantID-04911 From 8de6d9a5992b8ff227a9e24cd9e0026ba1e49b80 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Tue, 13 May 2025 15:41:08 +0700 Subject: [PATCH 34/64] Remove getDependantCount and getDependant and getDependant_impl from IAsset --- include/nbl/asset/IAsset.h | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/include/nbl/asset/IAsset.h b/include/nbl/asset/IAsset.h index a1689daa63..c3950c4912 100644 --- a/include/nbl/asset/IAsset.h +++ b/include/nbl/asset/IAsset.h @@ -156,20 +156,6 @@ class IAsset : virtual public core::IReferenceCounted //! inline bool isMutable() const {return m_mutable;} - //! - virtual size_t getDependantCount() const = 0; - inline IAsset* getDependant(const size_t ix) - { - if (ix(this)->getDependant(ix); - return retval; - } - virtual core::unordered_set computeDependants() const = 0; virtual bool valid() const = 0; @@ -179,8 +165,6 @@ class IAsset : virtual public core::IReferenceCounted //! Pure virtual destructor to ensure no instantiation NBL_API2 virtual ~IAsset() = 0; - virtual IAsset* getDependant_impl(const size_t ix) = 0; - private: friend IAssetManager; bool m_mutable = true; From 3f6599267befa369bc171f21dac3af67d06f7a0d Mon Sep 17 00:00:00 2001 From: kevyuu Date: Tue, 13 May 2025 15:41:41 +0700 Subject: [PATCH 35/64] Implement computeDependants for ICPUGraphicsPIpeline --- include/nbl/asset/ICPUGraphicsPipeline.h | 26 ++++-------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/include/nbl/asset/ICPUGraphicsPipeline.h b/include/nbl/asset/ICPUGraphicsPipeline.h index e376300121..0629f82f1c 100644 --- a/include/nbl/asset/ICPUGraphicsPipeline.h +++ b/include/nbl/asset/ICPUGraphicsPipeline.h @@ -43,15 +43,12 @@ class ICPUGraphicsPipeline final : public ICPUPipeline computeDependants() const override { - auto stageCount = 2; // the layout and renderpass + core::unordered_set dependants = { m_layout.get(), m_renderpass.get()}; for (const auto& info : m_specInfos) - { - if (info.shader) - stageCount++; - } - return stageCount; + if (info.shader) dependants.insert(info.shader.get()); + return dependants; } inline SCachedCreationParams& getCachedCreationParams() @@ -90,21 +87,6 @@ class ICPUGraphicsPipeline final : public ICPUPipeline(m_layout.get()); - if (ix==1) - return m_renderpass.get(); - size_t stageCount = 0; - for (auto& specInfo : m_specInfos) - { - if (specInfo.shader) - if ((stageCount++)==ix-2) return specInfo.shader.get(); - } - return nullptr; - } - std::array m_specInfos; private: From 89b8daaaf6618b4da8472629b3408ff55f85539e Mon Sep 17 00:00:00 2001 From: kevyuu Date: Tue, 13 May 2025 15:42:03 +0700 Subject: [PATCH 36/64] Implement computeDependants for ICPURayTracingPIpeline --- include/nbl/asset/ICPURayTracingPipeline.h | 88 ++++++++++++---------- 1 file changed, 47 insertions(+), 41 deletions(-) diff --git a/include/nbl/asset/ICPURayTracingPipeline.h b/include/nbl/asset/ICPURayTracingPipeline.h index 23a1d82225..5be344d1f2 100644 --- a/include/nbl/asset/ICPURayTracingPipeline.h +++ b/include/nbl/asset/ICPURayTracingPipeline.h @@ -19,22 +19,10 @@ class ICPURayTracingPipeline final : public ICPUPipeline; public: - struct SHitGroupSpecInfo { - SShaderSpecInfo closestHit; - SShaderSpecInfo anyHit; - SShaderSpecInfo intersection; - - SHitGroupSpecInfo clone(uint32_t depth) const - { - auto newSpecInfo = *this; - if (depth > 0u) - { - newSpecInfo.closestHit.shader = core::smart_refctd_ptr_static_cast(this->closestHit.shader->clone(depth - 1u)); - newSpecInfo.anyHit.shader = core::smart_refctd_ptr_static_cast(this->anyHit.shader->clone(depth - 1u)); - newSpecInfo.intersection.shader = core::smart_refctd_ptr_static_cast(this->intersection.shader->clone(depth - 1u)); - } - return newSpecInfo; - } + struct SHitGroupSpecInfos { + core::vector closestHits; + core::vector anyHits; + core::vector intersections; }; static core::smart_refctd_ptr create(const ICPUPipelineLayout* layout) @@ -48,23 +36,18 @@ class ICPURayTracingPipeline final : public ICPUPipelinem_raygen = m_raygen.clone(depth); - newPipeline->m_misses.resize(m_misses.size()); - for (auto specInfo_i = 0u; specInfo_i < m_misses.size(); specInfo_i++) - { - newPipeline->m_misses[specInfo_i] = m_misses[specInfo_i].clone(depth); - } - - newPipeline->m_hitGroups.resize(m_hitGroups.size()); - for (auto specInfo_i = 0u; specInfo_i < m_misses.size(); specInfo_i++) - { - newPipeline->m_hitGroups[specInfo_i] = m_hitGroups[specInfo_i].clone(depth); - } - - newPipeline->m_callables.resize(m_callables.size()); - for (auto specInfo_i = 0u; specInfo_i < m_callables.size(); specInfo_i++) - { - newPipeline->m_callables[specInfo_i] = m_callables[specInfo_i].clone(depth); - } + auto cloneSpecInfos = [depth](const core::vector& specInfos) -> core::vector { + core::vector results; + results.resize(specInfos.size()); + for (auto specInfo_i = 0u; specInfo_i < specInfos.size(); specInfo_i++) + results[specInfo_i] = specInfos[specInfo_i].clone(depth); + return results; + }; + newPipeline->m_misses = cloneSpecInfos(m_misses); + newPipeline->m_hitGroups.anyHits = cloneSpecInfos(m_hitGroups.anyHits); + newPipeline->m_hitGroups.closestHits = cloneSpecInfos(m_hitGroups.closestHits); + newPipeline->m_hitGroups.intersections = cloneSpecInfos(m_hitGroups.intersections); + newPipeline->m_callables = cloneSpecInfos(m_callables); newPipeline->m_params = m_params; return core::smart_refctd_ptr(newPipeline); @@ -75,17 +58,39 @@ class ICPURayTracingPipeline final : public ICPUPipeline computeDependants() const override final { + core::unordered_set dependants; + dependants.insert(m_raygen.shader.get()); + for (const auto& missInfo : m_misses) dependants.insert(missInfo.shader.get()); + for (const auto& anyHitInfo : m_hitGroups.anyHits) dependants.insert(anyHitInfo.shader.get()); + for (const auto& closestHitInfo : m_hitGroups.closestHits) dependants.insert(closestHitInfo.shader.get()); + for (const auto& intersectionInfo : m_hitGroups.intersections) dependants.insert(intersectionInfo.shader.get()); + for (const auto& callableInfo : m_callables) dependants.insert(callableInfo.shader.get()); + return dependants; + } + inline virtual std::span getSpecInfo(hlsl::ShaderStage stage) const override final { - switch (stage) - { - case hlsl::ShaderStage::ESS_RAYGEN: - return { &m_raygen, 1 }; - } + switch (stage) + { + case hlsl::ShaderStage::ESS_RAYGEN: + return { &m_raygen, 1 }; + case hlsl::ShaderStage::ESS_MISS: + return m_misses; + case hlsl::ShaderStage::ESS_ANY_HIT: + return m_hitGroups.anyHits; + case hlsl::ShaderStage::ESS_CLOSEST_HIT: + return m_hitGroups.closestHits; + case hlsl::ShaderStage::ESS_INTERSECTION: + return m_hitGroups.intersections; + case hlsl::ShaderStage::ESS_CALLABLE: + return m_callables; + + } return {}; } @@ -100,7 +105,8 @@ class ICPURayTracingPipeline final : public ICPUPipeline m_misses; - core::vector m_hitGroups; + SHitGroupSpecInfos m_hitGroups; core::vector m_callables; explicit ICPURayTracingPipeline(const ICPUPipelineLayout* layout) From 434d73e3063ef5a343ebf9a6909fbbb688a9553a Mon Sep 17 00:00:00 2001 From: kevyuu Date: Tue, 13 May 2025 15:42:26 +0700 Subject: [PATCH 37/64] Fix IGraphicsPIpeline constructor --- include/nbl/asset/IGraphicsPipeline.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/nbl/asset/IGraphicsPipeline.h b/include/nbl/asset/IGraphicsPipeline.h index ef49e4c03a..090a368c2f 100644 --- a/include/nbl/asset/IGraphicsPipeline.h +++ b/include/nbl/asset/IGraphicsPipeline.h @@ -110,7 +110,8 @@ class IGraphicsPipeline : public IPipeline, public IGraphics protected: explicit IGraphicsPipeline(const PipelineLayoutType* layout, const SCachedCreationParams& cachedParams, const renderpass_t* renderpass) : - IPipeline(core::smart_refctd_ptr(layout)), m_renderpass(core::smart_refctd_ptr(renderpass)) + IPipeline(core::smart_refctd_ptr(layout)), + m_params(cachedParams), m_renderpass(core::smart_refctd_ptr(renderpass)) {} SCachedCreationParams m_params = {}; From 1cd1771429d4bbb0c563273ad3f522dfa05e5c34 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Tue, 13 May 2025 15:42:46 +0700 Subject: [PATCH 38/64] Remove SUBGROUP_SIZE from IPIpeline --- include/nbl/asset/IPipeline.h | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/include/nbl/asset/IPipeline.h b/include/nbl/asset/IPipeline.h index c458c34afe..eb64de0b0d 100644 --- a/include/nbl/asset/IPipeline.h +++ b/include/nbl/asset/IPipeline.h @@ -105,21 +105,6 @@ class IPipelineBase }; using FLAGS = CreationFlags; - // Nabla requires device's reported subgroup size to be between 4 and 128 - enum class SUBGROUP_SIZE : uint8_t - { - // No constraint but probably means `gl_SubgroupSize` is Dynamically Uniform - UNKNOWN = 0, - // Allows the Subgroup Uniform `gl_SubgroupSize` to be non-Dynamically Uniform and vary between Device's min and max - VARYING = 1, - // The rest we encode as log2(x) of the required value - REQUIRE_4 = 2, - REQUIRE_8 = 3, - REQUIRE_16 = 4, - REQUIRE_32 = 5, - REQUIRE_64 = 6, - REQUIRE_128 = 7 - }; }; template From 5823a841f965293c6a53ca24dbdc3a91405d9913 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Tue, 13 May 2025 15:43:21 +0700 Subject: [PATCH 39/64] Refactor IRayTracingPipeline to use new SShaderSpecInfo scheme --- include/nbl/asset/IRayTracingPipeline.h | 172 +----------------------- 1 file changed, 5 insertions(+), 167 deletions(-) diff --git a/include/nbl/asset/IRayTracingPipeline.h b/include/nbl/asset/IRayTracingPipeline.h index 0bc2d68653..50ab7ba3f3 100644 --- a/include/nbl/asset/IRayTracingPipeline.h +++ b/include/nbl/asset/IRayTracingPipeline.h @@ -14,35 +14,6 @@ namespace nbl::asset class IRayTracingPipelineBase : public virtual core::IReferenceCounted { public: - struct SShaderGroupsParams - { - struct SIndex - { - constexpr static inline uint32_t Unused = 0xffFFffFFu; - uint32_t index = Unused; - }; - - struct SHitGroup - { - uint32_t closestHit = SIndex::Unused; - uint32_t anyHit = SIndex::Unused; - uint32_t intersection = SIndex::Unused; - }; - - SIndex raygen; - std::span misses; - std::span hits; - std::span callables; - - inline uint32_t getShaderGroupCount() const - { - return 1 + hits.size() + misses.size() + callables.size(); - } - - }; - using SGeneralShaderGroup = SShaderGroupsParams::SIndex; - using SHitShaderGroup = SShaderGroupsParams::SHitGroup; - struct SCachedCreationParams final { uint32_t maxRecursionDepth : 6 = 0; @@ -53,152 +24,19 @@ class IRayTracingPipelineBase : public virtual core::IReferenceCounted template class IRayTracingPipeline : public IPipeline, public IRayTracingPipelineBase { - using base_creation_params_t = IPipeline::SCreationParams; - public: - - using SGeneralShaderGroupContainer = core::smart_refctd_dynamic_array; - using SHitShaderGroupContainer = core::smart_refctd_dynamic_array; - - struct SCreationParams : base_creation_params_t - { - public: - #define base_flag(F) static_cast(base_creation_params_t::FLAGS::F) - enum class FLAGS : uint64_t - { - NONE = base_flag(NONE), - DISABLE_OPTIMIZATIONS = base_flag(DISABLE_OPTIMIZATIONS), - ALLOW_DERIVATIVES = base_flag(ALLOW_DERIVATIVES), - FAIL_ON_PIPELINE_COMPILE_REQUIRED = base_flag(FAIL_ON_PIPELINE_COMPILE_REQUIRED), - EARLY_RETURN_ON_FAILURE = base_flag(EARLY_RETURN_ON_FAILURE), - SKIP_BUILT_IN_PRIMITIVES = 1<<12, - SKIP_AABBS = 1<<13, - NO_NULL_ANY_HIT_SHADERS = 1<<14, - NO_NULL_CLOSEST_HIT_SHADERS = 1<<15, - NO_NULL_MISS_SHADERS = 1<<16, - NO_NULL_INTERSECTION_SHADERS = 1<<17, - ALLOW_MOTION = 1<<20, - }; - #undef base_flag - - protected: - using SpecInfo = IPipelineBase::SShaderSpecInfo; - template - inline bool impl_valid(ExtraLambda&& extra) const - { - if (!IPipeline::SCreationParams::layout) - return false; + using base_creation_params_t = IPipeline; - for (const auto info : shaders) - { - if (info.shader) - { - if (!extra(info)) - return false; - const auto stage = info.stage; - if ((stage & ~IShader::E_SHADER_STAGE::ESS_ALL_RAY_TRACING) != 0) - return false; - if (!std::has_single_bit>(stage)) - return false; - } - else - { - // every shader must not be null. use SIndex::Unused to represent unused shader. - return false; - } - } - - auto getShaderStage = [this](size_t index) -> IShader::E_SHADER_STAGE - { - return shaders[index].stage; - }; - - auto isValidShaderIndex = [this, getShaderStage](size_t index, IShader::E_SHADER_STAGE expectedStage, bool is_unused_shader_forbidden) -> bool - { - if (index == SShaderGroupsParams::SIndex::Unused) - return !is_unused_shader_forbidden; - if (index >= shaders.size()) - return false; - if (getShaderStage(index) != expectedStage) - return false; - return true; - }; - - if (!isValidShaderIndex(shaderGroups.raygen.index, IShader::E_SHADER_STAGE::ESS_RAYGEN, true)) - { - return false; - } - - for (const auto& shaderGroup : shaderGroups.hits) - { - // https://docs.vulkan.org/spec/latest/chapters/pipelines.html#VUID-VkRayTracingPipelineCreateInfoKHR-flags-03470 - if (!isValidShaderIndex(shaderGroup.anyHit, - IShader::E_SHADER_STAGE::ESS_ANY_HIT, - bool(flags & FLAGS::NO_NULL_ANY_HIT_SHADERS))) - return false; - - // https://docs.vulkan.org/spec/latest/chapters/pipelines.html#VUID-VkRayTracingPipelineCreateInfoKHR-flags-03471 - if (!isValidShaderIndex(shaderGroup.closestHit, - IShader::E_SHADER_STAGE::ESS_CLOSEST_HIT, - bool(flags & FLAGS::NO_NULL_CLOSEST_HIT_SHADERS))) - return false; - - if (!isValidShaderIndex(shaderGroup.intersection, - IShader::E_SHADER_STAGE::ESS_INTERSECTION, - false)) - return false; - } - - for (const auto& shaderGroup : shaderGroups.misses) - { - if (!isValidShaderIndex(shaderGroup.index, - IShader::E_SHADER_STAGE::ESS_MISS, - false)) - return false; - } - - for (const auto& shaderGroup : shaderGroups.callables) - { - if (!isValidShaderIndex(shaderGroup.index, IShader::E_SHADER_STAGE::ESS_CALLABLE, false)) - return false; - } - return true; - } - - public: - inline bool valid() const - { - return impl_valid([](const SpecInfo& info)->bool - { - if (!info.valid()) - return false; - return false; - }); - } - - std::span shaders = {}; - SShaderGroupsParams shaderGroups; - SCachedCreationParams cached = {}; - // TODO: Could guess the required flags from SPIR-V introspection of declared caps - core::bitflag flags = FLAGS::NONE; - }; + public: inline const SCachedCreationParams& getCachedCreationParams() const { return m_params; } protected: - explicit IRayTracingPipeline(const SCreationParams& _params) : - IPipeline(core::smart_refctd_ptr(_params.layout)), - m_params(_params.cached), - m_raygenShaderGroup(_params.shaderGroups.raygen), - m_missShaderGroups(core::make_refctd_dynamic_array(_params.shaderGroups.misses)), - m_hitShaderGroups(core::make_refctd_dynamic_array(_params.shaderGroups.hits)), - m_callableShaderGroups(core::make_refctd_dynamic_array(_params.shaderGroups.callables)) + explicit IRayTracingPipeline(const PipelineLayoutType* layout, const SCachedCreationParams& cachedParams) : + IPipeline(core::smart_refctd_ptr(layout)), + m_params(cachedParams) {} SCachedCreationParams m_params; - SGeneralShaderGroup m_raygenShaderGroup; - SGeneralShaderGroupContainer m_missShaderGroups; - SHitShaderGroupContainer m_hitShaderGroups; - SGeneralShaderGroupContainer m_callableShaderGroups; }; From 10ec458eb572b567f82774b18bee541da566d275 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Tue, 13 May 2025 15:44:10 +0700 Subject: [PATCH 40/64] Remove Subgroup related argument from IGPUPipeline --- include/nbl/video/IGPUPipeline.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/nbl/video/IGPUPipeline.h b/include/nbl/video/IGPUPipeline.h index 826026d9aa..fc4bc8d219 100644 --- a/include/nbl/video/IGPUPipeline.h +++ b/include/nbl/video/IGPUPipeline.h @@ -71,8 +71,6 @@ class IGPUPipelineBase { const asset::IShader* shader = nullptr; std::string_view entryPoint = ""; - asset::IPipelineBase::SUBGROUP_SIZE requiredSubgroupSize : 3 = asset::IPipelineBase::SUBGROUP_SIZE::UNKNOWN; //!< Default value of 8 means no requirement - uint8_t requireFullSubgroups : 1 = false; // Container choice implicitly satisfies: // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkSpecializationInfo.html#VUID-VkSpecializationInfo-constantID-04911 From 39904f7d86c251491969619cb1a338618399dda2 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Tue, 13 May 2025 15:44:46 +0700 Subject: [PATCH 41/64] Refactor IGPUComputePipeline to use IComputePipeline --- include/nbl/video/IGPUComputePipeline.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/nbl/video/IGPUComputePipeline.h b/include/nbl/video/IGPUComputePipeline.h index 42503e1f12..065c567ee2 100644 --- a/include/nbl/video/IGPUComputePipeline.h +++ b/include/nbl/video/IGPUComputePipeline.h @@ -6,6 +6,7 @@ #include "nbl/asset/IPipeline.h" +#include "nbl/asset/IComputePipeline.h" #include "nbl/video/IGPUPipeline.h" #include "nbl/video/SPipelineCreationParams.h" @@ -14,9 +15,9 @@ namespace nbl::video { -class IGPUComputePipeline : public IGPUPipeline> +class IGPUComputePipeline : public IGPUPipeline> { - using pipeline_t = asset::IPipeline; + using pipeline_t = asset::IComputePipeline; public: struct SCreationParams final : SPipelineCreationParams From 2ce032f87550e3d1a57a638696d8cae62bee53d6 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Tue, 13 May 2025 15:45:28 +0700 Subject: [PATCH 42/64] Refactor IGPURayTracingPipeline to use new SShaderSpecInfo scheme --- include/nbl/video/IGPURayTracingPipeline.h | 145 ++++++++++++++++++++- 1 file changed, 143 insertions(+), 2 deletions(-) diff --git a/include/nbl/video/IGPURayTracingPipeline.h b/include/nbl/video/IGPURayTracingPipeline.h index c41ed333a1..2a6701c9e6 100644 --- a/include/nbl/video/IGPURayTracingPipeline.h +++ b/include/nbl/video/IGPURayTracingPipeline.h @@ -15,6 +15,147 @@ class IGPURayTracingPipeline : public IGPUPipeline; public: + struct SCreationParams + { + #define base_flag(F) static_cast(IPipelineBase::FLAGS::F) + enum class FLAGS : uint64_t + { + NONE = base_flag(NONE), + DISABLE_OPTIMIZATIONS = base_flag(DISABLE_OPTIMIZATIONS), + ALLOW_DERIVATIVES = base_flag(ALLOW_DERIVATIVES), + FAIL_ON_PIPELINE_COMPILE_REQUIRED = base_flag(FAIL_ON_PIPELINE_COMPILE_REQUIRED), + EARLY_RETURN_ON_FAILURE = base_flag(EARLY_RETURN_ON_FAILURE), + SKIP_BUILT_IN_PRIMITIVES = 1<<12, + SKIP_AABBS = 1<<13, + NO_NULL_ANY_HIT_SHADERS = 1<<14, + NO_NULL_CLOSEST_HIT_SHADERS = 1<<15, + NO_NULL_MISS_SHADERS = 1<<16, + NO_NULL_INTERSECTION_SHADERS = 1<<17, + ALLOW_MOTION = 1<<20, + }; + #undef base_flag + + protected: + template + inline bool impl_valid(ExtraLambda&& extra) const + { + if (!m_layout) return false; + + for (const auto info : shaders) + { + if (info.shader) + { + if (!extra(info)) + return false; + const auto stage = info.stage; + if ((stage & ~hlsl::ShaderStage::ESS_ALL_RAY_TRACING) != 0) + return false; + if (!std::has_single_bit>(stage)) + return false; + } + else + { + // every shader must not be null. use SIndex::Unused to represent unused shader. + return false; + } + } + + auto getShaderStage = [this](size_t index) -> hlsl::ShaderStage + { + return shaders[index].stage; + }; + + auto isValidShaderIndex = [this, getShaderStage](size_t index, hlsl::ShaderStage expectedStage, bool is_unused_shader_forbidden) -> bool + { + if (index == SShaderGroupsParams::SIndex::Unused) + return !is_unused_shader_forbidden; + if (index >= shaders.size()) + return false; + if (getShaderStage(index) != expectedStage) + return false; + return true; + }; + + if (!isValidShaderIndex(shaderGroups.raygen.index, hlsl::ShaderStage::ESS_RAYGEN, true)) + { + return false; + } + + for (const auto& shaderGroup : shaderGroups.hits) + { + // https://docs.vulkan.org/spec/latest/chapters/pipelines.html#VUID-VkRayTracingPipelineCreateInfoKHR-flags-03470 + if (!isValidShaderIndex(shaderGroup.anyHit, + hlsl::ShaderStage::ESS_ANY_HIT, + bool(flags & FLAGS::NO_NULL_ANY_HIT_SHADERS))) + return false; + + // https://docs.vulkan.org/spec/latest/chapters/pipelines.html#VUID-VkRayTracingPipelineCreateInfoKHR-flags-03471 + if (!isValidShaderIndex(shaderGroup.closestHit, + hlsl::ShaderStage::ESS_CLOSEST_HIT, + bool(flags & FLAGS::NO_NULL_CLOSEST_HIT_SHADERS))) + return false; + + if (!isValidShaderIndex(shaderGroup.intersection, + hlsl::ShaderStage::ESS_INTERSECTION, + false)) + return false; + } + + for (const auto& shaderGroup : shaderGroups.misses) + { + if (!isValidShaderIndex(shaderGroup.index, + hlsl::ShaderStage::ESS_MISS, + false)) + return false; + } + + for (const auto& shaderGroup : shaderGroups.callables) + { + if (!isValidShaderIndex(shaderGroup.index, hlsl::ShaderStage::ESS_CALLABLE, false)) + return false; + } + return true; + } + + public: + inline bool valid() const + { + return impl_valid([](const SShaderSpecInfo& info)->bool + { + if (!info.valid()) + return false; + return false; + }); + } + + struct SShaderGroupsParams + { + struct SHitGroup + { + SShaderSpecInfo closestHit; + SShaderSpecInfo anyHit; + SShaderSpecInfo intersection; + }; + + SShaderSpecInfo raygen; + std::span misses; + std::span hits; + std::span callables; + + inline uint32_t getShaderGroupCount() const + { + return 1 + hits.size() + misses.size() + callables.size(); + } + + }; + + SShaderGroupsParams shaderGroups; + + SCachedCreationParams cached = {}; + // TODO: Could guess the required flags from SPIR-V introspection of declared caps + core::bitflag flags = FLAGS::NONE; + }; + struct SShaderGroupHandle { @@ -62,7 +203,7 @@ class IGPURayTracingPipeline : public IGPUPipelinebool + const bool valid = pipeline_t::SCreationParams::impl_valid([&retval](const SShaderSpecInfo& info)->bool { const auto dataSize = info.valid(); if (dataSize<0) @@ -81,7 +222,7 @@ class IGPURayTracingPipeline : public IGPUPipeline getShaders() const { return shaders; } + inline std::span getShaders() const { return shaders; } IGPUPipelineLayout* layout = nullptr; }; From 058657b8defebb5eff9ea56431bd1f9e20ffc4b2 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Tue, 13 May 2025 15:45:42 +0700 Subject: [PATCH 43/64] Restore deleted comments --- include/nbl/video/SPipelineCreationParams.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/nbl/video/SPipelineCreationParams.h b/include/nbl/video/SPipelineCreationParams.h index 969559d941..489bff4343 100644 --- a/include/nbl/video/SPipelineCreationParams.h +++ b/include/nbl/video/SPipelineCreationParams.h @@ -49,7 +49,7 @@ struct SPipelineCreationParams return basePipelineIndex!=NotDerivingFromPreviousPipeline || basePipeline; } - + // If you set this, then we don't take `basePipelineIndex` into account, the pointer takes precedence const PipelineType* basePipeline = nullptr; int32_t basePipelineIndex = NotDerivingFromPreviousPipeline; }; From 59fcc93d2f0c0ac1b2196426e34d9ed8d9586a13 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Thu, 15 May 2025 12:45:57 +0700 Subject: [PATCH 44/64] Implement all computeDependants for IAssets --- include/nbl/asset/ICPUAccelerationStructure.h | 21 +++---- include/nbl/asset/ICPUAnimationLibrary.h | 16 +----- include/nbl/asset/ICPUBuffer.h | 10 ++-- include/nbl/asset/ICPUBufferView.h | 9 ++- include/nbl/asset/ICPUComputePipeline.h | 9 --- include/nbl/asset/ICPUDescriptorSet.h | 5 +- include/nbl/asset/ICPUDescriptorSetLayout.h | 15 +++-- include/nbl/asset/ICPUImage.h | 7 ++- include/nbl/asset/ICPUImageView.h | 10 ++-- include/nbl/asset/ICPUMesh.h | 6 +- include/nbl/asset/ICPUMeshBuffer.h | 9 +-- include/nbl/asset/ICPUPipelineCache.h | 7 ++- include/nbl/asset/ICPUPipelineLayout.h | 22 +++----- include/nbl/asset/ICPURayTracingPipeline.h | 14 ----- include/nbl/asset/ICPURenderpass.h | 6 +- .../asset/ICPURenderpassIndependentPipeline.h | 7 ++- include/nbl/asset/ICPUSampler.h | 7 ++- include/nbl/asset/ICPUSkeleton.h | 9 +-- include/nbl/asset/IShader.h | 8 +-- src/nbl/asset/ICPUDescriptorSet.cpp | 55 +++++++++---------- 20 files changed, 107 insertions(+), 145 deletions(-) diff --git a/include/nbl/asset/ICPUAccelerationStructure.h b/include/nbl/asset/ICPUAccelerationStructure.h index 9c9af32f7b..affd165667 100644 --- a/include/nbl/asset/ICPUAccelerationStructure.h +++ b/include/nbl/asset/ICPUAccelerationStructure.h @@ -136,7 +136,10 @@ class ICPUBottomLevelAccelerationStructure final : public IPreHashed, public IBo } // Do not report anything as a dependant, we'll simply drop the data instead of discarding its contents - inline size_t getDependantCount() const override {return 0;} + inline core::unordered_set computeDependants() const override + { + return {}; + } inline core::blake3_hash_t computeContentHash() const override { @@ -236,8 +239,6 @@ class ICPUBottomLevelAccelerationStructure final : public IPreHashed, public IBo protected: virtual ~ICPUBottomLevelAccelerationStructure() = default; - inline IAsset* getDependant_impl(const size_t ix) override {return nullptr;} - inline void discardContent_impl() override { m_triangleGeoms = nullptr; @@ -263,8 +264,13 @@ class ICPUTopLevelAccelerationStructure final : public IAsset, public ITopLevelA // ICPUTopLevelAccelerationStructure() = default; - // - inline size_t getDependantCount() const override {return m_instances->size();} + inline core::unordered_set computeDependants() const override + { + core::unordered_set dependants; + for (const auto& instance : m_instances) + dependants.insert(instance.getBase().blas.get()); + return dependants; + } // inline auto& getBuildRangeInfo() @@ -360,11 +366,6 @@ class ICPUTopLevelAccelerationStructure final : public IAsset, public ITopLevelA protected: virtual ~ICPUTopLevelAccelerationStructure() = default; - inline IAsset* getDependant_impl(const size_t ix) override - { - return m_instances->operator[](ix).getBase().blas.get(); - } - private: core::smart_refctd_dynamic_array m_instances = nullptr; hlsl::acceleration_structures::top_level::BuildRangeInfo m_buildRangeInfo; diff --git a/include/nbl/asset/ICPUAnimationLibrary.h b/include/nbl/asset/ICPUAnimationLibrary.h index 1b02787597..5fea370b63 100644 --- a/include/nbl/asset/ICPUAnimationLibrary.h +++ b/include/nbl/asset/ICPUAnimationLibrary.h @@ -96,21 +96,9 @@ class ICPUAnimationLibrary final : public IAnimationLibrary, public constexpr static inline auto AssetType = ET_ANIMATION_LIBRARY; inline E_TYPE getAssetType() const override { return AssetType; } - inline size_t getDependantCount() const override {return 3;} - - protected: - inline IAsset* getDependant_impl(const size_t ix) override + inline core::unordered_set computeDependants() const override { - switch (ix) - { - case 0: - return m_keyframeStorageBinding.buffer.get(); - case 1: - return m_timestampStorageBinding.buffer.get(); - default: - break; - } - return m_animationStorageRange.buffer.get(); + return { m_keyframeStorageBinding.buffer.get(), m_timestampStorageBinding.buffer.get(), m_animationStorageRange.buffer.get() }; } }; diff --git a/include/nbl/asset/ICPUBuffer.h b/include/nbl/asset/ICPUBuffer.h index 5bb16bd0ac..2d495ef02e 100644 --- a/include/nbl/asset/ICPUBuffer.h +++ b/include/nbl/asset/ICPUBuffer.h @@ -75,7 +75,10 @@ class ICPUBuffer final : public asset::IBuffer, public IPreHashed constexpr static inline auto AssetType = ET_BUFFER; inline IAsset::E_TYPE getAssetType() const override final { return AssetType; } - inline size_t getDependantCount() const override { return 0; } + inline core::unordered_set computeDependants() const override + { + return {}; + } inline core::blake3_hash_t computeContentHash() const override { @@ -113,11 +116,6 @@ class ICPUBuffer final : public asset::IBuffer, public IPreHashed } protected: - inline IAsset* getDependant_impl(const size_t ix) override - { - return nullptr; - } - inline void discardContent_impl() override { if (m_data) diff --git a/include/nbl/asset/ICPUBufferView.h b/include/nbl/asset/ICPUBufferView.h index 3819136c98..7f3f676695 100644 --- a/include/nbl/asset/ICPUBufferView.h +++ b/include/nbl/asset/ICPUBufferView.h @@ -28,7 +28,10 @@ class ICPUBufferView : public IBufferView, public IAsset constexpr static inline auto AssetType = ET_BUFFER_VIEW; inline IAsset::E_TYPE getAssetType() const override { return AssetType; } - inline size_t getDependantCount() const override {return 1;} + inline core::unordered_set computeDependants() const override + { + return { m_buffer.get() }; + } ICPUBuffer* getUnderlyingBuffer() { @@ -51,10 +54,6 @@ class ICPUBufferView : public IBufferView, public IAsset protected: virtual ~ICPUBufferView() = default; - inline IAsset* getDependant_impl(const size_t ix) override - { - return m_buffer.get(); - } }; } diff --git a/include/nbl/asset/ICPUComputePipeline.h b/include/nbl/asset/ICPUComputePipeline.h index 01859e0c3f..8d8b343a3d 100644 --- a/include/nbl/asset/ICPUComputePipeline.h +++ b/include/nbl/asset/ICPUComputePipeline.h @@ -36,8 +36,6 @@ class ICPUComputePipeline final : public ICPUPipeline computeDependants() const override { return {m_layout.get(), m_specInfo.shader.get()}; @@ -62,13 +60,6 @@ class ICPUComputePipeline final : public ICPUPipeline(m_layout.get()); - } - private: SShaderSpecInfo m_specInfo; diff --git a/include/nbl/asset/ICPUDescriptorSet.h b/include/nbl/asset/ICPUDescriptorSet.h index 826c54cc39..77640b8f9f 100644 --- a/include/nbl/asset/ICPUDescriptorSet.h +++ b/include/nbl/asset/ICPUDescriptorSet.h @@ -47,8 +47,6 @@ class NBL_API2 ICPUDescriptorSet final : public IDescriptorSetgetTotalBindingCount()+1;} - // inline ICPUDescriptorSetLayout* getLayout() { @@ -79,10 +77,11 @@ class NBL_API2 ICPUDescriptorSet final : public IDescriptorSet clone(uint32_t _depth = ~0u) const override; + core::unordered_set computeDependants() const override; + protected: virtual ~ICPUDescriptorSet() = default; - IAsset* getDependant_impl(size_t ix) override; private: diff --git a/include/nbl/asset/ICPUDescriptorSetLayout.h b/include/nbl/asset/ICPUDescriptorSetLayout.h index 8f45a789ea..2ddf1e26be 100644 --- a/include/nbl/asset/ICPUDescriptorSetLayout.h +++ b/include/nbl/asset/ICPUDescriptorSetLayout.h @@ -57,15 +57,20 @@ class ICPUDescriptorSetLayout : public IDescriptorSetLayout, public constexpr static inline auto AssetType = ET_DESCRIPTOR_SET_LAYOUT; inline E_TYPE getAssetType() const override { return AssetType; } - inline size_t getDependantCount() const override {return m_immutableSamplers ? m_immutableSamplers->size():0;} + core::unordered_set computeDependants() const override + { + if (!m_immutableSamplers) return {}; + core::unordered_set dependants; + for (const auto& sampler: m_immutableSamplers) + { + dependants.insert(sampler.get()); + } + return dependants; + } protected: virtual ~ICPUDescriptorSetLayout() = default; - inline IAsset* getDependant_impl(const size_t ix) override - { - return m_immutableSamplers->operator[](ix).get(); - } }; } diff --git a/include/nbl/asset/ICPUImage.h b/include/nbl/asset/ICPUImage.h index c27cd21b86..2527fd1ecb 100644 --- a/include/nbl/asset/ICPUImage.h +++ b/include/nbl/asset/ICPUImage.h @@ -46,7 +46,10 @@ class NBL_API2 ICPUImage final : public IImage, public IPreHashed inline IAsset::E_TYPE getAssetType() const override { return AssetType; } // Do not report buffer as dependant, as we will simply drop it instead of discarding its contents! - inline size_t getDependantCount() const override {return 0;} + inline core::unordered_set computeDependants() const override + { + return {}; + } core::blake3_hash_t computeContentHash() const override; @@ -202,8 +205,6 @@ class NBL_API2 ICPUImage final : public IImage, public IPreHashed inline ICPUImage(const SCreationParams& _params) : IImage(_params) {} virtual ~ICPUImage() = default; - inline IAsset* getDependant_impl(const size_t ix) override {return nullptr;} - inline void discardContent_impl() override { buffer = nullptr; diff --git a/include/nbl/asset/ICPUImageView.h b/include/nbl/asset/ICPUImageView.h index 87df463021..6b3d562a60 100644 --- a/include/nbl/asset/ICPUImageView.h +++ b/include/nbl/asset/ICPUImageView.h @@ -49,8 +49,10 @@ class ICPUImageView final : public IImageView, public IAsset constexpr static inline auto AssetType = ET_IMAGE_VIEW; inline IAsset::E_TYPE getAssetType() const override { return AssetType; } - //! - inline size_t getDependantCount() const override {return 1;} + inline core::unordered_set computeDependants() const override + { + return { params.image.get() }; + } //! const SComponentMapping& getComponents() const { return params.components; } @@ -68,10 +70,6 @@ class ICPUImageView final : public IImageView, public IAsset protected: virtual ~ICPUImageView() = default; - inline IAsset* getDependant_impl(const size_t ix) override - { - return params.image.get(); - } }; } diff --git a/include/nbl/asset/ICPUMesh.h b/include/nbl/asset/ICPUMesh.h index a21f5f3f02..2648900ccc 100644 --- a/include/nbl/asset/ICPUMesh.h +++ b/include/nbl/asset/ICPUMesh.h @@ -82,10 +82,12 @@ class ICPUMesh final : public IMesh, public IAsset } //! CLASS IS DEPRECATED ANYWAY - inline size_t getDependantCount() const override {return 0;} + inline core::unordered_set computeDependants() const override + { + return {}; + } protected: - inline IAsset* getDependant_impl(const size_t ix) override {return nullptr;} private: core::vector> m_meshBuffers; diff --git a/include/nbl/asset/ICPUMeshBuffer.h b/include/nbl/asset/ICPUMeshBuffer.h index 532b622090..61e9168a98 100644 --- a/include/nbl/asset/ICPUMeshBuffer.h +++ b/include/nbl/asset/ICPUMeshBuffer.h @@ -611,11 +611,12 @@ class ICPUMeshBuffer final : public IMeshBuffer(const_cast(this)->getJointAABBs()); } - //! CLASS IS DEPRECATED ANYWAY - inline size_t getDependantCount() const override {return 0;} + //! Class is deprecated anyway. + inline core::unordered_set computeDependants() const override + { + return {}; + } - protected: - inline IAsset* getDependant_impl(const size_t ix) override {return nullptr;} }; } diff --git a/include/nbl/asset/ICPUPipelineCache.h b/include/nbl/asset/ICPUPipelineCache.h index 0c1d8c17cf..6fc019ce7f 100644 --- a/include/nbl/asset/ICPUPipelineCache.h +++ b/include/nbl/asset/ICPUPipelineCache.h @@ -60,7 +60,10 @@ class ICPUPipelineCache final : public IPreHashed return core::make_smart_refctd_ptr(std::move(cache_cp)); } - inline size_t getDependantCount() const override {return 0;} + inline core::unordered_set computeDependants() const override + { + return {}; + } // inline core::blake3_hash_t computeContentHash() const override @@ -86,8 +89,6 @@ class ICPUPipelineCache final : public IPreHashed const auto& getEntries() const {return m_cache;} protected: - inline IAsset* getDependant_impl(const size_t ix) override {return nullptr;} - inline void discardContent_impl() override { for (auto& entry : m_cache) diff --git a/include/nbl/asset/ICPUPipelineLayout.h b/include/nbl/asset/ICPUPipelineLayout.h index c4a76fdea9..994d480b17 100644 --- a/include/nbl/asset/ICPUPipelineLayout.h +++ b/include/nbl/asset/ICPUPipelineLayout.h @@ -30,14 +30,14 @@ class ICPUPipelineLayout : public IAsset, public IPipelineLayout&& _layout2, core::smart_refctd_ptr&& _layout3 ) : IPipelineLayout(_pcRanges,std::move(_layout0),std::move(_layout1),std::move(_layout2),std::move(_layout3)) {} - // - inline size_t getDependantCount() const override + inline core::unordered_set computeDependants() const override { - size_t count = 0; - for (auto i=0; i dependants; + for (auto i = 0; i < m_descSetLayouts.size(); i++) + { + if (m_descSetLayouts[i]) continue; + dependants.insert(m_descSetLayouts[i].get()); + } } // @@ -79,14 +79,6 @@ class ICPUPipelineLayout : public IAsset, public IPipelineLayout computeDependants() const override final { core::unordered_set dependants; dependants.insert(m_raygen.shader.get()); @@ -103,14 +97,6 @@ class ICPURayTracingPipeline final : public ICPUPipeline computeDependants() const override + { + return {}; + } protected: inline ICPURenderpass(const SCreationParams& _params, const SCreationParamValidationResult& _validation) : IRenderpass(_params, _validation) {} inline ~ICPURenderpass() = default; - inline IAsset* getDependant_impl(const size_t ix) override {return nullptr;} }; } diff --git a/include/nbl/asset/ICPURenderpassIndependentPipeline.h b/include/nbl/asset/ICPURenderpassIndependentPipeline.h index ed0171d11f..8638a4965b 100644 --- a/include/nbl/asset/ICPURenderpassIndependentPipeline.h +++ b/include/nbl/asset/ICPURenderpassIndependentPipeline.h @@ -66,7 +66,10 @@ class ICPURenderpassIndependentPipeline : public IRenderpassIndependentPipeline, _NBL_STATIC_INLINE_CONSTEXPR auto AssetType = ET_RENDERPASS_INDEPENDENT_PIPELINE; inline E_TYPE getAssetType() const override { return AssetType; } - inline size_t getDependantCount() const override {return 0;} + inline core::unordered_set computeDependants() const override + { + return {}; + } // inline const SCachedCreationParams& getCachedCreationParams() const {return IRenderpassIndependentPipeline::getCachedCreationParams();} @@ -137,8 +140,6 @@ class ICPURenderpassIndependentPipeline : public IRenderpassIndependentPipeline, : IRenderpassIndependentPipeline(params), m_layout(std::move(_layout)) {} virtual ~ICPURenderpassIndependentPipeline() = default; - inline IAsset* getDependant_impl(const size_t ix) override {return nullptr;} - core::smart_refctd_ptr m_layout; #if 0 std::array,GRAPHICS_SHADER_STAGE_COUNT> m_shaders = {}; diff --git a/include/nbl/asset/ICPUSampler.h b/include/nbl/asset/ICPUSampler.h index 27a918afaa..46cac56ee0 100644 --- a/include/nbl/asset/ICPUSampler.h +++ b/include/nbl/asset/ICPUSampler.h @@ -17,8 +17,6 @@ class ICPUSampler : public ISampler, public IAsset protected: virtual ~ICPUSampler() = default; - inline IAsset* getDependant_impl(const size_t ix) override {return nullptr;} - public: ICPUSampler(const SParams& _params) : ISampler(_params), IAsset() {} @@ -71,7 +69,10 @@ class ICPUSampler : public ISampler, public IAsset constexpr static inline auto AssetType = ET_SAMPLER; inline IAsset::E_TYPE getAssetType() const override { return AssetType; } - inline size_t getDependantCount() const override {return 0;} + inline core::unordered_set computeDependants() const override + { + return {}; + } }; } diff --git a/include/nbl/asset/ICPUSkeleton.h b/include/nbl/asset/ICPUSkeleton.h index 6f1c576ed8..ce03a9be54 100644 --- a/include/nbl/asset/ICPUSkeleton.h +++ b/include/nbl/asset/ICPUSkeleton.h @@ -79,14 +79,11 @@ class ICPUSkeleton final : public ISkeleton, public IAsset constexpr static inline auto AssetType = ET_SKELETON; inline E_TYPE getAssetType() const override { return AssetType; } - //! - inline size_t getDependantCount() const override {return 2;} - - protected: - inline IAsset* getDependant_impl(const size_t ix) override + inline core::unordered_set computeDependants() const override { - return (ix!=0 ? m_defaultTransforms:m_parentJointIDs).buffer.get(); + return { m_defaultTransforms.buffer.get(), m_parentJointIDs.buffer.get() }; } + }; } diff --git a/include/nbl/asset/IShader.h b/include/nbl/asset/IShader.h index a6dab09b54..5abd7d1980 100644 --- a/include/nbl/asset/IShader.h +++ b/include/nbl/asset/IShader.h @@ -50,8 +50,10 @@ class IShader : public IAsset constexpr static inline auto AssetType = ET_SHADER; inline E_TYPE getAssetType() const override { return AssetType; } - // - inline size_t getDependantCount() const override { return 1; } + inline core::unordered_set computeDependants() const override + { + return { m_code.get() }; + } // inline core::smart_refctd_ptr clone(uint32_t _depth=~0u) const override @@ -96,8 +98,6 @@ class IShader : public IAsset protected: virtual ~IShader() = default; - inline IAsset* getDependant_impl(const size_t ix) override {return m_code.get();} - std::string m_filepathHint; core::smart_refctd_ptr m_code; E_CONTENT_TYPE m_contentType; diff --git a/src/nbl/asset/ICPUDescriptorSet.cpp b/src/nbl/asset/ICPUDescriptorSet.cpp index 03724be1a2..a298fea491 100644 --- a/src/nbl/asset/ICPUDescriptorSet.cpp +++ b/src/nbl/asset/ICPUDescriptorSet.cpp @@ -108,36 +108,35 @@ core::smart_refctd_ptr ICPUDescriptorSet::clone(uint32_t _depth) const return cp; } -IAsset* ICPUDescriptorSet::getDependant_impl(size_t ix) +core::unordered_set ICPUDescriptorSet::computeDependants() const { - for (auto i=0u; i(IDescriptor::E_TYPE::ET_COUNT); i++) - if (m_descriptorInfos[i]) + core::unordered_set dependants = { m_layout.get() }; + for (auto i = 0u; i < static_cast(IDescriptor::E_TYPE::ET_COUNT); i++) { - const auto size = m_descriptorInfos[i]->size(); - if (ixoperator[](ix).desc.get(); - if (desc) - switch (IDescriptor::GetTypeCategory(static_cast(i))) - { - case IDescriptor::EC_BUFFER: - return static_cast(desc); - case IDescriptor::EC_SAMPLER: - return static_cast(desc); - case IDescriptor::EC_IMAGE: - return static_cast(desc); - case IDescriptor::EC_BUFFER_VIEW: - return static_cast(desc); - case IDescriptor::EC_ACCELERATION_STRUCTURE: - return static_cast(desc); - default: - break; - } - return nullptr; - } - else - ix -= size; + if (!m_descriptorInfos[i]) continue; + const auto size = m_descriptorInfos[i]->size(); + for (auto desc_i = 0u; desc_i < size; desc_i++) + { + auto* desc = m_descriptorInfos[i]->operator[](desc_i).desc.get(); + if (!desc) continue; + switch (IDescriptor::GetTypeCategory(static_cast(i))) + { + case IDescriptor::EC_BUFFER: + dependants.insert(static_cast(desc)); + case IDescriptor::EC_SAMPLER: + dependants.insert(static_cast(desc)); + case IDescriptor::EC_IMAGE: + dependants.insert(static_cast(desc)); + case IDescriptor::EC_BUFFER_VIEW: + dependants.insert(static_cast(desc)); + case IDescriptor::EC_ACCELERATION_STRUCTURE: + dependants.insert(static_cast(desc)); + default: + break; + } + } } - return nullptr; + return dependants; } + } \ No newline at end of file From 6884d4548e758c6591b7b291e2895457de4a36ab Mon Sep 17 00:00:00 2001 From: kevyuu Date: Fri, 16 May 2025 18:19:55 +0700 Subject: [PATCH 45/64] Add non const computeDependants to IAsset and its child classes --- include/nbl/asset/IAsset.h | 8 ++- include/nbl/asset/ICPUAccelerationStructure.h | 5 ++ include/nbl/asset/ICPUAnimationLibrary.h | 9 +++ include/nbl/asset/ICPUBuffer.h | 5 ++ include/nbl/asset/ICPUBufferView.h | 14 ++++- include/nbl/asset/ICPUComputePipeline.h | 36 +++++++---- include/nbl/asset/ICPUDescriptorSet.h | 1 + include/nbl/asset/ICPUDescriptorSetLayout.h | 28 ++++++--- include/nbl/asset/ICPUGraphicsPipeline.h | 23 +++++-- include/nbl/asset/ICPUImage.h | 5 ++ include/nbl/asset/ICPUImageView.h | 14 ++++- include/nbl/asset/ICPUMesh.h | 5 ++ include/nbl/asset/ICPUMeshBuffer.h | 5 ++ include/nbl/asset/ICPUPipeline.h | 2 +- include/nbl/asset/ICPUPipelineCache.h | 5 ++ include/nbl/asset/ICPUPipelineLayout.h | 13 ++++ include/nbl/asset/ICPURayTracingPipeline.h | 26 +++++--- include/nbl/asset/ICPURenderpass.h | 5 ++ .../asset/ICPURenderpassIndependentPipeline.h | 5 ++ include/nbl/asset/ICPUSampler.h | 5 ++ include/nbl/asset/ICPUSkeleton.h | 16 ++++- include/nbl/asset/IShader.h | 15 ++++- src/nbl/asset/ICPUDescriptorSet.cpp | 62 +++++++++++-------- 23 files changed, 248 insertions(+), 64 deletions(-) diff --git a/include/nbl/asset/IAsset.h b/include/nbl/asset/IAsset.h index c3950c4912..0e91b99c36 100644 --- a/include/nbl/asset/IAsset.h +++ b/include/nbl/asset/IAsset.h @@ -158,7 +158,13 @@ class IAsset : virtual public core::IReferenceCounted virtual core::unordered_set computeDependants() const = 0; - virtual bool valid() const = 0; + virtual core::unordered_set computeDependants() = 0; + + virtual bool valid() const + { + //TODO(kevinyu): Temporary set this to true to make changes compile. Will revisit this later for each asset + return true; + } protected: inline IAsset() = default; diff --git a/include/nbl/asset/ICPUAccelerationStructure.h b/include/nbl/asset/ICPUAccelerationStructure.h index affd165667..3ac794a888 100644 --- a/include/nbl/asset/ICPUAccelerationStructure.h +++ b/include/nbl/asset/ICPUAccelerationStructure.h @@ -141,6 +141,11 @@ class ICPUBottomLevelAccelerationStructure final : public IPreHashed, public IBo return {}; } + inline core::unordered_set computeDependants() override + { + return {}; + } + inline core::blake3_hash_t computeContentHash() const override { if (!missingContent()) diff --git a/include/nbl/asset/ICPUAnimationLibrary.h b/include/nbl/asset/ICPUAnimationLibrary.h index 5fea370b63..8a6cdaf52a 100644 --- a/include/nbl/asset/ICPUAnimationLibrary.h +++ b/include/nbl/asset/ICPUAnimationLibrary.h @@ -100,6 +100,15 @@ class ICPUAnimationLibrary final : public IAnimationLibrary, public { return { m_keyframeStorageBinding.buffer.get(), m_timestampStorageBinding.buffer.get(), m_animationStorageRange.buffer.get() }; } + + private: + + template + requires(std::same_as, ICPUAnimationLibrary>) + static auto computeDependantsImpl(Self* self) { + using asset_ptr_t = std::conditional_t, const IAsset*, IAsset*>; + return core::unordered_set{ self->m_keyframeStorageBinding.buffer.get(), self->m_timestampStorageBinding.buffer.get(), self->m_animationStorageRange.buffer.get() }; + } }; } diff --git a/include/nbl/asset/ICPUBuffer.h b/include/nbl/asset/ICPUBuffer.h index 2d495ef02e..0ad1d7bf48 100644 --- a/include/nbl/asset/ICPUBuffer.h +++ b/include/nbl/asset/ICPUBuffer.h @@ -80,6 +80,11 @@ class ICPUBuffer final : public asset::IBuffer, public IPreHashed return {}; } + inline core::unordered_set computeDependants() override + { + return {}; + } + inline core::blake3_hash_t computeContentHash() const override { core::blake3_hasher hasher; diff --git a/include/nbl/asset/ICPUBufferView.h b/include/nbl/asset/ICPUBufferView.h index 7f3f676695..55d50356c1 100644 --- a/include/nbl/asset/ICPUBufferView.h +++ b/include/nbl/asset/ICPUBufferView.h @@ -30,7 +30,12 @@ class ICPUBufferView : public IBufferView, public IAsset inline core::unordered_set computeDependants() const override { - return { m_buffer.get() }; + return computeDependantsImpl(this); + } + + inline core::unordered_set computeDependants() override + { + return computeDependantsImpl(this); } ICPUBuffer* getUnderlyingBuffer() @@ -54,6 +59,13 @@ class ICPUBufferView : public IBufferView, public IAsset protected: virtual ~ICPUBufferView() = default; + private: + template + requires(std::same_as, ICPUBufferView>) + static auto computeDependantsImpl(Self* self) { + using asset_ptr_t = std::conditional_t, const IAsset*, IAsset*>; + return core::unordered_set{ self->m_buffer.get() }; + } }; } diff --git a/include/nbl/asset/ICPUComputePipeline.h b/include/nbl/asset/ICPUComputePipeline.h index 8d8b343a3d..f6b689857f 100644 --- a/include/nbl/asset/ICPUComputePipeline.h +++ b/include/nbl/asset/ICPUComputePipeline.h @@ -25,31 +25,28 @@ class ICPUComputePipeline final : public ICPUPipeline(retval,core::dont_grab); } - inline core::smart_refctd_ptr clone_impl(core::smart_refctd_ptr&& layout, uint32_t depth) const override final - { - auto newPipeline = new ICPUComputePipeline(layout.get()); - newPipeline->m_specInfo = m_specInfo.clone(depth); - return core::smart_refctd_ptr(newPipeline, core::dont_grab); - } - constexpr static inline auto AssetType = ET_COMPUTE_PIPELINE; inline E_TYPE getAssetType() const override { return AssetType; } //! - virtual core::unordered_set computeDependants() const override + inline core::unordered_set computeDependants() const override + { + return computeDependantsImpl(this); + } + + inline core::unordered_set computeDependants() override { - return {m_layout.get(), m_specInfo.shader.get()}; + return computeDependantsImpl(this); } - inline virtual std::span getSpecInfo(hlsl::ShaderStage stage) const override final + inline std::span getSpecInfo(hlsl::ShaderStage stage) const override final { - if (stage==hlsl::ShaderStage::ESS_COMPUTE && isMutable()) + if (stage==hlsl::ShaderStage::ESS_COMPUTE) return {&m_specInfo,1}; return {}; } - - inline virtual bool valid() const override final + inline bool valid() const override { if (!m_layout) return false; if (!m_layout->valid()) return false; @@ -64,10 +61,23 @@ class ICPUComputePipeline final : public ICPUPipeline clone_impl(core::smart_refctd_ptr&& layout, uint32_t depth) const override final + { + auto newPipeline = new ICPUComputePipeline(layout.get()); + newPipeline->m_specInfo = m_specInfo.clone(depth); + return core::smart_refctd_ptr(newPipeline, core::dont_grab); + } + explicit ICPUComputePipeline(const ICPUPipelineLayout* layout): base_t(layout, {}) {} + template + requires(std::same_as, ICPUComputePipeline>) + static auto computeDependantsImpl(Self* self) { + using asset_ptr_t = std::conditional_t, const IAsset*, IAsset*>; + return core::unordered_set{ self->m_layout.get(), self->m_specInfo.shader.get() }; + } }; } diff --git a/include/nbl/asset/ICPUDescriptorSet.h b/include/nbl/asset/ICPUDescriptorSet.h index 77640b8f9f..c8a6f68d22 100644 --- a/include/nbl/asset/ICPUDescriptorSet.h +++ b/include/nbl/asset/ICPUDescriptorSet.h @@ -78,6 +78,7 @@ class NBL_API2 ICPUDescriptorSet final : public IDescriptorSet clone(uint32_t _depth = ~0u) const override; core::unordered_set computeDependants() const override; + core::unordered_set computeDependants() override; protected: virtual ~ICPUDescriptorSet() = default; diff --git a/include/nbl/asset/ICPUDescriptorSetLayout.h b/include/nbl/asset/ICPUDescriptorSetLayout.h index 2ddf1e26be..b2c06792d6 100644 --- a/include/nbl/asset/ICPUDescriptorSetLayout.h +++ b/include/nbl/asset/ICPUDescriptorSetLayout.h @@ -59,18 +59,32 @@ class ICPUDescriptorSetLayout : public IDescriptorSetLayout, public core::unordered_set computeDependants() const override { - if (!m_immutableSamplers) return {}; - core::unordered_set dependants; - for (const auto& sampler: m_immutableSamplers) - { - dependants.insert(sampler.get()); - } - return dependants; + return computeDependantsImpl(this); + } + + core::unordered_set computeDependants() override + { + return computeDependantsImpl(this); } protected: virtual ~ICPUDescriptorSetLayout() = default; + + private: + template + requires(std::same_as, ICPUDescriptorSetLayout>) + static auto computeDependantsImpl(Self* self) { + using asset_ptr_t = std::conditional_t, const IAsset*, IAsset*>; + core::unordered_set dependants; + if (!self->m_immutableSamplers) return dependants; + for (const auto& sampler: self->m_immutableSamplers) + { + dependants.insert(sampler.get()); + } + return dependants; + } + }; } diff --git a/include/nbl/asset/ICPUGraphicsPipeline.h b/include/nbl/asset/ICPUGraphicsPipeline.h index 0629f82f1c..dcdcfb495e 100644 --- a/include/nbl/asset/ICPUGraphicsPipeline.h +++ b/include/nbl/asset/ICPUGraphicsPipeline.h @@ -43,12 +43,14 @@ class ICPUGraphicsPipeline final : public ICPUPipeline computeDependants() const override + inline core::unordered_set computeDependants() const override { - core::unordered_set dependants = { m_layout.get(), m_renderpass.get()}; - for (const auto& info : m_specInfos) - if (info.shader) dependants.insert(info.shader.get()); - return dependants; + return computeDependantsImpl(this); + } + + inline core::unordered_set computeDependants() override + { + return computeDependantsImpl(this); } inline SCachedCreationParams& getCachedCreationParams() @@ -69,6 +71,7 @@ class ICPUGraphicsPipeline final : public ICPUPipelinevalid())return false; // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-dynamicRendering-06576 if (!m_renderpass || m_params.subpassIx >= m_renderpass->getSubpassCount()) return false; @@ -108,6 +111,16 @@ class ICPUGraphicsPipeline final : public ICPUPipeline(hlsl::ShaderStage::ESS_VERTEX + index); } + + template + requires(std::same_as, ICPUGraphicsPipeline>) + static auto computeDependantsImpl(Self* self) { + using asset_ptr_t = std::conditional_t, const IAsset*, IAsset*>; + core::unordered_set dependants = { self->m_layout.get(), self->m_renderpass.get()}; + for (const auto& info : self->m_specInfos) + if (info.shader) dependants.insert(info.shader.get()); + return dependants; + } }; } diff --git a/include/nbl/asset/ICPUImage.h b/include/nbl/asset/ICPUImage.h index 2527fd1ecb..b732e50492 100644 --- a/include/nbl/asset/ICPUImage.h +++ b/include/nbl/asset/ICPUImage.h @@ -51,6 +51,11 @@ class NBL_API2 ICPUImage final : public IImage, public IPreHashed return {}; } + inline core::unordered_set computeDependants() override + { + return {}; + } + core::blake3_hash_t computeContentHash() const override; // Having regions specififed to upload is optional! So to have content missing we must have regions but no buffer content diff --git a/include/nbl/asset/ICPUImageView.h b/include/nbl/asset/ICPUImageView.h index 6b3d562a60..9639df6eb9 100644 --- a/include/nbl/asset/ICPUImageView.h +++ b/include/nbl/asset/ICPUImageView.h @@ -51,7 +51,12 @@ class ICPUImageView final : public IImageView, public IAsset inline core::unordered_set computeDependants() const override { - return { params.image.get() }; + return computeDependantsImpl(this); + } + + inline core::unordered_set computeDependants() override + { + return computeDependantsImpl(this); } //! @@ -70,6 +75,13 @@ class ICPUImageView final : public IImageView, public IAsset protected: virtual ~ICPUImageView() = default; + private: + template + requires(std::same_as, ICPUImageView>) + static auto computeDependantsImpl(Self* self) { + using asset_ptr_t = std::conditional_t, const IAsset*, IAsset*>; + return core::unordered_set{ self->params.image.get() }; + } }; } diff --git a/include/nbl/asset/ICPUMesh.h b/include/nbl/asset/ICPUMesh.h index 2648900ccc..e9aaf53ba4 100644 --- a/include/nbl/asset/ICPUMesh.h +++ b/include/nbl/asset/ICPUMesh.h @@ -87,6 +87,11 @@ class ICPUMesh final : public IMesh, public IAsset return {}; } + inline core::unordered_set computeDependants() override + { + return {}; + } + protected: private: diff --git a/include/nbl/asset/ICPUMeshBuffer.h b/include/nbl/asset/ICPUMeshBuffer.h index 61e9168a98..c44d055c18 100644 --- a/include/nbl/asset/ICPUMeshBuffer.h +++ b/include/nbl/asset/ICPUMeshBuffer.h @@ -617,6 +617,11 @@ class ICPUMeshBuffer final : public IMeshBuffer computeDependants() override + { + return {}; + } + }; } diff --git a/include/nbl/asset/ICPUPipeline.h b/include/nbl/asset/ICPUPipeline.h index ae2c64372d..8fe7e38391 100644 --- a/include/nbl/asset/ICPUPipeline.h +++ b/include/nbl/asset/ICPUPipeline.h @@ -131,7 +131,7 @@ class ICPUPipeline : public IAsset, public PipelineNonAssetBase, public ICPUPipe inline std::span getSpecInfo(hlsl::ShaderStage stage) { if (!isMutable()) return {}; - const auto specInfo = static_cast(this)->getSpecInfo(stage); + const auto specInfo = const_cast(this)->getSpecInfo(stage); return { const_cast(specInfo.data()), specInfo.size() }; } diff --git a/include/nbl/asset/ICPUPipelineCache.h b/include/nbl/asset/ICPUPipelineCache.h index 6fc019ce7f..0ff912603d 100644 --- a/include/nbl/asset/ICPUPipelineCache.h +++ b/include/nbl/asset/ICPUPipelineCache.h @@ -65,6 +65,11 @@ class ICPUPipelineCache final : public IPreHashed return {}; } + inline core::unordered_set computeDependants() override + { + return {}; + } + // inline core::blake3_hash_t computeContentHash() const override { diff --git a/include/nbl/asset/ICPUPipelineLayout.h b/include/nbl/asset/ICPUPipelineLayout.h index 994d480b17..e755a22f07 100644 --- a/include/nbl/asset/ICPUPipelineLayout.h +++ b/include/nbl/asset/ICPUPipelineLayout.h @@ -79,6 +79,19 @@ class ICPUPipelineLayout : public IAsset, public IPipelineLayout + requires(std::same_as, ICPUPipelineLayout>) + static auto computeDependantsImpl(Self* self) { + using asset_ptr_t = std::conditional_t, const IAsset*, IAsset*>; + core::unordered_set dependants; + for (auto i = 0; i < self->m_descSetLayouts.size(); i++) + { + if (self->m_descSetLayouts[i]) continue; + dependants.insert(self->m_descSetLayouts[i].get()); + } + return dependants; + } + }; } diff --git a/include/nbl/asset/ICPURayTracingPipeline.h b/include/nbl/asset/ICPURayTracingPipeline.h index 5d975fa4dc..2b04a2f41b 100644 --- a/include/nbl/asset/ICPURayTracingPipeline.h +++ b/include/nbl/asset/ICPURayTracingPipeline.h @@ -57,14 +57,11 @@ class ICPURayTracingPipeline final : public ICPUPipeline computeDependants() const override final { - core::unordered_set dependants; - dependants.insert(m_raygen.shader.get()); - for (const auto& missInfo : m_misses) dependants.insert(missInfo.shader.get()); - for (const auto& anyHitInfo : m_hitGroups.anyHits) dependants.insert(anyHitInfo.shader.get()); - for (const auto& closestHitInfo : m_hitGroups.closestHits) dependants.insert(closestHitInfo.shader.get()); - for (const auto& intersectionInfo : m_hitGroups.intersections) dependants.insert(intersectionInfo.shader.get()); - for (const auto& callableInfo : m_callables) dependants.insert(callableInfo.shader.get()); - return dependants; + return computeDependantsImpl(this); + } + + virtual core::unordered_set computeDependants() override final { + return computeDependantsImpl(this); } inline virtual std::span getSpecInfo(hlsl::ShaderStage stage) const override final @@ -108,6 +105,19 @@ class ICPURayTracingPipeline final : public ICPUPipeline + requires(std::same_as, ICPURayTracingPipeline>) + static auto computeDependantsImpl(Self* self) { + using asset_ptr_t = std::conditional_t, const IAsset*, IAsset*>; + core::unordered_set dependants; + dependants.insert(self->m_raygen.shader.get()); + for (const auto& missInfo : self->m_misses) dependants.insert(missInfo.shader.get()); + for (const auto& anyHitInfo : self->m_hitGroups.anyHits) dependants.insert(anyHitInfo.shader.get()); + for (const auto& closestHitInfo : self->m_hitGroups.closestHits) dependants.insert(closestHitInfo.shader.get()); + for (const auto& intersectionInfo : self->m_hitGroups.intersections) dependants.insert(intersectionInfo.shader.get()); + for (const auto& callableInfo : self->m_callables) dependants.insert(callableInfo.shader.get()); + return dependants; + } }; } diff --git a/include/nbl/asset/ICPURenderpass.h b/include/nbl/asset/ICPURenderpass.h index bbb2e5003f..9cc73af881 100644 --- a/include/nbl/asset/ICPURenderpass.h +++ b/include/nbl/asset/ICPURenderpass.h @@ -43,6 +43,11 @@ class ICPURenderpass : public IRenderpass, public IAsset return {}; } + inline core::unordered_set computeDependants() override + { + return {}; + } + protected: inline ICPURenderpass(const SCreationParams& _params, const SCreationParamValidationResult& _validation) : IRenderpass(_params, _validation) {} inline ~ICPURenderpass() = default; diff --git a/include/nbl/asset/ICPURenderpassIndependentPipeline.h b/include/nbl/asset/ICPURenderpassIndependentPipeline.h index 8638a4965b..628785d2ab 100644 --- a/include/nbl/asset/ICPURenderpassIndependentPipeline.h +++ b/include/nbl/asset/ICPURenderpassIndependentPipeline.h @@ -71,6 +71,11 @@ class ICPURenderpassIndependentPipeline : public IRenderpassIndependentPipeline, return {}; } + inline core::unordered_set computeDependants() override + { + return {}; + } + // inline const SCachedCreationParams& getCachedCreationParams() const {return IRenderpassIndependentPipeline::getCachedCreationParams();} inline SCachedCreationParams& getCachedCreationParams() diff --git a/include/nbl/asset/ICPUSampler.h b/include/nbl/asset/ICPUSampler.h index 46cac56ee0..ed11e7695d 100644 --- a/include/nbl/asset/ICPUSampler.h +++ b/include/nbl/asset/ICPUSampler.h @@ -73,6 +73,11 @@ class ICPUSampler : public ISampler, public IAsset { return {}; } + + inline core::unordered_set computeDependants() override + { + return {}; + } }; } diff --git a/include/nbl/asset/ICPUSkeleton.h b/include/nbl/asset/ICPUSkeleton.h index ce03a9be54..51be7acc5a 100644 --- a/include/nbl/asset/ICPUSkeleton.h +++ b/include/nbl/asset/ICPUSkeleton.h @@ -81,9 +81,23 @@ class ICPUSkeleton final : public ISkeleton, public IAsset inline core::unordered_set computeDependants() const override { - return { m_defaultTransforms.buffer.get(), m_parentJointIDs.buffer.get() }; + return computeDependantsImpl(this); } + inline core::unordered_set computeDependants() override + { + return computeDependantsImpl(this); + } + + private: + template + requires(std::same_as, ICPUSkeleton>) + static auto computeDependantsImpl(Self* self) { + using asset_ptr_t = std::conditional_t, const IAsset*, IAsset*>; + core::unordered_set dependants; + return { self->m_defaultTransforms.buffer.get(), self->m_parentJointIDs.buffer.get() }; + return dependants; + } }; } diff --git a/include/nbl/asset/IShader.h b/include/nbl/asset/IShader.h index 5abd7d1980..59286e219d 100644 --- a/include/nbl/asset/IShader.h +++ b/include/nbl/asset/IShader.h @@ -52,7 +52,12 @@ class IShader : public IAsset inline core::unordered_set computeDependants() const override { - return { m_code.get() }; + return computeDependantsImpl(this); + } + + inline core::unordered_set computeDependants() override + { + return computeDependantsImpl(this); } // @@ -101,6 +106,14 @@ class IShader : public IAsset std::string m_filepathHint; core::smart_refctd_ptr m_code; E_CONTENT_TYPE m_contentType; + + private: + template + requires(std::same_as, IShader>) + static auto computeDependantsImpl(Self* self) { + using asset_ptr_t = std::conditional_t, const IAsset*, IAsset*>; + return core::unordered_set{self->m_code.get()}; + } }; } diff --git a/src/nbl/asset/ICPUDescriptorSet.cpp b/src/nbl/asset/ICPUDescriptorSet.cpp index a298fea491..a95074fdb7 100644 --- a/src/nbl/asset/ICPUDescriptorSet.cpp +++ b/src/nbl/asset/ICPUDescriptorSet.cpp @@ -108,35 +108,47 @@ core::smart_refctd_ptr ICPUDescriptorSet::clone(uint32_t _depth) const return cp; } -core::unordered_set ICPUDescriptorSet::computeDependants() const -{ - core::unordered_set dependants = { m_layout.get() }; - for (auto i = 0u; i < static_cast(IDescriptor::E_TYPE::ET_COUNT); i++) - { - if (!m_descriptorInfos[i]) continue; - const auto size = m_descriptorInfos[i]->size(); - for (auto desc_i = 0u; desc_i < size; desc_i++) +template + requires(std::same_as, ICPUDescriptorSet>) +static auto computeDependantsImpl(Self* self) { + using asset_ptr_t = std::conditional_t, const IAsset*, IAsset*>; + core::unordered_set dependants = { self->m_layout.get() }; + for (auto i = 0u; i < static_cast(IDescriptor::E_TYPE::ET_COUNT); i++) { - auto* desc = m_descriptorInfos[i]->operator[](desc_i).desc.get(); - if (!desc) continue; - switch (IDescriptor::GetTypeCategory(static_cast(i))) + if (!self->m_descriptorInfos[i]) continue; + const auto size = self->m_descriptorInfos[i]->size(); + for (auto desc_i = 0u; desc_i < size; desc_i++) { - case IDescriptor::EC_BUFFER: - dependants.insert(static_cast(desc)); - case IDescriptor::EC_SAMPLER: - dependants.insert(static_cast(desc)); - case IDescriptor::EC_IMAGE: - dependants.insert(static_cast(desc)); - case IDescriptor::EC_BUFFER_VIEW: - dependants.insert(static_cast(desc)); - case IDescriptor::EC_ACCELERATION_STRUCTURE: - dependants.insert(static_cast(desc)); - default: - break; + auto* desc = self->m_descriptorInfos[i]->operator[](desc_i).desc.get(); + if (!desc) continue; + switch (IDescriptor::GetTypeCategory(static_cast(i))) + { + case IDescriptor::EC_BUFFER: + dependants.insert(static_cast(desc)); + case IDescriptor::EC_SAMPLER: + dependants.insert(static_cast(desc)); + case IDescriptor::EC_IMAGE: + dependants.insert(static_cast(desc)); + case IDescriptor::EC_BUFFER_VIEW: + dependants.insert(static_cast(desc)); + case IDescriptor::EC_ACCELERATION_STRUCTURE: + dependants.insert(static_cast(desc)); + default: + break; + } } } - } - return dependants; + return dependants; +} + +core::unordered_set ICPUDescriptorSet::computeDependants() const +{ + return computeDependantsImpl(this); +} + +core::unordered_set ICPUDescriptorSet::computeDependants() +{ + return computeDependantsImpl(this); } } \ No newline at end of file From 2ac65f64277bb9bf3c9288104e36f32e639421f2 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Fri, 16 May 2025 18:26:59 +0700 Subject: [PATCH 46/64] Refactor anyDependantDiscardedContents and discardDependantsContents --- include/nbl/asset/IPreHashed.h | 56 +++++++++++++--------------------- 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/include/nbl/asset/IPreHashed.h b/include/nbl/asset/IPreHashed.h index 4ffda209df..86e1841f61 100644 --- a/include/nbl/asset/IPreHashed.h +++ b/include/nbl/asset/IPreHashed.h @@ -41,36 +41,31 @@ class IPreHashed : public IAsset static inline void discardDependantsContents(const std::span roots) { - struct stack_entry_t - { - const IAsset* asset; - core::unordered_set unvisitedChilds; - }; - core::stack stack; - core::unordered_set alreadyVisited; - auto push = [&stack,&alreadyVisited](const IAsset* node) -> void + core::stack stack; + core::unordered_set alreadyVisited; // whether we have push the node to the stack + core::unordered_set alreadyDescended; // whether we have push the children to the stack + auto push = [&stack,&alreadyVisited](IAsset* node) -> void { if (!node) return; const auto [dummy,inserted] = alreadyVisited.insert(node); if (inserted) - stack.push({ .asset = node, .unvisitedChilds = node->computeDependants()}); + stack.push(node); }; for (const auto& root : roots) push(root); while (!stack.empty()) { - auto& entry = stack.top(); - if (entry.unvisitedChilds.size() > 0) + auto* entry = stack.top(); + const auto [dummy, inserted] = alreadyDescended.insert(entry); + if (inserted) { - auto dep = *entry.unvisitedChilds.begin(); - entry.unvisitedChilds.erase(entry.unvisitedChilds.begin()); - push(dep); - } - else + core::unordered_set dependants = entry->computeDependants(); + for (auto* dependant : dependants) push(dependant); + } else { // post order traversal does discard - auto* isPrehashed = dynamic_cast(entry.asset); + auto* isPrehashed = dynamic_cast(entry); if (isPrehashed) isPrehashed->discardContent(); stack.pop(); @@ -79,13 +74,9 @@ class IPreHashed : public IAsset } static inline bool anyDependantDiscardedContents(const IAsset* root) { - struct stack_entry_t - { - const IAsset* asset; - core::unordered_set unvisitedChilds; - }; - core::stack stack; - core::unordered_set alreadyVisited; + core::stack stack; + core::unordered_set alreadyVisited; // whether we have push the node to the stack + core::unordered_set alreadyDescended; // whether we have push the children to the stack auto push = [&stack,&alreadyVisited](const IAsset* node) -> bool { if (!node) @@ -96,7 +87,7 @@ class IPreHashed : public IAsset auto* isPrehashed = dynamic_cast(node); if (isPrehashed && isPrehashed->missingContent()) return true; - stack.push({ .asset = node, .unvisitedChilds = node->computeDependants() }); + stack.push(node); } return false; }; @@ -104,16 +95,13 @@ class IPreHashed : public IAsset return true; while (!stack.empty()) { - auto& entry = stack.top(); - auto& unvisitedChilds = entry.unvisitedChilds; - if (unvisitedChilds.size() > 0) + auto* entry = stack.top(); + const auto [dummy, inserted] = alreadyDescended.insert(entry); + if (inserted) { - auto dep = *unvisitedChilds.begin(); - unvisitedChilds.erase(unvisitedChilds.begin()); - if (push(dep)) - return true; - } - else + core::unordered_set dependants = entry->computeDependants(); + for (auto* dependant : dependants) push(dependant); + } else stack.pop(); } return false; From 5c13a932887a527d8e53d201c4d96aca84994d05 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Tue, 20 May 2025 17:41:39 +0700 Subject: [PATCH 47/64] Remove impl_valid and rework SSpecializatioNValidationResult --- include/nbl/asset/IRayTracingPipeline.h | 21 +- include/nbl/video/IGPUComputePipeline.h | 20 +- include/nbl/video/IGPUGraphicsPipeline.h | 49 ++-- include/nbl/video/IGPUPipeline.h | 19 ++ include/nbl/video/IGPURayTracingPipeline.h | 234 ++++++-------------- include/nbl/video/SPipelineCreationParams.h | 49 ++-- 6 files changed, 152 insertions(+), 240 deletions(-) diff --git a/include/nbl/asset/IRayTracingPipeline.h b/include/nbl/asset/IRayTracingPipeline.h index 50ab7ba3f3..82b47f1fcb 100644 --- a/include/nbl/asset/IRayTracingPipeline.h +++ b/include/nbl/asset/IRayTracingPipeline.h @@ -24,10 +24,27 @@ class IRayTracingPipelineBase : public virtual core::IReferenceCounted template class IRayTracingPipeline : public IPipeline, public IRayTracingPipelineBase { - using base_creation_params_t = IPipeline; - public: + #define base_flag(F) static_cast(IPipelineBase::FLAGS::F) + enum class CreationFlags : uint64_t + { + NONE = base_flag(NONE), + DISABLE_OPTIMIZATIONS = base_flag(DISABLE_OPTIMIZATIONS), + ALLOW_DERIVATIVES = base_flag(ALLOW_DERIVATIVES), + FAIL_ON_PIPELINE_COMPILE_REQUIRED = base_flag(FAIL_ON_PIPELINE_COMPILE_REQUIRED), + EARLY_RETURN_ON_FAILURE = base_flag(EARLY_RETURN_ON_FAILURE), + SKIP_BUILT_IN_PRIMITIVES = 1<<12, + SKIP_AABBS = 1<<13, + NO_NULL_ANY_HIT_SHADERS = 1<<14, + NO_NULL_CLOSEST_HIT_SHADERS = 1<<15, + NO_NULL_MISS_SHADERS = 1<<16, + NO_NULL_INTERSECTION_SHADERS = 1<<17, + ALLOW_MOTION = 1<<20, + }; + #undef base_flag + using FLAGS = CreationFlags; + inline const SCachedCreationParams& getCachedCreationParams() const { return m_params; } protected: diff --git a/include/nbl/video/IGPUComputePipeline.h b/include/nbl/video/IGPUComputePipeline.h index 065c567ee2..2eb03cf2da 100644 --- a/include/nbl/video/IGPUComputePipeline.h +++ b/include/nbl/video/IGPUComputePipeline.h @@ -47,21 +47,19 @@ class IGPUComputePipeline : public IGPUPipelinesize()>0x7fffffff) - return {}; - count = static_cast(shader.entries->size()); - } - return {.count=dataSize ? count:0,.dataSize=static_cast(dataSize)}; + SSpecializationValidationResult retval = { + .count = 0, + .dataSize = 0, + }; + + if (!shader.accumulateSpecializationValidationResult(&retval)) + return {}; + + return retval; } IGPUPipelineLayout* layout = nullptr; diff --git a/include/nbl/video/IGPUGraphicsPipeline.h b/include/nbl/video/IGPUGraphicsPipeline.h index f5d6e40275..ae8924a1ab 100644 --- a/include/nbl/video/IGPUGraphicsPipeline.h +++ b/include/nbl/video/IGPUGraphicsPipeline.h @@ -32,15 +32,17 @@ class IGPUGraphicsPipeline : public IGPUPipeline - inline bool impl_valid(ExtraLambda&& extra) const + inline SSpecializationValidationResult valid() const { if (!layout) - return false; + return {}; + SSpecializationValidationResult retval = {.count=0,.dataSize=0}; + if (!layout) + return {}; // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-dynamicRendering-06576 if (!renderpass || cached.subpassIx>=renderpass->getSubpassCount()) - return false; + return {}; // TODO: check rasterization samples, etc. //rp->getCreationParameters().subpasses[i] @@ -49,41 +51,18 @@ class IGPUGraphicsPipeline : public IGPUPipelinebool - { - const auto dataSize = info.valid(); - if (dataSize<0) - return false; - else if (dataSize==0) - return true; - - const size_t count = info.entries ? info.entries->size():0x80000000ull; - if (count>0x7fffffff) - return {}; - retval += {.count=dataSize ? static_cast(count):0,.dataSize=static_cast(dataSize)}; - return retval; - }); - if (!valid) + if (!hasRequiredStages(stagePresence, cached.primitiveAssembly.primitiveType)) return {}; return retval; } diff --git a/include/nbl/video/IGPUPipeline.h b/include/nbl/video/IGPUPipeline.h index fc4bc8d219..ff6d97f17b 100644 --- a/include/nbl/video/IGPUPipeline.h +++ b/include/nbl/video/IGPUPipeline.h @@ -7,6 +7,7 @@ #define _NBL_VIDEO_I_GPU_PIPELINE_H_INCLUDED_ #include "nbl/video/IGPUPipelineLayout.h" +#include "nbl/video/SPipelineCreationParams.h" #include "nbl/asset/IPipeline.h" namespace nbl::video @@ -69,6 +70,24 @@ class IGPUPipelineBase { return static_cast(specData); } + bool accumulateSpecializationValidationResult(SSpecializationValidationResult* retval) const + { + const auto dataSize = valid(); + if (dataSize < 0) + return false; + if (dataSize == 0) + return true; + + const size_t count = entries ? entries->size() : 0x80000000ull; + if (count > 0x7fffffff) + return false; + *retval += { + .count = dataSize ? static_cast(count) : 0, + .dataSize = static_cast(dataSize), + }; + return *retval; + } + const asset::IShader* shader = nullptr; std::string_view entryPoint = ""; diff --git a/include/nbl/video/IGPURayTracingPipeline.h b/include/nbl/video/IGPURayTracingPipeline.h index 2a6701c9e6..f7a92252f7 100644 --- a/include/nbl/video/IGPURayTracingPipeline.h +++ b/include/nbl/video/IGPURayTracingPipeline.h @@ -15,118 +15,9 @@ class IGPURayTracingPipeline : public IGPUPipeline; public: - struct SCreationParams + struct SCreationParams : public SPipelineCreationParams { - #define base_flag(F) static_cast(IPipelineBase::FLAGS::F) - enum class FLAGS : uint64_t - { - NONE = base_flag(NONE), - DISABLE_OPTIMIZATIONS = base_flag(DISABLE_OPTIMIZATIONS), - ALLOW_DERIVATIVES = base_flag(ALLOW_DERIVATIVES), - FAIL_ON_PIPELINE_COMPILE_REQUIRED = base_flag(FAIL_ON_PIPELINE_COMPILE_REQUIRED), - EARLY_RETURN_ON_FAILURE = base_flag(EARLY_RETURN_ON_FAILURE), - SKIP_BUILT_IN_PRIMITIVES = 1<<12, - SKIP_AABBS = 1<<13, - NO_NULL_ANY_HIT_SHADERS = 1<<14, - NO_NULL_CLOSEST_HIT_SHADERS = 1<<15, - NO_NULL_MISS_SHADERS = 1<<16, - NO_NULL_INTERSECTION_SHADERS = 1<<17, - ALLOW_MOTION = 1<<20, - }; - #undef base_flag - - protected: - template - inline bool impl_valid(ExtraLambda&& extra) const - { - if (!m_layout) return false; - - for (const auto info : shaders) - { - if (info.shader) - { - if (!extra(info)) - return false; - const auto stage = info.stage; - if ((stage & ~hlsl::ShaderStage::ESS_ALL_RAY_TRACING) != 0) - return false; - if (!std::has_single_bit>(stage)) - return false; - } - else - { - // every shader must not be null. use SIndex::Unused to represent unused shader. - return false; - } - } - - auto getShaderStage = [this](size_t index) -> hlsl::ShaderStage - { - return shaders[index].stage; - }; - - auto isValidShaderIndex = [this, getShaderStage](size_t index, hlsl::ShaderStage expectedStage, bool is_unused_shader_forbidden) -> bool - { - if (index == SShaderGroupsParams::SIndex::Unused) - return !is_unused_shader_forbidden; - if (index >= shaders.size()) - return false; - if (getShaderStage(index) != expectedStage) - return false; - return true; - }; - - if (!isValidShaderIndex(shaderGroups.raygen.index, hlsl::ShaderStage::ESS_RAYGEN, true)) - { - return false; - } - - for (const auto& shaderGroup : shaderGroups.hits) - { - // https://docs.vulkan.org/spec/latest/chapters/pipelines.html#VUID-VkRayTracingPipelineCreateInfoKHR-flags-03470 - if (!isValidShaderIndex(shaderGroup.anyHit, - hlsl::ShaderStage::ESS_ANY_HIT, - bool(flags & FLAGS::NO_NULL_ANY_HIT_SHADERS))) - return false; - - // https://docs.vulkan.org/spec/latest/chapters/pipelines.html#VUID-VkRayTracingPipelineCreateInfoKHR-flags-03471 - if (!isValidShaderIndex(shaderGroup.closestHit, - hlsl::ShaderStage::ESS_CLOSEST_HIT, - bool(flags & FLAGS::NO_NULL_CLOSEST_HIT_SHADERS))) - return false; - - if (!isValidShaderIndex(shaderGroup.intersection, - hlsl::ShaderStage::ESS_INTERSECTION, - false)) - return false; - } - - for (const auto& shaderGroup : shaderGroups.misses) - { - if (!isValidShaderIndex(shaderGroup.index, - hlsl::ShaderStage::ESS_MISS, - false)) - return false; - } - - for (const auto& shaderGroup : shaderGroups.callables) - { - if (!isValidShaderIndex(shaderGroup.index, hlsl::ShaderStage::ESS_CALLABLE, false)) - return false; - } - return true; - } - - public: - inline bool valid() const - { - return impl_valid([](const SShaderSpecInfo& info)->bool - { - if (!info.valid()) - return false; - return false; - }); - } + using FLAGS = pipeline_t::FLAGS; struct SShaderGroupsParams { @@ -149,50 +40,12 @@ class IGPURayTracingPipeline : public IGPUPipeline flags = FLAGS::NONE; - }; - - - struct SShaderGroupHandle - { - private: - uint8_t data[video::SPhysicalDeviceLimits::ShaderGroupHandleSize]; - }; - static_assert(sizeof(SShaderGroupHandle) == video::SPhysicalDeviceLimits::ShaderGroupHandleSize); - - struct SHitGroupStackSize - { - uint16_t closestHit; - uint16_t anyHit; - uint16_t intersection; - }; - - using SGeneralShaderGroupContainer = core::smart_refctd_dynamic_array; - using SHitShaderGroupContainer = core::smart_refctd_dynamic_array; - - struct SCreationParams final : SPipelineCreationParams - { - #define base_flag(F) static_cast(IPipelineBase::CreationFlags::F) - enum class FLAGS : uint64_t - { - NONE = base_flag(NONE), - DISABLE_OPTIMIZATIONS = base_flag(DISABLE_OPTIMIZATIONS), - ALLOW_DERIVATIVES = base_flag(ALLOW_DERIVATIVES), - FAIL_ON_PIPELINE_COMPILE_REQUIRED = base_flag(FAIL_ON_PIPELINE_COMPILE_REQUIRED), - EARLY_RETURN_ON_FAILURE = base_flag(EARLY_RETURN_ON_FAILURE), - SKIP_BUILT_IN_PRIMITIVES = 1<<12, - SKIP_AABBS = 1<<13, - NO_NULL_ANY_HIT_SHADERS = 1<<14, - NO_NULL_CLOSEST_HIT_SHADERS = 1<<15, - NO_NULL_MISS_SHADERS = 1<<16, - NO_NULL_INTERSECTION_SHADERS = 1<<17, - ALLOW_MOTION = 1<<20, - }; - #undef base_flag inline SSpecializationValidationResult valid() const { @@ -200,31 +53,76 @@ class IGPURayTracingPipeline : public IGPUPipelinebool + + if (!shaderGroups.raygen.accumulateSpecializationValidationResult(&retval)) + return {}; + + for (const auto& shaderGroup : shaderGroups.hits) { - const auto dataSize = info.valid(); - if (dataSize<0) - return false; - else if (dataSize==0) - return true; - - const size_t count = info.entries ? info.entries->size():0x80000000ull; - if (count>0x7fffffff) + if (shaderGroup.intersection.shader) + { + if (!shaderGroup.intersection.accumulateSpecializationValidationResult(&retval)) return {}; - retval += {.count=dataSize ? static_cast(count):0,.dataSize=static_cast(dataSize)}; - return retval; - }); - if (!valid) - return {}; + } + + if (shaderGroup.closestHit.shader) + { + if (!shaderGroup.closestHit.accumulateSpecializationValidationResult(&retval)) + return {}; + } + + // https://docs.vulkan.org/spec/latest/chapters/pipelines.html#VUID-VkRayTracingPipelineCreateInfoKHR-flags-03470 + if (flags & FLAGS::NO_NULL_ANY_HIT_SHADERS && !shaderGroup.anyHit.shader) + return {}; + + if (shaderGroup.anyHit.shader) + { + if (!shaderGroup.anyHit.accumulateSpecializationValidationResult(&retval)) + return {}; + } + + // https://docs.vulkan.org/spec/latest/chapters/pipelines.html#VUID-VkRayTracingPipelineCreateInfoKHR-flags-03471 + if (flags & FLAGS::NO_NULL_CLOSEST_HIT_SHADERS && !shaderGroup.intersection.shader) + return {}; + } + + for (const auto& miss : shaderGroups.misses) + { + if (miss.shader) + { + if (!miss.accumulateSpecializationValidationResult(&retval)) + return {}; + } + } + + for (const auto& callable : shaderGroups.callables) + { + if (callable.shader) + { + if (!callable.accumulateSpecializationValidationResult(&retval)) + return {}; + } + } + return retval; } + }; - inline std::span getShaders() const { return shaders; } + struct SShaderGroupHandle + { + private: + uint8_t data[video::SPhysicalDeviceLimits::ShaderGroupHandleSize]; + }; + static_assert(sizeof(SShaderGroupHandle) == video::SPhysicalDeviceLimits::ShaderGroupHandleSize); - IGPUPipelineLayout* layout = nullptr; + struct SHitGroupStackSize + { + uint16_t closestHit; + uint16_t anyHit; + uint16_t intersection; }; inline core::bitflag getCreationFlags() const { return m_flags; } diff --git a/include/nbl/video/SPipelineCreationParams.h b/include/nbl/video/SPipelineCreationParams.h index 489bff4343..3a25560ae4 100644 --- a/include/nbl/video/SPipelineCreationParams.h +++ b/include/nbl/video/SPipelineCreationParams.h @@ -11,6 +11,31 @@ namespace nbl::video { +struct SSpecializationValidationResult +{ + constexpr static inline uint32_t Invalid = ~0u; + inline operator bool() const + { + return count!=Invalid && dataSize!=Invalid; + } + + inline SSpecializationValidationResult& operator+=(const SSpecializationValidationResult& other) + { + // TODO: check for overflow before adding + if (*this && other) + { + count += other.count; + dataSize += other.dataSize; + } + else + *this = {}; + return *this; + } + + uint32_t count = Invalid; + uint32_t dataSize = Invalid; +}; + // For now, due to API design we implicitly satisfy: // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-stage-08771 // to: @@ -18,30 +43,6 @@ namespace nbl::video template struct SPipelineCreationParams { - struct SSpecializationValidationResult - { - constexpr static inline uint32_t Invalid = ~0u; - inline operator bool() const - { - return count!=Invalid && dataSize!=Invalid; - } - - inline SSpecializationValidationResult& operator+=(const SSpecializationValidationResult& other) - { - // TODO: check for overflow before adding - if (*this && other) - { - count += other.count; - dataSize += other.dataSize; - } - else - *this = {}; - return *this; - } - - uint32_t count = Invalid; - uint32_t dataSize = Invalid; - }; constexpr static inline int32_t NotDerivingFromPreviousPipeline = -1; inline bool isDerivative() const From 9f43c02bab2d70e4f59ce7a2f50b9580e2583691 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Thu, 22 May 2025 15:28:25 +0700 Subject: [PATCH 48/64] Return Subgroup size to IPipelineBase --- include/nbl/asset/ICPUGraphicsPipeline.h | 28 ++++++++++++------------ include/nbl/asset/ICPUPipeline.h | 2 ++ include/nbl/asset/IComputePipeline.h | 18 +-------------- include/nbl/asset/IPipeline.h | 15 +++++++++++++ 4 files changed, 32 insertions(+), 31 deletions(-) diff --git a/include/nbl/asset/ICPUGraphicsPipeline.h b/include/nbl/asset/ICPUGraphicsPipeline.h index dcdcfb495e..4a7ee3b695 100644 --- a/include/nbl/asset/ICPUGraphicsPipeline.h +++ b/include/nbl/asset/ICPUGraphicsPipeline.h @@ -26,20 +26,6 @@ class ICPUGraphicsPipeline final : public ICPUPipeline(retval,core::dont_grab); } - inline core::smart_refctd_ptr clone_impl(core::smart_refctd_ptr&& layout, uint32_t depth) const override final - { - auto* newPipeline = new ICPUGraphicsPipeline(layout.get()); - newPipeline->m_params = m_params; - newPipeline->m_renderpass = m_renderpass; - - for (auto specInfo_i = 0u; specInfo_i < m_specInfos.size(); specInfo_i++) - { - newPipeline->m_specInfos[specInfo_i] = m_specInfos[specInfo_i].clone(depth); - } - - return core::smart_refctd_ptr(newPipeline, core::dont_grab); - } - constexpr static inline auto AssetType = ET_GRAPHICS_PIPELINE; inline E_TYPE getAssetType() const override { return AssetType; } @@ -121,6 +107,20 @@ class ICPUGraphicsPipeline final : public ICPUPipeline clone_impl(core::smart_refctd_ptr&& layout, uint32_t depth) const override final + { + auto* newPipeline = new ICPUGraphicsPipeline(layout.get()); + newPipeline->m_params = m_params; + newPipeline->m_renderpass = m_renderpass; + + for (auto specInfo_i = 0u; specInfo_i < m_specInfos.size(); specInfo_i++) + { + newPipeline->m_specInfos[specInfo_i] = m_specInfos[specInfo_i].clone(depth); + } + + return core::smart_refctd_ptr(newPipeline, core::dont_grab); + } }; } diff --git a/include/nbl/asset/ICPUPipeline.h b/include/nbl/asset/ICPUPipeline.h index 8fe7e38391..435aca5d40 100644 --- a/include/nbl/asset/ICPUPipeline.h +++ b/include/nbl/asset/ICPUPipeline.h @@ -70,6 +70,8 @@ class ICPUPipelineBase core::smart_refctd_ptr shader = nullptr; std::string entryPoint = ""; + IPipelineBase::SUBGROUP_SIZE requiredSubgroupSize = IPipelineBase::SUBGROUP_SIZE::UNKNOWN; //!< Default value of 8 means no requirement + // Container choice implicitly satisfies: // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkSpecializationInfo.html#VUID-VkSpecializationInfo-constantID-04911 core::unordered_map entries; diff --git a/include/nbl/asset/IComputePipeline.h b/include/nbl/asset/IComputePipeline.h index 4f439d7100..9ccef877c3 100644 --- a/include/nbl/asset/IComputePipeline.h +++ b/include/nbl/asset/IComputePipeline.h @@ -9,26 +9,10 @@ namespace nbl::asset class IComputePipelineBase : public virtual core::IReferenceCounted { public: - // Nabla requires device's reported subgroup size to be between 4 and 128 - enum class SUBGROUP_SIZE : uint8_t - { - // No constraint but probably means `gl_SubgroupSize` is Dynamically Uniform - UNKNOWN = 0, - // Allows the Subgroup Uniform `gl_SubgroupSize` to be non-Dynamically Uniform and vary between Device's min and max - VARYING = 1, - // The rest we encode as log2(x) of the required value - REQUIRE_4 = 2, - REQUIRE_8 = 3, - REQUIRE_16 = 4, - REQUIRE_32 = 5, - REQUIRE_64 = 6, - REQUIRE_128 = 7 - }; struct SCachedCreationParams final { - SUBGROUP_SIZE requiredSubgroupSize : 3 = SUBGROUP_SIZE::UNKNOWN; //!< Default value of 8 means no requirement - uint8_t requireFullSubgroups : 1 = false; + uint8_t requireFullSubgroups = false; }; }; diff --git a/include/nbl/asset/IPipeline.h b/include/nbl/asset/IPipeline.h index eb64de0b0d..c458c34afe 100644 --- a/include/nbl/asset/IPipeline.h +++ b/include/nbl/asset/IPipeline.h @@ -105,6 +105,21 @@ class IPipelineBase }; using FLAGS = CreationFlags; + // Nabla requires device's reported subgroup size to be between 4 and 128 + enum class SUBGROUP_SIZE : uint8_t + { + // No constraint but probably means `gl_SubgroupSize` is Dynamically Uniform + UNKNOWN = 0, + // Allows the Subgroup Uniform `gl_SubgroupSize` to be non-Dynamically Uniform and vary between Device's min and max + VARYING = 1, + // The rest we encode as log2(x) of the required value + REQUIRE_4 = 2, + REQUIRE_8 = 3, + REQUIRE_16 = 4, + REQUIRE_32 = 5, + REQUIRE_64 = 6, + REQUIRE_128 = 7 + }; }; template From bae94c58e8c73a7b111d0edfa4017a8770803809 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Thu, 22 May 2025 15:29:56 +0700 Subject: [PATCH 49/64] Fix missing bracket for getLayout --- include/nbl/asset/ICPUPipeline.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/nbl/asset/ICPUPipeline.h b/include/nbl/asset/ICPUPipeline.h index 435aca5d40..c7fe9b49e0 100644 --- a/include/nbl/asset/ICPUPipeline.h +++ b/include/nbl/asset/ICPUPipeline.h @@ -125,7 +125,7 @@ class ICPUPipeline : public IAsset, public PipelineNonAssetBase, public ICPUPipe core::smart_refctd_ptr layout; if (_depth > 0u) - layout = core::smart_refctd_ptr_static_cast(getLayout->clone(_depth-1u)); + layout = core::smart_refctd_ptr_static_cast(getLayout()->clone(_depth - 1u)); return clone_impl(std::move(layout), _depth); } From 0d8fe94aefe5d820c43d26d9a6235951f2969c6b Mon Sep 17 00:00:00 2001 From: kevyuu Date: Thu, 22 May 2025 15:30:17 +0700 Subject: [PATCH 50/64] Return Subgroup Size to every SShaderSpecInfo --- include/nbl/video/IGPUPipeline.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/nbl/video/IGPUPipeline.h b/include/nbl/video/IGPUPipeline.h index ff6d97f17b..f9a32786bf 100644 --- a/include/nbl/video/IGPUPipeline.h +++ b/include/nbl/video/IGPUPipeline.h @@ -91,6 +91,9 @@ class IGPUPipelineBase { const asset::IShader* shader = nullptr; std::string_view entryPoint = ""; + asset::IPipelineBase::SUBGROUP_SIZE requiredSubgroupSize = asset::IPipelineBase::SUBGROUP_SIZE::UNKNOWN; //!< Default value of 8 means no requirement + + // Container choice implicitly satisfies: // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkSpecializationInfo.html#VUID-VkSpecializationInfo-constantID-04911 const core::unordered_map* entries; From 4ed04c83eb5162747c7dce9514c9e445b4ffd941 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Thu, 22 May 2025 15:30:36 +0700 Subject: [PATCH 51/64] Fix stagePresence typo --- include/nbl/video/IGPUGraphicsPipeline.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/nbl/video/IGPUGraphicsPipeline.h b/include/nbl/video/IGPUGraphicsPipeline.h index ae8924a1ab..c44ef5ceb1 100644 --- a/include/nbl/video/IGPUGraphicsPipeline.h +++ b/include/nbl/video/IGPUGraphicsPipeline.h @@ -53,7 +53,7 @@ class IGPUGraphicsPipeline : public IGPUPipeline Date: Thu, 22 May 2025 15:30:56 +0700 Subject: [PATCH 52/64] Move clone_impl to private --- include/nbl/asset/ICPURayTracingPipeline.h | 44 +++++++++++----------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/include/nbl/asset/ICPURayTracingPipeline.h b/include/nbl/asset/ICPURayTracingPipeline.h index 2b04a2f41b..ed2c5d2409 100644 --- a/include/nbl/asset/ICPURayTracingPipeline.h +++ b/include/nbl/asset/ICPURayTracingPipeline.h @@ -31,27 +31,7 @@ class ICPURayTracingPipeline final : public ICPUPipeline(retval,core::dont_grab); } - inline core::smart_refctd_ptr clone_impl(core::smart_refctd_ptr&& layout, uint32_t depth) const override final - { - auto newPipeline = new ICPURayTracingPipeline(layout.get()); - newPipeline->m_raygen = m_raygen.clone(depth); - - auto cloneSpecInfos = [depth](const core::vector& specInfos) -> core::vector { - core::vector results; - results.resize(specInfos.size()); - for (auto specInfo_i = 0u; specInfo_i < specInfos.size(); specInfo_i++) - results[specInfo_i] = specInfos[specInfo_i].clone(depth); - return results; - }; - newPipeline->m_misses = cloneSpecInfos(m_misses); - newPipeline->m_hitGroups.anyHits = cloneSpecInfos(m_hitGroups.anyHits); - newPipeline->m_hitGroups.closestHits = cloneSpecInfos(m_hitGroups.closestHits); - newPipeline->m_hitGroups.intersections = cloneSpecInfos(m_hitGroups.intersections); - newPipeline->m_callables = cloneSpecInfos(m_callables); - - newPipeline->m_params = m_params; - return core::smart_refctd_ptr(newPipeline); - } + constexpr static inline auto AssetType = ET_RAYTRACING_PIPELINE; inline E_TYPE getAssetType() const override { return AssetType; } @@ -118,6 +98,28 @@ class ICPURayTracingPipeline final : public ICPUPipelinem_callables) dependants.insert(callableInfo.shader.get()); return dependants; } + + inline core::smart_refctd_ptr clone_impl(core::smart_refctd_ptr&& layout, uint32_t depth) const override final + { + auto newPipeline = new ICPURayTracingPipeline(layout.get()); + newPipeline->m_raygen = m_raygen.clone(depth); + + auto cloneSpecInfos = [depth](const core::vector& specInfos) -> core::vector { + core::vector results; + results.resize(specInfos.size()); + for (auto specInfo_i = 0u; specInfo_i < specInfos.size(); specInfo_i++) + results[specInfo_i] = specInfos[specInfo_i].clone(depth); + return results; + }; + newPipeline->m_misses = cloneSpecInfos(m_misses); + newPipeline->m_hitGroups.anyHits = cloneSpecInfos(m_hitGroups.anyHits); + newPipeline->m_hitGroups.closestHits = cloneSpecInfos(m_hitGroups.closestHits); + newPipeline->m_hitGroups.intersections = cloneSpecInfos(m_hitGroups.intersections); + newPipeline->m_callables = cloneSpecInfos(m_callables); + + newPipeline->m_params = m_params; + return core::smart_refctd_ptr(newPipeline); + } }; } From c01392c93f7f7490131b7bc9bb4aa56b2140ba34 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Thu, 22 May 2025 15:31:16 +0700 Subject: [PATCH 53/64] Implement getSpecInfoVec for ICPURayTracingPipeline --- include/nbl/asset/ICPURayTracingPipeline.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/include/nbl/asset/ICPURayTracingPipeline.h b/include/nbl/asset/ICPURayTracingPipeline.h index ed2c5d2409..5819099887 100644 --- a/include/nbl/asset/ICPURayTracingPipeline.h +++ b/include/nbl/asset/ICPURayTracingPipeline.h @@ -65,6 +65,28 @@ class ICPURayTracingPipeline final : public ICPUPipeline& getSpecInfoVec(hlsl::ShadeStage stage) + { + if (!isMutable()) return {}; + switch (stage) + { + // raygen is not stored as vector so we can't return it here. Use getSpecInfo + case hlsl::ShaderStage::ESS_MISS: + return m_misses; + case hlsl::ShaderStage::ESS_ANY_HIT: + return m_hitGroups.anyHits; + case hlsl::ShaderStage::ESS_CLOSEST_HIT: + return m_hitGroups.closestHits; + case hlsl::ShaderStage::ESS_INTERSECTION: + return m_hitGroups.intersections; + case hlsl::ShaderStage::ESS_CALLABLE: + return m_callables; + + } + return {}; + } + + inline virtual bool valid() const override final { // TODO(kevinyu): Fix this temporary dummy code From 7b3c0edd4c40380caec7735f3f903483c156bfed Mon Sep 17 00:00:00 2001 From: kevyuu Date: Thu, 22 May 2025 18:35:51 +0700 Subject: [PATCH 54/64] Fix getSpecInfoVec --- include/nbl/asset/ICPURayTracingPipeline.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/nbl/asset/ICPURayTracingPipeline.h b/include/nbl/asset/ICPURayTracingPipeline.h index 5819099887..8be23ffe64 100644 --- a/include/nbl/asset/ICPURayTracingPipeline.h +++ b/include/nbl/asset/ICPURayTracingPipeline.h @@ -65,25 +65,25 @@ class ICPURayTracingPipeline final : public ICPUPipeline& getSpecInfoVec(hlsl::ShadeStage stage) + inline core::vector* getSpecInfoVec(hlsl::ShaderStage stage) { - if (!isMutable()) return {}; + if (!isMutable()) return nullptr; switch (stage) { // raygen is not stored as vector so we can't return it here. Use getSpecInfo case hlsl::ShaderStage::ESS_MISS: - return m_misses; + return &m_misses; case hlsl::ShaderStage::ESS_ANY_HIT: - return m_hitGroups.anyHits; + return &m_hitGroups.anyHits; case hlsl::ShaderStage::ESS_CLOSEST_HIT: - return m_hitGroups.closestHits; + return &m_hitGroups.closestHits; case hlsl::ShaderStage::ESS_INTERSECTION: - return m_hitGroups.intersections; + return &m_hitGroups.intersections; case hlsl::ShaderStage::ESS_CALLABLE: - return m_callables; + return &m_callables; } - return {}; + return nullptr; } From 96db32b8bcc55dd9dfc49d1ec9117fec4f329fdd Mon Sep 17 00:00:00 2001 From: kevyuu Date: Thu, 22 May 2025 18:36:09 +0700 Subject: [PATCH 55/64] Implement ICPURayTracingPIpeline valid --- include/nbl/asset/ICPURayTracingPipeline.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/nbl/asset/ICPURayTracingPipeline.h b/include/nbl/asset/ICPURayTracingPipeline.h index 8be23ffe64..618c851883 100644 --- a/include/nbl/asset/ICPURayTracingPipeline.h +++ b/include/nbl/asset/ICPURayTracingPipeline.h @@ -89,7 +89,9 @@ class ICPURayTracingPipeline final : public ICPUPipelinevalid()) return false; + if (m_raygen.valid() == SShaderSpecInfo::INVALID_SPEC_INFO) return false; return true; } From 98f3153a21c755b30b0a9c89c28734ff1216426f Mon Sep 17 00:00:00 2001 From: kevyuu Date: Fri, 23 May 2025 13:11:55 +0700 Subject: [PATCH 56/64] Fix ICPUSkeleton.h computeDependants --- include/nbl/asset/ICPUSkeleton.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/include/nbl/asset/ICPUSkeleton.h b/include/nbl/asset/ICPUSkeleton.h index 51be7acc5a..a29adbabbc 100644 --- a/include/nbl/asset/ICPUSkeleton.h +++ b/include/nbl/asset/ICPUSkeleton.h @@ -94,9 +94,7 @@ class ICPUSkeleton final : public ISkeleton, public IAsset requires(std::same_as, ICPUSkeleton>) static auto computeDependantsImpl(Self* self) { using asset_ptr_t = std::conditional_t, const IAsset*, IAsset*>; - core::unordered_set dependants; - return { self->m_defaultTransforms.buffer.get(), self->m_parentJointIDs.buffer.get() }; - return dependants; + return core::unordered_set{ self->m_defaultTransforms.buffer.get(), self->m_parentJointIDs.buffer.get() }; } }; From 30f35af1f9fdd14a48994862e3214c08d8c38710 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Fri, 23 May 2025 13:12:17 +0700 Subject: [PATCH 57/64] Small fixes --- include/nbl/asset/ICPUAccelerationStructure.h | 2 +- include/nbl/asset/ICPUDescriptorSetLayout.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/nbl/asset/ICPUAccelerationStructure.h b/include/nbl/asset/ICPUAccelerationStructure.h index 3ac794a888..73365cbfce 100644 --- a/include/nbl/asset/ICPUAccelerationStructure.h +++ b/include/nbl/asset/ICPUAccelerationStructure.h @@ -272,7 +272,7 @@ class ICPUTopLevelAccelerationStructure final : public IAsset, public ITopLevelA inline core::unordered_set computeDependants() const override { core::unordered_set dependants; - for (const auto& instance : m_instances) + for (const auto& instance : *m_instances) dependants.insert(instance.getBase().blas.get()); return dependants; } diff --git a/include/nbl/asset/ICPUDescriptorSetLayout.h b/include/nbl/asset/ICPUDescriptorSetLayout.h index b2c06792d6..aea1520b6f 100644 --- a/include/nbl/asset/ICPUDescriptorSetLayout.h +++ b/include/nbl/asset/ICPUDescriptorSetLayout.h @@ -78,7 +78,7 @@ class ICPUDescriptorSetLayout : public IDescriptorSetLayout, public using asset_ptr_t = std::conditional_t, const IAsset*, IAsset*>; core::unordered_set dependants; if (!self->m_immutableSamplers) return dependants; - for (const auto& sampler: self->m_immutableSamplers) + for (const auto& sampler: *self->m_immutableSamplers) { dependants.insert(sampler.get()); } From 2983ff09b649e586867ebc417869f4422bd9a764 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Fri, 23 May 2025 13:12:32 +0700 Subject: [PATCH 58/64] Remove redundant final specifier --- include/nbl/asset/ICPUComputePipeline.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/nbl/asset/ICPUComputePipeline.h b/include/nbl/asset/ICPUComputePipeline.h index f6b689857f..27d16461a2 100644 --- a/include/nbl/asset/ICPUComputePipeline.h +++ b/include/nbl/asset/ICPUComputePipeline.h @@ -39,7 +39,7 @@ class ICPUComputePipeline final : public ICPUPipeline getSpecInfo(hlsl::ShaderStage stage) const override final + inline std::span getSpecInfo(hlsl::ShaderStage stage) const override { if (stage==hlsl::ShaderStage::ESS_COMPUTE) return {&m_specInfo,1}; From e218e7770e0c92c543f1ea017cd1204ac0375002 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Fri, 23 May 2025 13:12:55 +0700 Subject: [PATCH 59/64] Remove const so it can be cast to IAsset* --- include/nbl/asset/IPipeline.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/nbl/asset/IPipeline.h b/include/nbl/asset/IPipeline.h index c458c34afe..d2a85c42fb 100644 --- a/include/nbl/asset/IPipeline.h +++ b/include/nbl/asset/IPipeline.h @@ -133,7 +133,7 @@ class IPipeline : public IPipelineBase inline IPipeline(core::smart_refctd_ptr&& _layout) : m_layout(std::move(_layout)) {} - core::smart_refctd_ptr m_layout; + core::smart_refctd_ptr m_layout; }; } From b58e486d505f9dd2f030322b16a34e029e2964c1 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Fri, 23 May 2025 13:13:15 +0700 Subject: [PATCH 60/64] Fix RenderpassIndependentPipeline --- include/nbl/asset/ICPURenderpassIndependentPipeline.h | 6 ++++++ include/nbl/asset/IRenderpassIndependentPipeline.h | 5 ----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/include/nbl/asset/ICPURenderpassIndependentPipeline.h b/include/nbl/asset/ICPURenderpassIndependentPipeline.h index 628785d2ab..fbff6ee312 100644 --- a/include/nbl/asset/ICPURenderpassIndependentPipeline.h +++ b/include/nbl/asset/ICPURenderpassIndependentPipeline.h @@ -19,6 +19,12 @@ namespace nbl::asset class ICPURenderpassIndependentPipeline : public IRenderpassIndependentPipeline, public IAsset { public: + struct SCreationParams + { + std::span shaders = {}; + SCachedCreationParams cached = {}; + }; + //(TODO) it is true however it causes DSs to not be cached when ECF_DONT_CACHE_TOP_LEVEL is set which isnt really intuitive constexpr static inline uint32_t DESC_SET_HIERARCHYLEVELS_BELOW = 0u; // TODO: @Crisspl HOW ON EARTH DOES THIS MAKE SENSE!? diff --git a/include/nbl/asset/IRenderpassIndependentPipeline.h b/include/nbl/asset/IRenderpassIndependentPipeline.h index 7f33b6abc4..feeaff7c99 100644 --- a/include/nbl/asset/IRenderpassIndependentPipeline.h +++ b/include/nbl/asset/IRenderpassIndependentPipeline.h @@ -28,11 +28,6 @@ class IRenderpassIndependentPipeline SRasterizationParams rasterization = {}; SBlendParams blend = {}; }; - struct SCreationParams - { - std::span shaders = {}; - SCachedCreationParams cached = {}; - }; inline const SCachedCreationParams& getCachedCreationParams() const {return m_cachedParams;} From 1f3a4775530484bca85ddf8dc46b5e0bc0c46aa1 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Fri, 23 May 2025 13:15:23 +0700 Subject: [PATCH 61/64] Fix SpirvIntrospector --- include/nbl/asset/ICPUPipeline.h | 8 +++++--- include/nbl/asset/utils/CSPIRVIntrospector.h | 4 ++-- src/nbl/asset/utils/CSPIRVIntrospector.cpp | 20 ++++++++++---------- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/include/nbl/asset/ICPUPipeline.h b/include/nbl/asset/ICPUPipeline.h index c7fe9b49e0..9674b872e0 100644 --- a/include/nbl/asset/ICPUPipeline.h +++ b/include/nbl/asset/ICPUPipeline.h @@ -72,9 +72,10 @@ class ICPUPipelineBase IPipelineBase::SUBGROUP_SIZE requiredSubgroupSize = IPipelineBase::SUBGROUP_SIZE::UNKNOWN; //!< Default value of 8 means no requirement + using spec_constant_map_t = core::unordered_map; // Container choice implicitly satisfies: // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkSpecializationInfo.html#VUID-VkSpecializationInfo-constantID-04911 - core::unordered_map entries; + spec_constant_map_t entries; // By requiring Nabla Core Profile features we implicitly satisfy: // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-flags-02784 // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-flags-02785 @@ -92,7 +93,7 @@ class ICPUPipelineBase } }; - virtual std::span getSpecInfo(const hlsl::ShaderStage stage) const = 0; + virtual std::span getSpecInfo(hlsl::ShaderStage stage) const = 0; }; @@ -130,7 +131,8 @@ class ICPUPipeline : public IAsset, public PipelineNonAssetBase, public ICPUPipe return clone_impl(std::move(layout), _depth); } - inline std::span getSpecInfo(hlsl::ShaderStage stage) + // Note(kevinyu): For some reason overload resolution cannot find this function when I name id getSpecInfo. It always use the const variant. Will check on it later. + inline std::span getSpecInfoMut(hlsl::ShaderStage stage) { if (!isMutable()) return {}; const auto specInfo = const_cast(this)->getSpecInfo(stage); diff --git a/include/nbl/asset/utils/CSPIRVIntrospector.h b/include/nbl/asset/utils/CSPIRVIntrospector.h index 3d6455e020..fa497f08aa 100644 --- a/include/nbl/asset/utils/CSPIRVIntrospector.h +++ b/include/nbl/asset/utils/CSPIRVIntrospector.h @@ -582,7 +582,7 @@ class NBL_API2 CSPIRVIntrospector : public core::Uncopyable } // returns true if successfully added all the info to self, false if incompatible with what's already in our pipeline or incomplete (e.g. missing spec constants) - bool merge(const CStageIntrospectionData* stageData, const IPipelineBase::SShaderSpecInfo::spec_constant_map_t* specConstants=nullptr); + bool merge(const CStageIntrospectionData* stageData, const ICPUPipelineBase::SShaderSpecInfo::spec_constant_map_t* specConstants=nullptr); // core::smart_refctd_dynamic_array createPushConstantRangesFromIntrospection(core::smart_refctd_ptr& introspection); @@ -643,7 +643,7 @@ class NBL_API2 CSPIRVIntrospector : public core::Uncopyable } //! creates pipeline for a single IShader - core::smart_refctd_ptr createApproximateComputePipelineFromIntrospection(const IPipelineBase::SShaderSpecInfo& info, core::smart_refctd_ptr&& layout=nullptr); + core::smart_refctd_ptr createApproximateComputePipelineFromIntrospection(const ICPUPipelineBase::SShaderSpecInfo& info, core::smart_refctd_ptr&& layout=nullptr); #if 0 // wait until Renderpass Indep completely gone and Graphics Pipeline is used in a new way && Graphics Pipeline Libraries struct CShaderStages diff --git a/src/nbl/asset/utils/CSPIRVIntrospector.cpp b/src/nbl/asset/utils/CSPIRVIntrospector.cpp index 8b43c676b7..214ffdddbb 100644 --- a/src/nbl/asset/utils/CSPIRVIntrospector.cpp +++ b/src/nbl/asset/utils/CSPIRVIntrospector.cpp @@ -3,6 +3,8 @@ // For conditions of distribution and use, see copyright notice in nabla.h #include "nbl/asset/utils/CSPIRVIntrospector.h" + +#include "nbl/asset/ICPUPipeline.h" #include "nbl/asset/utils/spvUtils.h" #include "nbl_spirv_cross/spirv_parser.hpp" @@ -106,15 +108,15 @@ static CSPIRVIntrospector::CStageIntrospectionData::VAR_TYPE spvcrossType2E_TYPE } } -core::smart_refctd_ptr CSPIRVIntrospector::createApproximateComputePipelineFromIntrospection(const IPipelineBase::SShaderSpecInfo& info, core::smart_refctd_ptr&& layout/* = nullptr*/) +core::smart_refctd_ptr CSPIRVIntrospector::createApproximateComputePipelineFromIntrospection(const ICPUPipelineBase::SShaderSpecInfo& info, core::smart_refctd_ptr&& layout/* = nullptr*/) { - if (info.stage!=IShader::E_SHADER_STAGE::ESS_COMPUTE || info.valid()==IPipelineBase::SShaderSpecInfo::INVALID_SPEC_INFO) + if (info.valid()==ICPUPipelineBase::SShaderSpecInfo::INVALID_SPEC_INFO) return nullptr; CStageIntrospectionData::SParams params; params.entryPoint = info.entryPoint; params.shader = core::smart_refctd_ptr(info.shader); - params.stage = info.stage; + params.stage = hlsl::ShaderStage::ESS_COMPUTE; auto introspection = introspect(params); @@ -174,15 +176,13 @@ core::smart_refctd_ptr CSPIRVIntrospector::createApproximat layout = pplnIntrospectData->createApproximatePipelineLayoutFromIntrospection(introspection); } - ICPUComputePipeline::SCreationParams pplnCreationParams; - pplnCreationParams.layout = layout.get(); - pplnCreationParams.shader = info; - pplnCreationParams.layout = layout.get(); - return ICPUComputePipeline::create(pplnCreationParams); + auto pipeline = ICPUComputePipeline::create(layout.get()); + pipeline->getSpecInfoMut(hlsl::ShaderStage::ESS_COMPUTE)[0] = info; + return pipeline; } // returns true if successfully added all the info to self, false if incompatible with what's already in our pipeline or incomplete (e.g. missing spec constants) -NBL_API2 bool CSPIRVIntrospector::CPipelineIntrospectionData::merge(const CSPIRVIntrospector::CStageIntrospectionData* stageData, const IPipelineBase::SShaderSpecInfo::spec_constant_map_t* specConstants) +NBL_API2 bool CSPIRVIntrospector::CPipelineIntrospectionData::merge(const CSPIRVIntrospector::CStageIntrospectionData* stageData, const ICPUPipelineBase::SShaderSpecInfo::spec_constant_map_t* specConstants) { if (!stageData) return false; @@ -218,7 +218,7 @@ NBL_API2 bool CSPIRVIntrospector::CPipelineIntrospectionData::merge(const CSPIRV if (specConstantFound == specConstants->end()) return false; - descInfo.count = specConstantFound->second; + descInfo.count = (specConstantFound->second.size() != 0); } else { From d042f42597fb6e12f9be04bb045145934de09d08 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Fri, 23 May 2025 20:26:30 +0700 Subject: [PATCH 62/64] Add some utility function to IGPURayTracingPipeline SShaderGroup --- include/nbl/video/IGPURayTracingPipeline.h | 28 ++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/include/nbl/video/IGPURayTracingPipeline.h b/include/nbl/video/IGPURayTracingPipeline.h index f7a92252f7..66e3a01072 100644 --- a/include/nbl/video/IGPURayTracingPipeline.h +++ b/include/nbl/video/IGPURayTracingPipeline.h @@ -38,6 +38,34 @@ class IGPURayTracingPipeline : public IGPUPipeline Date: Fri, 23 May 2025 20:26:47 +0700 Subject: [PATCH 63/64] Fix debloat logic in logical device --- include/nbl/video/ILogicalDevice.h | 10 +- src/nbl/video/ILogicalDevice.cpp | 177 +++++++++++++++++++++++++---- 2 files changed, 158 insertions(+), 29 deletions(-) diff --git a/include/nbl/video/ILogicalDevice.h b/include/nbl/video/ILogicalDevice.h index 49364f3a54..ab0d5bea06 100644 --- a/include/nbl/video/ILogicalDevice.h +++ b/include/nbl/video/ILogicalDevice.h @@ -1097,7 +1097,7 @@ class NBL_API2 ILogicalDevice : public core::IReferenceCounted, public IDeviceMe virtual core::smart_refctd_ptr createFramebuffer_impl(IGPUFramebuffer::SCreationParams&& params) = 0; template - inline CreationParams::SSpecializationValidationResult commonCreatePipelines(IGPUPipelineCache* const pipelineCache, const std::span params, ExtraLambda&& extra) + inline SSpecializationValidationResult commonCreatePipelines(IGPUPipelineCache* const pipelineCache, const std::span params, ExtraLambda&& extra) { if (pipelineCache && !pipelineCache->wasCreatedBy(this)) { @@ -1110,7 +1110,7 @@ class NBL_API2 ILogicalDevice : public core::IReferenceCounted, public IDeviceMe return {}; } - typename CreationParams::SSpecializationValidationResult retval = {.count=0,.dataSize=0}; + SSpecializationValidationResult retval = {.count=0,.dataSize=0}; for (auto i=0; i createInfos, core::smart_refctd_ptr* const output, - const IGPUComputePipeline::SCreationParams::SSpecializationValidationResult& validation + const SSpecializationValidationResult& validation ) = 0; virtual void createGraphicsPipelines_impl( IGPUPipelineCache* const pipelineCache, const std::span params, core::smart_refctd_ptr* const output, - const IGPUGraphicsPipeline::SCreationParams::SSpecializationValidationResult& validation + const SSpecializationValidationResult& validation ) = 0; virtual void createRayTracingPipelines_impl( IGPUPipelineCache* const pipelineCache, const std::span createInfos, core::smart_refctd_ptr* const output, - const IGPURayTracingPipeline::SCreationParams::SSpecializationValidationResult& validation + const SSpecializationValidationResult& validation ) = 0; virtual core::smart_refctd_ptr createQueryPool_impl(const IQueryPool::SCreationParams& params) = 0; diff --git a/src/nbl/video/ILogicalDevice.cpp b/src/nbl/video/ILogicalDevice.cpp index 26cfc4c6a8..d43ef7c58c 100644 --- a/src/nbl/video/ILogicalDevice.cpp +++ b/src/nbl/video/ILogicalDevice.cpp @@ -7,11 +7,70 @@ using namespace nbl; using namespace nbl::video; -static void debloatShaders(const asset::ISPIRVDebloater& debloater, std::span shaderSpecs, core::vector>& outShaders, asset::IPipelineBase::SShaderSpecInfo* outShaderSpecInfos, system::logger_opt_ptr logger = nullptr) +class SpirvDebloatTask +{ + public: + using EntryPoints = core::set; + + SpirvDebloatTask(asset::ISPIRVDebloater* debloater, system::logger_opt_ptr logger) : m_debloater(debloater), m_logger(logger) + { + + } + + void insertEntryPoint(const IGPUPipelineBase::SShaderSpecInfo& shaderSpec, hlsl::ShaderStage stage) + { + const auto* shader = shaderSpec.shader; + auto it = m_entryPointsMap.find(shader); + if (it == m_entryPointsMap.end() || it->first != shader) + it = m_entryPointsMap.emplace_hint(it, shader, EntryPoints()); + it->second.insert({ .name = shaderSpec.entryPoint, .stage = stage }); + } + + IGPUPipelineBase::SShaderSpecInfo debloat(const IGPUPipelineBase::SShaderSpecInfo& shaderSpec, core::vector>& outShaders) + { + const auto* shader = shaderSpec.shader; + const auto& entryPoints = m_entryPointsMap[shader]; + + auto debloatedShaderSpec = shaderSpec; + if (shader != nullptr) + { + if (!m_debloatedShadersMap.contains(shader)) + { + const auto outShadersData = outShaders.data(); + outShaders.push_back(m_debloater->debloat(shader, entryPoints, m_logger)); + assert(outShadersData == outShaders.data()); + m_debloatedShadersMap.emplace(shader, outShaders.back().get()); + } + const auto debloatedShader = m_debloatedShadersMap[shader]; + debloatedShaderSpec.shader = debloatedShader; + } + return debloatedShaderSpec; + } + + private: + core::map m_entryPointsMap; + core::map m_debloatedShadersMap; + asset::ISPIRVDebloater* m_debloater; + const system::logger_opt_ptr m_logger; +}; + +using DebloaterEntryPoints = core::set; +static void insertEntryPoint(const IGPUPipelineBase::SShaderSpecInfo& shaderSpec, hlsl::ShaderStage stage, + core::map entryPointsMap) +{ + const auto* shader = shaderSpec.shader; + auto it = entryPointsMap.find(shader); + if (it == entryPointsMap.end() || it->first != shader) + it = entryPointsMap.emplace_hint(it, shader, DebloaterEntryPoints()); + it->second.insert({ .name = shaderSpec.entryPoint, .stage = stage }); +}; + +static void debloatShaders(const asset::ISPIRVDebloater& debloater, std::span shaderSpecs, core::vector>& outShaders, IGPUPipelineBase::SShaderSpecInfo* outShaderSpecInfos, system::logger_opt_ptr logger = nullptr) { using EntryPoints = core::set; core::map entryPointsMap; + // collect all entry points first before we debloat for (const auto& shaderSpec : shaderSpecs) { const auto* shader = shaderSpec.shader; @@ -781,10 +840,10 @@ asset::ICPUPipelineCache::SCacheKey ILogicalDevice::getPipelineCacheKey() const bool ILogicalDevice::createComputePipelines(IGPUPipelineCache* const pipelineCache, const std::span params, core::smart_refctd_ptr* const output) { std::fill_n(output,params.size(),nullptr); - IGPUComputePipeline::SCreationParams::SSpecializationValidationResult specConstantValidation = commonCreatePipelines(pipelineCache,params,[this](const asset::IPipelineBase::SShaderSpecInfo& info)->bool + SSpecializationValidationResult specConstantValidation = commonCreatePipelines(pipelineCache,params,[this](const IGPUPipelineBase::SShaderSpecInfo& info)->bool { // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineShaderStageCreateInfo.html#VUID-VkPipelineShaderStageCreateInfo-pNext-02755 - if (info.requiredSubgroupSize>=asset::IPipelineBase::SShaderSpecInfo::SUBGROUP_SIZE::REQUIRE_4 && !getPhysicalDeviceLimits().requiredSubgroupSizeStages.hasFlags(info.stage)) + if (info.requiredSubgroupSize>=asset::IPipelineBase::SUBGROUP_SIZE::REQUIRE_4 && !getPhysicalDeviceLimits().requiredSubgroupSizeStages.hasFlags(hlsl::ShaderStage::ESS_COMPUTE)) { NBL_LOG_ERROR("Invalid shader stage"); return false; @@ -808,7 +867,11 @@ bool ILogicalDevice::createComputePipelines(IGPUPipelineCache* const pipelineCac for (auto ix = 0u; ix < params.size(); ix++) { const auto& ci = params[ix]; - debloatShaders(*m_spirvDebloater.get(), ci.getShaders(), debloatedShaders, &newParams[ix].shader, m_logger); + const core::set entryPoints = { asset::ISPIRVDebloater::EntryPoint{.name = ci.shader.entryPoint, .stage = hlsl::ShaderStage::ESS_COMPUTE} }; + debloatedShaders.push_back(m_spirvDebloater->debloat(ci.shader.shader, entryPoints, m_logger)); + auto debloatedShaderSpec = ci.shader; + debloatedShaderSpec.shader = debloatedShaders.back().get(); + newParams[ix].shader = debloatedShaderSpec; } createComputePipelines_impl(pipelineCache,newParams,output,specConstantValidation); @@ -834,12 +897,10 @@ bool ILogicalDevice::createGraphicsPipelines( ) { std::fill_n(output, params.size(), nullptr); - IGPUGraphicsPipeline::SCreationParams::SSpecializationValidationResult specConstantValidation = commonCreatePipelines(nullptr, params, - [this](const asset::IPipelineBase::SShaderSpecInfo& info)->bool + SSpecializationValidationResult specConstantValidation = commonCreatePipelines(nullptr, params, + [this](const IGPUPipelineBase::SShaderSpecInfo& info)->bool { - if (info.stage != hlsl::ShaderStage::ESS_VERTEX) - return true; - return info.shader; + return info.shader != nullptr; } ); if (!specConstantValidation) @@ -858,9 +919,6 @@ bool ILogicalDevice::createGraphicsPipelines( core::vector> debloatedShaders; // vector to hold all the debloated shaders, so the pointer from the new ShaderSpecInfo is not dangling debloatedShaders.reserve(shaderCount); - core::vector debloatedShaderSpecs(shaderCount); - auto outShaderSpecs = debloatedShaderSpecs.data(); - for (auto ix = 0u; ix < params.size(); ix++) { const auto& ci = params[ix]; @@ -953,9 +1011,19 @@ bool ILogicalDevice::createGraphicsPipelines( } } } + + SpirvDebloatTask debloatTask(m_spirvDebloater.get(), m_logger); + debloatTask.insertEntryPoint(ci.vertexShader, hlsl::ShaderStage::ESS_VERTEX); + debloatTask.insertEntryPoint(ci.tesselationControlShader, hlsl::ShaderStage::ESS_TESSELLATION_CONTROL); + debloatTask.insertEntryPoint(ci.tesselationEvaluationShader, hlsl::ShaderStage::ESS_TESSELLATION_EVALUATION); + debloatTask.insertEntryPoint(ci.geometryShader, hlsl::ShaderStage::ESS_GEOMETRY); + debloatTask.insertEntryPoint(ci.fragmentShader, hlsl::ShaderStage::ESS_FRAGMENT); - newParams[ix].shaders = std::span(outShaderSpecs, ci.getShaders().size()); - debloatShaders(*m_spirvDebloater.get(), ci.getShaders(), debloatedShaders, outShaderSpecs, m_logger); + newParams[ix].vertexShader = debloatTask.debloat(ci.vertexShader, debloatedShaders); + newParams[ix].tesselationControlShader = debloatTask.debloat(ci.tesselationControlShader, debloatedShaders); + newParams[ix].tesselationEvaluationShader = debloatTask.debloat(ci.tesselationEvaluationShader, debloatedShaders); + newParams[ix].geometryShader = debloatTask.debloat(ci.geometryShader, debloatedShaders); + newParams[ix].fragmentShader = debloatTask.debloat(ci.fragmentShader, debloatedShaders); } createGraphicsPipelines_impl(pipelineCache, newParams, output, specConstantValidation); @@ -980,7 +1048,7 @@ bool ILogicalDevice::createRayTracingPipelines(IGPUPipelineCache* const pipeline core::smart_refctd_ptr* const output) { std::fill_n(output,params.size(),nullptr); - IGPURayTracingPipeline::SCreationParams::SSpecializationValidationResult specConstantValidation = commonCreatePipelines(pipelineCache,params,[this](const asset::IPipelineBase::SShaderSpecInfo& info)->bool + SSpecializationValidationResult specConstantValidation = commonCreatePipelines(pipelineCache,params,[this](const IGPUPipelineBase::SShaderSpecInfo& info)->bool { return true; }); @@ -1028,15 +1096,43 @@ bool ILogicalDevice::createRayTracingPipelines(IGPUPipelineCache* const pipeline } core::vector newParams(params.begin(), params.end()); - const auto shaderCount = std::accumulate(params.begin(), params.end(), 0, [](uint32_t sum, auto& param) + const auto raygenCount = params.size(); // assume every param have raygen + const auto missShaderCount = std::accumulate(params.begin(), params.end(), 0, [](uint32_t sum, auto& param) { - return sum + param.getShaders().size(); + return sum + param.shaderGroups.getMissShaderCount(); }); + const auto hitShaderCount = std::accumulate(params.begin(), params.end(), 0, [](uint32_t sum, auto& param) + { + return sum + param.shaderGroups.getHitShaderCount(); + }); + const auto callableShaderCount = std::accumulate(params.begin(), params.end(), 0, [](uint32_t sum, auto& param) + { + return sum + param.shaderGroups.getCallableShaderCount(); + }); + const auto shaderCount = raygenCount + missShaderCount + hitShaderCount + callableShaderCount; core::vector> debloatedShaders; // vector to hold all the debloated shaders, so the pointer from the new ShaderSpecInfo is not dangling debloatedShaders.reserve(shaderCount); - core::vector debloatedShaderSpecs(shaderCount); - auto outShaderSpecs = debloatedShaderSpecs.data(); + const auto missGroupCount = std::accumulate(params.begin(), params.end(), 0, [](uint32_t sum, auto& param) + { + return sum + param.shaderGroups.misses.size(); + }); + const auto hitGroupCount = std::accumulate(params.begin(), params.end(), 0, [](uint32_t sum, auto& param) + { + return sum + param.shaderGroups.hits.size(); + }); + const auto callableGroupCount = std::accumulate(params.begin(), params.end(), 0, [](uint32_t sum, auto& param) + { + return sum + param.shaderGroups.callables.size(); + }); + + + core::vector debloatedMissSpecs(missGroupCount); + auto debloatedMissSpecData = debloatedMissSpecs.data(); + core::vector debloatedHitSpecs(hitGroupCount); + auto debloatedHitSpecData = debloatedHitSpecs.data(); + core::vector debloatedCallableSpecs(callableGroupCount); + auto debloatedCallableSpecData = debloatedCallableSpecs.data(); const auto& limits = getPhysicalDeviceLimits(); for (auto ix = 0u; ix < params.size(); ix++) @@ -1050,14 +1146,47 @@ bool ILogicalDevice::createRayTracingPipelines(IGPUPipelineCache* const pipeline NBL_LOG_ERROR("Invalid maxRecursionDepth. maxRecursionDepth(%u) exceed the limits(%u)", param.cached.maxRecursionDepth, limits.maxRayRecursionDepth); return false; } - if (param.getShaders().empty()) + + SpirvDebloatTask debloatTask(m_spirvDebloater.get(), m_logger); + debloatTask.insertEntryPoint(param.shaderGroups.raygen, hlsl::ShaderStage::ESS_RAYGEN); + for (const auto& miss : param.shaderGroups.misses) + debloatTask.insertEntryPoint(miss, hlsl::ShaderStage::ESS_MISS); + for (const auto& hit : param.shaderGroups.hits) { - NBL_LOG_ERROR("Pipeline must have at least one shader."); - return false; + debloatTask.insertEntryPoint(hit.closestHit, hlsl::ShaderStage::ESS_CLOSEST_HIT); + debloatTask.insertEntryPoint(hit.anyHit, hlsl::ShaderStage::ESS_ANY_HIT); + debloatTask.insertEntryPoint(hit.intersection, hlsl::ShaderStage::ESS_INTERSECTION); + } + for (const auto& callable : param.shaderGroups.callables) + debloatTask.insertEntryPoint(callable, hlsl::ShaderStage::ESS_CALLABLE); + + newParams[ix] = param; + newParams[ix].shaderGroups.raygen = debloatTask.debloat(param.shaderGroups.raygen, debloatedShaders); + + newParams[ix].shaderGroups.misses = { debloatedMissSpecData, param.shaderGroups.misses.size() }; + for (const auto& miss: param.shaderGroups.misses) + { + *debloatedMissSpecData = debloatTask.debloat(miss, debloatedShaders); + debloatedMissSpecData++; } - newParams[ix].shaders = std::span(outShaderSpecs, param.getShaders().size()); - debloatShaders(*m_spirvDebloater.get(), param.getShaders(), debloatedShaders, outShaderSpecs, m_logger); + newParams[ix].shaderGroups.hits = { debloatedHitSpecData, param.shaderGroups.hits.size() }; + for (const auto& hit: param.shaderGroups.hits) + { + *debloatedHitSpecData = { + .closestHit = debloatTask.debloat(hit.closestHit, debloatedShaders), + .intersection = debloatTask.debloat(hit.intersection, debloatedShaders), + .anyHit = debloatTask.debloat(hit.anyHit, debloatedShaders), + }; + debloatedHitSpecData++; + } + + newParams[ix].shaderGroups.callables = { debloatedCallableSpecData, param.shaderGroups.callables.size() }; + for (const auto& callable: param.shaderGroups.callables) + { + *debloatedCallableSpecData = debloatTask.debloat(callable, debloatedShaders); + debloatedCallableSpecData++; + } } createRayTracingPipelines_impl(pipelineCache, newParams,output,specConstantValidation); From f1fe0899869a762e377751ec9e85b68cde83e7f9 Mon Sep 17 00:00:00 2001 From: kevyuu Date: Fri, 23 May 2025 20:57:12 +0700 Subject: [PATCH 64/64] Remove unused funciton in ILogicalDevice.cpp --- src/nbl/video/ILogicalDevice.cpp | 52 -------------------------------- 1 file changed, 52 deletions(-) diff --git a/src/nbl/video/ILogicalDevice.cpp b/src/nbl/video/ILogicalDevice.cpp index d43ef7c58c..7714219836 100644 --- a/src/nbl/video/ILogicalDevice.cpp +++ b/src/nbl/video/ILogicalDevice.cpp @@ -54,58 +54,6 @@ class SpirvDebloatTask const system::logger_opt_ptr m_logger; }; -using DebloaterEntryPoints = core::set; -static void insertEntryPoint(const IGPUPipelineBase::SShaderSpecInfo& shaderSpec, hlsl::ShaderStage stage, - core::map entryPointsMap) -{ - const auto* shader = shaderSpec.shader; - auto it = entryPointsMap.find(shader); - if (it == entryPointsMap.end() || it->first != shader) - it = entryPointsMap.emplace_hint(it, shader, DebloaterEntryPoints()); - it->second.insert({ .name = shaderSpec.entryPoint, .stage = stage }); -}; - -static void debloatShaders(const asset::ISPIRVDebloater& debloater, std::span shaderSpecs, core::vector>& outShaders, IGPUPipelineBase::SShaderSpecInfo* outShaderSpecInfos, system::logger_opt_ptr logger = nullptr) -{ - using EntryPoints = core::set; - core::map entryPointsMap; - - - // collect all entry points first before we debloat - for (const auto& shaderSpec : shaderSpecs) { - const auto* shader = shaderSpec.shader; - auto it = entryPointsMap.find(shader); - if (it == entryPointsMap.end() || it->first != shader) - it = entryPointsMap.emplace_hint(it, shader, EntryPoints()); - it->second.insert({ .name = shaderSpec.entryPoint, .stage = shaderSpec.stage }); - } - - core::map debloatedShaders; - for (const auto& shaderSpec: shaderSpecs) - { - const auto* shader = shaderSpec.shader; - const auto& entryPoints = entryPointsMap[shader]; - - auto debloatedShaderSpec = shaderSpec; - if (shader != nullptr) - { - if (!debloatedShaders.contains(shader)) - { - const auto outShadersData = outShaders.data(); - outShaders.push_back(debloater.debloat(shader, entryPoints, logger)); - assert(outShadersData == outShaders.data()); - debloatedShaders.emplace(shader, outShaders.back().get()); - } - const auto debloatedShader = debloatedShaders[shader]; - debloatedShaderSpec.shader = debloatedShader; - } - *outShaderSpecInfos = debloatedShaderSpec; - - outShaderSpecInfos++; - } - -} - ILogicalDevice::ILogicalDevice(core::smart_refctd_ptr&& api, const IPhysicalDevice* const physicalDevice, const SCreationParams& params, const bool runningInRenderdoc) : m_api(api), m_physicalDevice(physicalDevice), m_enabledFeatures(params.featuresToEnable), m_compilerSet(params.compilerSet), m_logger(m_physicalDevice->getDebugCallback() ? m_physicalDevice->getDebugCallback()->getLogger() : nullptr),