-
Notifications
You must be signed in to change notification settings - Fork 65
Add sub-allocated descriptor sets #657
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 10 commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
cc54740
Add sub-allocated descriptor set header
deprilula28 d10059f
Add some reusable binding API
deprilula28 347ff63
Work on using descriptor set layout directly
deprilula28 e1282c7
Remove out old bindings
deprilula28 28611be
Use pool address allocator
deprilula28 6c6046c
Use map
deprilula28 190067a
PR reviews
deprilula28 289e424
PR reviews
deprilula28 e0e91ff
Work on deferred freeing the descriptors
deprilula28 68582ea
Work on having descriptor set match with its sub allocator
deprilula28 d716848
PR reviews
deprilula28 4fd4b8f
Fix example
deprilula28 58c4e90
Add writing of descriptors on the allocate method
deprilula28 41b9a5b
Work on try allocate and timings
deprilula28 d608e78
Add PR comments
deprilula28 b326ca7
Work on nullifying descriptors
deprilula28 894a47c
Keep descriptor writes outside the allocate function
deprilula28 59c65ae
Include exporting of allocate descriptor writes instead of using them
deprilula28 1228f5f
Merge branch 'vulkan_1_3' into suballocdescriptorset
deprilula28 54250a6
Update examples submodule
deprilula28 2c35289
Update SubAllocatedDescriptorSet.h
devshgraphicsprogramming a2e2be4
Forgot that the nullification needs to be done between event-wait and…
devshgraphicsprogramming bc5b22d
PR review and fix compilation errors
deprilula28 912ed7a
PR reviews & nullifying descriptors
deprilula28 89e6440
Fix multi timeline functionality
deprilula28 ede586f
Update example
deprilula28 5531903
Implement depletion of sub alloc descriptor set
deprilula28 79c3a23
Fix API for nullify
deprilula28 6b5630d
Fix tabs & spaces
deprilula28 aca4c74
More PR reviews
deprilula28 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Submodule examples_tests
updated
5 files
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
// 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_SUB_ALLOCATED_DESCRIPTOR_SET_H_ | ||
#define _NBL_VIDEO_SUB_ALLOCATED_DESCRIPTOR_SET_H | ||
|
||
#include "nbl/video/alloc/IBufferAllocator.h" | ||
|
||
#include <type_traits> | ||
|
||
namespace nbl::video | ||
{ | ||
|
||
class SubAllocatedDescriptorSet : public core::IReferenceCounted | ||
{ | ||
public: | ||
// address allocator gives offsets | ||
// reserved allocator allocates memory to keep the address allocator state inside | ||
using AddressAllocator = core::PoolAddressAllocator<uint32_t>; | ||
using ReservedAllocator = core::allocator<uint8_t>; | ||
using size_type = typename AddressAllocator::size_type; | ||
using value_type = typename AddressAllocator::size_type; | ||
static constexpr value_type invalid_value = AddressAllocator::invalid_address; | ||
|
||
class DeferredFreeFunctor | ||
{ | ||
public: | ||
inline DeferredFreeFunctor(SubAllocatedDescriptorSet* composed, uint32_t binding, size_type count, value_type* addresses) | ||
: m_addresses(addresses, addresses + count), m_binding(binding), m_composed(composed) | ||
{ | ||
} | ||
|
||
// Just does the de-allocation | ||
inline void operator()() | ||
{ | ||
// isn't assert already debug-only? | ||
#ifdef _NBL_DEBUG | ||
assert(m_composed); | ||
#endif // _NBL_DEBUG | ||
m_composed->multi_deallocate(m_binding, m_addresses.size(), &m_addresses[0]); | ||
devshgraphicsprogramming marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
// Takes count of allocations we want to free up as reference, true is returned if | ||
// the amount of allocations freed was >= allocationsToFreeUp | ||
// False is returned if there are more allocations to free up | ||
inline bool operator()(size_type allocationsToFreeUp) | ||
devshgraphicsprogramming marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
auto prevCount = m_addresses.size(); | ||
operator()(); | ||
auto totalFreed = m_addresses.size() - prevCount; | ||
|
||
// This does the same logic as bool operator()(size_type&) on | ||
// CAsyncSingleBufferSubAllocator | ||
return totalFreed >= allocationsToFreeUp; | ||
} | ||
protected: | ||
SubAllocatedDescriptorSet* m_composed; | ||
uint32_t m_binding; | ||
std::vector<value_type> m_addresses; | ||
deprilula28 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}; | ||
protected: | ||
struct SubAllocDescriptorSetRange { | ||
std::shared_ptr<AddressAllocator> addressAllocator; | ||
std::shared_ptr<ReservedAllocator> reservedAllocator; | ||
devshgraphicsprogramming marked this conversation as resolved.
Show resolved
Hide resolved
|
||
size_t reservedSize; | ||
}; | ||
MultiTimelineEventHandlerST<DeferredFreeFunctor> eventHandler; | ||
devshgraphicsprogramming marked this conversation as resolved.
Show resolved
Hide resolved
|
||
std::map<uint32_t, SubAllocDescriptorSetRange> m_allocatableRanges = {}; | ||
core::smart_refctd_ptr<video::IGPUDescriptorSet> m_descriptorSet; | ||
|
||
#ifdef _NBL_DEBUG | ||
std::recursive_mutex stAccessVerfier; | ||
#endif // _NBL_DEBUG | ||
|
||
devshgraphicsprogramming marked this conversation as resolved.
Show resolved
Hide resolved
|
||
constexpr static inline uint32_t MaxDescriptorSetAllocationAlignment = 1u; | ||
constexpr static inline uint32_t MinDescriptorSetAllocationSize = 1u; | ||
|
||
public: | ||
|
||
// constructors | ||
template<typename... Args> | ||
inline SubAllocatedDescriptorSet(video::IGPUDescriptorSet* descriptorSet) | ||
devshgraphicsprogramming marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
auto layout = descriptorSet->getLayout(); | ||
for (uint32_t descriptorType = 0; descriptorType < static_cast<uint32_t>(asset::IDescriptor::E_TYPE::ET_COUNT); descriptorType++) | ||
{ | ||
auto descType = static_cast<asset::IDescriptor::E_TYPE>(descriptorType); | ||
auto& redirect = layout->getDescriptorRedirect(descType); | ||
|
||
for (uint32_t i = 0; i < redirect.getBindingCount(); i++) | ||
{ | ||
auto binding = redirect.getBinding(i); | ||
auto storageIndex = redirect.findBindingStorageIndex(binding); | ||
|
||
auto count = redirect.getCount(storageIndex); | ||
auto flags = redirect.getCreateFlags(storageIndex); | ||
|
||
// Only bindings with these flags will be allocatable | ||
if (flags.hasFlags(core::bitflag(IGPUDescriptorSetLayout::SBinding::E_CREATE_FLAGS::ECF_UPDATE_AFTER_BIND_BIT) | ||
| IGPUDescriptorSetLayout::SBinding::E_CREATE_FLAGS::ECF_UPDATE_UNUSED_WHILE_PENDING_BIT | ||
| IGPUDescriptorSetLayout::SBinding::E_CREATE_FLAGS::ECF_PARTIALLY_BOUND_BIT)) | ||
{ | ||
SubAllocDescriptorSetRange range; | ||
range.reservedSize = AddressAllocator::reserved_size(MaxDescriptorSetAllocationAlignment, static_cast<size_type>(count), MinDescriptorSetAllocationSize); | ||
range.reservedAllocator = std::shared_ptr<ReservedAllocator>(new ReservedAllocator()); | ||
range.addressAllocator = std::shared_ptr<AddressAllocator>(new AddressAllocator( | ||
range.reservedAllocator->allocate(range.reservedSize, _NBL_SIMD_ALIGNMENT), | ||
static_cast<size_type>(0), 0u, MaxDescriptorSetAllocationAlignment, static_cast<size_type>(count), | ||
MinDescriptorSetAllocationSize | ||
)); | ||
m_allocatableRanges.emplace(binding.data, range); | ||
} | ||
} | ||
} | ||
m_descriptorSet = core::smart_refctd_ptr(descriptorSet); | ||
} | ||
|
||
~SubAllocatedDescriptorSet() | ||
{ | ||
for (uint32_t i = 0; i < m_allocatableRanges.size(); i++) | ||
{ | ||
auto& range = m_allocatableRanges[i]; | ||
if (range.reservedSize == 0) | ||
continue; | ||
auto ptr = reinterpret_cast<const uint8_t*>(core::address_allocator_traits<AddressAllocator>::getReservedSpacePtr(*range.addressAllocator)); | ||
range.addressAllocator = nullptr; | ||
range.reservedAllocator->deallocate(const_cast<uint8_t*>(ptr), range.reservedSize); | ||
devshgraphicsprogramming marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} | ||
|
||
// whether that binding index can be sub-allocated | ||
bool isBindingAllocatable(uint32_t binding) { return m_allocatableRanges.find(binding) != m_allocatableRanges.end(); } | ||
|
||
AddressAllocator* getBindingAllocator(uint32_t binding) | ||
{ | ||
auto range = m_allocatableRanges.find(binding); | ||
assert(range != m_allocatableRanges.end());// Check if this binding has an allocator | ||
devshgraphicsprogramming marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return range->second.addressAllocator.get(); | ||
} | ||
|
||
// main methods | ||
devshgraphicsprogramming marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
#ifdef _NBL_DEBUG | ||
std::unique_lock<std::recursive_mutex> stAccessVerifyDebugGuard() | ||
{ | ||
std::unique_lock<std::recursive_mutex> tLock(stAccessVerfier,std::try_to_lock_t()); | ||
assert(tLock.owns_lock()); | ||
return tLock; | ||
} | ||
#else | ||
bool stAccessVerifyDebugGuard() { return false; } | ||
#endif | ||
|
||
//! Warning `outAddresses` needs to be primed with `invalid_value` values, otherwise no allocation happens for elements not equal to `invalid_value` | ||
inline void multi_allocate(uint32_t binding, size_type count, value_type* outAddresses) | ||
{ | ||
auto debugGuard = stAccessVerifyDebugGuard(); | ||
|
||
auto allocator = getBindingAllocator(binding); | ||
for (size_type i=0; i<count; i++) | ||
{ | ||
if (outAddresses[i]!=AddressAllocator::invalid_address) | ||
continue; | ||
|
||
outAddresses[i] = allocator->alloc_addr(1,1); | ||
// TODO: should also write something to the descriptor set (or probably leave that to the caller?) | ||
devshgraphicsprogramming marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} | ||
inline void multi_deallocate(uint32_t binding, size_type count, const size_type* addr) | ||
{ | ||
auto debugGuard = stAccessVerifyDebugGuard(); | ||
|
||
auto allocator = getBindingAllocator(binding); | ||
for (size_type i=0; i<count; i++) | ||
{ | ||
if (addr[i]==AddressAllocator::invalid_address) | ||
continue; | ||
|
||
allocator->free_addr(addr[i],1); | ||
// TODO: should also write something to the descriptor sets | ||
devshgraphicsprogramming marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} | ||
//! | ||
inline void multi_deallocate(const ISemaphore::SWaitInfo& futureWait, DeferredFreeFunctor&& functor) noexcept | ||
{ | ||
auto debugGuard = stAccessVerifyDebugGuard(); | ||
eventHandler.latch(futureWait,std::move(functor)); | ||
} | ||
// TODO: improve signature of this function in the future | ||
template<typename T=core::IReferenceCounted> | ||
devshgraphicsprogramming marked this conversation as resolved.
Show resolved
Hide resolved
|
||
inline void multi_deallocate(uint32_t binding, uint32_t count, const value_type* addr, const ISemaphore::SWaitInfo& futureWait) noexcept | ||
{ | ||
if (futureWait.semaphore) | ||
multi_deallocate(futureWait, DeferredFreeFunctor(&this, binding, count, addr)); | ||
else | ||
multi_deallocate(binding, count, addr); | ||
} | ||
//! Returns free events still outstanding | ||
inline uint32_t cull_frees() noexcept | ||
{ | ||
auto debugGuard = stAccessVerifyDebugGuard(); | ||
return eventHandler.poll().eventsLeft; | ||
devshgraphicsprogramming marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
}; | ||
|
||
} | ||
|
||
#endif |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.