66
77#include < type_traits>
88
9- #include " nbl/core/alloc/null_allocator.h"
10-
119#include " nbl/asset/IBuffer.h"
1210#include " nbl/asset/IAsset.h"
1311#include " nbl/asset/IPreHashed.h"
1412
13+ #include " nbl/core/alloc/refctd_memory_resource.h"
14+
1515namespace nbl ::asset
1616{
1717
@@ -22,57 +22,80 @@ namespace nbl::asset
2222
2323 @see IAsset
2424*/
25- class ICPUBuffer : public asset ::IBuffer, public IPreHashed
25+ class ICPUBuffer final : public asset::IBuffer, public IPreHashed
2626{
27- protected:
28- // ! Non-allocating constructor for CCustormAllocatorCPUBuffer derivative
29- ICPUBuffer (size_t sizeInBytes, void * dat) : asset::IBuffer({ dat ? sizeInBytes : 0 ,EUF_TRANSFER_DST_BIT }), data(dat) {}
30-
3127 public:
32- // ! Constructor. TODO: remove, alloc can fail, should be a static create method instead!
33- /* * @param sizeInBytes Size in bytes. If `dat` argument is present, it denotes size of data pointed by `dat`, otherwise - size of data to be allocated.
34- */
35- ICPUBuffer (size_t sizeInBytes) : asset::IBuffer({0 ,EUF_TRANSFER_DST_BIT})
28+ struct SCreationParams : asset::IBuffer::SCreationParams
3629 {
37- data = _NBL_ALIGNED_MALLOC (sizeInBytes,_NBL_SIMD_ALIGNMENT);
38- if (!data) // FIXME: cannot fail like that, need factory `create` methods
39- return ;
30+ size_t size;
31+ void * data = nullptr ;
32+ size_t alignment = _NBL_SIMD_ALIGNMENT;
33+ core::smart_refctd_ptr<core::refctd_memory_resource> memoryResource = nullptr ;
34+
35+ SCreationParams& operator =(const asset::IBuffer::SCreationParams& rhs)
36+ {
37+ static_cast <asset::IBuffer::SCreationParams&>(*this ) = rhs;
38+ return *this ;
39+ }
40+ };
41+
42+ // ! allocates uninitialized memory, copies `data` into allocation if `!data` not nullptr
43+ core::smart_refctd_ptr<ICPUBuffer> static create (SCreationParams&& params)
44+ {
45+ if (!params.memoryResource )
46+ params.memoryResource = core::getDefaultMemoryResource ();
47+
48+ auto data = params.memoryResource ->allocate (params.size , params.alignment );
49+ if (!data)
50+ return nullptr ;
51+ if (params.data )
52+ memcpy (data, params.data , params.size );
53+ params.data = data;
54+
55+ return core::smart_refctd_ptr<ICPUBuffer>(new ICPUBuffer (std::move (params)), core::dont_grab);
56+ }
4057
41- m_creationParams.size = sizeInBytes;
58+ // ! does not allocate memory, adopts the `data` pointer, no copies done
59+ core::smart_refctd_ptr<ICPUBuffer> static create (SCreationParams&& params, core::adopt_memory_t )
60+ {
61+ if (!params.data )
62+ return nullptr ;
63+ if (!params.memoryResource )
64+ params.memoryResource = core::getDefaultMemoryResource ();
65+ return core::smart_refctd_ptr<ICPUBuffer>(new ICPUBuffer (std::move (params)), core::dont_grab);
4266 }
4367
4468 core::smart_refctd_ptr<IAsset> clone (uint32_t = ~0u ) const override final
4569 {
46- auto cp = core::make_smart_refctd_ptr<ICPUBuffer>( m_creationParams.size );
47- memcpy (cp->getPointer (), data , m_creationParams.size );
70+ auto cp = create ({ . size = m_creationParams.size , . data = m_data, . alignment = m_alignment } );
71+ memcpy (cp->getPointer (), m_data , m_creationParams.size );
4872 cp->setContentHash (getContentHash ());
4973 return cp;
5074 }
5175
5276 constexpr static inline auto AssetType = ET_BUFFER;
5377 inline IAsset::E_TYPE getAssetType () const override final { return AssetType; }
5478
55- inline size_t getDependantCount () const override {return 0 ;}
79+ inline size_t getDependantCount () const override { return 0 ; }
5680
57- //
5881 inline core::blake3_hash_t computeContentHash () const override
5982 {
60- core::blake3_hasher hasher;
61- if (data )
62- hasher.update (data, m_creationParams.size );
63- return static_cast <core::blake3_hash_t >(hasher);
83+ core::blake3_hasher hasher;
84+ if (m_data )
85+ hasher.update (m_data, m_creationParams.size );
86+ return static_cast <core::blake3_hash_t >(hasher);
6487 }
6588
66- inline bool missingContent () const override {return !data; }
89+ inline bool missingContent () const override { return !m_data; }
6790
6891 // ! Returns pointer to data.
69- const void * getPointer () const {return data; }
70- void * getPointer ()
71- {
92+ const void * getPointer () const { return m_data; }
93+ void * getPointer ()
94+ {
7295 assert (isMutable ());
73- return data ;
96+ return m_data ;
7497 }
75-
98+
7699 inline core::bitflag<E_USAGE_FLAGS> getUsageFlags () const
77100 {
78101 return m_creationParams.usage ;
@@ -90,93 +113,33 @@ class ICPUBuffer : public asset::IBuffer, public IPreHashed
90113 return true ;
91114 }
92115
93- protected:
94- inline IAsset* getDependant_impl (const size_t ix) override
95- {
96- return nullptr ;
97- }
98-
99- inline void discardContent_impl () override
100- {
101- return freeData ();
102- }
103-
104- // REMEMBER TO CALL FROM DTOR!
105- // TODO: idea, make the `ICPUBuffer` an ADT, and use the default allocator CCPUBuffer instead for consistency
106- // TODO: idea make a macro for overriding all `delete` operators of a class to enforce a finalizer that runs in reverse order to destructors (to allow polymorphic cleanups)
107- virtual inline void freeData ()
108- {
109- if (data)
110- _NBL_ALIGNED_FREE (data);
111- data = nullptr ;
112- m_creationParams.size = 0ull ;
113- }
114-
115- void * data;
116- };
117-
118-
119- template <
120- typename Allocator = _NBL_DEFAULT_ALLOCATOR_METATYPE<uint8_t >,
121- bool = std::is_same<Allocator, core::null_allocator<typename Allocator::value_type> >::value
122- >
123- class CCustomAllocatorCPUBuffer ;
124-
125- using CDummyCPUBuffer = CCustomAllocatorCPUBuffer<core::null_allocator<uint8_t >, true >;
126-
127- // ! Specialization of ICPUBuffer capable of taking custom allocators
128- /*
129- Take a look that with this usage you have to specify custom alloctor
130- passing an object type for allocation and a pointer to allocated
131- data for it's storage by ICPUBuffer.
132-
133- So the need for the class existence is for common following tricks - among others creating an
134- \bICPUBuffer\b over an already existing \bvoid*\b array without any \imemcpy\i or \itaking over the memory ownership\i.
135- You can use it with a \bnull_allocator\b that adopts memory (it is a bit counter intuitive because \badopt = take\b ownership,
136- but a \inull allocator\i doesn't do anything, even free the memory, so you're all good).
137- */
138-
139- template <typename Allocator>
140- class CCustomAllocatorCPUBuffer <Allocator,true > : public ICPUBuffer
141- {
142- static_assert (sizeof (typename Allocator::value_type) == 1u , " Allocator::value_type must be of size 1" );
143- protected:
144- Allocator m_allocator;
145-
146- virtual ~CCustomAllocatorCPUBuffer () final
147- {
148- freeData ();
149- }
150- inline void freeData () override
151- {
152- if (ICPUBuffer::data)
153- m_allocator.deallocate (reinterpret_cast <typename Allocator::pointer>(ICPUBuffer::data), ICPUBuffer::m_creationParams.size );
154- ICPUBuffer::data = nullptr ; // so that ICPUBuffer won't try deallocating
155- }
156-
157- public:
158- CCustomAllocatorCPUBuffer (size_t sizeInBytes, void * dat, core::adopt_memory_t , Allocator&& alctr = Allocator()) : ICPUBuffer(sizeInBytes,dat), m_allocator(std::move(alctr))
159- {
160- }
161- };
162-
163- template <typename Allocator>
164- class CCustomAllocatorCPUBuffer <Allocator, false > : public CCustomAllocatorCPUBuffer<Allocator, true >
165- {
166- using Base = CCustomAllocatorCPUBuffer<Allocator, true >;
167-
168- protected:
169- virtual ~CCustomAllocatorCPUBuffer () = default ;
170- inline void freeData () override {}
171-
172- public:
173- using Base::Base;
174-
175- // TODO: remove, alloc can fail, should be a static create method instead!
176- CCustomAllocatorCPUBuffer (size_t sizeInBytes, const void * dat, Allocator&& alctr = Allocator()) : Base(sizeInBytes, alctr.allocate(sizeInBytes), core::adopt_memory, std::move(alctr))
177- {
178- memcpy (Base::data,dat,sizeInBytes);
179- }
116+ protected:
117+ inline IAsset* getDependant_impl (const size_t ix) override
118+ {
119+ return nullptr ;
120+ }
121+
122+ inline void discardContent_impl () override
123+ {
124+ if (m_data)
125+ m_mem_resource->deallocate (m_data, m_creationParams.size , m_alignment);
126+ m_data = nullptr ;
127+ m_mem_resource = nullptr ;
128+ m_creationParams.size = 0ull ;
129+ }
130+
131+ private:
132+ ICPUBuffer (SCreationParams&& params) :
133+ asset::IBuffer ({ params.size , EUF_TRANSFER_DST_BIT }), m_data(params.data),
134+ m_mem_resource (params.memoryResource), m_alignment(params.alignment) {}
135+
136+ ~ICPUBuffer () override {
137+ discardContent_impl ();
138+ }
139+
140+ void * m_data;
141+ core::smart_refctd_ptr<core::refctd_memory_resource> m_mem_resource;
142+ size_t m_alignment;
180143};
181144
182145} // end namespace nbl::asset
0 commit comments