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
1513namespace nbl ::asset
1614{
1715
16+ struct SICPUBufferCreationParams
17+ {
18+ size_t size;
19+ void * data = nullptr ;
20+ size_t alignment = _NBL_SIMD_ALIGNMENT;
21+ std::pmr::memory_resource* memoryResource = nullptr ;
22+ };
23+
1824// ! One of CPU class-object representing an Asset
25+ // ! TODO: remove, alloc can fail, should be a static create method instead!
1926/* *
2027 One of Assets used for storage of large arrays, so that storage can be decoupled
2128 from other objects such as meshbuffers, images, animations and shader source/bytecode.
2229
2330 @see IAsset
2431*/
25- class ICPUBuffer : public asset ::IBuffer, public IPreHashed
32+ class ICPUBuffer final : public asset::IBuffer, public IPreHashed
2633{
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-
3134 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})
36- {
37- data = _NBL_ALIGNED_MALLOC (sizeInBytes,_NBL_SIMD_ALIGNMENT);
38- if (!data) // FIXME: cannot fail like that, need factory `create` methods
39- return ;
35+ ICPUBuffer (size_t size, void * data, std::pmr::memory_resource* memoryResource, size_t alignment, bool adopt_memory) :
36+ asset::IBuffer ({ size, EUF_TRANSFER_DST_BIT }), m_data(data), m_mem_resource(memoryResource), m_alignment(alignment), m_adopt_memory(adopt_memory) {}
4037
41- m_creationParams.size = sizeInBytes;
38+ // ! allocates uninitialized memory, copies `data` into allocation if `!data` not nullptr
39+ core::smart_refctd_ptr<ICPUBuffer> static create (const SICPUBufferCreationParams& params) {
40+ std::pmr::memory_resource* memoryResource = params.memoryResource ;
41+ if (!params.memoryResource )
42+ memoryResource = std::pmr::get_default_resource ();
43+
44+ auto data = memoryResource->allocate (params.size , params.alignment );
45+ if (!data)
46+ return nullptr ;
47+
48+ if (params.data )
49+ memcpy (data, params.data , params.size );
50+
51+ return core::make_smart_refctd_ptr<ICPUBuffer>(params.size , data, memoryResource, params.alignment , false );
52+ }
53+
54+ // ! does not allocate memory, adopts the `data` pointer, no copies done
55+ core::smart_refctd_ptr<ICPUBuffer> static create (const SICPUBufferCreationParams& params, core::adopt_memory_t ) {
56+ std::pmr::memory_resource* memoryResource;
57+ if (!params.memoryResource )
58+ memoryResource = std::pmr::get_default_resource ();
59+ return core::make_smart_refctd_ptr<ICPUBuffer>(params.size , params.data , memoryResource, params.alignment , true );
4260 }
4361
4462 core::smart_refctd_ptr<IAsset> clone (uint32_t = ~0u ) const override final
4563 {
46- auto cp = core::make_smart_refctd_ptr<ICPUBuffer>( m_creationParams.size );
47- memcpy (cp->getPointer (), data , m_creationParams.size );
64+ auto cp = create ({ m_creationParams.size , m_data } );
65+ memcpy (cp->getPointer (), m_data , m_creationParams.size );
4866 cp->setContentHash (getContentHash ());
4967 return cp;
5068 }
5169
5270 constexpr static inline auto AssetType = ET_BUFFER;
5371 inline IAsset::E_TYPE getAssetType () const override final { return AssetType; }
5472
55- inline size_t getDependantCount () const override {return 0 ;}
73+ inline size_t getDependantCount () const override { return 0 ; }
5674
5775 //
5876 inline core::blake3_hash_t computeContentHash () const override
5977 {
60- core::blake3_hasher hasher;
61- if (data )
62- hasher.update (data, m_creationParams.size );
63- return static_cast <core::blake3_hash_t >(hasher);
78+ core::blake3_hasher hasher;
79+ if (m_data )
80+ hasher.update (m_data, m_creationParams.size );
81+ return static_cast <core::blake3_hash_t >(hasher);
6482 }
6583
66- inline bool missingContent () const override {return !data; }
84+ inline bool missingContent () const override { return !m_data; }
6785
6886 // ! Returns pointer to data.
69- const void * getPointer () const {return data; }
70- void * getPointer ()
71- {
87+ const void * getPointer () const { return m_data; }
88+ void * getPointer ()
89+ {
7290 assert (isMutable ());
73- return data ;
91+ return m_data ;
7492 }
75-
93+
7694 inline core::bitflag<E_USAGE_FLAGS> getUsageFlags () const
7795 {
7896 return m_creationParams.usage ;
@@ -90,93 +108,30 @@ class ICPUBuffer : public asset::IBuffer, public IPreHashed
90108 return true ;
91109 }
92110
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- }
111+ protected:
112+ inline IAsset* getDependant_impl (const size_t ix) override
113+ {
114+ return nullptr ;
115+ }
116+
117+ inline void discardContent_impl () override
118+ {
119+ return freeData ();
120+ }
121+
122+ // REMEMBER TO CALL FROM DTOR!
123+ virtual inline void freeData ()
124+ {
125+ if (!m_adopt_memory && m_data)
126+ m_mem_resource->deallocate (m_data, m_creationParams.size , m_alignment);
127+ m_data = nullptr ;
128+ m_creationParams.size = 0ull ;
129+ }
130+
131+ void * m_data;
132+ std::pmr::memory_resource* m_mem_resource;
133+ size_t m_alignment;
134+ bool m_adopt_memory;
180135};
181136
182137} // end namespace nbl::asset
0 commit comments