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.

334 lines
9.0 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. // A Fixed-allocation class for maintaining a 1d or 2d or 3d array of data in a structure-of-arrays
  8. // (SOA) sse-friendly manner.
  9. // =============================================================================//
  10. #ifndef UTLSOACONTAINER_H
  11. #define UTLSOACONTAINER_H
  12. #ifdef _WIN32
  13. #pragma once
  14. #endif
  15. #include "tier0/platform.h"
  16. #include "tier0/dbg.h"
  17. #include "tier0/threadtools.h"
  18. #include "tier1/utlmemory.h"
  19. #include "tier1/utlblockmemory.h"
  20. #include "mathlib/ssemath.h"
  21. // strided pointers. gives you a class that acts like a pointer, but the ++ and += operators do the
  22. // right thing
  23. template<class T> class CStridedPtr
  24. {
  25. protected:
  26. T *m_pData;
  27. size_t m_nStride;
  28. public:
  29. FORCEINLINE CStridedPtr<T>( void *pData, size_t nByteStride )
  30. {
  31. m_pData = reinterpret_cast<T *>( pData );
  32. m_nStride = nByteStride / sizeof( T );
  33. }
  34. FORCEINLINE CStridedPtr<T>( void ) {}
  35. T *operator->(void) const
  36. {
  37. return m_pData;
  38. }
  39. T & operator*(void) const
  40. {
  41. return *m_pData;
  42. }
  43. FORCEINLINE operator T *(void)
  44. {
  45. return m_pData;
  46. }
  47. FORCEINLINE CStridedPtr<T> & operator++(void)
  48. {
  49. m_pData += m_nStride;
  50. return *this;
  51. }
  52. FORCEINLINE void operator+=( size_t nNumElements )
  53. {
  54. m_pData += nNumElements * m_nStride;
  55. }
  56. };
  57. template<class T> class CStridedConstPtr
  58. {
  59. protected:
  60. const T *m_pData;
  61. size_t m_nStride;
  62. public:
  63. FORCEINLINE CStridedConstPtr<T>( void const *pData, size_t nByteStride )
  64. {
  65. m_pData = reinterpret_cast<T const *>( pData );
  66. m_nStride = nByteStride / sizeof( T );
  67. }
  68. FORCEINLINE CStridedConstPtr<T>( void ) {}
  69. const T *operator->(void) const
  70. {
  71. return m_pData;
  72. }
  73. const T & operator*(void) const
  74. {
  75. return *m_pData;
  76. }
  77. FORCEINLINE operator const T *(void) const
  78. {
  79. return m_pData;
  80. }
  81. FORCEINLINE CStridedConstPtr<T> &operator++(void)
  82. {
  83. m_pData += m_nStride;
  84. return *this;
  85. }
  86. FORCEINLINE void operator+=( size_t nNumElements )
  87. {
  88. m_pData += nNumElements*m_nStride;
  89. }
  90. };
  91. // allowed field data types. if you change these values, you need to change the tables in the .cpp file
  92. enum EAttributeDataType
  93. {
  94. ATTRDATATYPE_FLOAT = 0, // a float attribute
  95. ATTRDATATYPE_4V = 1, // vector data type, stored as class FourVectors
  96. ATTRDATATYPE_INT = 2, // integer. not especially sse-able on
  97. // all architectures.
  98. ATTRDATATYPE_POINTER = 3, // a pointer.
  99. ATTRDATATYPE_NONE = -1, // pad and varargs ender
  100. };
  101. #define MAX_SOA_FIELDS 32
  102. class CSOAContainer
  103. {
  104. protected:
  105. int m_nColumns; // # of rows and columns created with
  106. int m_nRows;
  107. int m_nSlices;
  108. int m_nPaddedColumns; // # of columns rounded up for sse
  109. int m_nNumQuadsPerRow; // # of groups of 4 elements per row
  110. uint8 *m_pDataMemory; // the actual data memory
  111. uint8 *m_pAttributePtrs[MAX_SOA_FIELDS];
  112. EAttributeDataType m_nDataType[MAX_SOA_FIELDS];
  113. size_t m_nStrideInBytes[MAX_SOA_FIELDS]; // stride from one field datum to another
  114. size_t m_nRowStrideInBytes[MAX_SOA_FIELDS]; // stride from one row datum to another per field
  115. size_t m_nSliceStrideInBytes[MAX_SOA_FIELDS]; // stride from one slice datum to another per field
  116. uint32 m_nFieldPresentMask;
  117. FORCEINLINE void Init( void )
  118. {
  119. memset( m_nDataType, 0xff, sizeof( m_nDataType ) );
  120. m_pDataMemory = 0;
  121. m_nColumns = m_nPaddedColumns = m_nRows = m_nSlices = 0;
  122. m_nFieldPresentMask = 0;
  123. }
  124. public:
  125. CSOAContainer( void ) // an empoty one with no attributes
  126. {
  127. Init();
  128. }
  129. void Purge( void ); // set back to un-initted state, freeing memory
  130. ~CSOAContainer( void );
  131. // easy constructor for 2d using varargs. call like
  132. // #define ATTR_RED 0
  133. // #define ATTR_GREEN 1
  134. // #define ATTR_BLUE 2
  135. // CSOAContainer myimage( 256, 256, ATTR_RED, ATTRDATATYPE_FLOAT, ATTR_GREEN, ATTRDATATYPE_FLOAT,
  136. // ATTR_BLUE, ATTRDATATYPE_FLOAT, -1 );
  137. CSOAContainer( int nCols, int nRows, ... );
  138. size_t ElementSize( void ) const; // total bytes per element. not super fast.
  139. // set the data type for an attribute. If you set the data type, but tell it not to allocate,
  140. // the data type will be set but writes will assert, and reads will give you back zeros.
  141. FORCEINLINE void SetAttributeType( int nAttrIdx, EAttributeDataType nDataType, bool bAllocateMemory = true )
  142. {
  143. Assert( !m_pDataMemory ); // can't change after memory allocated
  144. Assert( nAttrIdx < MAX_SOA_FIELDS );
  145. m_nDataType[nAttrIdx] = nDataType;
  146. if ( ( m_nDataType[nAttrIdx] != ATTRDATATYPE_NONE ) && bAllocateMemory )
  147. m_nFieldPresentMask |= ( 1 << nAttrIdx );
  148. else
  149. m_nFieldPresentMask &= ~( 1 << nAttrIdx );
  150. }
  151. FORCEINLINE int NumRows( void ) const
  152. {
  153. return m_nRows;
  154. }
  155. FORCEINLINE int NumCols( void ) const
  156. {
  157. return m_nColumns;
  158. }
  159. FORCEINLINE int NumSlices( void ) const
  160. {
  161. return m_nSlices;
  162. }
  163. FORCEINLINE void AssertDataType( int nAttrIdx, EAttributeDataType nDataType ) const
  164. {
  165. Assert( nAttrIdx >= 0 );
  166. Assert( nAttrIdx < MAX_SOA_FIELDS );
  167. Assert( m_nStrideInBytes[nAttrIdx] );
  168. }
  169. // # of groups of 4 elements per row
  170. FORCEINLINE int NumQuadsPerRow( void ) const
  171. {
  172. return m_nNumQuadsPerRow;
  173. }
  174. FORCEINLINE int Count( void ) const // for 1d data
  175. {
  176. return NumCols();
  177. }
  178. FORCEINLINE int NumElements( void ) const
  179. {
  180. return NumCols() * NumRows() * NumSlices();
  181. }
  182. // how much to step to go from the end of one row to the start of the next one. Basically, how
  183. // many bytes to add at the end of a row when iterating over the whole 2d array with ++
  184. FORCEINLINE size_t RowToRowStep( int nAttrIdx ) const
  185. {
  186. return 0;
  187. }
  188. FORCEINLINE void *RowPtr( int nAttributeIdx, int nRowNumber, int nSliceNumber = 0 ) const
  189. {
  190. Assert( nRowNumber < m_nRows );
  191. Assert( nAttributeIdx < MAX_SOA_FIELDS );
  192. Assert( m_nDataType[nAttributeIdx] != ATTRDATATYPE_NONE );
  193. Assert( m_nFieldPresentMask & ( 1 << nAttributeIdx ) );
  194. return m_pAttributePtrs[nAttributeIdx] +
  195. + nRowNumber * m_nRowStrideInBytes[nAttributeIdx]
  196. + nSliceNumber * m_nSliceStrideInBytes[nAttributeIdx];
  197. }
  198. FORCEINLINE void const *ConstRowPtr( int nAttributeIdx, int nRowNumber, int nSliceNumber = 0 ) const
  199. {
  200. Assert( nRowNumber < m_nRows );
  201. Assert( nAttributeIdx < MAX_SOA_FIELDS );
  202. Assert( m_nDataType[nAttributeIdx] != ATTRDATATYPE_NONE );
  203. return m_pAttributePtrs[nAttributeIdx]
  204. + nRowNumber * m_nRowStrideInBytes[nAttributeIdx]
  205. + nSliceNumber * m_nSliceStrideInBytes[nAttributeIdx];
  206. }
  207. template<class T> FORCEINLINE T *ElementPointer( int nAttributeIdx,
  208. int nX = 0, int nY = 0, int nZ = 0 ) const
  209. {
  210. Assert( nAttributeIdx < MAX_SOA_FIELDS );
  211. Assert( nX < m_nColumns );
  212. Assert( nY < m_nRows );
  213. Assert( nZ < m_nSlices );
  214. Assert( m_nDataType[nAttributeIdx] != ATTRDATATYPE_NONE );
  215. Assert( m_nDataType[nAttributeIdx] != ATTRDATATYPE_4V );
  216. return reinterpret_cast<T *>( m_pAttributePtrs[nAttributeIdx]
  217. + nX * sizeof( float )
  218. + nY * m_nRowStrideInBytes[nAttributeIdx]
  219. + nZ * m_nSliceStrideInBytes[nAttributeIdx]
  220. );
  221. }
  222. FORCEINLINE size_t ItemByteStride( int nAttributeIdx ) const
  223. {
  224. Assert( nAttributeIdx < MAX_SOA_FIELDS );
  225. Assert( m_nDataType[nAttributeIdx] != ATTRDATATYPE_NONE );
  226. return m_nStrideInBytes[ nAttributeIdx ];
  227. }
  228. // copy the attribute data from another soacontainer. must be compatible geometry
  229. void CopyAttrFrom( CSOAContainer const &other, int nAttributeIdx );
  230. // copy the attribute data from another attribute. must be compatible data format
  231. void CopyAttrToAttr( int nSrcAttributeIndex, int nDestAttributeIndex);
  232. // move all the data from one csoacontainer to another, leaving the source empty.
  233. // this is just a pointer copy.
  234. FORCEINLINE void MoveDataFrom( CSOAContainer other )
  235. {
  236. (*this) = other;
  237. other.Init();
  238. }
  239. void AllocateData( int nNCols, int nNRows, int nSlices = 1 ); // actually allocate the memory and set the pointers up
  240. // arithmetic and data filling functions. All SIMD and hopefully fast
  241. // set all elements of a float attribute to random #s
  242. void RandomizeAttribute( int nAttr, float flMin, float flMax ) const ;
  243. // fill 2d a rectangle with values interpolated from 4 corner values.
  244. void FillAttrWithInterpolatedValues( int nAttr, float flValue00, float flValue10, float flValue01, float flValue11 ) const;
  245. void FillAttrWithInterpolatedValues( int nAttr, Vector flValue00, Vector flValue10,
  246. Vector const &flValue01, Vector const &flValue11 ) const;
  247. };
  248. class CFltX4AttributeIterator : public CStridedConstPtr<fltx4>
  249. {
  250. FORCEINLINE CFltX4AttributeIterator( CSOAContainer const *pContainer, int nAttribute, int nRowNumber = 0 )
  251. : CStridedConstPtr<fltx4>( pContainer->ConstRowPtr( nAttribute, nRowNumber),
  252. pContainer->ItemByteStride( nAttribute ) )
  253. {
  254. }
  255. };
  256. class CFltX4AttributeWriteIterator : public CStridedPtr<fltx4>
  257. {
  258. FORCEINLINE CFltX4AttributeWriteIterator( CSOAContainer const *pContainer, int nAttribute, int nRowNumber = 0 )
  259. : CStridedPtr<fltx4>( pContainer->RowPtr( nAttribute, nRowNumber),
  260. pContainer->ItemByteStride( nAttribute ) )
  261. {
  262. }
  263. };
  264. #endif