1 | // |
2 | // Redistribution and use in source and binary forms, with or without |
3 | // modification, are permitted provided that the following conditions |
4 | // are met: |
5 | // * Redistributions of source code must retain the above copyright |
6 | // notice, this list of conditions and the following disclaimer. |
7 | // * Redistributions in binary form must reproduce the above copyright |
8 | // notice, this list of conditions and the following disclaimer in the |
9 | // documentation and/or other materials provided with the distribution. |
10 | // * Neither the name of NVIDIA CORPORATION nor the names of its |
11 | // contributors may be used to endorse or promote products derived |
12 | // from this software without specific prior written permission. |
13 | // |
14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY |
15 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
17 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
18 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
19 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
20 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
21 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
22 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
23 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
24 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
25 | // |
26 | // Copyright (c) 2008-2021 NVIDIA Corporation. All rights reserved. |
27 | |
28 | #ifndef PXCUDACONTEXTMANAGER_PXCUDAMEMORYMANAGER_H |
29 | #define PXCUDACONTEXTMANAGER_PXCUDAMEMORYMANAGER_H |
30 | |
31 | #include "foundation/PxPreprocessor.h" |
32 | |
33 | #if PX_SUPPORT_GPU_PHYSX |
34 | |
35 | #include "task/PxTaskDefine.h" |
36 | |
37 | // some macros to keep the source code more readable |
38 | #define PX_ALLOC_INFO(name, ID) __FILE__, __LINE__, name, physx::PxAllocId::ID |
39 | #define PX_ALLOC_INFO_PARAMS_DECL(p0, p1, p2, p3) const char* file = p0, int line = p1, const char* allocName = p2, physx::PxAllocId::Enum allocId = physx::PxAllocId::p3 |
40 | #define PX_ALLOC_INFO_PARAMS_DEF() const char* file, int line, const char* allocName, physx::PxAllocId::Enum allocId |
41 | #define PX_ALLOC_INFO_PARAMS_INPUT() file, line, allocName, allocId |
42 | #define PX_ALLOC_INFO_PARAMS_INPUT_INFO(info) info.getFileName(), info.getLine(), info.getAllocName(), info.getAllocId() |
43 | |
44 | #ifndef NULL // don't want to include <string.h> |
45 | #define NULL 0 |
46 | #endif |
47 | |
48 | namespace physx |
49 | { |
50 | |
51 | PX_PUSH_PACK_DEFAULT |
52 | |
53 | /** \brief ID of the Feature which owns/allocated memory from the heap |
54 | * |
55 | * Maximum of 64k IDs allowed. |
56 | */ |
57 | struct PxAllocId |
58 | { |
59 | /** |
60 | * \brief ID of the Feature which owns/allocated memory from the heap |
61 | */ |
62 | enum Enum |
63 | { |
64 | UNASSIGNED, //!< default |
65 | APEX, //!< APEX stuff not further classified |
66 | PARTICLES, //!< all particle related |
67 | GPU_UTIL, //!< e.g. RadixSort (used in SPH and deformable self collision) |
68 | CLOTH, //!< all cloth related |
69 | NUM_IDS //!< number of IDs, be aware that ApexHeapStats contains PxAllocIdStats[NUM_IDS] |
70 | }; |
71 | }; |
72 | |
73 | /// \brief memory type managed by a heap |
74 | struct PxCudaBufferMemorySpace |
75 | { |
76 | /** |
77 | * \brief memory type managed by a heap |
78 | */ |
79 | enum Enum |
80 | { |
81 | T_GPU, |
82 | T_PINNED_HOST, |
83 | T_WRITE_COMBINED, |
84 | T_HOST, |
85 | COUNT |
86 | }; |
87 | }; |
88 | |
89 | /// \brief class to track allocation statistics, see PxgMirrored |
90 | class PxAllocInfo |
91 | { |
92 | public: |
93 | /** |
94 | * \brief AllocInfo default constructor |
95 | */ |
96 | PxAllocInfo() {} |
97 | |
98 | /** |
99 | * \brief AllocInfo constructor that initializes all of the members |
100 | */ |
101 | PxAllocInfo(const char* file, int line, const char* allocName, PxAllocId::Enum allocId) |
102 | : mFileName(file) |
103 | , mLine(line) |
104 | , mAllocName(allocName) |
105 | , mAllocId(allocId) |
106 | {} |
107 | |
108 | /// \brief get the allocation file name |
109 | inline const char* getFileName() const |
110 | { |
111 | return mFileName; |
112 | } |
113 | |
114 | /// \brief get the allocation line |
115 | inline int getLine() const |
116 | { |
117 | return mLine; |
118 | } |
119 | |
120 | /// \brief get the allocation name |
121 | inline const char* getAllocName() const |
122 | { |
123 | return mAllocName; |
124 | } |
125 | |
126 | /// \brief get the allocation ID |
127 | inline PxAllocId::Enum getAllocId() const |
128 | { |
129 | return mAllocId; |
130 | } |
131 | |
132 | private: |
133 | const char* mFileName; |
134 | int mLine; |
135 | const char* mAllocName; |
136 | PxAllocId::Enum mAllocId; |
137 | }; |
138 | |
139 | /// \brief statistics collected per AllocationId by HeapManager. |
140 | struct PxAllocIdStats |
141 | { |
142 | size_t size; //!< currently allocated memory by this ID |
143 | size_t maxSize; //!< max allocated memory by this ID |
144 | size_t elements; //!< number of current allocations by this ID |
145 | size_t maxElements; //!< max number of allocations by this ID |
146 | }; |
147 | |
148 | class PxCudaMemoryManager; |
149 | typedef size_t PxCudaBufferPtr; |
150 | |
151 | /// \brief Hint flag to tell how the buffer will be used |
152 | struct PxCudaBufferFlags |
153 | { |
154 | /// \brief Enumerations for the hint flag to tell how the buffer will be used |
155 | enum Enum |
156 | { |
157 | F_READ = (1 << 0), |
158 | F_WRITE = (1 << 1), |
159 | F_READ_WRITE = F_READ | F_WRITE |
160 | }; |
161 | }; |
162 | |
163 | |
164 | /// \brief Memory statistics struct returned by CudaMemMgr::getStats() |
165 | struct PxCudaMemoryManagerStats |
166 | { |
167 | |
168 | size_t heapSize; //!< Size of all pages allocated for this memory type (allocated + free). |
169 | size_t totalAllocated; //!< Size occupied by the current allocations. |
170 | size_t maxAllocated; //!< High water mark of allocations since the SDK was created. |
171 | PxAllocIdStats allocIdStats[PxAllocId::NUM_IDS]; //!< Stats for each allocation ID, see PxAllocIdStats |
172 | }; |
173 | |
174 | |
175 | /// \brief Buffer type: made of hint flags and the memory space (Device Memory, Pinned Host Memory, ...) |
176 | struct PxCudaBufferType |
177 | { |
178 | /// \brief PxCudaBufferType copy constructor |
179 | PX_INLINE PxCudaBufferType(const PxCudaBufferType& t) |
180 | : memorySpace(t.memorySpace) |
181 | , flags(t.flags) |
182 | {} |
183 | |
184 | /// \brief PxCudaBufferType constructor to explicitely assign members |
185 | PX_INLINE PxCudaBufferType(PxCudaBufferMemorySpace::Enum _memSpace, PxCudaBufferFlags::Enum _flags) |
186 | : memorySpace(_memSpace) |
187 | , flags(_flags) |
188 | {} |
189 | |
190 | PxCudaBufferMemorySpace::Enum memorySpace; //!< specifies which memory space for the buffer |
191 | PxCudaBufferFlags::Enum flags; //!< specifies the usage flags for the buffer |
192 | }; |
193 | |
194 | |
195 | /// \brief Buffer which keeps informations about allocated piece of memory. |
196 | class PxCudaBuffer |
197 | { |
198 | public: |
199 | /// Retrieves the manager over which the buffer was allocated. |
200 | virtual PxCudaMemoryManager* getCudaMemoryManager() const = 0; |
201 | |
202 | /// Releases the buffer and the memory it used, returns true if successful. |
203 | virtual bool free() = 0; |
204 | |
205 | /// Realloc memory. Use to shrink or resize the allocated chunk of memory of this buffer. |
206 | /// Returns true if successful. Fails if the operation would change the address and need a memcopy. |
207 | /// In that case the user has to allocate, copy and free the memory with separate steps. |
208 | /// Realloc to size 0 always returns false and doesn't change the state. |
209 | virtual bool realloc(size_t size, PX_ALLOC_INFO_PARAMS_DECL(NULL, 0, NULL, UNASSIGNED)) = 0; |
210 | |
211 | /// Returns the type of the allocated memory. |
212 | virtual const PxCudaBufferType& getType() const = 0; |
213 | |
214 | /// Returns the pointer to the allocated memory. |
215 | virtual PxCudaBufferPtr getPtr() const = 0; |
216 | |
217 | /// Returns the size of the allocated memory. |
218 | virtual size_t getSize() const = 0; |
219 | |
220 | protected: |
221 | /// \brief protected destructor |
222 | virtual ~PxCudaBuffer() {} |
223 | }; |
224 | |
225 | |
226 | /// \brief Allocator class for different kinds of CUDA related memory. |
227 | class PxCudaMemoryManager |
228 | { |
229 | public: |
230 | /// Allocate memory of given type and size. Returns a CudaBuffer if successful. Returns NULL if failed. |
231 | virtual PxCudaBuffer* alloc(const PxCudaBufferType& type, size_t size, PX_ALLOC_INFO_PARAMS_DECL(NULL, 0, NULL, UNASSIGNED)) = 0; |
232 | |
233 | /// Basic heap allocator without PxCudaBuffer |
234 | virtual PxCudaBufferPtr alloc(PxCudaBufferMemorySpace::Enum memorySpace, size_t size, PX_ALLOC_INFO_PARAMS_DECL(NULL, 0, NULL, UNASSIGNED)) = 0; |
235 | |
236 | /// Basic heap deallocator without PxCudaBuffer |
237 | virtual bool free(PxCudaBufferMemorySpace::Enum memorySpace, PxCudaBufferPtr addr) = 0; |
238 | |
239 | /// Basic heap realloc without PxCudaBuffer |
240 | virtual bool realloc(PxCudaBufferMemorySpace::Enum memorySpace, PxCudaBufferPtr addr, size_t size, PX_ALLOC_INFO_PARAMS_DECL(NULL, 0, NULL, UNASSIGNED)) = 0; |
241 | |
242 | /// Retrieve stats for the memory of given type. See PxCudaMemoryManagerStats. |
243 | virtual void getStats(const PxCudaBufferType& type, PxCudaMemoryManagerStats& outStats) = 0; |
244 | |
245 | /// Ensure that a given amount of free memory is available. Triggers CUDA allocations in size of (2^n * pageSize) if necessary. |
246 | /// Returns false if page allocations failed. |
247 | virtual bool reserve(const PxCudaBufferType& type, size_t size) = 0; |
248 | |
249 | /// Set the page size. The managed memory grows by blocks 2^n * pageSize. Page allocations trigger CUDA driver allocations, |
250 | /// so the page size should be reasonably big. Returns false if input size was invalid, i.e. not power of two. |
251 | /// Default is 2 MB. |
252 | virtual bool setPageSize(const PxCudaBufferType& type, size_t size) = 0; |
253 | |
254 | /// Set the upper limit until which pages of a given memory type can be allocated. |
255 | /// Reducing the max when it is already hit does not shrink the memory until it is deallocated by releasing the buffers which own the memory. |
256 | virtual bool setMaxMemorySize(const PxCudaBufferType& type, size_t size) = 0; |
257 | |
258 | /// Returns the base size. The base memory block stays persistently allocated over the SDKs life time. |
259 | virtual size_t getBaseSize(const PxCudaBufferType& type) = 0; |
260 | |
261 | /// Returns the currently set page size. The memory grows and shrinks in blocks of size (2^n pageSize) |
262 | virtual size_t getPageSize(const PxCudaBufferType& type) = 0; |
263 | |
264 | /// Returns the upper limit until which the manager is allowed to allocate additional pages from the CUDA driver. |
265 | virtual size_t getMaxMemorySize(const PxCudaBufferType& type) = 0; |
266 | |
267 | /// Get device mapped pinned host mem ptr. Operation only valid for memory space PxCudaBufferMemorySpace::T_PINNED_HOST. |
268 | virtual PxCudaBufferPtr getMappedPinnedPtr(PxCudaBufferPtr hostPtr) = 0; |
269 | |
270 | protected: |
271 | /// \brief protected destructor |
272 | virtual ~PxCudaMemoryManager() {} |
273 | }; |
274 | |
275 | PX_POP_PACK |
276 | |
277 | |
278 | } // end physx namespace |
279 | |
280 | #endif // PX_SUPPORT_GPU_PHYSX |
281 | #endif // PXCUDACONTEXTMANAGER_PXCUDAMEMORYMANAGER_H |
282 | |