Skip to content

Commit

Permalink
Merge pull request #345 from Devsh-Graphics-Programming/descriptor_li…
Browse files Browse the repository at this point in the history
…fetime_tracking

Descriptor lifetime tracking & Command Pool revamp
  • Loading branch information
devshgraphicsprogramming authored Mar 10, 2023
2 parents d173c04 + 1acc6c4 commit 14cf8e7
Show file tree
Hide file tree
Showing 76 changed files with 5,911 additions and 2,866 deletions.
1 change: 1 addition & 0 deletions cmake/common.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ macro(nbl_create_executable_project _EXTRA_SOURCES _EXTRA_OPTIONS _EXTRA_INCLUDE

target_include_directories(${EXECUTABLE_NAME}
PUBLIC "${NBL_ROOT_PATH}/examples_tests/common"
PUBLIC "${NBL_ROOT_PATH_BINARY}/include"
PUBLIC ../../include
PRIVATE ${_EXTRA_INCLUDES}
)
Expand Down
2 changes: 1 addition & 1 deletion include/nbl/asset/ICPUBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class ICPUBuffer : public asset::IBuffer, public asset::IAsset
}

_NBL_STATIC_INLINE_CONSTEXPR auto AssetType = ET_BUFFER;
inline E_TYPE getAssetType() const override { return AssetType; }
inline IAsset::E_TYPE getAssetType() const override { return AssetType; }

virtual size_t conservativeSizeEstimate() const override { return getSize(); }

Expand Down
2 changes: 1 addition & 1 deletion include/nbl/asset/ICPUBufferView.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class ICPUBufferView : public IBufferView<ICPUBuffer>, public IAsset
}

_NBL_STATIC_INLINE_CONSTEXPR auto AssetType = ET_BUFFER_VIEW;
inline E_TYPE getAssetType() const override { return AssetType; }
inline IAsset::E_TYPE getAssetType() const override { return AssetType; }

ICPUBuffer* getUnderlyingBuffer()
{
Expand Down
341 changes: 103 additions & 238 deletions include/nbl/asset/ICPUDescriptorSet.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O.
// Copyright (C) 2018-2022 - 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

Expand All @@ -25,250 +25,115 @@ namespace nbl::asset
@see IDescriptorSet
*/

class ICPUDescriptorSet final : public IDescriptorSet<ICPUDescriptorSetLayout>, public IAsset, public impl::IEmulatedDescriptorSet<ICPUDescriptorSetLayout>
class ICPUDescriptorSet final : public IDescriptorSet<ICPUDescriptorSetLayout>, public IAsset
{
using impl_t = impl::IEmulatedDescriptorSet<ICPUDescriptorSetLayout>;
public:
using base_t = IDescriptorSet<ICPUDescriptorSetLayout>;

//! Contructor preallocating memory for SDescriptorBindings which user can fill later (using non-const getDescriptors()).
//! @see getDescriptors()
ICPUDescriptorSet(core::smart_refctd_ptr<ICPUDescriptorSetLayout>&& _layout) : base_t(std::move(_layout)), IAsset(), impl_t(m_layout.get())
{
}


inline size_t conservativeSizeEstimate() const override
{
return sizeof(void*)+m_descriptors->size()*sizeof(SDescriptorInfo)+m_bindingInfo->size()*sizeof(impl::IEmulatedDescriptorSet<ICPUDescriptorSetLayout>::SBindingInfo);
}

core::smart_refctd_ptr<IAsset> clone(uint32_t _depth = ~0u) const override
{
auto layout = (_depth > 0u && m_layout) ? core::smart_refctd_ptr_static_cast<ICPUDescriptorSetLayout>(m_layout->clone(_depth - 1u)) : m_layout;
auto cp = core::make_smart_refctd_ptr<ICPUDescriptorSet>(std::move(layout));
clone_common(cp.get());

const uint32_t max_ix = getMaxDescriptorBindingIndex();
for (uint32_t i = 0u; i <= max_ix; ++i)
{
auto cloneDescriptor = [](const core::smart_refctd_ptr<IDescriptor>& _desc, uint32_t _depth) -> core::smart_refctd_ptr<IDescriptor> {
if (!_desc)
return nullptr;

IAsset* asset = nullptr;
switch (_desc->getTypeCategory())
{
case IDescriptor::EC_BUFFER:
asset = static_cast<ICPUBuffer*>(_desc.get()); break;
case IDescriptor::EC_BUFFER_VIEW:
asset = static_cast<ICPUBufferView*>(_desc.get()); break;
case IDescriptor::EC_IMAGE:
asset = static_cast<ICPUImageView*>(_desc.get()); break;
}

auto cp = asset->clone(_depth);

switch (_desc->getTypeCategory())
{
case IDescriptor::EC_BUFFER:
return core::smart_refctd_ptr_static_cast<ICPUBuffer>(std::move(cp));
case IDescriptor::EC_BUFFER_VIEW:
return core::smart_refctd_ptr_static_cast<ICPUBufferView>(std::move(cp));
case IDescriptor::EC_IMAGE:
return core::smart_refctd_ptr_static_cast<ICPUImageView>(std::move(cp));
}
return nullptr;
};

auto desc = getDescriptors(i);
auto cp_desc = cp->getDescriptors(i);

const E_DESCRIPTOR_TYPE type = getDescriptorsType(i);
for (uint32_t d = 0u; d < desc.size(); ++d)
{
cp_desc.begin()[d] = desc.begin()[d];
if (_depth > 0u)
{
cp_desc.begin()[d].desc = cloneDescriptor(cp_desc.begin()[d].desc, _depth-1u);
if (cp_desc.begin()[d].image.sampler && type==EDT_COMBINED_IMAGE_SAMPLER)
cp_desc.begin()[d].image.sampler = core::smart_refctd_ptr_static_cast<ICPUSampler>(cp_desc.begin()[d].image.sampler->clone(_depth-1u));
}
}
}

return cp;
}

inline void convertToDummyObject(uint32_t referenceLevelsBelowToConvert=0u) override
{
convertToDummyObject_common(referenceLevelsBelowToConvert);

if (referenceLevelsBelowToConvert)
{
--referenceLevelsBelowToConvert;
m_layout->convertToDummyObject(referenceLevelsBelowToConvert);
for (auto it=m_descriptors->begin(); it!=m_descriptors->end(); it++)
{
auto descriptor = it->desc.get();
if (!descriptor)
continue;
switch (descriptor->getTypeCategory())
{
case IDescriptor::EC_BUFFER:
static_cast<asset::ICPUBuffer*>(descriptor)->convertToDummyObject(referenceLevelsBelowToConvert);
break;
case IDescriptor::EC_IMAGE:
static_cast<asset::ICPUImageView*>(descriptor)->convertToDummyObject(referenceLevelsBelowToConvert);
if (descriptor->getTypeCategory()==IDescriptor::EC_IMAGE && it->image.sampler)
it->image.sampler->convertToDummyObject(referenceLevelsBelowToConvert);
break;
case IDescriptor::EC_BUFFER_VIEW:
static_cast<asset::ICPUBufferView*>(descriptor)->convertToDummyObject(referenceLevelsBelowToConvert);
break;
}
}
}
//dont drop descriptors so that we can access GPU descriptors through driver->getGPUObjectsFromAssets()
//m_descriptors = nullptr;
//m_bindingInfo = nullptr;
}

_NBL_STATIC_INLINE_CONSTEXPR auto AssetType = ET_DESCRIPTOR_SET;
inline E_TYPE getAssetType() const override { return AssetType; }

inline ICPUDescriptorSetLayout* getLayout()
{
assert(!isImmutable_debug());
return m_layout.get();
}
inline const ICPUDescriptorSetLayout* getLayout() const { return m_layout.get(); }

//!
inline uint32_t getMaxDescriptorBindingIndex() const
{
return m_bindingInfo ? static_cast<uint32_t>(m_bindingInfo->size()-1u):0u;
}

//!
inline E_DESCRIPTOR_TYPE getDescriptorsType(uint32_t index) const
{
if (m_bindingInfo && index<m_bindingInfo->size())
return m_bindingInfo->operator[](index).descriptorType;
return EDT_INVALID;
}

//! Can modify the array of descriptors bound to a particular bindings
inline core::SRange<SDescriptorInfo> getDescriptors(uint32_t index)
{
assert(!isImmutable_debug());

if (m_bindingInfo && index<m_bindingInfo->size())
{
const auto& info = m_bindingInfo->operator[](index);
auto _begin = m_descriptors->begin()+info.offset;
if (index+1u!=m_bindingInfo->size())
return core::SRange<SDescriptorInfo>{_begin, m_descriptors->begin()+m_bindingInfo->operator[](index+1u).offset};
else
return core::SRange<SDescriptorInfo>{_begin, m_descriptors->end()};
}
else
return core::SRange<SDescriptorInfo>{nullptr, nullptr};
}
inline core::SRange<const SDescriptorInfo> getDescriptors(uint32_t index) const
{
if (m_bindingInfo && index<m_bindingInfo->size())
{
const auto& info = m_bindingInfo->operator[](index);
auto _begin = m_descriptors->begin()+info.offset;
if (index+1u!=m_bindingInfo->size())
return core::SRange<const SDescriptorInfo>{_begin, m_descriptors->begin()+m_bindingInfo->operator[](index+1u).offset};
else
return core::SRange<const SDescriptorInfo>{_begin, m_descriptors->end()};
}
else
return core::SRange<const SDescriptorInfo>{nullptr, nullptr};
}

inline auto getTotalDescriptorCount() const
using base_t = IDescriptorSet<ICPUDescriptorSetLayout>;

public:
//! Contructor preallocating memory for SDescriptorInfos which user can fill later (using non-const getDescriptorInfos()).
//! @see getDescriptorInfos()
ICPUDescriptorSet(core::smart_refctd_ptr<ICPUDescriptorSetLayout>&& _layout) : base_t(std::move(_layout)), IAsset()
{
for (uint32_t t = 0u; t < static_cast<uint32_t>(IDescriptor::E_TYPE::ET_COUNT); ++t)
{
return m_descriptors->size();
}
const auto type = static_cast<IDescriptor::E_TYPE>(t);
const uint32_t count = m_layout->getTotalDescriptorCount(type);
if (count == 0u)
continue;

bool canBeRestoredFrom(const IAsset* _other) const override
{
auto* other = static_cast<const ICPUDescriptorSet*>(_other);
return m_layout->canBeRestoredFrom(other->m_layout.get());
m_descriptorInfos[t] = core::make_refctd_dynamic_array<core::smart_refctd_dynamic_array<ICPUDescriptorSet::SDescriptorInfo>>(count);
}

protected:
void restoreFromDummy_impl(IAsset* _other, uint32_t _levelsBelow) override
}

_NBL_STATIC_INLINE_CONSTEXPR auto AssetType = ET_DESCRIPTOR_SET;
inline E_TYPE getAssetType() const override { return AssetType; }

inline ICPUDescriptorSetLayout* getLayout()
{
assert(!isImmutable_debug());
return m_layout.get();
}

inline const ICPUDescriptorSetLayout* getLayout() const { return m_layout.get(); }

inline bool canBeRestoredFrom(const IAsset* _other) const override
{
auto* other = static_cast<const ICPUDescriptorSet*>(_other);
return m_layout->canBeRestoredFrom(other->m_layout.get());
}

inline size_t conservativeSizeEstimate() const override
{
assert(!"Invalid code path.");
return 0xdeadbeefull;
}

inline core::SRange<SDescriptorInfo> 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
// from const functions in the asset converter.
// Relevant comments/conversations:
// https://github.com/Devsh-Graphics-Programming/Nabla/pull/345#discussion_r1054258384
// https://github.com/Devsh-Graphics-Programming/Nabla/pull/345#discussion_r1056289599
//
// assert(!isImmutable_debug());
if (!m_descriptorInfos[static_cast<uint32_t>(type)])
return { nullptr, nullptr };
else
return { m_descriptorInfos[static_cast<uint32_t>(type)]->begin(), m_descriptorInfos[static_cast<uint32_t>(type)]->end() };
}

core::SRange<SDescriptorInfo> getDescriptorInfos(const ICPUDescriptorSetLayout::CBindingRedirect::binding_number_t binding, IDescriptor::E_TYPE type = IDescriptor::E_TYPE::ET_COUNT);

core::SRange<const SDescriptorInfo> getDescriptorInfos(const ICPUDescriptorSetLayout::CBindingRedirect::binding_number_t binding, IDescriptor::E_TYPE type = IDescriptor::E_TYPE::ET_COUNT) const;

core::smart_refctd_ptr<IAsset> clone(uint32_t _depth = ~0u) const override;

void convertToDummyObject(uint32_t referenceLevelsBelowToConvert = 0u) override;

protected:
void restoreFromDummy_impl(IAsset* _other, uint32_t _levelsBelow) override;

bool isAnyDependencyDummy_impl(uint32_t _levelsBelow) const override;

virtual ~ICPUDescriptorSet() = default;

private:
static inline IDescriptor::E_CATEGORY getCategoryFromType(const IDescriptor::E_TYPE type)
{
auto category = IDescriptor::E_CATEGORY::EC_COUNT;
switch (type)
{
auto* other = static_cast<ICPUDescriptorSet*>(_other);

if (_levelsBelow)
{
--_levelsBelow;
restoreFromDummy_impl_call(m_layout.get(), other->getLayout(), _levelsBelow);
for (auto it = m_descriptors->begin(); it != m_descriptors->end(); it++)
{
auto descriptor = it->desc.get();
if (!descriptor)
continue;
const auto i = it - m_descriptors->begin();
auto* d_other = other->m_descriptors->begin()[i].desc.get();

switch (descriptor->getTypeCategory())
{
case IDescriptor::EC_BUFFER:
restoreFromDummy_impl_call(static_cast<ICPUBuffer*>(descriptor), static_cast<ICPUBuffer*>(d_other), _levelsBelow);
break;
case IDescriptor::EC_IMAGE:
restoreFromDummy_impl_call(static_cast<ICPUImageView*>(descriptor), static_cast<ICPUImageView*>(d_other), _levelsBelow);
if (descriptor->getTypeCategory() == IDescriptor::EC_IMAGE && it->image.sampler)
restoreFromDummy_impl_call(it->image.sampler.get(), other->m_descriptors->begin()[i].image.sampler.get(), _levelsBelow);
break;
case IDescriptor::EC_BUFFER_VIEW:
restoreFromDummy_impl_call(static_cast<ICPUBufferView*>(descriptor), static_cast<ICPUBufferView*>(d_other), _levelsBelow);
break;
}
}
}
}

bool isAnyDependencyDummy_impl(uint32_t _levelsBelow) const override
{
--_levelsBelow;
if (m_layout->isAnyDependencyDummy(_levelsBelow))
return true;
for (auto it = m_descriptors->begin(); it != m_descriptors->end(); it++)
{
auto descriptor = it->desc.get();
if (!descriptor)
continue;

switch (descriptor->getTypeCategory())
{
case IDescriptor::EC_BUFFER:
if (static_cast<ICPUBuffer*>(descriptor)->isAnyDependencyDummy(_levelsBelow))
return true;
break;
case IDescriptor::EC_IMAGE:
if (static_cast<ICPUImageView*>(descriptor)->isAnyDependencyDummy(_levelsBelow))
return true;
if (it->image.sampler && it->image.sampler->isAnyDependencyDummy(_levelsBelow))
return true;
break;
case IDescriptor::EC_BUFFER_VIEW:
if (static_cast<ICPUBufferView*>(descriptor)->isAnyDependencyDummy(_levelsBelow))
return true;
break;
}
}
return false;
case IDescriptor::E_TYPE::ET_COMBINED_IMAGE_SAMPLER: [[fallthrough]];
case IDescriptor::E_TYPE::ET_STORAGE_IMAGE: [[fallthrough]];
case IDescriptor::E_TYPE::ET_INPUT_ATTACHMENT:
category = IDescriptor::E_CATEGORY::EC_IMAGE;
break;

case IDescriptor::E_TYPE::ET_UNIFORM_BUFFER: [[fallthrough]];
case IDescriptor::E_TYPE::ET_UNIFORM_BUFFER_DYNAMIC: [[fallthrough]];
case IDescriptor::E_TYPE::ET_STORAGE_BUFFER: [[fallthrough]];
case IDescriptor::E_TYPE::ET_STORAGE_BUFFER_DYNAMIC:
category = IDescriptor::E_CATEGORY::EC_BUFFER;
break;

case IDescriptor::E_TYPE::ET_UNIFORM_TEXEL_BUFFER:
case IDescriptor::E_TYPE::ET_STORAGE_TEXEL_BUFFER:
category = IDescriptor::E_CATEGORY::EC_BUFFER_VIEW;
break;

case IDescriptor::E_TYPE::ET_ACCELERATION_STRUCTURE:
category = IDescriptor::E_CATEGORY::EC_ACCELERATION_STRUCTURE;
break;

default:
assert(!"Invalid code path.");
}
return category;
}

virtual ~ICPUDescriptorSet() = default;
core::smart_refctd_dynamic_array<ICPUDescriptorSet::SDescriptorInfo> m_descriptorInfos[static_cast<uint32_t>(IDescriptor::E_TYPE::ET_COUNT)];
};

}
Expand Down
Loading

0 comments on commit 14cf8e7

Please sign in to comment.