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