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