frameAllocator.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #ifndef _FRAMEALLOCATOR_H_
  23. #define _FRAMEALLOCATOR_H_
  24. #ifndef _PLATFORM_H_
  25. #include "platform/platform.h"
  26. #endif
  27. /// This #define is used by the FrameAllocator to align starting addresses to
  28. /// be byte aligned to this value. This is important on the 360 and possibly
  29. /// on other platforms as well. Use this #define anywhere alignment is needed.
  30. ///
  31. /// NOTE: Do not change this value per-platform unless you have a very good
  32. /// reason for doing so. It has the potential to cause inconsistencies in
  33. /// memory which is allocated and expected to be contiguous.
  34. #define FRAMEALLOCATOR_BYTE_ALIGNMENT 4
  35. /// Temporary memory pool for per-frame allocations.
  36. ///
  37. /// In the course of rendering a frame, it is often necessary to allocate
  38. /// many small chunks of memory, then free them all in a batch. For instance,
  39. /// say we're allocating storage for some vertex calculations:
  40. ///
  41. /// @code
  42. /// // Get FrameAllocator memory...
  43. /// U32 waterMark = FrameAllocator::getWaterMark();
  44. /// F32 * ptr = (F32*)FrameAllocator::alloc(sizeof(F32)*2*targetMesh->vertsPerFrame);
  45. ///
  46. /// ... calculations ...
  47. ///
  48. /// // Free frameAllocator memory
  49. /// FrameAllocator::setWaterMark(waterMark);
  50. /// @endcode
  51. class FrameAllocator
  52. {
  53. static U8* smBuffer;
  54. static U32 smHighWaterMark;
  55. static U32 smWaterMark;
  56. #ifdef TORQUE_DEBUG
  57. static U32 smMaxFrameAllocation;
  58. #endif
  59. public:
  60. inline static void init(const U32 frameSize);
  61. inline static void destroy();
  62. inline static void* alloc(const U32 allocSize);
  63. inline static void setWaterMark(const U32);
  64. inline static U32 getWaterMark();
  65. inline static U32 getHighWaterMark();
  66. #ifdef TORQUE_DEBUG
  67. static U32 getMaxFrameAllocation() { return smMaxFrameAllocation; }
  68. #endif
  69. };
  70. void FrameAllocator::init(const U32 frameSize)
  71. {
  72. #ifdef FRAMEALLOCATOR_DEBUG_GUARD
  73. AssertISV( false, "FRAMEALLOCATOR_DEBUG_GUARD has been removed because it allows non-contiguous memory allocation by the FrameAllocator, and this is *not* ok." );
  74. #endif
  75. AssertFatal(smBuffer == NULL, "Error, already initialized");
  76. smBuffer = new U8[frameSize];
  77. smWaterMark = 0;
  78. smHighWaterMark = frameSize;
  79. }
  80. void FrameAllocator::destroy()
  81. {
  82. AssertFatal(smBuffer != NULL, "Error, not initialized");
  83. delete [] smBuffer;
  84. smBuffer = NULL;
  85. smWaterMark = 0;
  86. smHighWaterMark = 0;
  87. }
  88. void* FrameAllocator::alloc(const U32 allocSize)
  89. {
  90. U32 _allocSize = allocSize;
  91. AssertFatal(smBuffer != NULL, "Error, no buffer!");
  92. AssertFatal(smWaterMark + _allocSize <= smHighWaterMark, "Error alloc too large, increase frame size!");
  93. smWaterMark = ( smWaterMark + ( FRAMEALLOCATOR_BYTE_ALIGNMENT - 1 ) ) & (~( FRAMEALLOCATOR_BYTE_ALIGNMENT - 1 ));
  94. // Sanity check.
  95. AssertFatal( !( smWaterMark & ( FRAMEALLOCATOR_BYTE_ALIGNMENT - 1 ) ), "Frame allocation is not on a specified byte boundry." );
  96. U8* p = &smBuffer[smWaterMark];
  97. smWaterMark += _allocSize;
  98. #ifdef TORQUE_DEBUG
  99. if (smWaterMark > smMaxFrameAllocation)
  100. smMaxFrameAllocation = smWaterMark;
  101. #endif
  102. return p;
  103. }
  104. void FrameAllocator::setWaterMark(const U32 waterMark)
  105. {
  106. AssertFatal(waterMark < smHighWaterMark, "Error, invalid waterMark");
  107. smWaterMark = waterMark;
  108. }
  109. U32 FrameAllocator::getWaterMark()
  110. {
  111. return smWaterMark;
  112. }
  113. U32 FrameAllocator::getHighWaterMark()
  114. {
  115. return smHighWaterMark;
  116. }
  117. /// Helper class to deal with FrameAllocator usage.
  118. ///
  119. /// The purpose of this class is to make it simpler and more reliable to use the
  120. /// FrameAllocator. Simply use it like this:
  121. ///
  122. /// @code
  123. /// FrameAllocatorMarker mem;
  124. ///
  125. /// char *buff = (char*)mem.alloc(100);
  126. /// @endcode
  127. ///
  128. /// When you leave the scope you defined the FrameAllocatorMarker in, it will
  129. /// automatically restore the watermark on the FrameAllocator. In situations
  130. /// with complex branches, this can be a significant headache remover, as you
  131. /// don't have to remember to reset the FrameAllocator on every posssible branch.
  132. class FrameAllocatorMarker
  133. {
  134. U32 mMarker;
  135. public:
  136. FrameAllocatorMarker()
  137. {
  138. mMarker = FrameAllocator::getWaterMark();
  139. }
  140. ~FrameAllocatorMarker()
  141. {
  142. FrameAllocator::setWaterMark(mMarker);
  143. }
  144. void* alloc(const U32 allocSize) const
  145. {
  146. return FrameAllocator::alloc(allocSize);
  147. }
  148. template<typename T>
  149. T* alloc(const U32 numElements) const
  150. {
  151. return reinterpret_cast<T *>(FrameAllocator::alloc(numElements * sizeof(T)));
  152. }
  153. };
  154. /// Class for temporary variables that you want to allocate easily using
  155. /// the FrameAllocator. For example:
  156. /// @code
  157. /// FrameTemp<char> tempStr(32); // NOTE! This parameter is NOT THE SIZE IN BYTES. See constructor docs.
  158. /// dStrcat( tempStr, SomeOtherString, 32 * sizeof(char) );
  159. /// tempStr[2] = 'l';
  160. /// Con::printf( tempStr );
  161. /// Con::printf( "Foo: %s", ~tempStr );
  162. /// @endcode
  163. ///
  164. /// This will automatically handle getting and restoring the watermark of the
  165. /// FrameAllocator when it goes out of scope. You should notice the strange
  166. /// operator in front of tempStr on the printf call. This is normally a unary
  167. /// operator for ones-complement, but in this class it will simply return the
  168. /// memory of the allocation. It's the same as doing (const char *)tempStr
  169. /// in the above case. The reason why it is necessary for the second printf
  170. /// and not the first is because the second one is taking a variable arg
  171. /// list and so it isn't getting the cast so that it's cast operator can
  172. /// properly return the memory instead of the FrameTemp object itself.
  173. ///
  174. /// @note It is important to note that this object is designed to just be a
  175. /// temporary array of a dynamic size. Some wierdness may occur if you try
  176. /// to perform crazy pointer stuff with it using regular operators on it.
  177. template<class T>
  178. class FrameTemp
  179. {
  180. protected:
  181. U32 mWaterMark;
  182. T *mMemory;
  183. U32 mNumObjectsInMemory;
  184. public:
  185. /// Constructor will store the FrameAllocator watermark and allocate the memory off
  186. /// of the FrameAllocator.
  187. ///
  188. /// @note It is important to note that, unlike the FrameAllocatorMarker and the
  189. /// FrameAllocator itself, the argument to allocate is NOT the size in bytes,
  190. /// doing:
  191. /// @code
  192. /// FrameTemp<F64> f64s(5);
  193. /// @endcode
  194. /// Is the same as
  195. /// @code
  196. /// F64 *f64s = new F64[5];
  197. /// @endcode
  198. ///
  199. /// @param count The number of objects to allocate
  200. FrameTemp( const U32 count = 1 ) : mNumObjectsInMemory( count )
  201. {
  202. AssertFatal( count > 0, "Allocating a FrameTemp with less than one instance" );
  203. mWaterMark = FrameAllocator::getWaterMark();
  204. mMemory = reinterpret_cast<T *>( FrameAllocator::alloc( sizeof( T ) * count ) );
  205. for( S32 i = 0; i < mNumObjectsInMemory; i++ )
  206. constructInPlace<T>( &mMemory[i] );
  207. }
  208. /// Destructor restores the watermark
  209. ~FrameTemp()
  210. {
  211. // Call destructor
  212. for( S32 i = 0; i < mNumObjectsInMemory; i++ )
  213. destructInPlace<T>( &mMemory[i] );
  214. FrameAllocator::setWaterMark( mWaterMark );
  215. }
  216. /// NOTE: This will return the memory, NOT perform a ones-complement
  217. T* operator ~() { return mMemory; };
  218. /// NOTE: This will return the memory, NOT perform a ones-complement
  219. const T* operator ~() const { return mMemory; };
  220. /// NOTE: This will dereference the memory, NOT do standard unary plus behavior
  221. T& operator +() { return *mMemory; };
  222. /// NOTE: This will dereference the memory, NOT do standard unary plus behavior
  223. const T& operator +() const { return *mMemory; };
  224. T& operator *() { return *mMemory; };
  225. const T& operator *() const { return *mMemory; };
  226. T** operator &() { return &mMemory; };
  227. const T** operator &() const { return &mMemory; };
  228. operator T*() { return mMemory; }
  229. operator const T*() const { return mMemory; }
  230. operator T&() { return *mMemory; }
  231. operator const T&() const { return *mMemory; }
  232. operator T() { return *mMemory; }
  233. operator const T() const { return *mMemory; }
  234. T& operator []( U32 i ) { return mMemory[ i ]; }
  235. const T& operator []( U32 i ) const { return mMemory[ i ]; }
  236. T& operator []( S32 i ) { return mMemory[ i ]; }
  237. const T& operator []( S32 i ) const { return mMemory[ i ]; }
  238. /// @name Vector-like Interface
  239. /// @{
  240. T *address() const { return mMemory; }
  241. dsize_t size() const { return mNumObjectsInMemory; }
  242. /// @}
  243. };
  244. //-----------------------------------------------------------------------------
  245. // FrameTemp specializations for types with no constructor/destructor
  246. #define FRAME_TEMP_NC_SPEC(type) \
  247. template<> \
  248. inline FrameTemp<type>::FrameTemp( const U32 count ) \
  249. { \
  250. AssertFatal( count > 0, "Allocating a FrameTemp with less than one instance" ); \
  251. mWaterMark = FrameAllocator::getWaterMark(); \
  252. mMemory = reinterpret_cast<type *>( FrameAllocator::alloc( sizeof( type ) * count ) ); \
  253. mNumObjectsInMemory = 0; \
  254. } \
  255. template<>\
  256. inline FrameTemp<type>::~FrameTemp() \
  257. { \
  258. FrameAllocator::setWaterMark( mWaterMark ); \
  259. } \
  260. FRAME_TEMP_NC_SPEC(char);
  261. FRAME_TEMP_NC_SPEC(float);
  262. FRAME_TEMP_NC_SPEC(double);
  263. FRAME_TEMP_NC_SPEC(bool);
  264. FRAME_TEMP_NC_SPEC(int);
  265. FRAME_TEMP_NC_SPEC(short);
  266. FRAME_TEMP_NC_SPEC(unsigned char);
  267. FRAME_TEMP_NC_SPEC(unsigned int);
  268. FRAME_TEMP_NC_SPEC(unsigned short);
  269. #undef FRAME_TEMP_NC_SPEC
  270. //-----------------------------------------------------------------------------
  271. #endif // _H_FRAMEALLOCATOR_