6
6
7
7
#include < type_traits>
8
8
9
- #include " nbl/core/alloc/null_allocator.h"
10
-
11
9
#include " nbl/asset/IBuffer.h"
12
10
#include " nbl/asset/IAsset.h"
13
11
#include " nbl/asset/IPreHashed.h"
14
12
15
13
namespace nbl ::asset
16
14
{
17
15
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
+
18
24
// ! One of CPU class-object representing an Asset
25
+ // ! TODO: remove, alloc can fail, should be a static create method instead!
19
26
/* *
20
27
One of Assets used for storage of large arrays, so that storage can be decoupled
21
28
from other objects such as meshbuffers, images, animations and shader source/bytecode.
22
29
23
30
@see IAsset
24
31
*/
25
- class ICPUBuffer : public asset ::IBuffer, public IPreHashed
32
+ class ICPUBuffer final : public asset::IBuffer, public IPreHashed
26
33
{
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
-
31
34
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) {}
40
37
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 );
42
60
}
43
61
44
62
core::smart_refctd_ptr<IAsset> clone (uint32_t = ~0u ) const override final
45
63
{
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 );
48
66
cp->setContentHash (getContentHash ());
49
67
return cp;
50
68
}
51
69
52
70
constexpr static inline auto AssetType = ET_BUFFER;
53
71
inline IAsset::E_TYPE getAssetType () const override final { return AssetType; }
54
72
55
- inline size_t getDependantCount () const override {return 0 ;}
73
+ inline size_t getDependantCount () const override { return 0 ; }
56
74
57
75
//
58
76
inline core::blake3_hash_t computeContentHash () const override
59
77
{
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);
64
82
}
65
83
66
- inline bool missingContent () const override {return !data; }
84
+ inline bool missingContent () const override { return !m_data; }
67
85
68
86
// ! 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
+ {
72
90
assert (isMutable ());
73
- return data ;
91
+ return m_data ;
74
92
}
75
-
93
+
76
94
inline core::bitflag<E_USAGE_FLAGS> getUsageFlags () const
77
95
{
78
96
return m_creationParams.usage ;
@@ -90,93 +108,30 @@ class ICPUBuffer : public asset::IBuffer, public IPreHashed
90
108
return true ;
91
109
}
92
110
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;
180
135
};
181
136
182
137
} // end namespace nbl::asset
0 commit comments