diff --git a/examples_tests b/examples_tests index daea3f951b..dd466f6db4 160000 --- a/examples_tests +++ b/examples_tests @@ -1 +1 @@ -Subproject commit daea3f951b59a4b53cec81c44786f5934994176e +Subproject commit dd466f6db4bdedd66f60bacdcc62b1409b10baf5 diff --git a/include/nbl/asset/ICPUDescriptorSet.h b/include/nbl/asset/ICPUDescriptorSet.h index 805f8e1bed..7c49a385ea 100644 --- a/include/nbl/asset/ICPUDescriptorSet.h +++ b/include/nbl/asset/ICPUDescriptorSet.h @@ -67,7 +67,7 @@ class NBL_API2 ICPUDescriptorSet final : public IDescriptorSet getDescriptorInfoStorage(const IDescriptor::E_TYPE type) const + inline std::span getDescriptorInfoStorage(const IDescriptor::E_TYPE type) const { // TODO: @Hazardu // Cannot do the mutability check here because it requires the function to be non-const, but the function cannot be non-const because it's called @@ -78,14 +78,14 @@ class NBL_API2 ICPUDescriptorSet final : public IDescriptorSet(type)]) - return { nullptr, nullptr }; + return { }; else return { m_descriptorInfos[static_cast(type)]->begin(), m_descriptorInfos[static_cast(type)]->end() }; } - core::SRange getDescriptorInfos(const ICPUDescriptorSetLayout::CBindingRedirect::binding_number_t binding, IDescriptor::E_TYPE type = IDescriptor::E_TYPE::ET_COUNT); + std::span getDescriptorInfos(const ICPUDescriptorSetLayout::CBindingRedirect::binding_number_t binding, IDescriptor::E_TYPE type = IDescriptor::E_TYPE::ET_COUNT); - core::SRange getDescriptorInfos(const ICPUDescriptorSetLayout::CBindingRedirect::binding_number_t binding, IDescriptor::E_TYPE type = IDescriptor::E_TYPE::ET_COUNT) const; + std::span getDescriptorInfos(const ICPUDescriptorSetLayout::CBindingRedirect::binding_number_t binding, IDescriptor::E_TYPE type = IDescriptor::E_TYPE::ET_COUNT) const; core::smart_refctd_ptr clone(uint32_t _depth = ~0u) const override; @@ -99,38 +99,6 @@ class NBL_API2 ICPUDescriptorSet final : public IDescriptorSet m_descriptorInfos[static_cast(IDescriptor::E_TYPE::ET_COUNT)]; }; diff --git a/include/nbl/asset/ICPUDescriptorSetLayout.h b/include/nbl/asset/ICPUDescriptorSetLayout.h index c4e7041013..c80ad92167 100644 --- a/include/nbl/asset/ICPUDescriptorSetLayout.h +++ b/include/nbl/asset/ICPUDescriptorSetLayout.h @@ -34,20 +34,20 @@ class ICPUDescriptorSetLayout : public IDescriptorSetLayout, public for (uint32_t t = 0; t < static_cast(asset::IDescriptor::E_TYPE::ET_COUNT); ++t) cp->m_descriptorRedirects[t] = m_descriptorRedirects[t].clone(); cp->m_immutableSamplerRedirect = m_immutableSamplerRedirect.clone(); - cp->m_mutableSamplerRedirect = m_mutableSamplerRedirect.clone(); + cp->m_mutableCombinedSamplerRedirect = m_mutableCombinedSamplerRedirect.clone(); - if (m_samplers) + if (m_immutableSamplers) { - cp->m_samplers = core::make_refctd_dynamic_array(m_samplers->size()); + cp->m_immutableSamplers = core::make_refctd_dynamic_array(m_immutableSamplers->size()); if (_depth > 0u) { - for (size_t i = 0ull; i < m_samplers->size(); ++i) - (*cp->m_samplers)[i] = core::smart_refctd_ptr_static_cast((*m_samplers)[i]->clone(_depth - 1u)); + for (size_t i = 0ull; i < m_immutableSamplers->size(); ++i) + (*cp->m_immutableSamplers)[i] = core::smart_refctd_ptr_static_cast((*m_immutableSamplers)[i]->clone(_depth - 1u)); } else { - std::copy(m_samplers->begin(), m_samplers->end(), cp->m_samplers->begin()); + std::copy(m_immutableSamplers->begin(), m_immutableSamplers->end(), cp->m_immutableSamplers->begin()); } } @@ -60,9 +60,9 @@ class ICPUDescriptorSetLayout : public IDescriptorSetLayout, public for (uint32_t t = 0; t < static_cast(asset::IDescriptor::E_TYPE::ET_COUNT); ++t) result += m_descriptorRedirects[t].conservativeSizeEstimate(); result += m_immutableSamplerRedirect.conservativeSizeEstimate(); - result += m_mutableSamplerRedirect.conservativeSizeEstimate(); + result += m_mutableCombinedSamplerRedirect.conservativeSizeEstimate(); - result += m_samplers->size() * sizeof(void*); + result += m_immutableSamplers->size() * sizeof(void*); return result; } @@ -74,9 +74,9 @@ class ICPUDescriptorSetLayout : public IDescriptorSetLayout, public if (referenceLevelsBelowToConvert) { --referenceLevelsBelowToConvert; - if (m_samplers) + if (m_immutableSamplers) { - for (auto it=m_samplers->begin(); it!=m_samplers->end(); it++) + for (auto it=m_immutableSamplers->begin(); it!=m_immutableSamplers->end(); it++) it->get()->convertToDummyObject(referenceLevelsBelowToConvert); } } @@ -90,15 +90,15 @@ class ICPUDescriptorSetLayout : public IDescriptorSetLayout, public auto* other = static_cast(_other); if (getTotalBindingCount() != other->getTotalBindingCount()) return false; - if ((!m_samplers) != (!other->m_samplers)) + if ((!m_immutableSamplers) != (!other->m_immutableSamplers)) return false; - if (m_samplers && m_samplers->size() != other->m_samplers->size()) + if (m_immutableSamplers && m_immutableSamplers->size() != other->m_immutableSamplers->size()) return false; - if (m_samplers) + if (m_immutableSamplers) { - for (uint32_t i = 0u; i < m_samplers->size(); ++i) + for (uint32_t i = 0u; i < m_immutableSamplers->size(); ++i) { - if (!(*m_samplers)[i]->canBeRestoredFrom((*other->m_samplers)[i].get())) + if (!(*m_immutableSamplers)[i]->canBeRestoredFrom((*other->m_immutableSamplers)[i].get())) return false; } } @@ -115,21 +115,21 @@ class ICPUDescriptorSetLayout : public IDescriptorSetLayout, public return; --_levelsBelow; - if (m_samplers) + if (m_immutableSamplers) { - for (uint32_t i = 0u; i < m_samplers->size(); ++i) - restoreFromDummy_impl_call((*m_samplers)[i].get(), (*other->m_samplers)[i].get(), _levelsBelow); + for (uint32_t i = 0u; i < m_immutableSamplers->size(); ++i) + restoreFromDummy_impl_call((*m_immutableSamplers)[i].get(), (*other->m_immutableSamplers)[i].get(), _levelsBelow); } } bool isAnyDependencyDummy_impl(uint32_t _levelsBelow) const override { --_levelsBelow; - if (m_samplers) + if (m_immutableSamplers) { - for (uint32_t i = 0u; i < m_samplers->size(); ++i) + for (uint32_t i = 0u; i < m_immutableSamplers->size(); ++i) { - if ((*m_samplers)[i]->isAnyDependencyDummy(_levelsBelow)) + if ((*m_immutableSamplers)[i]->isAnyDependencyDummy(_levelsBelow)) return true; } } diff --git a/include/nbl/asset/ICPUSampler.h b/include/nbl/asset/ICPUSampler.h index e93538e693..384ddb8846 100644 --- a/include/nbl/asset/ICPUSampler.h +++ b/include/nbl/asset/ICPUSampler.h @@ -77,7 +77,7 @@ class ICPUSampler : public ISampler, public IAsset _NBL_STATIC_INLINE_CONSTEXPR auto AssetType = ET_SAMPLER; - inline E_TYPE getAssetType() const override { return AssetType; } + inline IAsset::E_TYPE getAssetType() const override { return AssetType; } bool canBeRestoredFrom(const IAsset* _other) const override { diff --git a/include/nbl/asset/IDescriptor.h b/include/nbl/asset/IDescriptor.h index 1792491558..c315308582 100644 --- a/include/nbl/asset/IDescriptor.h +++ b/include/nbl/asset/IDescriptor.h @@ -14,7 +14,9 @@ class IDescriptor : public virtual core::IReferenceCounted public: enum class E_TYPE : uint8_t { - ET_COMBINED_IMAGE_SAMPLER = 0, + ET_SAMPLER = 0, + ET_COMBINED_IMAGE_SAMPLER, + ET_SAMPLED_IMAGE, ET_STORAGE_IMAGE, ET_UNIFORM_TEXEL_BUFFER, ET_STORAGE_TEXEL_BUFFER, @@ -39,6 +41,7 @@ class IDescriptor : public virtual core::IReferenceCounted enum E_CATEGORY : uint8_t { EC_BUFFER = 0, + EC_SAMPLER, EC_IMAGE, EC_BUFFER_VIEW, EC_ACCELERATION_STRUCTURE, @@ -48,24 +51,23 @@ class IDescriptor : public virtual core::IReferenceCounted { switch (type) { + case E_TYPE::ET_SAMPLER: + return EC_SAMPLER; case E_TYPE::ET_COMBINED_IMAGE_SAMPLER: + case E_TYPE::ET_SAMPLED_IMAGE: case E_TYPE::ET_STORAGE_IMAGE: case E_TYPE::ET_INPUT_ATTACHMENT: return EC_IMAGE; - break; case E_TYPE::ET_UNIFORM_TEXEL_BUFFER: case E_TYPE::ET_STORAGE_TEXEL_BUFFER: return EC_BUFFER_VIEW; - break; case E_TYPE::ET_UNIFORM_BUFFER: case E_TYPE::ET_STORAGE_BUFFER: case E_TYPE::ET_UNIFORM_BUFFER_DYNAMIC: case E_TYPE::ET_STORAGE_BUFFER_DYNAMIC: return EC_BUFFER; - break; case E_TYPE::ET_ACCELERATION_STRUCTURE: return EC_ACCELERATION_STRUCTURE; - break; default: break; } diff --git a/include/nbl/asset/IDescriptorSet.h b/include/nbl/asset/IDescriptorSet.h index a4aca538b4..418446be1b 100644 --- a/include/nbl/asset/IDescriptorSet.h +++ b/include/nbl/asset/IDescriptorSet.h @@ -45,25 +45,28 @@ class IDescriptorSet : public virtual core::IReferenceCounted // TODO: try to re auto operator<=>(const SBufferInfo&) const = default; }; - struct SImageInfo - { - // This will be ignored if the DS layout already has an immutable sampler specified for the binding. - core::smart_refctd_ptr sampler; - IImage::LAYOUT imageLayout; - }; + struct SImageInfo + { + IImage::LAYOUT imageLayout; + }; + struct SCombinedImageSamplerInfo : SImageInfo + { + core::smart_refctd_ptr sampler; + }; core::smart_refctd_ptr desc; union SBufferImageInfo { SBufferImageInfo() { - memset(&buffer, 0, core::max(sizeof(buffer), sizeof(image))); + memset(&buffer, 0, core::max(sizeof(buffer), sizeof(combinedImageSampler))); }; ~SBufferImageInfo() {}; SBufferInfo buffer; SImageInfo image; + SCombinedImageSamplerInfo combinedImageSampler; } info; SDescriptorInfo() {} @@ -92,26 +95,29 @@ class IDescriptorSet : public virtual core::IReferenceCounted // TODO: try to re } ~SDescriptorInfo() { - if (desc && desc->getTypeCategory()==IDescriptor::EC_IMAGE) - info.image.sampler = nullptr; + if (desc && desc->getTypeCategory() == IDescriptor::EC_IMAGE) + info.combinedImageSampler.sampler = nullptr; } inline SDescriptorInfo& operator=(const SDescriptorInfo& other) { - if (desc && desc->getTypeCategory()==IDescriptor::EC_IMAGE) - info.image.sampler = nullptr; + if (desc and desc->getTypeCategory()==IDescriptor::EC_IMAGE) + info.combinedImageSampler.sampler = nullptr; desc = other.desc; - const auto type = desc->getTypeCategory(); - if (type!=IDescriptor::EC_IMAGE) - info.buffer = other.info.buffer; - else - info.image = other.info.image; + if (desc) + { + const auto type = desc->getTypeCategory(); + if (type != IDescriptor::EC_IMAGE) + info.buffer = other.info.buffer; + else + info.combinedImageSampler = other.info.combinedImageSampler; + } return *this; } inline SDescriptorInfo& operator=(SDescriptorInfo&& other) { - if (desc && desc->getTypeCategory()==IDescriptor::EC_IMAGE) - info.image = {nullptr,IImage::LAYOUT::UNDEFINED}; + if (desc and desc->getTypeCategory() == IDescriptor::EC_IMAGE) + info.combinedImageSampler = {IImage::LAYOUT::UNDEFINED, nullptr}; desc = std::move(other.desc); if (desc) { @@ -119,14 +125,14 @@ class IDescriptorSet : public virtual core::IReferenceCounted // TODO: try to re if (type!=IDescriptor::EC_IMAGE) info.buffer = other.info.buffer; else - info.image = other.info.image; + info.combinedImageSampler = other.info.combinedImageSampler; } return *this; } inline bool operator!=(const SDescriptorInfo& other) const { - if (desc != desc) + if (desc != other.desc) return true; return info.buffer != other.info.buffer; } diff --git a/include/nbl/asset/IDescriptorSetLayout.h b/include/nbl/asset/IDescriptorSetLayout.h index fac0a0d136..0e980b9bea 100644 --- a/include/nbl/asset/IDescriptorSetLayout.h +++ b/include/nbl/asset/IDescriptorSetLayout.h @@ -57,9 +57,9 @@ class IDescriptorSetLayout : public virtual core::IReferenceCounted // TODO: tr core::bitflag createFlags; core::bitflag stageFlags; uint32_t count; - // Use this if you want an immutable sampler that is baked into the DS layout itself. - // If its `nullptr` then the sampler used is mutable and can be specified while writing the image descriptor to a binding while updating the DS. - const core::smart_refctd_ptr* samplers; + // Use this if you want immutable samplers that are baked into the DS layout itself. + // If it's `nullptr` then the samplers used are mutable and can be specified while writing the image descriptor to a binding while updating the DS. + const core::smart_refctd_ptr* immutableSamplers; }; // Maps a binding to a local (to descriptor set layout) offset. @@ -70,19 +70,22 @@ class IDescriptorSetLayout : public virtual core::IReferenceCounted // TODO: tr struct binding_number_t { - inline binding_number_t(const uint32_t d) : data(d) {} + explicit inline binding_number_t(const uint32_t d) : data(d) {} + inline binding_number_t() : data(0) {} uint32_t data; }; struct storage_offset_t { - inline storage_offset_t(const uint32_t d) : data(d) {} + explicit inline storage_offset_t(const uint32_t d) : data(d) {} + inline storage_offset_t() : data(0) {} uint32_t data; }; struct storage_range_index_t { - inline storage_range_index_t(const uint32_t d) : data(d) {} + explicit inline storage_range_index_t(const uint32_t d) : data(d) {} + inline storage_range_index_t() : data(0) {} uint32_t data; }; @@ -93,18 +96,18 @@ class IDescriptorSetLayout : public virtual core::IReferenceCounted // TODO: tr inline storage_range_index_t findBindingStorageIndex(const binding_number_t binding) const { if (!m_bindingNumbers) - return { Invalid }; + return storage_range_index_t(Invalid); assert(m_storageOffsets && (m_count != 0u)); auto found = std::lower_bound(m_bindingNumbers, m_bindingNumbers + m_count, binding, [](binding_number_t a, binding_number_t b) -> bool {return a.data < b.data; }); if ((found >= m_bindingNumbers + m_count) || (found->data != binding.data)) - return { Invalid }; + return storage_range_index_t(Invalid); const uint32_t foundIndex = found - m_bindingNumbers; assert(foundIndex < m_count); - return { foundIndex }; + return storage_range_index_t(foundIndex); } inline binding_number_t getBinding(const storage_range_index_t index) const @@ -134,7 +137,7 @@ class IDescriptorSetLayout : public virtual core::IReferenceCounted // TODO: tr inline storage_offset_t getStorageOffset(const storage_range_index_t index) const { assert(index.data < m_count); - return (index.data == 0u) ? 0u : m_storageOffsets[index.data - 1]; + return storage_offset_t((index.data == 0u) ? 0u : m_storageOffsets[index.data - 1].data); } // The following are merely convenience functions for one off use. @@ -162,7 +165,7 @@ class IDescriptorSetLayout : public virtual core::IReferenceCounted // TODO: tr { const auto index = findBindingStorageIndex(binding); if (index.data == Invalid) - return { Invalid }; + return storage_offset_t(Invalid); return getStorageOffset(index); } @@ -308,19 +311,19 @@ class IDescriptorSetLayout : public virtual core::IReferenceCounted // TODO: tr for (uint32_t b = 0u; b < bindingCnt; ++b) { - uint32_t bindingNumber = m_descriptorRedirects[t].m_bindingNumbers[b].data; - uint32_t otherBindingNumber = CBindingRedirect::Invalid; + auto bindingNumber = m_descriptorRedirects[t].m_bindingNumbers[b]; + CBindingRedirect::template binding_number_t otherBindingNumber(CBindingRedirect::Invalid); // TODO: std::find instead? for (uint32_t ob = 0u; ob < otherBindingCnt; ++ob) { - if (bindingNumber == other->m_descriptorRedirects[t].m_bindingNumbers[ob].data) + if (bindingNumber.data == other->m_descriptorRedirects[t].m_bindingNumbers[ob].data) { - otherBindingNumber = ob; + otherBindingNumber.data = ob; break; } } - if (otherBindingNumber == CBindingRedirect::Invalid) + if (otherBindingNumber.data == CBindingRedirect::Invalid) return false; @@ -363,18 +366,20 @@ class IDescriptorSetLayout : public virtual core::IReferenceCounted // TODO: tr if (!areRedirectsEqual(m_immutableSamplerRedirect, _other->m_immutableSamplerRedirect)) return false; - if (!areRedirectsEqual(m_mutableSamplerRedirect, _other->m_mutableSamplerRedirect)) + if (!areRedirectsEqual(m_mutableCombinedSamplerRedirect, _other->m_mutableCombinedSamplerRedirect)) return false; - if (m_samplers && _other->m_samplers) - return std::equal(m_samplers->begin(), m_samplers->end(), _other->m_samplers->begin(), _other->m_samplers->end()); + if (m_immutableSamplers && _other->m_immutableSamplers) + return std::equal(m_immutableSamplers->begin(), m_immutableSamplers->end(), _other->m_immutableSamplers->begin(), _other->m_immutableSamplers->end()); else - return !m_samplers && !_other->m_samplers; + return !m_immutableSamplers && !_other->m_immutableSamplers; } - inline uint32_t getTotalMutableSamplerCount() const { return m_mutableSamplerRedirect.getTotalCount(); } + inline uint32_t getTotalMutableCombinedSamplerCount() const { return m_mutableCombinedSamplerRedirect.getTotalCount(); } + // Immutable sampler descriptors are not counted here inline uint32_t getTotalDescriptorCount(const IDescriptor::E_TYPE type) const { return m_descriptorRedirects[static_cast(type)].getTotalCount(); } + // Immutable sampler bindings are not counted here inline uint32_t getTotalBindingCount() const { uint32_t result = 0u; @@ -386,14 +391,14 @@ class IDescriptorSetLayout : public virtual core::IReferenceCounted // TODO: tr inline const CBindingRedirect& getDescriptorRedirect(const IDescriptor::E_TYPE type) const { return m_descriptorRedirects[static_cast(type)]; } inline const CBindingRedirect& getImmutableSamplerRedirect() const { return m_immutableSamplerRedirect; } - inline const CBindingRedirect& getMutableSamplerRedirect() const { return m_mutableSamplerRedirect; } + inline const CBindingRedirect& getMutableCombinedSamplerRedirect() const { return m_mutableCombinedSamplerRedirect; } inline core::SRange> getImmutableSamplers() const { - if (!m_samplers) + if (!m_immutableSamplers) return { nullptr, nullptr }; - return { m_samplers->cbegin(), m_samplers->cend() }; + return { m_immutableSamplers->cbegin(), m_immutableSamplers->cend() }; } protected: @@ -405,14 +410,22 @@ class IDescriptorSetLayout : public virtual core::IReferenceCounted // TODO: tr for (const auto& b : _bindings) { - buildInfo_descriptors[static_cast(b.type)].emplace_back(b.binding, b.createFlags, b.stageFlags, b.count); - - if (b.type == IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER) - { - if (b.samplers) - buildInfo_immutableSamplers.emplace_back(b.binding, b.createFlags, b.stageFlags, b.count); - else - buildInfo_mutableSamplers.emplace_back(b.binding, b.createFlags, b.stageFlags, b.count); + switch (b.type) { + case IDescriptor::E_TYPE::ET_SAMPLER: + if (b.immutableSamplers) + buildInfo_immutableSamplers.emplace_back(b.binding, b.createFlags, b.stageFlags, b.count); + else + buildInfo_descriptors[size_t(IDescriptor::E_TYPE::ET_SAMPLER)].emplace_back(b.binding, b.createFlags, b.stageFlags, b.count); + break; + case IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER: + if (b.immutableSamplers) + buildInfo_immutableSamplers.emplace_back(b.binding, b.createFlags, b.stageFlags, b.count); + else + buildInfo_mutableSamplers.emplace_back(b.binding, b.createFlags, b.stageFlags, b.count); + [[fallthrough]]; + default: + buildInfo_descriptors[static_cast(b.type)].emplace_back(b.binding, b.createFlags, b.stageFlags, b.count); + break; } } @@ -420,20 +433,20 @@ class IDescriptorSetLayout : public virtual core::IReferenceCounted // TODO: tr m_descriptorRedirects[type] = CBindingRedirect(std::move(buildInfo_descriptors[type])); m_immutableSamplerRedirect = CBindingRedirect(std::move(buildInfo_immutableSamplers)); - m_mutableSamplerRedirect = CBindingRedirect(std::move(buildInfo_mutableSamplers)); + m_mutableCombinedSamplerRedirect = CBindingRedirect(std::move(buildInfo_mutableSamplers)); const uint32_t immutableSamplerCount = m_immutableSamplerRedirect.getTotalCount(); - m_samplers = immutableSamplerCount ? core::make_refctd_dynamic_array>>(immutableSamplerCount) : nullptr; + m_immutableSamplers = immutableSamplerCount ? core::make_refctd_dynamic_array>>(immutableSamplerCount) : nullptr; for (const auto& b : _bindings) { - if (b.type == IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER && b.samplers) + if ((b.type == IDescriptor::E_TYPE::ET_SAMPLER or b.type == IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER) and b.immutableSamplers) { const auto localOffset = m_immutableSamplerRedirect.getStorageOffset(typename CBindingRedirect::binding_number_t(b.binding)).data; assert(localOffset != m_immutableSamplerRedirect.Invalid); - auto* dst = m_samplers->begin() + localOffset; - std::copy_n(b.samplers, b.count, dst); + auto* dst = m_immutableSamplers->begin() + localOffset; + std::copy_n(b.immutableSamplers, b.count, dst); } } } @@ -442,9 +455,9 @@ class IDescriptorSetLayout : public virtual core::IReferenceCounted // TODO: tr CBindingRedirect m_descriptorRedirects[static_cast(asset::IDescriptor::E_TYPE::ET_COUNT)]; CBindingRedirect m_immutableSamplerRedirect; - CBindingRedirect m_mutableSamplerRedirect; + CBindingRedirect m_mutableCombinedSamplerRedirect; - core::smart_refctd_dynamic_array> m_samplers = nullptr; + core::smart_refctd_dynamic_array> m_immutableSamplers = nullptr; }; } diff --git a/include/nbl/asset/ISampler.h b/include/nbl/asset/ISampler.h index d5d5b9157a..c9f7aa9834 100644 --- a/include/nbl/asset/ISampler.h +++ b/include/nbl/asset/ISampler.h @@ -12,7 +12,7 @@ namespace nbl namespace asset { -class ISampler : public virtual core::IReferenceCounted +class ISampler : public IDescriptor { public: //! Texture coord clamp mode outside [0.0, 1.0] @@ -120,6 +120,8 @@ class ISampler : public virtual core::IReferenceCounted } PACK_STRUCT; #include "nbl/nblunpack.h" + E_CATEGORY getTypeCategory() const override { return EC_SAMPLER; } + protected: ISampler(const SParams& _params) : m_params(_params) {} virtual ~ISampler() = default; diff --git a/include/nbl/asset/metadata/IRenderpassIndependentPipelineMetadata.h b/include/nbl/asset/metadata/IRenderpassIndependentPipelineMetadata.h index 1cb6dcbc2f..416c04823b 100644 --- a/include/nbl/asset/metadata/IRenderpassIndependentPipelineMetadata.h +++ b/include/nbl/asset/metadata/IRenderpassIndependentPipelineMetadata.h @@ -107,7 +107,9 @@ class IRenderpassIndependentPipelineMetadata : public core::Interface }; enum class E_TYPE: uint8_t { + ET_SAMPLER = nbl::core::to_underlying(IDescriptor::E_TYPE::ET_SAMPLER), ET_COMBINED_IMAGE_SAMPLER = nbl::core::to_underlying(IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER), + ET_SAMPLED_IMAGE = nbl::core::to_underlying(IDescriptor::E_TYPE::ET_SAMPLED_IMAGE), ET_STORAGE_IMAGE = nbl::core::to_underlying(IDescriptor::E_TYPE::ET_STORAGE_IMAGE), ET_UNIFORM_TEXEL_BUFFER = nbl::core::to_underlying(IDescriptor::E_TYPE::ET_UNIFORM_TEXEL_BUFFER), ET_STORAGE_TEXEL_BUFFER = nbl::core::to_underlying(IDescriptor::E_TYPE::ET_STORAGE_TEXEL_BUFFER), diff --git a/include/nbl/asset/utils/ICPUVirtualTexture.h b/include/nbl/asset/utils/ICPUVirtualTexture.h index d1bcd96339..b20f142160 100644 --- a/include/nbl/asset/utils/ICPUVirtualTexture.h +++ b/include/nbl/asset/utils/ICPUVirtualTexture.h @@ -535,8 +535,9 @@ class ICPUVirtualTexture final : public IVirtualTexturegetDescriptorInfos(_pgtBinding, IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER); + auto pgtInfos = _dstSet->getDescriptorInfos(redirect_t::binding_number_t(_pgtBinding), IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER); if (pgtInfos.empty()) return false; // TODO: Log @@ -545,13 +546,13 @@ class ICPUVirtualTexture final : public IVirtualTexture(getPageTableView()); } auto updateSamplersBinding = [&](const uint32_t binding, const auto& views) -> bool { - auto infos = _dstSet->getDescriptorInfos(binding, IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER); + auto infos = _dstSet->getDescriptorInfos(redirect_t::binding_number_t(binding), IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER); if (infos.size() < views.size()) return false; // TODO: Log @@ -561,7 +562,7 @@ class ICPUVirtualTexture final : public IVirtualTexturecreateDescriptorSetLayout(bindings); } diff --git a/include/nbl/video/CVulkanCommon.h b/include/nbl/video/CVulkanCommon.h index de21c85963..1af4dd886e 100644 --- a/include/nbl/video/CVulkanCommon.h +++ b/include/nbl/video/CVulkanCommon.h @@ -997,8 +997,12 @@ inline constexpr VkDescriptorType getVkDescriptorTypeFromDescriptorType(const as { switch (descriptorType) { + case asset::IDescriptor::E_TYPE::ET_SAMPLER: + return VK_DESCRIPTOR_TYPE_SAMPLER; case asset::IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER: return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + case asset::IDescriptor::E_TYPE::ET_SAMPLED_IMAGE: + return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; case asset::IDescriptor::E_TYPE::ET_STORAGE_IMAGE: return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; case asset::IDescriptor::E_TYPE::ET_UNIFORM_TEXEL_BUFFER: diff --git a/include/nbl/video/IDescriptorPool.h b/include/nbl/video/IDescriptorPool.h index 236a3c912e..e4844bfcd5 100644 --- a/include/nbl/video/IDescriptorPool.h +++ b/include/nbl/video/IDescriptorPool.h @@ -55,7 +55,7 @@ class NBL_API2 IDescriptorPool : public IBackendObject return data[idx]; } - inline uint32_t getMutableSamplerOffset() const { return data[static_cast(asset::IDescriptor::E_TYPE::ET_COUNT)]; } + inline uint32_t getMutableCombinedSamplerOffset() const { return data[static_cast(asset::IDescriptor::E_TYPE::ET_COUNT)]; } inline uint32_t getSetOffset() const { return data[static_cast(asset::IDescriptor::E_TYPE::ET_COUNT) + 1]; } inline uint32_t& getSetOffset() { return data[static_cast(asset::IDescriptor::E_TYPE::ET_COUNT) + 1]; } @@ -101,7 +101,11 @@ class NBL_API2 IDescriptorPool : public IBackendObject core::smart_refctd_ptr* baseAddress; switch (type) { + case asset::IDescriptor::E_TYPE::ET_SAMPLER: + baseAddress = reinterpret_cast*>(m_mutableStandaloneSamplerStorage.get()); + break; case asset::IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER: + case asset::IDescriptor::E_TYPE::ET_SAMPLED_IMAGE: baseAddress = reinterpret_cast*>(m_textureStorage.get()); break; case asset::IDescriptor::E_TYPE::ET_STORAGE_IMAGE: @@ -139,9 +143,9 @@ class NBL_API2 IDescriptorPool : public IBackendObject return baseAddress; } - inline core::smart_refctd_ptr* getMutableSamplerStorage() const + inline core::smart_refctd_ptr* getMutableCombinedSamplerStorage() const { - return reinterpret_cast*>(m_mutableSamplerStorage.get()); + return reinterpret_cast*>(m_mutableCombinedSamplerStorage.get()); } friend class IGPUDescriptorSet; @@ -218,7 +222,8 @@ class NBL_API2 IDescriptorPool : public IBackendObject std::unique_ptr m_allocatedDescriptorSets = nullptr; // This array might be sparse. std::unique_ptr>[]> m_textureStorage; - std::unique_ptr>[]> m_mutableSamplerStorage; + std::unique_ptr>[]> m_mutableCombinedSamplerStorage; + std::unique_ptr>[]> m_mutableStandaloneSamplerStorage; std::unique_ptr>[]> m_storageImageStorage; // storage image | input attachment std::unique_ptr>[]> m_UBO_SSBOStorage; // ubo | ssbo | ubo dynamic | ssbo dynamic std::unique_ptr>[]> m_UTB_STBStorage; // utb | stb diff --git a/include/nbl/video/IGPUDescriptorSet.h b/include/nbl/video/IGPUDescriptorSet.h index c8ce45b097..ca2619d999 100644 --- a/include/nbl/video/IGPUDescriptorSet.h +++ b/include/nbl/video/IGPUDescriptorSet.h @@ -57,19 +57,29 @@ class IGPUDescriptorSet : public asset::IDescriptorSet(asset::IDescriptor::E_TYPE::ET_COUNT); t++) + for (auto t = 0u; t < static_cast(asset::IDescriptor::E_TYPE::ET_COUNT); t++) { const auto type = static_cast(t); const auto& bindingRedirect = getLayout()->getDescriptorRedirect(type); - if (bindingRedirect.getStorageOffset(redirect_t::binding_number_t{binding}).data!=redirect_t::Invalid) + bindingStorageIndex = bindingRedirect.findBindingStorageIndex(binding); + if (bindingStorageIndex.data != redirect_t::Invalid) return type; } return asset::IDescriptor::E_TYPE::ET_COUNT; } + // If you only need the type + inline asset::IDescriptor::E_TYPE getBindingType(const IGPUDescriptorSetLayout::CBindingRedirect::binding_number_t binding) const + { + IGPUDescriptorSetLayout::CBindingRedirect::storage_range_index_t dummy(0); + return getBindingType(binding, dummy); + } + + + protected: IGPUDescriptorSet(core::smart_refctd_ptr&& _layout, core::smart_refctd_ptr&& pool, IDescriptorPool::SStorageOffsets&& offsets); virtual ~IGPUDescriptorSet(); @@ -77,18 +87,37 @@ class IGPUDescriptorSet : public asset::IDescriptorSet* getDescriptors(const asset::IDescriptor::E_TYPE type, const uint32_t binding) const + inline core::smart_refctd_ptr* getDescriptors(const asset::IDescriptor::E_TYPE type, const redirect_t::binding_number_t binding) const { - const auto localOffset = getLayout()->getDescriptorRedirect(type).getStorageOffset(redirect_t::binding_number_t{ binding }).data; + const auto localOffset = getLayout()->getDescriptorRedirect(type).getStorageOffset(binding).data; if (localOffset == ~0) return nullptr; @@ -99,13 +128,41 @@ class IGPUDescriptorSet : public asset::IDescriptorSet* getMutableSamplers(const uint32_t binding) const + // Same as above, but amortizes lookup if you already have an index into the type's redirect + inline core::smart_refctd_ptr* getDescriptors(const asset::IDescriptor::E_TYPE type, const redirect_t::storage_range_index_t bindingStorageIndex) const + { + const auto localOffset = getLayout()->getDescriptorRedirect(type).getStorageOffset(bindingStorageIndex).data; + if (localOffset == ~0) + return nullptr; + + auto* descriptors = getAllDescriptors(type); + if (!descriptors) + return nullptr; + + return descriptors + localOffset; + } + + inline core::smart_refctd_ptr* getMutableCombinedSamplers(const redirect_t::binding_number_t binding) const + { + const auto localOffset = getLayout()->getMutableCombinedSamplerRedirect().getStorageOffset(binding).data; + if (localOffset == getLayout()->getMutableCombinedSamplerRedirect().Invalid) + return nullptr; + + auto* samplers = getAllMutableCombinedSamplers(); + if (!samplers) + return nullptr; + + return samplers + localOffset; + } + + // Same as above, but amortizes lookup if you already have an index + inline core::smart_refctd_ptr* getMutableCombinedSamplers(const redirect_t::storage_range_index_t bindingStorageIndex) const { - const auto localOffset = getLayout()->getMutableSamplerRedirect().getStorageOffset(redirect_t::binding_number_t{ binding }).data; - if (localOffset == getLayout()->getMutableSamplerRedirect().Invalid) + const auto localOffset = getLayout()->getMutableCombinedSamplerRedirect().getStorageOffset(bindingStorageIndex).data; + if (localOffset == getLayout()->getMutableCombinedSamplerRedirect().Invalid) return nullptr; - auto* samplers = getAllMutableSamplers(); + auto* samplers = getAllMutableCombinedSamplers(); if (!samplers) return nullptr; @@ -125,13 +182,13 @@ class IGPUDescriptorSet : public asset::IDescriptorSet* getAllMutableSamplers() const + inline core::smart_refctd_ptr* getAllMutableCombinedSamplers() const { - auto* baseAddress = m_pool->getMutableSamplerStorage(); + auto* baseAddress = m_pool->getMutableCombinedSamplerStorage(); if (baseAddress == nullptr) return nullptr; - const auto offset = m_storageOffsets.getMutableSamplerOffset(); + const auto offset = m_storageOffsets.getMutableCombinedSamplerOffset(); if (offset == ~0u) return nullptr; diff --git a/include/nbl/video/IGPUDescriptorSetLayout.h b/include/nbl/video/IGPUDescriptorSetLayout.h index 289468c046..afb1a3216c 100644 --- a/include/nbl/video/IGPUDescriptorSetLayout.h +++ b/include/nbl/video/IGPUDescriptorSetLayout.h @@ -24,25 +24,30 @@ class IGPUDescriptorSetLayout : public asset::IDescriptorSetLayout, using base_t = asset::IDescriptorSetLayout; public: + + inline bool versionChangeInvalidatesCommandBuffer() const { return m_versionChangeInvalidatesCommandBuffer; } + + static inline bool writeIncrementsVersion(const core::bitflag bindingCreateFlags) { + return not (bindingCreateFlags.hasFlags(SBinding::E_CREATE_FLAGS::ECF_UPDATE_AFTER_BIND_BIT) or bindingCreateFlags.hasFlags(SBinding::E_CREATE_FLAGS::ECF_UPDATE_UNUSED_WHILE_PENDING_BIT)); + } + + protected: inline IGPUDescriptorSetLayout(core::smart_refctd_ptr&& dev, const std::span _bindings) : base_t(_bindings), IBackendObject(std::move(dev)) { for (const auto& binding : _bindings) { - if (binding.createFlags.hasFlags(SBinding::E_CREATE_FLAGS::ECF_UPDATE_AFTER_BIND_BIT) || binding.createFlags.hasFlags(SBinding::E_CREATE_FLAGS::ECF_UPDATE_UNUSED_WHILE_PENDING_BIT)) + if (not (binding.createFlags.hasFlags(SBinding::E_CREATE_FLAGS::ECF_UPDATE_AFTER_BIND_BIT) or binding.createFlags.hasFlags(SBinding::E_CREATE_FLAGS::ECF_UPDATE_UNUSED_WHILE_PENDING_BIT))) { - m_canUpdateAfterBind = true; + m_versionChangeInvalidatesCommandBuffer = true; break; } } } - inline bool canUpdateAfterBind() const { return m_canUpdateAfterBind; } - - protected: virtual ~IGPUDescriptorSetLayout() = default; bool m_isPushDescLayout = false; - bool m_canUpdateAfterBind = false; + bool m_versionChangeInvalidatesCommandBuffer = false; }; } diff --git a/include/nbl/video/ILogicalDevice.h b/include/nbl/video/ILogicalDevice.h index da87b69a1a..84557c2edb 100644 --- a/include/nbl/video/ILogicalDevice.h +++ b/include/nbl/video/ILogicalDevice.h @@ -891,7 +891,7 @@ class NBL_API2 ILogicalDevice : public core::IReferenceCounted, public IDeviceMe const asset::IDescriptor::E_TYPE* pWriteTypes; uint32_t bufferCount = 0u; uint32_t bufferViewCount = 0u; - uint32_t imageCount = 0u; + uint32_t imageCount = 0u; // combined image/samplers as well as samplers belong here, since they're written through a VkDescriptorImageInfo uint32_t accelerationStructureCount = 0u; uint32_t accelerationStructureWriteCount = 0u; }; diff --git a/src/nbl/asset/IAssetManager.cpp b/src/nbl/asset/IAssetManager.cpp index b6a93b75ca..fc3d9b0de0 100644 --- a/src/nbl/asset/IAssetManager.cpp +++ b/src/nbl/asset/IAssetManager.cpp @@ -245,7 +245,7 @@ void IAssetManager::insertBuiltinAssets() binding3.type = IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER; binding3.count = 1u; binding3.stageFlags = static_cast(asset::ICPUShader::ESS_FRAGMENT); - binding3.samplers = nullptr; + binding3.immutableSamplers = nullptr; auto ds3Layout = core::make_smart_refctd_ptr(&binding3, &binding3 + 1); addBuiltInToCaches(ds3Layout, "nbl/builtin/material/lambertian/singletexture/descriptor_set_layout/3"); // TODO find everything what has been using it so far @@ -360,7 +360,7 @@ void IAssetManager::insertBuiltinAssets() //for filling this UBO with actual data, one can use asset::SBasicViewParameters struct defined in nbl/asset/asset_utils.h asset::fillBufferWithDeadBeef(ubo.get()); - auto descriptorInfos = ds1->getDescriptorInfos(0u, IDescriptor::E_TYPE::ET_UNIFORM_BUFFER); + auto descriptorInfos = ds1->getDescriptorInfos(ICPUDescriptorSetLayout::CBindingRedirect::binding_number_t(0), IDescriptor::E_TYPE::ET_UNIFORM_BUFFER); descriptorInfos.begin()[0].desc = std::move(ubo); descriptorInfos.begin()[0].info.buffer.offset = 0ull; descriptorInfos.begin()[0].info.buffer.size = UBO_SZ; diff --git a/src/nbl/asset/ICPUDescriptorSet.cpp b/src/nbl/asset/ICPUDescriptorSet.cpp index 5cdf430fd9..9457fb2147 100644 --- a/src/nbl/asset/ICPUDescriptorSet.cpp +++ b/src/nbl/asset/ICPUDescriptorSet.cpp @@ -3,14 +3,14 @@ namespace nbl::asset { -core::SRange ICPUDescriptorSet::getDescriptorInfos(const ICPUDescriptorSetLayout::CBindingRedirect::binding_number_t binding, IDescriptor::E_TYPE type) +std::span ICPUDescriptorSet::getDescriptorInfos(const ICPUDescriptorSetLayout::CBindingRedirect::binding_number_t binding, IDescriptor::E_TYPE type) { assert(!isImmutable_debug()); auto immutableResult = const_cast(this)->getDescriptorInfos(binding, type); - return {const_cast(immutableResult.begin()), const_cast(immutableResult.end())}; + return {const_cast(immutableResult.data()), immutableResult.size()}; } -core::SRange ICPUDescriptorSet::getDescriptorInfos(const ICPUDescriptorSetLayout::CBindingRedirect::binding_number_t binding, IDescriptor::E_TYPE type) const +std::span ICPUDescriptorSet::getDescriptorInfos(const ICPUDescriptorSetLayout::CBindingRedirect::binding_number_t binding, IDescriptor::E_TYPE type) const { if (type == IDescriptor::E_TYPE::ET_COUNT) { @@ -26,20 +26,20 @@ core::SRange ICPUDescriptorSet::getDes } if (type == IDescriptor::E_TYPE::ET_COUNT) - return { nullptr, nullptr }; + return { }; } const auto& redirect = getLayout()->getDescriptorRedirect(type); const auto bindingNumberIndex = redirect.findBindingStorageIndex(binding); if (bindingNumberIndex.data == redirect.Invalid) - return { nullptr, nullptr }; + return { }; const auto offset = redirect.getStorageOffset(asset::ICPUDescriptorSetLayout::CBindingRedirect::storage_range_index_t{ bindingNumberIndex }).data; const auto count = redirect.getCount(asset::ICPUDescriptorSetLayout::CBindingRedirect::storage_range_index_t{ bindingNumberIndex }); auto infosBegin = m_descriptorInfos[static_cast(type)]->begin() + offset; - return { infosBegin, infosBegin + count }; + return { infosBegin, count }; } core::smart_refctd_ptr ICPUDescriptorSet::clone(uint32_t _depth) const @@ -57,10 +57,10 @@ core::smart_refctd_ptr ICPUDescriptorSet::clone(uint32_t _depth) const const auto& srcDescriptorInfo = m_descriptorInfos[t]->begin()[i]; auto& dstDescriptorInfo = cp->m_descriptorInfos[t]->begin()[i]; - auto category = getCategoryFromType(type); + auto category = IDescriptor::GetTypeCategory(type); if (category == IDescriptor::E_CATEGORY::EC_IMAGE) - dstDescriptorInfo.info.image = srcDescriptorInfo.info.image; + dstDescriptorInfo.info.combinedImageSampler = srcDescriptorInfo.info.combinedImageSampler; else dstDescriptorInfo.info.buffer = srcDescriptorInfo.info.buffer; @@ -71,7 +71,9 @@ core::smart_refctd_ptr ICPUDescriptorSet::clone(uint32_t _depth) const assert(srcDescriptorInfo.desc); IAsset* descriptor = nullptr; - if (category == IDescriptor::E_CATEGORY::EC_IMAGE) + if (category == IDescriptor::E_CATEGORY::EC_SAMPLER) + descriptor = static_cast(srcDescriptorInfo.desc.get()); + else if (category == IDescriptor::E_CATEGORY::EC_IMAGE) descriptor = static_cast(srcDescriptorInfo.desc.get()); else if (category == IDescriptor::E_CATEGORY::EC_BUFFER_VIEW) descriptor = static_cast(srcDescriptorInfo.desc.get()); @@ -80,7 +82,9 @@ core::smart_refctd_ptr ICPUDescriptorSet::clone(uint32_t _depth) const auto descriptorClone = descriptor->clone(_depth - 1); - if (category == IDescriptor::E_CATEGORY::EC_IMAGE) + if (category == IDescriptor::E_CATEGORY::EC_SAMPLER) + dstDescriptorInfo.desc = core::smart_refctd_ptr_static_cast(std::move(descriptorClone)); + else if (category == IDescriptor::E_CATEGORY::EC_IMAGE) dstDescriptorInfo.desc = core::smart_refctd_ptr_static_cast(std::move(descriptorClone)); else if (category == IDescriptor::E_CATEGORY::EC_BUFFER_VIEW) dstDescriptorInfo.desc = core::smart_refctd_ptr_static_cast(std::move(descriptorClone)); @@ -91,8 +95,8 @@ core::smart_refctd_ptr ICPUDescriptorSet::clone(uint32_t _depth) const // Clone the sampler. { - if ((category == IDescriptor::E_CATEGORY::EC_IMAGE) && srcDescriptorInfo.info.image.sampler) - dstDescriptorInfo.info.image.sampler = core::smart_refctd_ptr_static_cast(srcDescriptorInfo.info.image.sampler->clone(_depth - 1u)); + if (category == IDescriptor::E_CATEGORY::EC_IMAGE and srcDescriptorInfo.info.combinedImageSampler.sampler) + dstDescriptorInfo.info.combinedImageSampler.sampler = core::smart_refctd_ptr_static_cast(srcDescriptorInfo.info.combinedImageSampler.sampler->clone(_depth - 1u)); } } else @@ -123,7 +127,7 @@ void ICPUDescriptorSet::convertToDummyObject(uint32_t referenceLevelsBelowToConv auto descriptorInfos = m_descriptorInfos[t]->begin(); assert(descriptorInfos); - const auto category = getCategoryFromType(type); + const auto category = IDescriptor::GetTypeCategory(type); for (uint32_t i = 0u; i < descriptorCount; ++i) { switch (category) @@ -132,11 +136,16 @@ void ICPUDescriptorSet::convertToDummyObject(uint32_t referenceLevelsBelowToConv static_cast(descriptorInfos[i].desc.get())->convertToDummyObject(referenceLevelsBelowToConvert); break; + case IDescriptor::E_CATEGORY::EC_SAMPLER: + { + static_cast(descriptorInfos[i].desc.get())->convertToDummyObject(referenceLevelsBelowToConvert); + } break; + case IDescriptor::E_CATEGORY::EC_IMAGE: { static_cast(descriptorInfos[i].desc.get())->convertToDummyObject(referenceLevelsBelowToConvert); - if (descriptorInfos[i].info.image.sampler) - descriptorInfos[i].info.image.sampler->convertToDummyObject(referenceLevelsBelowToConvert); + if (descriptorInfos[i].info.combinedImageSampler.sampler) + descriptorInfos[i].info.combinedImageSampler.sampler->convertToDummyObject(referenceLevelsBelowToConvert); } break; case IDescriptor::EC_BUFFER_VIEW: @@ -174,7 +183,7 @@ void ICPUDescriptorSet::restoreFromDummy_impl(IAsset* _other, uint32_t _levelsBe auto otherDescriptorInfos = other->m_descriptorInfos[t]->begin(); - const auto category = getCategoryFromType(type); + const auto category = IDescriptor::GetTypeCategory(type); for (uint32_t i = 0u; i < descriptorCount; ++i) { switch (category) @@ -183,11 +192,16 @@ void ICPUDescriptorSet::restoreFromDummy_impl(IAsset* _other, uint32_t _levelsBe restoreFromDummy_impl_call(static_cast(descriptorInfos[i].desc.get()), static_cast(otherDescriptorInfos[i].desc.get()), _levelsBelow); break; + case IDescriptor::EC_SAMPLER: + { + restoreFromDummy_impl_call(static_cast(descriptorInfos[i].desc.get()), static_cast(otherDescriptorInfos[i].desc.get()), _levelsBelow); + } break; + case IDescriptor::EC_IMAGE: { restoreFromDummy_impl_call(static_cast(descriptorInfos[i].desc.get()), static_cast(otherDescriptorInfos[i].desc.get()), _levelsBelow); - if (descriptorInfos[i].info.image.sampler && otherDescriptorInfos[i].info.image.sampler) - restoreFromDummy_impl_call(descriptorInfos[i].info.image.sampler.get(), otherDescriptorInfos[i].info.image.sampler.get(), _levelsBelow); + if (descriptorInfos[i].info.combinedImageSampler.sampler && otherDescriptorInfos[i].info.combinedImageSampler.sampler) + restoreFromDummy_impl_call(descriptorInfos[i].info.combinedImageSampler.sampler.get(), otherDescriptorInfos[i].info.combinedImageSampler.sampler.get(), _levelsBelow); } break; case IDescriptor::EC_BUFFER_VIEW: @@ -220,7 +234,7 @@ bool ICPUDescriptorSet::isAnyDependencyDummy_impl(uint32_t _levelsBelow) const auto descriptorInfos = m_descriptorInfos[t]->begin(); assert(descriptorInfos); - const auto category = getCategoryFromType(type); + const auto category = IDescriptor::GetTypeCategory(type); for (uint32_t i = 0u; i < descriptorCount; ++i) { switch (category) @@ -230,12 +244,18 @@ bool ICPUDescriptorSet::isAnyDependencyDummy_impl(uint32_t _levelsBelow) const return true; break; + case IDescriptor::EC_SAMPLER: + { + if (static_cast(descriptorInfos[i].desc.get())->isAnyDependencyDummy(_levelsBelow)) + return true; + } break; + case IDescriptor::EC_IMAGE: { if (static_cast(descriptorInfos[i].desc.get())->isAnyDependencyDummy(_levelsBelow)) return true; - if (descriptorInfos[i].info.image.sampler && descriptorInfos[i].info.image.sampler->isAnyDependencyDummy(_levelsBelow)) + if (descriptorInfos[i].info.combinedImageSampler.sampler && descriptorInfos[i].info.combinedImageSampler.sampler->isAnyDependencyDummy(_levelsBelow)) return true; } break; diff --git a/src/nbl/asset/interchange/CGraphicsPipelineLoaderMTL.cpp b/src/nbl/asset/interchange/CGraphicsPipelineLoaderMTL.cpp index bebaeda14c..70ac5d2d19 100644 --- a/src/nbl/asset/interchange/CGraphicsPipelineLoaderMTL.cpp +++ b/src/nbl/asset/interchange/CGraphicsPipelineLoaderMTL.cpp @@ -738,7 +738,7 @@ core::smart_refctd_ptr CGraphicsPipelineLoaderMTL::makeDescSe auto dummy2d = _ctx.loaderOverride->findDefaultAsset("nbl/builtin/image_view/dummy2d",_ctx.inner,_ctx.topHierarchyLevel+ICPURenderpassIndependentPipeline::IMAGEVIEW_HIERARCHYLEVELS_BELOW).first; for (uint32_t i = 0u; i <= CMTLMetadata::CRenderpassIndependentPipeline::EMP_REFL_POSX; ++i) { - auto descriptorInfos = ds->getDescriptorInfos(i, IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER); + auto descriptorInfos = ds->getDescriptorInfos(ICPUDescriptorSetLayout::CBindingRedirect::binding_number_t(i), IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER); descriptorInfos.begin()[0].desc = _views[i] ? std::move(_views[i]) : dummy2d; descriptorInfos.begin()[0].info.image.imageLayout = IImage::LAYOUT::READ_ONLY_OPTIMAL; } diff --git a/src/nbl/video/CVulkanLogicalDevice.cpp b/src/nbl/video/CVulkanLogicalDevice.cpp index e583f1ca97..332a46b3ec 100644 --- a/src/nbl/video/CVulkanLogicalDevice.cpp +++ b/src/nbl/video/CVulkanLogicalDevice.cpp @@ -551,13 +551,13 @@ core::smart_refctd_ptr CVulkanLogicalDevice::createDesc vkDescSetLayoutBinding.stageFlags = getVkShaderStageFlagsFromShaderStage(binding.stageFlags); vkDescSetLayoutBinding.pImmutableSamplers = nullptr; - if (binding.type==asset::IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER && binding.samplers && binding.count) + if ((binding.type == asset::IDescriptor::E_TYPE::ET_SAMPLER or binding.type==asset::IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER) and binding.immutableSamplers and binding.count) { // If descriptorType is VK_DESCRIPTOR_TYPE_SAMPLER or VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, and descriptorCount is not 0 and pImmutableSamplers is not NULL: // pImmutableSamplers must be a valid pointer to an array of descriptorCount valid VkSampler handles. const uint32_t samplerOffset = vk_samplers.size(); for (uint32_t i=0u; i(binding.samplers[i].get())->getInternalObject()); + vk_samplers.push_back(static_cast(binding.immutableSamplers[i].get())->getInternalObject()); vkDescSetLayoutBinding.pImmutableSamplers = vk_samplers.data()+samplerOffset; } } @@ -681,6 +681,14 @@ void CVulkanLogicalDevice::updateDescriptorSets_impl(const SUpdateDescriptorSets outWrite->descriptorCount = write.count; switch (asset::IDescriptor::GetTypeCategory(type)) { + case asset::IDescriptor::EC_SAMPLER: + { + outWrite->pImageInfo = outImageInfo; + for (auto j = 0u; j < write.count; j++, outImageInfo++) + { + outImageInfo->sampler = static_cast(infos[j].desc.get())->getInternalObject(); + } + } break; case asset::IDescriptor::EC_BUFFER: { outWrite->pBufferInfo = outBufferInfo; @@ -697,7 +705,7 @@ void CVulkanLogicalDevice::updateDescriptorSets_impl(const SUpdateDescriptorSets outWrite->pImageInfo = outImageInfo; for (auto j=0u; jsampler = imageInfo.sampler ? static_cast(imageInfo.sampler.get())->getInternalObject():VK_NULL_HANDLE; outImageInfo->imageView = static_cast(infos[j].desc.get())->getInternalObject(); outImageInfo->imageLayout = getVkImageLayoutFromImageLayout(imageInfo.imageLayout); @@ -766,7 +774,7 @@ void CVulkanLogicalDevice::nullifyDescriptors_impl(const SDropDescriptorSetsPara for (auto i=0; igetBindingType(write.binding); + auto descriptorType = write.dstSet->getBindingType(IGPUDescriptorSetLayout::CBindingRedirect::binding_number_t(write.binding)); outWrite->dstSet = static_cast(write.dstSet)->getInternalObject(); outWrite->dstBinding = write.binding; @@ -778,6 +786,7 @@ void CVulkanLogicalDevice::nullifyDescriptors_impl(const SDropDescriptorSetsPara case asset::IDescriptor::EC_BUFFER: outWrite->pBufferInfo = reinterpret_cast(nullDescriptors.data()); break; + case asset::IDescriptor::EC_SAMPLER: case asset::IDescriptor::EC_IMAGE: outWrite->pImageInfo = reinterpret_cast(nullDescriptors.data()); break; diff --git a/src/nbl/video/IDescriptorPool.cpp b/src/nbl/video/IDescriptorPool.cpp index cfce368542..1d47900efb 100644 --- a/src/nbl/video/IDescriptorPool.cpp +++ b/src/nbl/video/IDescriptorPool.cpp @@ -10,15 +10,17 @@ IDescriptorPool::IDescriptorPool(core::smart_refctd_ptr&& for (auto i = 0; i < static_cast(asset::IDescriptor::E_TYPE::ET_COUNT); ++i) m_descriptorAllocators[i] = std::make_unique(m_creationParameters.maxDescriptorCount[i], m_creationParameters.flags.hasFlags(ECF_FREE_DESCRIPTOR_SET_BIT)); - // For mutable samplers. We don't know if there will be mutable samplers in sets allocated by this pool when we create the pool. + // For mutable samplers pertaining to combined image samplers. We don't know if there will be mutable samplers in sets allocated by this pool when we create the pool. m_descriptorAllocators[static_cast(asset::IDescriptor::E_TYPE::ET_COUNT)] = std::make_unique(m_creationParameters.maxDescriptorCount[static_cast(asset::IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER)], m_creationParameters.flags.hasFlags(ECF_FREE_DESCRIPTOR_SET_BIT)); // Initialize the storages. - m_textureStorage = std::make_unique>[]>(m_creationParameters.maxDescriptorCount[static_cast(asset::IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER)]); - m_mutableSamplerStorage = std::make_unique>[]>(m_creationParameters.maxDescriptorCount[static_cast(asset::IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER)]); + m_textureStorage = std::make_unique>[]>(m_creationParameters.maxDescriptorCount[static_cast(asset::IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER)] + m_creationParameters.maxDescriptorCount[static_cast(asset::IDescriptor::E_TYPE::ET_SAMPLED_IMAGE)]); + m_mutableCombinedSamplerStorage = std::make_unique>[]>(m_creationParameters.maxDescriptorCount[static_cast(asset::IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER)]); + // Keep standalone samplers separate from the ones in combined + m_mutableStandaloneSamplerStorage = std::make_unique>[]>(m_creationParameters.maxDescriptorCount[static_cast(asset::IDescriptor::E_TYPE::ET_SAMPLER)]); m_storageImageStorage = std::make_unique>[]>(m_creationParameters.maxDescriptorCount[static_cast(asset::IDescriptor::E_TYPE::ET_STORAGE_IMAGE)] + m_creationParameters.maxDescriptorCount[static_cast(asset::IDescriptor::E_TYPE::ET_INPUT_ATTACHMENT)]); m_UBO_SSBOStorage = std::make_unique>[]>(m_creationParameters.maxDescriptorCount[static_cast(asset::IDescriptor::E_TYPE::ET_UNIFORM_BUFFER)] + m_creationParameters.maxDescriptorCount[static_cast(asset::IDescriptor::E_TYPE::ET_STORAGE_BUFFER)] + m_creationParameters.maxDescriptorCount[static_cast(asset::IDescriptor::E_TYPE::ET_UNIFORM_BUFFER_DYNAMIC)] + m_creationParameters.maxDescriptorCount[static_cast(asset::IDescriptor::E_TYPE::ET_STORAGE_BUFFER_DYNAMIC)]); - m_UTB_STBStorage = std::make_unique>[]>(m_creationParameters.maxDescriptorCount[static_cast(asset::IDescriptor::E_TYPE::ET_UNIFORM_TEXEL_BUFFER)] + m_creationParameters.maxDescriptorCount[static_cast(asset::IDescriptor::E_TYPE::ET_STORAGE_BUFFER_DYNAMIC)]); + m_UTB_STBStorage = std::make_unique>[]>(m_creationParameters.maxDescriptorCount[static_cast(asset::IDescriptor::E_TYPE::ET_UNIFORM_TEXEL_BUFFER)] + m_creationParameters.maxDescriptorCount[static_cast(asset::IDescriptor::E_TYPE::ET_STORAGE_TEXEL_BUFFER)]); m_accelerationStructureStorage = std::make_unique>[]>(m_creationParameters.maxDescriptorCount[static_cast(asset::IDescriptor::E_TYPE::ET_ACCELERATION_STRUCTURE)]); m_allocatedDescriptorSets = std::make_unique(m_creationParameters.maxSets); @@ -112,7 +114,7 @@ bool IDescriptorPool::allocateStorageOffsets(SStorageOffsets& offsets, const IGP uint32_t maxCount = 0u; if (i == static_cast(asset::IDescriptor::E_TYPE::ET_COUNT)) { - count = layout->getTotalMutableSamplerCount(); + count = layout->getTotalMutableCombinedSamplerCount(); maxCount = m_creationParameters.maxDescriptorCount[static_cast(asset::IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER)]; } else @@ -202,13 +204,13 @@ void IDescriptorPool::deleteSetStorage(const uint32_t setIndex) m_descriptorAllocators[i]->free(allocatedOffset, count); } - const auto mutableSamplerCount = set->getLayout()->getTotalMutableSamplerCount(); + const auto mutableSamplerCount = set->getLayout()->getTotalMutableCombinedSamplerCount(); if (mutableSamplerCount > 0) { - const uint32_t allocatedOffset = set->m_storageOffsets.getMutableSamplerOffset(); + const uint32_t allocatedOffset = set->m_storageOffsets.getMutableCombinedSamplerOffset(); assert(allocatedOffset != ~0u); - std::destroy_n(getMutableSamplerStorage() + allocatedOffset, mutableSamplerCount); + std::destroy_n(getMutableCombinedSamplerStorage() + allocatedOffset, mutableSamplerCount); if (allowsFreeing()) m_descriptorAllocators[static_cast(asset::IDescriptor::E_TYPE::ET_COUNT)]->free(allocatedOffset, mutableSamplerCount); diff --git a/src/nbl/video/IGPUCommandBuffer.cpp b/src/nbl/video/IGPUCommandBuffer.cpp index 23ef9c7f9d..5cf306ede2 100644 --- a/src/nbl/video/IGPUCommandBuffer.cpp +++ b/src/nbl/video/IGPUCommandBuffer.cpp @@ -728,7 +728,7 @@ bool IGPUCommandBuffer::bindDescriptorSets( return false; for (uint32_t i=0u; igetLayout()->canUpdateAfterBind()) + if (pDescriptorSets[i] && pDescriptorSets[i]->getLayout()->versionChangeInvalidatesCommandBuffer()) { const auto currentVersion = pDescriptorSets[i]->getVersion(); diff --git a/src/nbl/video/IGPUDescriptorSet.cpp b/src/nbl/video/IGPUDescriptorSet.cpp index 3313ed3388..350e810bb0 100644 --- a/src/nbl/video/IGPUDescriptorSet.cpp +++ b/src/nbl/video/IGPUDescriptorSet.cpp @@ -23,10 +23,10 @@ IGPUDescriptorSet::IGPUDescriptorSet(core::smart_refctd_ptrgetTotalDescriptorCount(type)); } - const auto mutableSamplerCount = m_layout->getTotalMutableSamplerCount(); + const auto mutableSamplerCount = m_layout->getTotalMutableCombinedSamplerCount(); if (mutableSamplerCount > 0) { - auto mutableSamplers = getAllMutableSamplers(); + auto mutableSamplers = getAllMutableCombinedSamplers(); assert(mutableSamplers); std::uninitialized_default_construct_n(mutableSamplers, mutableSamplerCount); } @@ -38,16 +38,31 @@ IGPUDescriptorSet::~IGPUDescriptorSet() m_pool->deleteSetStorage(m_storageOffsets.getSetOffset()); } -asset::IDescriptor::E_TYPE IGPUDescriptorSet::validateWrite(const IGPUDescriptorSet::SWriteDescriptorSet& write) const +IGPUDescriptorSet::SWriteValidationResult IGPUDescriptorSet::validateWrite(const IGPUDescriptorSet::SWriteDescriptorSet& write) const { assert(write.dstSet == this); const char* debugName = getDebugName(); + using redirect_t = IGPUDescriptorSetLayout::CBindingRedirect; + const redirect_t::binding_number_t bindingNumber(write.binding); + + SWriteValidationResult validationResult; // screw it, we'll need to replace the descriptor writing with update templates of descriptor buffer soon anyway - const auto descriptorType = getBindingType(write.binding); + const auto descriptorType = getBindingType(bindingNumber, validationResult.descriptorRedirectBindingIndex); + if (asset::IDescriptor::E_TYPE::ET_COUNT == descriptorType) + { + if (debugName) + m_pool->m_logger.log("Descriptor set (%s, %p) has no binding %u.", system::ILogger::ELL_ERROR, debugName, this, write.binding); + else + m_pool->m_logger.log("Descriptor set (%p) has no binding %u.", system::ILogger::ELL_ERROR, this, write.binding); - auto* descriptors = getDescriptors(descriptorType,write.binding); + validationResult.type = asset::IDescriptor::E_TYPE::ET_COUNT; + return validationResult; + } + + auto* descriptors = getDescriptors(descriptorType, validationResult.descriptorRedirectBindingIndex); + // Left this check, but if the above passed then this should never be nullptr I believe if (!descriptors) { if (debugName) @@ -55,125 +70,191 @@ asset::IDescriptor::E_TYPE IGPUDescriptorSet::validateWrite(const IGPUDescriptor else m_pool->m_logger.log("Descriptor set (%p) doesn't allow descriptor of such type at binding %u.", system::ILogger::ELL_ERROR, this, write.binding); - return asset::IDescriptor::E_TYPE::ET_COUNT; + validationResult.type = asset::IDescriptor::E_TYPE::ET_COUNT; + return validationResult; } - core::smart_refctd_ptr* mutableSamplers = nullptr; - if (descriptorType==asset::IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER && write.info->info.image.sampler) + for (uint32_t i = 0; i < write.count; ++i) + { + if (asset::IDescriptor::GetTypeCategory(descriptorType) != write.info[i].desc->getTypeCategory()) + { + if (debugName) + m_pool->m_logger.log("Descriptor set (%s, %p) doesn't allow descriptor of such type category at binding %u.", system::ILogger::ELL_ERROR, debugName, this, write.binding); + else + m_pool->m_logger.log("Descriptor set (%p) doesn't allow descriptor of such type category at binding %u.", system::ILogger::ELL_ERROR, this, write.binding); + + validationResult.type = asset::IDescriptor::E_TYPE::ET_COUNT; + return validationResult; + } + } + + if (descriptorType == asset::IDescriptor::E_TYPE::ET_SAMPLER or (descriptorType == asset::IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER and write.info->info.combinedImageSampler.sampler)) { if (m_layout->getImmutableSamplerRedirect().getCount(IGPUDescriptorSetLayout::CBindingRedirect::binding_number_t{ write.binding }) != 0) { if (debugName) - m_pool->m_logger.log("Descriptor set (%s, %p) doesn't allow immutable samplers at binding %u, but immutable samplers found.", system::ILogger::ELL_ERROR, debugName, this, write.binding); + m_pool->m_logger.log("Trying to write samplers at binding %u of Descriptor set (%s, %p), but those are immutable.", system::ILogger::ELL_ERROR, write.binding, debugName, this); else - m_pool->m_logger.log("Descriptor set (%p) doesn't allow immutable samplers at binding %u, but immutable samplers found.", system::ILogger::ELL_ERROR, this, write.binding); - return asset::IDescriptor::E_TYPE::ET_COUNT; + m_pool->m_logger.log("Trying to write samplers at binding %u of Descriptor set (%p), but those are immutable.", system::ILogger::ELL_ERROR, write.binding, this); + validationResult.type = asset::IDescriptor::E_TYPE::ET_COUNT; + return validationResult; } for (uint32_t i=0; igetTypeCategory()) - { + auto* sampler = descriptorType == asset::IDescriptor::E_TYPE::ET_SAMPLER ? reinterpret_cast(write.info[i].desc.get()) : write.info[i].info.combinedImageSampler.sampler.get(); + if (not sampler) { if (debugName) - m_pool->m_logger.log("Descriptor set (%s, %p) doesn't allow descriptor of such type category at binding %u.", system::ILogger::ELL_ERROR, debugName, this, write.binding); + m_pool->m_logger.log("Null sampler provided when trying to write descriptor set (%s, %p) at binding %u. All writes should provide a sampler.", system::ILogger::ELL_ERROR, debugName, this, write.binding); else - m_pool->m_logger.log("Descriptor set (%p) doesn't allow descriptor of such type category at binding %u.", system::ILogger::ELL_ERROR, this, write.binding); - - return asset::IDescriptor::E_TYPE::ET_COUNT; + m_pool->m_logger.log("Null sampler provided when trying to write descriptor set (%p) at binding %u. All writes should provide a sampler.", system::ILogger::ELL_ERROR, this, write.binding); + validationResult.type = asset::IDescriptor::E_TYPE::ET_COUNT; + return validationResult; } - auto* sampler = write.info[i].info.image.sampler.get(); - if (!sampler || !sampler->isCompatibleDevicewise(write.dstSet)) - { + if (not sampler->isCompatibleDevicewise(write.dstSet)) { const char* samplerDebugName = sampler->getDebugName(); if (samplerDebugName && debugName) - m_pool->m_logger.log("Sampler (%s, %p) does not exist or is not device-compatible with descriptor set (%s, %p).", system::ILogger::ELL_ERROR, samplerDebugName, sampler, debugName, write.dstSet); + m_pool->m_logger.log("Sampler (%s, %p) does not exist or is not device-compatible with descriptor set (%s, %p).", system::ILogger::ELL_ERROR, samplerDebugName, sampler, debugName, this); else - m_pool->m_logger.log("Sampler (%p) does not exist or is not device-compatible with descriptor set (%p).", system::ILogger::ELL_ERROR, sampler, write.dstSet); - return asset::IDescriptor::E_TYPE::ET_COUNT; + m_pool->m_logger.log("Sampler (%p) does not exist or is not device-compatible with descriptor set (%p).", system::ILogger::ELL_ERROR, sampler, this); + validationResult.type = asset::IDescriptor::E_TYPE::ET_COUNT; + return validationResult; } } + if (descriptorType == asset::IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER) { + validationResult.mutableSamplerRedirectBindingIndex = getLayout()->getMutableCombinedSamplerRedirect().findBindingStorageIndex(bindingNumber); + auto mutableSamplers = getMutableCombinedSamplers(validationResult.mutableSamplerRedirectBindingIndex); + + // Should never reach here, the GetTypeCategory check earlier should ensure that + if (!mutableSamplers) + { + if (debugName) + m_pool->m_logger.log("Descriptor set (%s, %p) only allows standalone mutable samplers at binding %u (no combined image samplers).", system::ILogger::ELL_ERROR, debugName, this, write.binding); + else + m_pool->m_logger.log("Descriptor set (%p) only allows standalone mutable samplers at binding %u (no combined image samplers).", system::ILogger::ELL_ERROR, this, write.binding); - mutableSamplers = getMutableSamplers(write.binding); - if (!mutableSamplers) + validationResult.type = asset::IDescriptor::E_TYPE::ET_COUNT; + return validationResult; + } + } + } + + // https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#descriptorsets-combinedimagesampler + if (asset::IDescriptor::GetTypeCategory(descriptorType) == asset::IDescriptor::EC_IMAGE) + for (uint32_t i = 0; i < write.count; ++i) + { + auto layout = write.info[i].info.image.imageLayout; + if (not (asset::IImage::LAYOUT::GENERAL == layout or asset::IImage::LAYOUT::SHARED_PRESENT == layout or asset::IImage::LAYOUT::READ_ONLY_OPTIMAL == layout)) { if (debugName) - m_pool->m_logger.log("Descriptor set (%s, %p) doesn't allow mutable samplers at binding %u.", system::ILogger::ELL_ERROR, debugName, this, write.binding); + m_pool->m_logger.log("When writing to descriptor set (%s, %p), an image was provided with a layout that isn't GENERAL, SHARED_PRESENT or READ_ONLY_OPTIMAL", system::ILogger::ELL_ERROR, debugName, this); else - m_pool->m_logger.log("Descriptor set (%p) doesn't allow mutable samplers at binding %u.", system::ILogger::ELL_ERROR, this, write.binding); - - return asset::IDescriptor::E_TYPE::ET_COUNT; + m_pool->m_logger.log("When writing to descriptor set (%p), an image was provided with a layout that isn't GENERAL, SHARED_PRESENT or READ_ONLY_OPTIMAL", system::ILogger::ELL_ERROR, this); } } - return descriptorType; + validationResult.type = descriptorType; + return validationResult; } -void IGPUDescriptorSet::processWrite(const IGPUDescriptorSet::SWriteDescriptorSet& write, const asset::IDescriptor::E_TYPE type) +void IGPUDescriptorSet::processWrite(const IGPUDescriptorSet::SWriteDescriptorSet& write, const SWriteValidationResult& validationResult) { assert(write.dstSet == this); - auto* descriptors = getDescriptors(type,write.binding); + auto* descriptors = getDescriptors(validationResult.type, validationResult.descriptorRedirectBindingIndex); assert(descriptors); core::smart_refctd_ptr* mutableSamplers = nullptr; - if (type==asset::IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER && write.info->info.image.sampler) + if (validationResult.type == asset::IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER + and write.info->info.combinedImageSampler.sampler) { - mutableSamplers = getMutableSamplers(write.binding); + mutableSamplers = getMutableCombinedSamplers(validationResult.mutableSamplerRedirectBindingIndex); assert(mutableSamplers); } - for (auto j=0; jgetDescriptorRedirect(validationResult.type); + auto bindingCreateFlags = bindingRedirect.getCreateFlags(validationResult.descriptorRedirectBindingIndex); + if (IGPUDescriptorSetLayout::writeIncrementsVersion(bindingCreateFlags)) + incrementVersion(); } void IGPUDescriptorSet::dropDescriptors(const IGPUDescriptorSet::SDropDescriptorSet& drop) { assert(drop.dstSet == this); - const auto descriptorType = getBindingType(drop.binding); - - auto* dstDescriptors = drop.dstSet->getDescriptors(descriptorType, drop.binding); - auto* dstSamplers = drop.dstSet->getMutableSamplers(drop.binding); + using redirect_t = IGPUDescriptorSetLayout::CBindingRedirect; + const redirect_t::binding_number_t bindingNumber(drop.binding); + redirect_t::storage_range_index_t descriptorRedirectBindingIndex; + const auto descriptorType = getBindingType(bindingNumber, descriptorRedirectBindingIndex); - if (dstDescriptors) - for (uint32_t i = 0; i < drop.count; i++) - dstDescriptors[drop.arrayElement + i] = nullptr; + auto* dstDescriptors = drop.dstSet->getDescriptors(descriptorType, descriptorRedirectBindingIndex); + if (dstDescriptors) + for (uint32_t i = 0; i < drop.count; i++) + dstDescriptors[drop.arrayElement + i] = nullptr; - if (dstSamplers) - for (uint32_t i = 0; i < drop.count; i++) - dstSamplers[drop.arrayElement + i] = nullptr; - - // we only increment the version to detect UPDATE-AFTER-BIND and automagically invalidate descriptor sets - // so, only if we do the path that writes descriptors, do we want to increment version - if (getOriginDevice()->getEnabledFeatures().nullDescriptor) + if (asset::IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER == descriptorType) { - incrementVersion(); + auto* dstSamplers = drop.dstSet->getMutableCombinedSamplers(bindingNumber); + if (dstSamplers) + for (uint32_t i = 0; i < drop.count; i++) + dstSamplers[drop.arrayElement + i] = nullptr; } + + // we only increment the version to detect UPDATE-AFTER-BIND and automagically invalidate descriptor sets + // so, only if we do the path that writes descriptors, do we want to increment version + auto& bindingRedirect = m_layout->getDescriptorRedirect(descriptorType); + auto bindingCreateFlags = bindingRedirect.getCreateFlags(descriptorRedirectBindingIndex); + if (IGPUDescriptorSetLayout::writeIncrementsVersion(bindingCreateFlags)) + incrementVersion(); } -bool IGPUDescriptorSet::validateCopy(const IGPUDescriptorSet::SCopyDescriptorSet& copy) const +IGPUDescriptorSet::SCopyValidationResult IGPUDescriptorSet::validateCopy(const IGPUDescriptorSet::SCopyDescriptorSet& copy) const { assert(copy.dstSet == this); + using redirect_t = IGPUDescriptorSetLayout::CBindingRedirect; + redirect_t::binding_number_t srcBindingNumber(copy.srcBinding); + redirect_t::binding_number_t dstBindingNumber(copy.dstBinding); + const char* srcDebugName = copy.srcSet->getDebugName(); const char* dstDebugName = copy.dstSet->getDebugName(); + const auto srcLayout = copy.srcSet->getLayout(); + const auto dstLayout = copy.dstSet->getLayout(); + + SCopyValidationResult validationResult; + for (uint32_t t = 0; t < static_cast(asset::IDescriptor::E_TYPE::ET_COUNT); ++t) { - const auto type = static_cast(t); + validationResult.type = static_cast(t); + + validationResult.srcDescriptorRedirectBindingIndex = srcLayout->getDescriptorRedirect(validationResult.type).findBindingStorageIndex(srcBindingNumber); + validationResult.dstDescriptorRedirectBindingIndex = dstLayout->getDescriptorRedirect(validationResult.type).findBindingStorageIndex(dstBindingNumber); + auto* srcDescriptors = copy.srcSet->getDescriptors(validationResult.type, validationResult.srcDescriptorRedirectBindingIndex); + auto* dstDescriptors = copy.dstSet->getDescriptors(validationResult.type, validationResult.dstDescriptorRedirectBindingIndex); - auto* srcDescriptors = copy.srcSet->getDescriptors(type, copy.srcBinding); - auto* dstDescriptors = copy.dstSet->getDescriptors(type, copy.dstBinding); + if (!srcDescriptors) + { + assert(!dstDescriptors); + continue; + } + assert(dstDescriptors); - auto* srcSamplers = copy.srcSet->getMutableSamplers(copy.srcBinding); - auto* dstSamplers = copy.dstSet->getMutableSamplers(copy.dstBinding); + core::smart_refctd_ptr *srcSamplers = nullptr, *dstSamplers = nullptr; + if (asset::IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER == validationResult.type) + { + validationResult.srcMutableSamplerRedirectBindingIndex = srcLayout->getMutableCombinedSamplerRedirect().findBindingStorageIndex(srcBindingNumber); + validationResult.dstMutableSamplerRedirectBindingIndex = dstLayout->getMutableCombinedSamplerRedirect().findBindingStorageIndex(dstBindingNumber); + srcSamplers = copy.srcSet->getMutableCombinedSamplers(validationResult.srcMutableSamplerRedirectBindingIndex); + dstSamplers = copy.dstSet->getMutableCombinedSamplers(validationResult.dstMutableSamplerRedirectBindingIndex); + } if ((!srcDescriptors != !dstDescriptors) || (!srcSamplers != !dstSamplers)) { @@ -182,37 +263,34 @@ bool IGPUDescriptorSet::validateCopy(const IGPUDescriptorSet::SCopyDescriptorSet else m_pool->m_logger.log("Incompatible copy from descriptor set (%p) at binding %u to descriptor set (%p) at binding %u.", system::ILogger::ELL_ERROR, copy.srcSet, copy.srcBinding, copy.dstSet, copy.dstBinding); - return false; + validationResult.type = asset::IDescriptor::E_TYPE::ET_COUNT; + return validationResult; } } - return true; + return validationResult; } -void IGPUDescriptorSet::processCopy(const IGPUDescriptorSet::SCopyDescriptorSet& copy) +void IGPUDescriptorSet::processCopy(const IGPUDescriptorSet::SCopyDescriptorSet& copy, const SCopyValidationResult& validationResult) { assert(copy.dstSet == this); - for (uint32_t t = 0; t < static_cast(asset::IDescriptor::E_TYPE::ET_COUNT); ++t) - { - const auto type = static_cast(t); - - auto* srcDescriptors = copy.srcSet->getDescriptors(type, copy.srcBinding); - auto* dstDescriptors = copy.dstSet->getDescriptors(type, copy.dstBinding); - assert(!(!srcDescriptors != !dstDescriptors)); + auto& bindingRedirect = m_layout->getDescriptorRedirect(validationResult.type); - auto* srcSamplers = copy.srcSet->getMutableSamplers(copy.srcBinding); - auto* dstSamplers = copy.dstSet->getMutableSamplers(copy.dstBinding); - assert(!(!srcSamplers != !dstSamplers)); + auto* srcDescriptors = copy.srcSet->getDescriptors(validationResult.type, validationResult.srcDescriptorRedirectBindingIndex); + auto* dstDescriptors = copy.dstSet->getDescriptors(validationResult.type, validationResult.dstDescriptorRedirectBindingIndex); - if (srcDescriptors && dstDescriptors) - std::copy_n(srcDescriptors, copy.count, dstDescriptors); + auto* srcSamplers = validationResult.type != asset::IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER ? nullptr : copy.srcSet->getMutableCombinedSamplers(validationResult.srcMutableSamplerRedirectBindingIndex); + auto* dstSamplers = validationResult.type != asset::IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER ? nullptr : copy.dstSet->getMutableCombinedSamplers(validationResult.dstMutableSamplerRedirectBindingIndex); + + auto bindingCreateFlags = bindingRedirect.getCreateFlags(validationResult.dstDescriptorRedirectBindingIndex); + if (IGPUDescriptorSetLayout::writeIncrementsVersion(bindingCreateFlags)) + incrementVersion(); - if (srcSamplers && dstSamplers) - std::copy_n(srcSamplers, copy.count, dstSamplers); - } + std::copy_n(srcDescriptors, copy.count, dstDescriptors); - incrementVersion(); + if (srcSamplers && dstSamplers) + std::copy_n(srcSamplers, copy.count, dstSamplers); } } \ No newline at end of file diff --git a/src/nbl/video/ILogicalDevice.cpp b/src/nbl/video/ILogicalDevice.cpp index c902efb63b..9c15108fc7 100644 --- a/src/nbl/video/ILogicalDevice.cpp +++ b/src/nbl/video/ILogicalDevice.cpp @@ -380,6 +380,7 @@ core::smart_refctd_ptr ILogicalDevice::createDescriptor // TODO: MORE VALIDATION, but after descriptor indexing. bool variableLengthArrayDescriptorFound = false; + bool updateableAfterBindBindingFound = false; uint32_t variableLengthArrayDescriptorBindingNr = 0; uint32_t highestBindingNr = 0u; uint32_t maxSamplersCount = 0u; @@ -392,15 +393,19 @@ core::smart_refctd_ptr ILogicalDevice::createDescriptor dynamicSSBOCount++; else if (binding.type==asset::IDescriptor::E_TYPE::ET_UNIFORM_BUFFER_DYNAMIC) dynamicUBOCount++; - else if (binding.type==asset::IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER && binding.samplers) + // If binding comes with samplers, we're specifying that this binding corresponds to immutable samplers + else if ((binding.type == asset::IDescriptor::E_TYPE::ET_SAMPLER or binding.type==asset::IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER) and binding.immutableSamplers) { - auto* samplers = binding.samplers; + auto* samplers = binding.immutableSamplers; for (uint32_t i=0u; iwasCreatedBy(this)) + if ((not samplers[i]) or (not samplers[i]->wasCreatedBy(this))) return nullptr; maxSamplersCount += binding.count; } + if (bindings[i].createFlags & IGPUDescriptorSetLayout::SBinding::E_CREATE_FLAGS::ECF_UPDATE_AFTER_BIND_BIT) + updateableAfterBindBindingFound = true; + // validate if only last binding is run-time sized and there is only one run-time sized binding bool isCurrentDescriptorVariableLengthArray = static_cast(bindings[i].createFlags & IGPUDescriptorSetLayout::SBinding::E_CREATE_FLAGS::ECF_VARIABLE_DESCRIPTOR_COUNT_BIT); // no 2 run-time sized descriptors allowed @@ -415,6 +420,10 @@ core::smart_refctd_ptr ILogicalDevice::createDescriptor highestBindingNr = std::max(highestBindingNr, bindings[i].binding); } + // https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-VkDescriptorSetLayoutCreateInfo-descriptorType-03001 + if (updateableAfterBindBindingFound and dynamicSSBOCount + dynamicUBOCount != 0) + return nullptr; + // only last binding can be run-time sized if (variableLengthArrayDescriptorFound && variableLengthArrayDescriptorBindingNr != highestBindingNr) return nullptr; @@ -429,22 +438,27 @@ core::smart_refctd_ptr ILogicalDevice::createDescriptor bool ILogicalDevice::updateDescriptorSets(const std::span descriptorWrites, const std::span descriptorCopies) { + using redirect_t = IGPUDescriptorSetLayout::CBindingRedirect; SUpdateDescriptorSetsParams params = {.writes=descriptorWrites,.copies=descriptorCopies}; core::vector writeTypes(descriptorWrites.size()); auto outCategory = writeTypes.data(); params.pWriteTypes = outCategory; - for (const auto& write : descriptorWrites) + core::vector writeValidationResults(descriptorWrites.size()); + for (auto i = 0u; i < descriptorWrites.size(); i++) { + const auto& write = descriptorWrites[i]; auto* ds = write.dstSet; if (!ds || !ds->wasCreatedBy(this)) return false; const auto writeCount = write.count; - switch (asset::IDescriptor::GetTypeCategory(*outCategory=ds->validateWrite(write))) + writeValidationResults[i] = ds->validateWrite(write); + switch (asset::IDescriptor::GetTypeCategory(*outCategory = writeValidationResults[i].type)) { case asset::IDescriptor::EC_BUFFER: params.bufferCount += writeCount; break; + case asset::IDescriptor::EC_SAMPLER: case asset::IDescriptor::EC_IMAGE: params.imageCount += writeCount; break; @@ -461,8 +475,10 @@ bool ILogicalDevice::updateDescriptorSets(const std::span copyValidationResults(descriptorCopies.size()); + for (auto i = 0; i < descriptorCopies.size(); i++) { + const auto& copy = descriptorCopies[i]; const auto* srcDS = copy.srcSet; const auto* dstDS = static_cast(copy.dstSet); if (!dstDS || !dstDS->wasCreatedBy(this)) @@ -470,18 +486,22 @@ bool ILogicalDevice::updateDescriptorSets(const std::spanisCompatibleDevicewise(srcDS)) return false; - if (!dstDS->validateCopy(copy)) + copyValidationResults[i] = dstDS->validateCopy(copy); + if (asset::IDescriptor::E_TYPE::ET_COUNT == copyValidationResults[i].type) return false; } for (auto i=0; iprocessWrite(write,params.pWriteTypes[i]); + write.dstSet->processWrite(write, writeValidationResults[i]); } - for (const auto& copy : descriptorCopies) - copy.dstSet->processCopy(copy); - + for (auto i = 0; i < descriptorCopies.size(); i++) + { + const auto& copy = descriptorCopies[i]; + copy.dstSet->processCopy(copy, copyValidationResults[i]); + } + updateDescriptorSets_impl(params); return true; @@ -496,13 +516,14 @@ bool ILogicalDevice::nullifyDescriptors(const std::spanwasCreatedBy(this)) return false; - auto bindingType = ds->getBindingType(drop.binding); + auto bindingType = ds->getBindingType(IGPUDescriptorSetLayout::CBindingRedirect::binding_number_t(drop.binding)); auto writeCount = drop.count; switch (asset::IDescriptor::GetTypeCategory(bindingType)) { case asset::IDescriptor::EC_BUFFER: params.bufferCount += writeCount; break; + case asset::IDescriptor::EC_SAMPLER: case asset::IDescriptor::EC_IMAGE: params.imageCount += writeCount; break;