frameAllocator.h 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. //-----------------------------------------------------------------------------
  2. // Copyright (C) 2023-2024 tgemit contributors.
  3. // See AUTHORS file and git repository for contributor information.
  4. //
  5. // SPDX-License-Identifier: MIT
  6. //-----------------------------------------------------------------------------
  7. #ifndef _FRAMEALLOCATOR_H_
  8. #define _FRAMEALLOCATOR_H_
  9. #ifndef _PLATFORM_H_
  10. #include "platform/platform.h"
  11. #endif
  12. /// Implements an buffer which allocates data based on the alignment of type T.
  13. ///
  14. /// Example usage:
  15. ///
  16. /// @code
  17. /// AlignedBufferAllocator<U32> alloc32;
  18. /// alloc32.initWithElements(new U32[10], 10);
  19. ///
  20. /// void* ptr = alloc32.allocBytes(2);
  21. /// // Reset back to start
  22. /// alloc32.setPosition(0);
  23. /// @endcode
  24. ///
  25. template<typename T> class AlignedBufferAllocator
  26. {
  27. protected:
  28. T* mBuffer;
  29. U32 mHighWaterMark;
  30. U32 mWaterMark;
  31. public:
  32. typedef T ValueType;
  33. AlignedBufferAllocator() : mBuffer(NULL), mHighWaterMark(0), mWaterMark(0)
  34. {
  35. }
  36. /// Inits allocator based on a ptr to a memory block of size numElements * sizeof(T)
  37. inline void initWithElements(T* ptr, U32 numElements)
  38. {
  39. mBuffer = ptr;
  40. mHighWaterMark = numElements;
  41. mWaterMark = 0;
  42. }
  43. /// Inits allocator based on a ptr to a memory block of size bytes
  44. inline void initWithBytes(T* ptr, dsize_t bytes)
  45. {
  46. mBuffer = ptr;
  47. mHighWaterMark = (U32)(calcMaxElementSize(bytes));
  48. mWaterMark = 0;
  49. }
  50. /// Allocs numBytes worth of elements
  51. inline T* allocBytes(const size_t numBytes)
  52. {
  53. T* ptr = &mBuffer[mWaterMark];
  54. size_t numElements = calcRequiredElementSize(numBytes);
  55. if (((size_t)mWaterMark + (size_t)numElements) > (size_t)mHighWaterMark) // safety check
  56. {
  57. #ifdef TORQUE_MEM_DEBUG
  58. AssertFatal(false, "Overflow");
  59. #endif
  60. return NULL;
  61. }
  62. mWaterMark += (U32)numElements;
  63. return ptr;
  64. }
  65. /// Allocates numElements elements
  66. inline T* allocElements(const U32 numElements)
  67. {
  68. T* ptr = &mBuffer[mWaterMark];
  69. if (((size_t)mWaterMark + (size_t)numElements) > (size_t)mHighWaterMark) // safety check
  70. {
  71. #ifdef TORQUE_MEM_DEBUG
  72. AssertFatal(false, "Overflow");
  73. #endif
  74. return NULL;
  75. }
  76. mWaterMark += numElements;
  77. return ptr;
  78. }
  79. /// Sets current aligned watermark position
  80. inline void setPosition(const U32 waterMark)
  81. {
  82. AssertFatal(waterMark <= mHighWaterMark, "Error, invalid waterMark");
  83. mWaterMark = waterMark;
  84. }
  85. /// Calculates maximum elements required to store numBytes bytes (may overshoot)
  86. static inline U32 calcRequiredElementSize(const dsize_t numBytes)
  87. {
  88. return (U32)((numBytes + (sizeof(T) - 1)) / sizeof(T));
  89. }
  90. /// Calculates maximum elements required to store numBytes bytes
  91. static inline U32 calcMaxElementSize(const dsize_t numBytes)
  92. {
  93. return (U32)(numBytes / sizeof(T));
  94. }
  95. static inline U32 calcRequiredPaddedByteSize(const dsize_t numBytes)
  96. {
  97. return calcRequiredElementSize(numBytes) * sizeof(T);
  98. }
  99. inline T* getAlignedBuffer() const
  100. {
  101. return mBuffer;
  102. }
  103. inline T* getAlignedBufferEnd() const
  104. {
  105. return mBuffer + mHighWaterMark;
  106. }
  107. inline U32 getPosition() const
  108. {
  109. return mWaterMark;
  110. }
  111. inline U32 getSize() const
  112. {
  113. return mHighWaterMark;
  114. }
  115. inline U32 getElementsLeft() const
  116. {
  117. return mHighWaterMark - mWaterMark;
  118. }
  119. inline dsize_t getPositionBytes() const
  120. {
  121. return mWaterMark * sizeof(T);
  122. }
  123. inline dsize_t getSizeBytes() const
  124. {
  125. return mHighWaterMark * sizeof(T);
  126. }
  127. };
  128. ///
  129. /// Implements an AlignedBufferAllocator<T> which manages its own memory.
  130. ///
  131. template<typename T> class ManagedAlignedBufferAllocator : public AlignedBufferAllocator<T>
  132. {
  133. typedef AlignedBufferAllocator<T> Parent;
  134. public:
  135. T* mMemory;
  136. ManagedAlignedBufferAllocator() : mMemory(NULL)
  137. {
  138. }
  139. ~ManagedAlignedBufferAllocator()
  140. {
  141. destroy();
  142. }
  143. void init(const dsize_t byteSize)
  144. {
  145. AssertFatal(mMemory == NULL, "ManagedAlignedBufferAllocator already initialized");
  146. U32 frameSize = Parent::calcRequiredElementSize(byteSize);
  147. mMemory = new U32[frameSize];
  148. AlignedBufferAllocator<T>::initWithElements(mMemory, frameSize);
  149. }
  150. void destroy()
  151. {
  152. Parent::setPosition(0);
  153. delete[] mMemory;
  154. mMemory = NULL;
  155. }
  156. };
  157. /// Implements a thread-local global buffer for frame-based allocations.
  158. /// All allocations are aligned to U32.
  159. ///
  160. /// Example usage:
  161. ///
  162. /// @code
  163. /// U32 waterMark = FrameAllocator::getWaterMark();
  164. /// void* ptr = FrameAllocator::alloc(10);
  165. /// // Cleanup...
  166. /// FrameAllocator::setWaterMark(waterMark);
  167. /// @endcode
  168. ///
  169. /// See also: FrameAllocatorMarker, FrameTemp.
  170. ///
  171. /// NOTE: worker threads which use FrameAllocator should call init and destroy. i.e.
  172. ///
  173. /// @code
  174. /// FrameAllocator::init(1024 * 1024 * 12);
  175. /// // Do work...
  176. /// FrameAllocator::destroy();
  177. /// @endcode
  178. ///
  179. class FrameAllocator
  180. {
  181. protected:
  182. static thread_local ManagedAlignedBufferAllocator<U32> smFrameAllocator;
  183. #ifdef TORQUE_MEM_DEBUG
  184. static thread_local dsize_t smMaxAllocationBytes;
  185. #endif
  186. public:
  187. inline TORQUE_FORCEINLINE static void init(const dsize_t byteSize) { return smFrameAllocator.init(byteSize); }
  188. inline TORQUE_FORCEINLINE static void destroy() { smFrameAllocator.destroy(); }
  189. inline TORQUE_FORCEINLINE static void* alloc(const dsize_t numBytes)
  190. {
  191. #ifdef TORQUE_MEM_DEBUG
  192. const dsize_t allocBytes = smFrameAllocator.getPositionBytes();
  193. smMaxAllocationBytes = allocBytes > smMaxAllocationBytes ? allocBytes : smMaxAllocationBytes;
  194. #endif
  195. return smFrameAllocator.allocBytes(numBytes);
  196. }
  197. inline TORQUE_FORCEINLINE static U32 getWaterMark() { return smFrameAllocator.getPosition(); }
  198. inline TORQUE_FORCEINLINE static dsize_t getWaterMarkBytes() { return smFrameAllocator.getPositionBytes(); }
  199. inline TORQUE_FORCEINLINE static void setWaterMark(U32 pos) { return smFrameAllocator.setPosition(pos); }
  200. inline TORQUE_FORCEINLINE static U32 getHighWaterMark() { return smFrameAllocator.getSizeBytes(); }
  201. };
  202. /// Helper class which saves and restores the previous water mark level from FrameAllocator based on scope.
  203. ///
  204. /// Example usage:
  205. ///
  206. /// @code
  207. /// FrameAllocatorMarker marker;
  208. /// void* ptr = marker.alloc(1024);
  209. /// @endcode
  210. ///
  211. class FrameAllocatorMarker
  212. {
  213. U32 mPosition;
  214. public:
  215. FrameAllocatorMarker()
  216. {
  217. mPosition = FrameAllocator::getWaterMark();
  218. }
  219. ~FrameAllocatorMarker()
  220. {
  221. FrameAllocator::setWaterMark(mPosition);
  222. }
  223. /// Allocs numBytes of memory from FrameAllocator
  224. inline TORQUE_FORCEINLINE static void* alloc(const dsize_t numBytes)
  225. {
  226. return FrameAllocator::alloc(numBytes);
  227. }
  228. };
  229. /// Helper class which temporarily allocates a set of elements of type T from FrameAllocator,
  230. /// restoring the water mark when the scope has ended as with FrameAllocatorMarker.
  231. ///
  232. /// Example usage:
  233. ///
  234. /// @code
  235. /// FrameTemp<UTF8> textMarker(64);
  236. /// for (U32 i=0; i<textMarker.size(); i++)
  237. /// {
  238. /// textMarker[i] = '\0';
  239. /// }
  240. /// @endcode
  241. ///
  242. ///
  243. template<class T>
  244. class FrameTemp
  245. {
  246. T* mData;
  247. U32 mSize;
  248. U32 mPosition;
  249. public:
  250. FrameTemp(const U32 numElements = 0)
  251. {
  252. mPosition = FrameAllocator::getWaterMark();
  253. mData = (T*)FrameAllocator::alloc(sizeof(T) * numElements);
  254. mSize = numElements;
  255. }
  256. ~FrameTemp()
  257. {
  258. for (U32 i = 0; i < mSize; i++)
  259. destructInPlace(&mData[i]);
  260. FrameAllocator::setWaterMark(mPosition);
  261. }
  262. // Operators
  263. inline TORQUE_FORCEINLINE T& operator*() { return *mData; }
  264. inline TORQUE_FORCEINLINE const T& operator*() const { return *mData; }
  265. inline TORQUE_FORCEINLINE T** operator&() { return &mData; }
  266. inline TORQUE_FORCEINLINE T* const * operator&() const { return &mData; }
  267. inline TORQUE_FORCEINLINE operator T&() { return *mData; }
  268. inline TORQUE_FORCEINLINE operator const T&() const { return *mData; }
  269. inline TORQUE_FORCEINLINE operator T* () { return mData; }
  270. inline TORQUE_FORCEINLINE operator const T* () const { return mData; }
  271. inline TORQUE_FORCEINLINE operator T () { return *mData; }
  272. inline TORQUE_FORCEINLINE operator const T () const { return *mData; }
  273. inline TORQUE_FORCEINLINE T& operator[](const dsize_t idx) { return mData[idx]; }
  274. inline TORQUE_FORCEINLINE const T& operator[](const dsize_t idx) const { return mData[idx]; }
  275. // Utils
  276. inline TORQUE_FORCEINLINE T* address() const { return mData; }
  277. inline TORQUE_FORCEINLINE const U32 size() const { return mSize; }
  278. inline TORQUE_FORCEINLINE const U32 getObjectCount() const { return mSize; }
  279. };
  280. #endif // _H_FRAMEALLOCATOR_