123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #ifndef _FRAMEALLOCATOR_H_
- #define _FRAMEALLOCATOR_H_
- #ifndef _PLATFORM_H_
- #include "platform/platform.h"
- #endif
- /// 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.
- #define FRAMEALLOCATOR_BYTE_ALIGNMENT 4
- /// Temporary memory pool for per-frame allocations.
- ///
- /// In the course of rendering a frame, it is often necessary to allocate
- /// many small chunks of memory, then free them all in a batch. For instance,
- /// say we're allocating storage for some vertex calculations:
- ///
- /// @code
- /// // Get FrameAllocator memory...
- /// U32 waterMark = FrameAllocator::getWaterMark();
- /// F32 * ptr = (F32*)FrameAllocator::alloc(sizeof(F32)*2*targetMesh->vertsPerFrame);
- ///
- /// ... calculations ...
- ///
- /// // Free frameAllocator memory
- /// FrameAllocator::setWaterMark(waterMark);
- /// @endcode
- class FrameAllocator
- {
- static U8* smBuffer;
- static U32 smHighWaterMark;
- static U32 smWaterMark;
- #ifdef TORQUE_DEBUG
- static U32 smMaxFrameAllocation;
- #endif
- public:
- inline static void init(const U32 frameSize);
- inline static void destroy();
- inline static void* alloc(const U32 allocSize);
- inline static void setWaterMark(const U32);
- inline static U32 getWaterMark();
- inline static U32 getHighWaterMark();
- #ifdef TORQUE_DEBUG
- static U32 getMaxFrameAllocation() { return smMaxFrameAllocation; }
- #endif
- };
- void FrameAllocator::init(const U32 frameSize)
- {
- #ifdef FRAMEALLOCATOR_DEBUG_GUARD
- AssertISV( false, "FRAMEALLOCATOR_DEBUG_GUARD has been removed because it allows non-contiguous memory allocation by the FrameAllocator, and this is *not* ok." );
- #endif
- AssertFatal(smBuffer == NULL, "Error, already initialized");
- smBuffer = new U8[frameSize];
- smWaterMark = 0;
- smHighWaterMark = frameSize;
- }
- void FrameAllocator::destroy()
- {
- AssertFatal(smBuffer != NULL, "Error, not initialized");
- delete [] smBuffer;
- smBuffer = NULL;
- smWaterMark = 0;
- smHighWaterMark = 0;
- }
- void* FrameAllocator::alloc(const U32 allocSize)
- {
- U32 _allocSize = allocSize;
- AssertFatal(smBuffer != NULL, "Error, no buffer!");
- AssertFatal(smWaterMark + _allocSize <= smHighWaterMark, "Error alloc too large, increase frame size!");
- smWaterMark = ( smWaterMark + ( FRAMEALLOCATOR_BYTE_ALIGNMENT - 1 ) ) & (~( FRAMEALLOCATOR_BYTE_ALIGNMENT - 1 ));
- // Sanity check.
- AssertFatal( !( smWaterMark & ( FRAMEALLOCATOR_BYTE_ALIGNMENT - 1 ) ), "Frame allocation is not on a specified byte boundry." );
- U8* p = &smBuffer[smWaterMark];
- smWaterMark += _allocSize;
- #ifdef TORQUE_DEBUG
- if (smWaterMark > smMaxFrameAllocation)
- smMaxFrameAllocation = smWaterMark;
- #endif
- return p;
- }
- void FrameAllocator::setWaterMark(const U32 waterMark)
- {
- AssertFatal(waterMark < smHighWaterMark, "Error, invalid waterMark");
- smWaterMark = waterMark;
- }
- U32 FrameAllocator::getWaterMark()
- {
- return smWaterMark;
- }
- U32 FrameAllocator::getHighWaterMark()
- {
- return smHighWaterMark;
- }
- /// Helper class to deal with FrameAllocator usage.
- ///
- /// The purpose of this class is to make it simpler and more reliable to use the
- /// FrameAllocator. Simply use it like this:
- ///
- /// @code
- /// FrameAllocatorMarker mem;
- ///
- /// char *buff = (char*)mem.alloc(100);
- /// @endcode
- ///
- /// When you leave the scope you defined the FrameAllocatorMarker in, it will
- /// automatically restore the watermark on the FrameAllocator. In situations
- /// with complex branches, this can be a significant headache remover, as you
- /// don't have to remember to reset the FrameAllocator on every posssible branch.
- class FrameAllocatorMarker
- {
- U32 mMarker;
- public:
- FrameAllocatorMarker()
- {
- mMarker = FrameAllocator::getWaterMark();
- }
- ~FrameAllocatorMarker()
- {
- FrameAllocator::setWaterMark(mMarker);
- }
- void* alloc(const U32 allocSize) const
- {
- return FrameAllocator::alloc(allocSize);
- }
- template<typename T>
- T* alloc(const U32 numElements) const
- {
- return reinterpret_cast<T *>(FrameAllocator::alloc(numElements * sizeof(T)));
- }
- };
- /// Class for temporary variables that you want to allocate easily using
- /// the FrameAllocator. For example:
- /// @code
- /// FrameTemp<char> tempStr(32); // NOTE! This parameter is NOT THE SIZE IN BYTES. See constructor docs.
- /// dStrcat( tempStr, SomeOtherString, 32 * sizeof(char) );
- /// tempStr[2] = 'l';
- /// Con::printf( tempStr );
- /// Con::printf( "Foo: %s", ~tempStr );
- /// @endcode
- ///
- /// This will automatically handle getting and restoring the watermark of the
- /// FrameAllocator when it goes out of scope. You should notice the strange
- /// operator in front of tempStr on the printf call. This is normally a unary
- /// operator for ones-complement, but in this class it will simply return the
- /// memory of the allocation. It's the same as doing (const char *)tempStr
- /// in the above case. The reason why it is necessary for the second printf
- /// and not the first is because the second one is taking a variable arg
- /// list and so it isn't getting the cast so that it's cast operator can
- /// properly return the memory instead of the FrameTemp object itself.
- ///
- /// @note It is important to note that this object is designed to just be a
- /// temporary array of a dynamic size. Some wierdness may occur if you try
- /// to perform crazy pointer stuff with it using regular operators on it.
- template<class T>
- class FrameTemp
- {
- protected:
- U32 mWaterMark;
- T *mMemory;
- U32 mNumObjectsInMemory;
- public:
- /// Constructor will store the FrameAllocator watermark and allocate the memory off
- /// of the FrameAllocator.
- ///
- /// @note It is important to note that, unlike the FrameAllocatorMarker and the
- /// FrameAllocator itself, the argument to allocate is NOT the size in bytes,
- /// doing:
- /// @code
- /// FrameTemp<F64> f64s(5);
- /// @endcode
- /// Is the same as
- /// @code
- /// F64 *f64s = new F64[5];
- /// @endcode
- ///
- /// @param count The number of objects to allocate
- FrameTemp( const U32 count = 1 ) : mNumObjectsInMemory( count )
- {
- AssertFatal( count > 0, "Allocating a FrameTemp with less than one instance" );
- mWaterMark = FrameAllocator::getWaterMark();
- mMemory = reinterpret_cast<T *>( FrameAllocator::alloc( sizeof( T ) * count ) );
- for( S32 i = 0; i < mNumObjectsInMemory; i++ )
- constructInPlace<T>( &mMemory[i] );
- }
- /// Destructor restores the watermark
- ~FrameTemp()
- {
- // Call destructor
- for( S32 i = 0; i < mNumObjectsInMemory; i++ )
- destructInPlace<T>( &mMemory[i] );
- FrameAllocator::setWaterMark( mWaterMark );
- }
- /// NOTE: This will return the memory, NOT perform a ones-complement
- T* operator ~() { return mMemory; };
- /// NOTE: This will return the memory, NOT perform a ones-complement
- const T* operator ~() const { return mMemory; };
- /// NOTE: This will dereference the memory, NOT do standard unary plus behavior
- T& operator +() { return *mMemory; };
- /// NOTE: This will dereference the memory, NOT do standard unary plus behavior
- const T& operator +() const { return *mMemory; };
- T& operator *() { return *mMemory; };
- const T& operator *() const { return *mMemory; };
- T** operator &() { return &mMemory; };
- const T** operator &() const { return &mMemory; };
- operator T*() { return mMemory; }
- operator const T*() const { return mMemory; }
- operator T&() { return *mMemory; }
- operator const T&() const { return *mMemory; }
- operator T() { return *mMemory; }
- operator const T() const { return *mMemory; }
-
- T& operator []( U32 i ) { return mMemory[ i ]; }
- const T& operator []( U32 i ) const { return mMemory[ i ]; }
- T& operator []( S32 i ) { return mMemory[ i ]; }
- const T& operator []( S32 i ) const { return mMemory[ i ]; }
- /// @name Vector-like Interface
- /// @{
- T *address() const { return mMemory; }
- dsize_t size() const { return mNumObjectsInMemory; }
- /// @}
- };
- //-----------------------------------------------------------------------------
- // FrameTemp specializations for types with no constructor/destructor
- #define FRAME_TEMP_NC_SPEC(type) \
- template<> \
- inline FrameTemp<type>::FrameTemp( const U32 count ) \
- { \
- AssertFatal( count > 0, "Allocating a FrameTemp with less than one instance" ); \
- mWaterMark = FrameAllocator::getWaterMark(); \
- mMemory = reinterpret_cast<type *>( FrameAllocator::alloc( sizeof( type ) * count ) ); \
- mNumObjectsInMemory = 0; \
- } \
- template<>\
- inline FrameTemp<type>::~FrameTemp() \
- { \
- FrameAllocator::setWaterMark( mWaterMark ); \
- } \
- FRAME_TEMP_NC_SPEC(char);
- FRAME_TEMP_NC_SPEC(float);
- FRAME_TEMP_NC_SPEC(double);
- FRAME_TEMP_NC_SPEC(bool);
- 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);
- #undef FRAME_TEMP_NC_SPEC
- //-----------------------------------------------------------------------------
- #endif // _H_FRAMEALLOCATOR_
|