UraniumCompute 0.1.0
A GPU accelerated parallel task scheduler
IDeviceMemory.h
1#pragma once
2#include <UnCompute/Backend/IBuffer.h>
3#include <UnCompute/Backend/MemoryKindFlags.h>
4#include <UnCompute/Base/Flags.h>
5#include <UnCompute/Containers/ArraySlice.h>
6#include <limits>
7
8namespace UN
9{
12 {
13 const char* Name = nullptr;
14 UInt64 Size = 0;
15 MemoryKindFlags Flags = MemoryKindFlags::None;
17
18 inline DeviceMemoryDesc() = default;
19
20 inline DeviceMemoryDesc(const char* name, MemoryKindFlags flags, UInt64 size, ArraySlice<IDeviceObject*> objects)
21 : Name(name)
22 , Size(size)
23 , Flags(flags)
24 , Objects(objects)
25 {
26 }
27 };
28
31 {
32 public:
34
36 inline static constexpr UInt64 WholeSize = std::numeric_limits<UInt64>::max();
37
38 [[nodiscard]] virtual const DescriptorType& GetDesc() const = 0;
39
45 virtual ResultCode Init(const DescriptorType& desc) = 0;
46
56 virtual ResultCode Map(UInt64 byteOffset, UInt64 byteSize, void** ppData) = 0;
57
61 virtual void Unmap() = 0;
62
73 [[nodiscard]] virtual bool IsCompatible(IDeviceObject* pObject, UInt64 sizeLimit) = 0;
74
84 [[nodiscard]] virtual bool IsCompatible(IDeviceObject* pObject) = 0;
85 };
86
89 {
90 IDeviceMemory* m_pMemory = nullptr;
91 UInt64 m_ByteOffset = 0;
92 UInt64 m_ByteSize = 0;
93
94 public:
95 inline DeviceMemorySlice() = default;
96
102 inline explicit DeviceMemorySlice(IDeviceMemory* pMemory, UInt64 byteOffset = 0,
103 UInt64 byteSize = IDeviceMemory::WholeSize)
104 {
105 m_pMemory = pMemory;
106 m_ByteOffset = byteOffset;
107 m_ByteSize = std::min(byteSize, pMemory->GetDesc().Size - byteOffset);
108 UN_Assert(byteSize == IDeviceMemory::WholeSize || byteSize <= pMemory->GetDesc().Size - byteOffset,
109 "Invalid memory slice size");
110 }
111
113 [[nodiscard]] inline IDeviceMemory* GetDeviceMemory() const
114 {
115 return m_pMemory;
116 }
117
119 [[nodiscard]] inline UInt64 GetByteOffset() const
120 {
121 return m_ByteOffset;
122 }
123
125 [[nodiscard]] inline UInt64 GetByteSize() const
126 {
127 return m_ByteSize;
128 }
129
135 [[nodiscard]] inline ResultCode Map(void** ppData) const
136 {
137 return m_pMemory->Map(m_ByteOffset, m_ByteSize, ppData);
138 }
139
143 [[nodiscard]] inline void* Map() const
144 {
145 void* pResult;
146 if (auto result = m_pMemory->Map(m_ByteOffset, m_ByteSize, &pResult); Failed(result))
147 {
148 UN_Error(false, "Couldn't map memory, IDeviceMemory::Map returned {}", result);
149 return nullptr;
150 }
151
152 return pResult;
153 }
154
162 [[nodiscard]] inline ResultCode Map(UInt64 byteOffset, UInt64 byteSize, void** ppData) const
163 {
164 UN_Assert(byteSize == IDeviceMemory::WholeSize || byteSize <= m_pMemory->GetDesc().Size - byteOffset,
165 "Invalid memory map size");
166
167 return m_pMemory->Map(
168 m_ByteOffset + byteOffset, std::min(byteSize, m_pMemory->GetDesc().Size - byteOffset - m_ByteOffset), ppData);
169 }
170
177 [[nodiscard]] inline void* Map(UInt64 byteOffset, UInt64 byteSize = IDeviceMemory::WholeSize) const
178 {
179 UN_Assert(byteSize == IDeviceMemory::WholeSize || byteSize <= m_pMemory->GetDesc().Size - byteOffset,
180 "Invalid memory map size");
181
182 void* pResult;
183 if (Succeeded(m_pMemory->Map(m_ByteOffset + byteOffset,
184 std::min(byteSize, m_pMemory->GetDesc().Size - byteOffset - m_ByteOffset),
185 &pResult)))
186 {
187 return pResult;
188 }
189
190 UN_Error(false, "Couldn't map memory");
191 return nullptr;
192 }
193
197 inline void Unmap() const
198 {
199 m_pMemory->Unmap();
200 }
201
211 [[nodiscard]] inline bool IsCompatible(IDeviceObject* pObject) const
212 {
213 return m_pMemory->IsCompatible(pObject, m_ByteSize);
214 }
215 };
216
218 template<class T>
220 {
221 DeviceMemorySlice m_MemorySlice;
222 T* m_Map = nullptr;
223
224 inline MemoryMapHelper() = default;
225
226 inline explicit MemoryMapHelper(const DeviceMemorySlice& memorySlice, T* map)
227 : m_MemorySlice(memorySlice)
228 , m_Map(map)
229 {
230 }
231
232 public:
233 inline MemoryMapHelper(MemoryMapHelper&& other) noexcept
234 : m_MemorySlice(other.m_MemorySlice)
235 , m_Map(other.m_Map)
236 {
237 other.m_MemorySlice = {};
238 other.m_Map = nullptr;
239 }
240
241 inline ~MemoryMapHelper()
242 {
243 if (m_Map)
244 {
245 m_MemorySlice.Unmap();
246 }
247 }
248
249 inline T& operator[](USize index)
250 {
251 UN_Assert(IsValid(), "MemoryMapHelper was in invalid state");
252 UN_Assert(index * sizeof(T) < m_MemorySlice.GetByteSize(), "Index out of range in MemoryMapHelper");
253 return m_Map[index];
254 }
255
257 [[nodiscard]] inline UInt64 Length() const
258 {
259 UN_Assert(IsValid(), "MemoryMapHelper was in invalid state");
260 return m_MemorySlice.GetByteSize() / sizeof(T);
261 }
262
264 [[nodiscard]] inline UInt64 ByteSize() const
265 {
266 UN_Assert(IsValid(), "MemoryMapHelper was in invalid state");
267 return m_MemorySlice.GetByteSize();
268 }
269
271 [[nodiscard]] inline bool IsValid() const
272 {
273 return m_Map;
274 }
275
277 inline explicit operator bool() const
278 {
279 return IsValid();
280 }
281
283 [[nodiscard]] inline T* Data() const
284 {
285 UN_Assert(IsValid(), "MemoryMapHelper was in invalid state");
286 return m_Map;
287 }
288
304 inline static MemoryMapHelper Map(const DeviceMemorySlice& memorySlice)
305 {
306 void* map;
307 auto result = memorySlice.Map(&map);
308 if (Succeeded(result))
309 {
310 return MemoryMapHelper(memorySlice, static_cast<T*>(map));
311 }
312
313 return {};
314 }
315
333 inline static MemoryMapHelper Map(IDeviceMemory* pMemory, UInt64 byteOffset = 0,
334 UInt64 byteSize = IDeviceMemory::WholeSize)
335 {
336 return Map(DeviceMemorySlice(pMemory, byteOffset, byteSize));
337 }
338
339 inline T* begin()
340 {
341 UN_Assert(IsValid(), "MemoryMapHelper was in invalid state");
342 return m_Map;
343 }
344
345 inline T* end()
346 {
347 UN_Assert(IsValid(), "MemoryMapHelper was in invalid state");
348 return m_Map + Length();
349 }
350 };
351} // namespace UN
This class represents a non-owning slice of contiguously stored elements.
Definition: ArraySlice.h:12
A slice of device memory.
Definition: IDeviceMemory.h:89
void Unmap() const
Unmap the mapped memory.
Definition: IDeviceMemory.h:197
bool IsCompatible(IDeviceObject *pObject) const
Check if the memory is compatible with an object.
Definition: IDeviceMemory.h:211
ResultCode Map(UInt64 byteOffset, UInt64 byteSize, void **ppData) const
Map the part of device memory represented by this slice.
Definition: IDeviceMemory.h:162
ResultCode Map(void **ppData) const
Map the part of device memory represented by this slice.
Definition: IDeviceMemory.h:135
IDeviceMemory * GetDeviceMemory() const
Get the underlying device memory object.
Definition: IDeviceMemory.h:113
void * Map(UInt64 byteOffset, UInt64 byteSize=IDeviceMemory::WholeSize) const
Map the part of device memory represented by this slice.
Definition: IDeviceMemory.h:177
UInt64 GetByteSize() const
Get slice size in bytes.
Definition: IDeviceMemory.h:125
DeviceMemorySlice(IDeviceMemory *pMemory, UInt64 byteOffset=0, UInt64 byteSize=IDeviceMemory::WholeSize)
Create a device memory slice.
Definition: IDeviceMemory.h:102
void * Map() const
Map the part of device memory represented by this slice.
Definition: IDeviceMemory.h:143
UInt64 GetByteOffset() const
Get slice offset in bytes.
Definition: IDeviceMemory.h:119
This class holds a handle to backend-specific memory.
Definition: IDeviceMemory.h:31
static constexpr UInt64 WholeSize
Special constant that represents the whole memory size.
Definition: IDeviceMemory.h:36
virtual ResultCode Map(UInt64 byteOffset, UInt64 byteSize, void **ppData)=0
Map the device memory to access it from the host.
virtual ResultCode Init(const DescriptorType &desc)=0
Allocate memory with specified descriptor.
virtual void Unmap()=0
Unmap the mapped memory.
virtual bool IsCompatible(IDeviceObject *pObject)=0
Check if the memory is compatible with an object.
virtual bool IsCompatible(IDeviceObject *pObject, UInt64 sizeLimit)=0
Check if the memory is compatible with an object.
Base interface for all compute backend objects.
Definition: IDeviceObject.h:30
Helper class for memory mapping, implements indexing operators and bound checking.
Definition: IDeviceMemory.h:220
UInt64 Length() const
Get size of the mapped data as a number of elements of type T.
Definition: IDeviceMemory.h:257
bool IsValid() const
Check if an instance of the class is in valid state.
Definition: IDeviceMemory.h:271
static MemoryMapHelper Map(IDeviceMemory *pMemory, UInt64 byteOffset=0, UInt64 byteSize=IDeviceMemory::WholeSize)
Map the device memory.
Definition: IDeviceMemory.h:333
T * Data() const
Get a pointer to the mapped memory.
Definition: IDeviceMemory.h:283
UInt64 ByteSize() const
Get size of the mapped data in bytes.
Definition: IDeviceMemory.h:264
static MemoryMapHelper Map(const DeviceMemorySlice &memorySlice)
Map the device memory slice.
Definition: IDeviceMemory.h:304
Device memory descriptor.
Definition: IDeviceMemory.h:12
const char * Name
Device memory debug name.
Definition: IDeviceMemory.h:13
UInt64 Size
Memory size in bytes.
Definition: IDeviceMemory.h:14
MemoryKindFlags Flags
Memory kind flags.
Definition: IDeviceMemory.h:15
ArraySlice< IDeviceObject * > Objects
Resource objects that the memory must be compatible with.
Definition: IDeviceMemory.h:16