Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

348 lines
9.7 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: A fast stack memory allocator that uses virtual memory if available
  4. //
  5. //===========================================================================//
  6. #ifndef MEMSTACK_H
  7. #define MEMSTACK_H
  8. #if defined( _WIN32 )
  9. #pragma once
  10. #endif
  11. #include "tier1/utlvector.h"
  12. #if defined( _WIN32 ) || defined( _PS3 )
  13. #define MEMSTACK_VIRTUAL_MEMORY_AVAILABLE
  14. #endif
  15. //-----------------------------------------------------------------------------
  16. typedef unsigned MemoryStackMark_t;
  17. class CMemoryStack
  18. {
  19. public:
  20. CMemoryStack();
  21. ~CMemoryStack();
  22. bool Init( const char *pszAllocOwner, unsigned maxSize = 0, unsigned commitSize = 0, unsigned initialCommit = 0, unsigned alignment = 16 );
  23. #ifdef _GAMECONSOLE
  24. bool InitPhysical( const char *pszAllocOwner, uint size, uint nBaseAddrAlignment, uint alignment = 16, uint32 nAdditionalFlags = 0 );
  25. #endif
  26. void Term();
  27. int GetSize();
  28. int GetMaxSize();
  29. int GetUsed();
  30. void *Alloc( unsigned bytes, bool bClear = false ) RESTRICT;
  31. MemoryStackMark_t GetCurrentAllocPoint();
  32. void FreeToAllocPoint( MemoryStackMark_t mark, bool bDecommit = true );
  33. void FreeAll( bool bDecommit = true );
  34. void Access( void **ppRegion, unsigned *pBytes );
  35. void PrintContents();
  36. void *GetBase();
  37. const void *GetBase() const { return const_cast<CMemoryStack *>(this)->GetBase(); }
  38. bool CommitSize( int );
  39. void SetAllocOwner( const char *pszAllocOwner );
  40. private:
  41. bool CommitTo( byte * ) RESTRICT;
  42. void RegisterAllocation();
  43. void RegisterDeallocation( bool bShouldSpew );
  44. byte *m_pNextAlloc;
  45. byte *m_pCommitLimit;
  46. byte *m_pAllocLimit;
  47. byte *m_pBase;
  48. bool m_bRegisteredAllocation;
  49. bool m_bPhysical;
  50. char *m_pszAllocOwner;
  51. unsigned m_maxSize;
  52. unsigned m_alignment;
  53. #ifdef MEMSTACK_VIRTUAL_MEMORY_AVAILABLE
  54. unsigned m_commitSize;
  55. unsigned m_minCommit;
  56. #endif
  57. #if defined( MEMSTACK_VIRTUAL_MEMORY_AVAILABLE ) && defined( _PS3 )
  58. IVirtualMemorySection *m_pVirtualMemorySection;
  59. #endif
  60. };
  61. //-------------------------------------
  62. FORCEINLINE void *CMemoryStack::Alloc( unsigned bytes, bool bClear ) RESTRICT
  63. {
  64. Assert( m_pBase );
  65. bytes = MAX( bytes, m_alignment );
  66. bytes = AlignValue( bytes, m_alignment );
  67. void *pResult = m_pNextAlloc;
  68. byte *pNextAlloc = m_pNextAlloc + bytes;
  69. if ( pNextAlloc > m_pCommitLimit )
  70. {
  71. if ( !CommitTo( pNextAlloc ) )
  72. {
  73. return NULL;
  74. }
  75. }
  76. if ( bClear )
  77. {
  78. memset( pResult, 0, bytes );
  79. }
  80. m_pNextAlloc = pNextAlloc;
  81. return pResult;
  82. }
  83. //-------------------------------------
  84. inline bool CMemoryStack::CommitSize( int nBytes )
  85. {
  86. if ( GetSize() != nBytes )
  87. {
  88. return CommitTo( m_pBase + nBytes );
  89. }
  90. return true;
  91. }
  92. //-------------------------------------
  93. inline int CMemoryStack::GetMaxSize()
  94. {
  95. return m_maxSize;
  96. }
  97. //-------------------------------------
  98. inline int CMemoryStack::GetUsed()
  99. {
  100. return ( m_pNextAlloc - m_pBase );
  101. }
  102. //-------------------------------------
  103. inline void *CMemoryStack::GetBase()
  104. {
  105. return m_pBase;
  106. }
  107. //-------------------------------------
  108. inline MemoryStackMark_t CMemoryStack::GetCurrentAllocPoint()
  109. {
  110. return ( m_pNextAlloc - m_pBase );
  111. }
  112. //-----------------------------------------------------------------------------
  113. // The CUtlMemoryStack class:
  114. // A fixed memory class
  115. //-----------------------------------------------------------------------------
  116. template< typename T, typename I, size_t MAX_SIZE, size_t COMMIT_SIZE = 0, size_t INITIAL_COMMIT = 0 >
  117. class CUtlMemoryStack
  118. {
  119. public:
  120. // constructor, destructor
  121. CUtlMemoryStack( int nGrowSize = 0, int nInitSize = 0 ) { m_MemoryStack.Init( "CUtlMemoryStack", MAX_SIZE * sizeof(T), COMMIT_SIZE * sizeof(T), INITIAL_COMMIT * sizeof(T), 4 ); COMPILE_TIME_ASSERT( sizeof(T) % 4 == 0 ); }
  122. CUtlMemoryStack( T* pMemory, int numElements ) { Assert( 0 ); }
  123. // Can we use this index?
  124. bool IsIdxValid( I i ) const { long x=i; return (x >= 0) && (x < m_nAllocated); }
  125. // Specify the invalid ('null') index that we'll only return on failure
  126. static const I INVALID_INDEX = ( I )-1; // For use with COMPILE_TIME_ASSERT
  127. static I InvalidIndex() { return INVALID_INDEX; }
  128. class Iterator_t
  129. {
  130. Iterator_t( I i ) : index( i ) {}
  131. I index;
  132. friend class CUtlMemoryStack<T,I,MAX_SIZE, COMMIT_SIZE, INITIAL_COMMIT>;
  133. public:
  134. bool operator==( const Iterator_t it ) const { return index == it.index; }
  135. bool operator!=( const Iterator_t it ) const { return index != it.index; }
  136. };
  137. Iterator_t First() const { return Iterator_t( m_nAllocated ? 0 : InvalidIndex() ); }
  138. Iterator_t Next( const Iterator_t &it ) const { return Iterator_t( it.index < m_nAllocated ? it.index + 1 : InvalidIndex() ); }
  139. I GetIndex( const Iterator_t &it ) const { return it.index; }
  140. bool IsIdxAfter( I i, const Iterator_t &it ) const { return i > it.index; }
  141. bool IsValidIterator( const Iterator_t &it ) const { long x=it.index; return x >= 0 && x < m_nAllocated; }
  142. Iterator_t InvalidIterator() const { return Iterator_t( InvalidIndex() ); }
  143. // Gets the base address
  144. T* Base() { return (T*)m_MemoryStack.GetBase(); }
  145. const T* Base() const { return (const T*)m_MemoryStack.GetBase(); }
  146. // element access
  147. T& operator[]( I i ) { Assert( IsIdxValid(i) ); return Base()[i]; }
  148. const T& operator[]( I i ) const { Assert( IsIdxValid(i) ); return Base()[i]; }
  149. T& Element( I i ) { Assert( IsIdxValid(i) ); return Base()[i]; }
  150. const T& Element( I i ) const { Assert( IsIdxValid(i) ); return Base()[i]; }
  151. // Attaches the buffer to external memory....
  152. void SetExternalBuffer( T* pMemory, int numElements ) { Assert( 0 ); }
  153. // Size
  154. int NumAllocated() const { return m_nAllocated; }
  155. int Count() const { return m_nAllocated; }
  156. // Grows the memory, so that at least allocated + num elements are allocated
  157. void Grow( int num = 1 ) { Assert( num > 0 ); m_nAllocated += num; m_MemoryStack.Alloc( num * sizeof(T) ); }
  158. // Makes sure we've got at least this much memory
  159. void EnsureCapacity( int num ) { Assert( num <= MAX_SIZE ); if ( m_nAllocated < num ) Grow( num - m_nAllocated ); }
  160. // Memory deallocation
  161. void Purge() { m_MemoryStack.FreeAll(); m_nAllocated = 0; }
  162. // is the memory externally allocated?
  163. bool IsExternallyAllocated() const { return false; }
  164. // Set the size by which the memory grows
  165. void SetGrowSize( int size ) { Assert( 0 ); }
  166. // Identify the owner of this memory stack's memory
  167. void SetAllocOwner( const char *pszAllocOwner ) { m_MemoryStack.SetAllocOwner( pszAllocOwner ); }
  168. private:
  169. CMemoryStack m_MemoryStack;
  170. int m_nAllocated;
  171. };
  172. #ifdef _X360
  173. //-----------------------------------------------------------------------------
  174. // A memory stack used for allocating physical memory on the 360
  175. // Usage pattern anticipates we usually never go over the initial allocation
  176. // When we do so, we're ok with slightly slower allocation
  177. //-----------------------------------------------------------------------------
  178. class CPhysicalMemoryStack
  179. {
  180. public:
  181. CPhysicalMemoryStack();
  182. ~CPhysicalMemoryStack();
  183. // The physical memory stack is allocated in chunks. We will initially
  184. // allocate nInitChunkCount chunks, which will always be in memory.
  185. // When FreeAll() is called, it will free down to the initial chunk count
  186. // but not below it.
  187. bool Init( size_t nChunkSizeInBytes, size_t nAlignment, int nInitialChunkCount, uint32 nAdditionalFlags );
  188. void Term();
  189. size_t GetSize() const;
  190. size_t GetPeakUsed() const;
  191. size_t GetUsed() const;
  192. size_t GetFramePeakUsed() const;
  193. MemoryStackMark_t GetCurrentAllocPoint() const;
  194. void FreeToAllocPoint( MemoryStackMark_t mark, bool bUnused = true ); // bUnused is for interface compat with CMemoryStack
  195. void *Alloc( size_t nSizeInBytes, bool bClear = false ) RESTRICT;
  196. void FreeAll( bool bUnused = true ); // bUnused is for interface compat with CMemoryStack
  197. void PrintContents();
  198. private:
  199. void *AllocFromOverflow( size_t nSizeInBytes );
  200. struct PhysicalChunk_t
  201. {
  202. uint8 *m_pBase;
  203. uint8 *m_pNextAlloc;
  204. uint8 *m_pAllocLimit;
  205. };
  206. PhysicalChunk_t m_InitialChunk;
  207. CUtlVector< PhysicalChunk_t > m_ExtraChunks;
  208. size_t m_nUsage;
  209. size_t m_nFramePeakUsage;
  210. size_t m_nPeakUsage;
  211. size_t m_nAlignment;
  212. size_t m_nChunkSizeInBytes;
  213. int m_nFirstAvailableChunk;
  214. int m_nAdditionalFlags;
  215. PhysicalChunk_t *m_pLastAllocedChunk;
  216. };
  217. //-------------------------------------
  218. FORCEINLINE void *CPhysicalMemoryStack::Alloc( size_t nSizeInBytes, bool bClear ) RESTRICT
  219. {
  220. if ( nSizeInBytes )
  221. {
  222. nSizeInBytes = AlignValue( nSizeInBytes, m_nAlignment );
  223. }
  224. else
  225. {
  226. nSizeInBytes = m_nAlignment;
  227. }
  228. // Can't do an allocation bigger than the chunk size
  229. Assert( nSizeInBytes <= m_nChunkSizeInBytes );
  230. void *pResult = m_InitialChunk.m_pNextAlloc;
  231. uint8 *pNextAlloc = m_InitialChunk.m_pNextAlloc + nSizeInBytes;
  232. if ( pNextAlloc <= m_InitialChunk.m_pAllocLimit )
  233. {
  234. m_InitialChunk.m_pNextAlloc = pNextAlloc;
  235. m_pLastAllocedChunk = &m_InitialChunk;
  236. }
  237. else
  238. {
  239. pResult = AllocFromOverflow( nSizeInBytes );
  240. }
  241. m_nUsage += nSizeInBytes;
  242. m_nFramePeakUsage = MAX( m_nUsage, m_nFramePeakUsage );
  243. m_nPeakUsage = MAX( m_nUsage, m_nPeakUsage );
  244. if ( bClear )
  245. {
  246. memset( pResult, 0, nSizeInBytes );
  247. }
  248. return pResult;
  249. }
  250. //-------------------------------------
  251. inline size_t CPhysicalMemoryStack::GetPeakUsed() const
  252. {
  253. return m_nPeakUsage;
  254. }
  255. //-------------------------------------
  256. inline size_t CPhysicalMemoryStack::GetUsed() const
  257. {
  258. return m_nUsage;
  259. }
  260. inline size_t CPhysicalMemoryStack::GetFramePeakUsed() const
  261. {
  262. return m_nFramePeakUsage;
  263. }
  264. inline MemoryStackMark_t CPhysicalMemoryStack::GetCurrentAllocPoint() const
  265. {
  266. Assert( m_pLastAllocedChunk );
  267. return ( m_pLastAllocedChunk->m_pNextAlloc - m_pLastAllocedChunk->m_pBase );
  268. }
  269. #endif // _X360
  270. #endif // MEMSTACK_H