|
12 | 12 | namespace nbl::video |
13 | 13 | { |
14 | 14 |
|
15 | | -// address allocator gives offsets |
16 | | -// reserved allocator allocates memory to keep the address allocator state inside |
17 | | -template<class AddrAllocator, class ReservAllocator=core::allocator<uint8_t>> |
18 | 15 | class SubAllocatedDescriptorSet : public core::IReferenceCounted |
19 | 16 | { |
20 | | - public: |
21 | | - using AddressAllocator = AddrAllocator; |
22 | | - using ReservedAllocator = ReservAllocator; |
23 | | - using size_type = typename AddressAllocator::size_type; |
24 | | - using value_type = typename AddressAllocator::size_type; |
25 | | - static constexpr value_type invalid_value = AddressAllocator::invalid_address; |
26 | | - |
27 | | - // constructors |
28 | | - template<typename... Args> |
29 | | - inline SubAllocatedDescriptorSet(const std::span<const video::IGPUDescriptorSetLayout::SBinding> bindings, |
30 | | - ReservedAllocator&& _reservedAllocator, const value_type maxAllocatableAlignment, Args&&... args) |
31 | | - { |
32 | | - auto allocatableDescriptors = 0; |
33 | | - m_allocatableRanges.reserve(bindings.size()); |
34 | | - |
35 | | - for (auto& binding : bindings) |
36 | | - { |
37 | | - SubAllocDescriptorSetRange range; |
38 | | - range.offset = allocatableDescriptors; |
39 | | - range.binding = binding; |
40 | | - // Only bindings with these flags will be allocatable |
41 | | - if (binding.createFlags.hasFlags(core::bitflag(IGPUDescriptorSetLayout::SBinding::E_CREATE_FLAGS::ECF_UPDATE_AFTER_BIND_BIT) |
42 | | - | IGPUDescriptorSetLayout::SBinding::E_CREATE_FLAGS::ECF_UPDATE_UNUSED_WHILE_PENDING_BIT |
43 | | - | IGPUDescriptorSetLayout::SBinding::E_CREATE_FLAGS::ECF_PARTIALLY_BOUND_BIT)) |
44 | | - { |
45 | | - allocatableDescriptors += binding.count; |
46 | | - } |
47 | | - m_allocatableRanges.push_back(range); |
48 | | - } |
49 | | - |
50 | | - m_addressAllocator = AddrAllocator( |
51 | | - _reservedAllocator.allocate(AddressAllocator::reserved_size(maxAllocatableAlignment, static_cast<size_type>(allocatableDescriptors), args...), _NBL_SIMD_ALIGNMENT), |
52 | | - static_cast<size_type>(0), 0u, maxAllocatableAlignment, static_cast<size_type>(allocatableDescriptors), std::forward<Args>(args)... |
53 | | - ); |
54 | | - m_reservedAllocator = ReservedAllocator(std::move(_reservedAllocator)); |
55 | | - m_reservedSize = allocatableDescriptors; |
56 | | - } |
57 | | - // version with default constructed reserved allocator |
58 | | - template<typename... Args> |
59 | | - explicit inline SubAllocatedDescriptorSet(const std::span<const video::IGPUDescriptorSetLayout::SBinding> bindings, |
60 | | - const value_type maxAllocatableAlignment, Args&&... args) : |
61 | | - SubAllocatedDescriptorSet(bindings,ReservedAllocator(),maxAllocatableAlignment,std::forward<Args>(args)...) |
62 | | - { |
63 | | - } |
64 | | - ~SubAllocatedDescriptorSet() |
65 | | - { |
66 | | - auto ptr = reinterpret_cast<const uint8_t*>(core::address_allocator_traits<AddressAllocator>::getReservedSpacePtr(m_addressAllocator)); |
67 | | - m_reservedAllocator.deallocate(const_cast<uint8_t*>(ptr),m_reservedSize); |
68 | | - } |
69 | | - |
70 | | - // anyone gonna use it? |
71 | | - inline const AddressAllocator& getAddressAllocator() const {return m_addressAllocator;} |
72 | | - |
73 | | - // |
74 | | - inline ReservedAllocator& getReservedAllocator() {return m_reservedAllocator;} |
75 | | - |
76 | | - // main methods |
77 | | - |
78 | | - //! Warning `outAddresses` needs to be primed with `invalid_value` values, otherwise no allocation happens for elements not equal to `invalid_value` |
79 | | - template<typename... Args> |
80 | | - inline void multi_allocate(uint32_t count, value_type* outAddresses, const size_type* sizes, const Args&... args) |
81 | | - { |
82 | | - core::address_allocator_traits<AddressAllocator>::multi_alloc_addr(m_addressAllocator,count,outAddresses,sizes,1,args...); |
83 | | - } |
84 | | - inline void multi_deallocate(uint32_t count, const size_type* addr, const size_type* sizes) |
85 | | - { |
86 | | - core::address_allocator_traits<AddressAllocator>::multi_free_addr(m_addressAllocator,count,addr,sizes); |
87 | | - } |
88 | | - |
89 | | - // to conform to IBufferAllocator concept |
90 | | - template<typename... Args> |
91 | | - inline value_type allocate(const size_type bytes, const size_type alignment, const Args&... args) |
92 | | - { |
93 | | - value_type retval = invalid_value; |
94 | | - multi_allocate(&retval,&bytes,&alignment,args...); |
95 | | - return retval; |
96 | | - } |
97 | | - template<typename... Args> |
98 | | - inline void deallocate(value_type& allocation, Args&&... args) |
99 | | - { |
100 | | - multi_deallocate(std::forward<Args>(args)...); |
101 | | - allocation = invalid_value; |
102 | | - } |
103 | | - |
104 | | - protected: |
105 | | - AddressAllocator m_addressAllocator; |
106 | | - ReservedAllocator m_reservedAllocator; |
107 | | - size_t m_reservedSize; // FIXME: uninitialized variable |
108 | | - |
109 | | - struct SubAllocDescriptorSetRange { |
110 | | - uint32_t offset; |
111 | | - video::IGPUDescriptorSetLayout::SBinding binding; |
112 | | - }; |
113 | | - std::vector<SubAllocDescriptorSetRange> m_allocatableRanges = {}; |
| 17 | +public: |
| 18 | + // address allocator gives offsets |
| 19 | + // reserved allocator allocates memory to keep the address allocator state inside |
| 20 | + using AddressAllocator = core::GeneralpurposeAddressAllocator<uint32_t>; |
| 21 | + using ReservedAllocator = core::allocator<uint8_t>; |
| 22 | + using size_type = typename AddressAllocator::size_type; |
| 23 | + using value_type = typename AddressAllocator::size_type; |
| 24 | + static constexpr value_type invalid_value = AddressAllocator::invalid_address; |
| 25 | + |
| 26 | +protected: |
| 27 | + struct SubAllocDescriptorSetRange { |
| 28 | + video::IGPUDescriptorSetLayout::SBinding binding; |
| 29 | + std::shared_ptr<AddressAllocator> addressAllocator; |
| 30 | + std::shared_ptr<ReservedAllocator> reservedAllocator; |
| 31 | + size_t reservedSize; |
| 32 | + }; |
| 33 | + std::vector<SubAllocDescriptorSetRange> m_allocatableRanges = {}; |
| 34 | + |
| 35 | + |
| 36 | +public: |
| 37 | + // constructors |
| 38 | + template<typename... Args> |
| 39 | + inline SubAllocatedDescriptorSet(const std::span<const video::IGPUDescriptorSetLayout::SBinding> bindings, |
| 40 | + const value_type maxAllocatableAlignment, Args&&... args) |
| 41 | + { |
| 42 | + m_allocatableRanges.reserve(bindings.size()); |
| 43 | + |
| 44 | + for (auto& binding : bindings) |
| 45 | + { |
| 46 | + SubAllocDescriptorSetRange range; |
| 47 | + range.binding = binding; |
| 48 | + range.reservedSize = 0; |
| 49 | + // Only bindings with these flags will be allocatable |
| 50 | + if (binding.createFlags.hasFlags(core::bitflag(IGPUDescriptorSetLayout::SBinding::E_CREATE_FLAGS::ECF_UPDATE_AFTER_BIND_BIT) |
| 51 | + | IGPUDescriptorSetLayout::SBinding::E_CREATE_FLAGS::ECF_UPDATE_UNUSED_WHILE_PENDING_BIT |
| 52 | + | IGPUDescriptorSetLayout::SBinding::E_CREATE_FLAGS::ECF_PARTIALLY_BOUND_BIT)) |
| 53 | + { |
| 54 | + range.reservedSize = AddressAllocator::reserved_size(maxAllocatableAlignment, static_cast<size_type>(binding.count), args...); |
| 55 | + range.reservedAllocator = std::shared_ptr<ReservedAllocator>(new ReservedAllocator()); |
| 56 | + range.addressAllocator = std::shared_ptr<AddressAllocator>(new AddressAllocator( |
| 57 | + range.reservedAllocator->allocate(range.reservedSize, _NBL_SIMD_ALIGNMENT), |
| 58 | + static_cast<size_type>(0), 0u, maxAllocatableAlignment, static_cast<size_type>(binding.count), std::forward<Args>(args)... |
| 59 | + )); |
| 60 | + } |
| 61 | + m_allocatableRanges.push_back(range); |
| 62 | + } |
| 63 | + |
| 64 | + } |
| 65 | + |
| 66 | + ~SubAllocatedDescriptorSet() |
| 67 | + { |
| 68 | + for (uint32_t i = 0; i < m_allocatableRanges.size(); i++) |
| 69 | + { |
| 70 | + auto& range = m_allocatableRanges[i]; |
| 71 | + if (range.reservedSize == 0) |
| 72 | + continue; |
| 73 | + |
| 74 | + auto ptr = reinterpret_cast<const uint8_t*>(core::address_allocator_traits<AddressAllocator>::getReservedSpacePtr(*range.addressAllocator)); |
| 75 | + range.reservedAllocator->deallocate(const_cast<uint8_t*>(ptr), range.reservedSize); |
| 76 | + } |
| 77 | + } |
| 78 | + |
| 79 | + // main methods |
| 80 | + |
| 81 | + //! Warning `outAddresses` needs to be primed with `invalid_value` values, otherwise no allocation happens for elements not equal to `invalid_value` |
| 82 | + template<typename... Args> |
| 83 | + inline void multi_allocate(uint32_t binding, uint32_t count, value_type* outAddresses, const size_type* sizes, const Args&... args) |
| 84 | + { |
| 85 | + auto& range = m_allocatableRanges[binding]; |
| 86 | + assert(range.reservedSize); // Check if this binding has an allocator |
| 87 | + core::address_allocator_traits<AddressAllocator>::multi_alloc_addr(*range.addressAllocator, count, outAddresses, sizes, 1, args...); |
| 88 | + } |
| 89 | + inline void multi_deallocate(uint32_t binding, uint32_t count, const size_type* addr, const size_type* sizes) |
| 90 | + { |
| 91 | + auto& range = m_allocatableRanges[binding]; |
| 92 | + assert(range.reservedSize); // Check if this binding has an allocator |
| 93 | + core::address_allocator_traits<AddressAllocator>::multi_free_addr(*range.addressAllocator, count, addr, sizes); |
| 94 | + } |
114 | 95 | }; |
115 | 96 |
|
116 | 97 | } |
|
0 commit comments