#ifndef UTLSOACONTAINER_H #define UTLSOACONTAINER_H #ifdef _WIN32 #pragma once #endif #include "platform.h" #include "dbg.h" #include "threadtools.h" #include "utlmemory.h" #include "utlblockmemory.h" #include "ssemath.h" template class CStridedPtr { protected: T* m_pData; size_t m_nStride; public: FORCEINLINE CStridedPtr(void* pData, size_t nByteStride) { m_pData = reinterpret_cast(pData); m_nStride = nByteStride / sizeof(T); } FORCEINLINE CStridedPtr(void) {} T* operator->(void) const { return m_pData; } T& operator*(void) const { return *m_pData; } FORCEINLINE operator T* (void) { return m_pData; } FORCEINLINE CStridedPtr& operator++(void) { m_pData += m_nStride; return *this; } FORCEINLINE void operator+=(size_t nNumElements) { m_pData += nNumElements * m_nStride; } }; template class CStridedConstPtr { protected: const T* m_pData; size_t m_nStride; public: FORCEINLINE CStridedConstPtr(void const* pData, size_t nByteStride) { m_pData = reinterpret_cast(pData); m_nStride = nByteStride / sizeof(T); } FORCEINLINE CStridedConstPtr(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& operator++(void) { m_pData += m_nStride; return *this; } FORCEINLINE void operator+=(size_t nNumElements) { m_pData += nNumElements * m_nStride; } }; enum EAttributeDataType { ATTRDATATYPE_FLOAT = 0, ATTRDATATYPE_4V = 1, ATTRDATATYPE_INT = 2, ATTRDATATYPE_POINTER = 3, ATTRDATATYPE_NONE = -1, }; #define MAX_SOA_FIELDS 32 class CSOAContainer { protected: int m_nColumns; int m_nRows; int m_nSlices; int m_nPaddedColumns; int m_nNumQuadsPerRow; uint8* m_pDataMemory; uint8* m_pAttributePtrs[MAX_SOA_FIELDS]; EAttributeDataType m_nDataType[MAX_SOA_FIELDS]; size_t m_nStrideInBytes[MAX_SOA_FIELDS]; size_t m_nRowStrideInBytes[MAX_SOA_FIELDS]; size_t m_nSliceStrideInBytes[MAX_SOA_FIELDS]; 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) { Init(); } void Purge(void); ~CSOAContainer(void); CSOAContainer(int nCols, int nRows, ...); size_t ElementSize(void) const; FORCEINLINE void SetAttributeType(int nAttrIdx, EAttributeDataType nDataType, bool bAllocateMemory = true) { Assert(!m_pDataMemory); 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]); } FORCEINLINE int NumQuadsPerRow(void) const { return m_nNumQuadsPerRow; } FORCEINLINE int Count(void) const { return NumCols(); } FORCEINLINE int NumElements(void) const { return NumCols() * NumRows() * NumSlices(); } 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 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(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]; } void CopyAttrFrom(CSOAContainer const& other, int nAttributeIdx); void CopyAttrToAttr(int nSrcAttributeIndex, int nDestAttributeIndex); FORCEINLINE void MoveDataFrom(CSOAContainer other) { (*this) = other; other.Init(); } void AllocateData(int nNCols, int nNRows, int nSlices = 1); void RandomizeAttribute(int nAttr, float flMin, float flMax) const; 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 { FORCEINLINE CFltX4AttributeIterator(CSOAContainer const* pContainer, int nAttribute, int nRowNumber = 0) : CStridedConstPtr(pContainer->ConstRowPtr(nAttribute, nRowNumber), pContainer->ItemByteStride(nAttribute)) { } }; class CFltX4AttributeWriteIterator : public CStridedPtr { FORCEINLINE CFltX4AttributeWriteIterator(CSOAContainer const* pContainer, int nAttribute, int nRowNumber = 0) : CStridedPtr(pContainer->RowPtr(nAttribute, nRowNumber), pContainer->ItemByteStride(nAttribute)) { } }; #endif