Counter Strike : Global Offensive Source Code
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.

444 lines
12 KiB

  1. //==== Copyright � 1996-2008, Valve Corporation, All rights reserved. =======//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #ifndef VERTEXDATA_H
  7. #define VERTEXDATA_H
  8. #ifdef COMPILER_MSVC
  9. #pragma once
  10. #endif
  11. #include "tier0/platform.h"
  12. #include "rendersystem/irenderdevice.h"
  13. //-----------------------------------------------------------------------------
  14. // Vertex field creation
  15. //-----------------------------------------------------------------------------
  16. template< class T > class ALIGN16 CVertexData
  17. {
  18. public:
  19. CVertexData( IRenderContext* pRenderContext, HRenderBuffer hVertexBuffer );
  20. CVertexData( IRenderContext* pRenderContext, RenderBufferType_t nType, int nVertexCount, const char *pDebugName, const char *pBudgetGroup );
  21. ~CVertexData();
  22. // Begins, ends modification of the vertex buffer (returns true if the lock succeeded)
  23. // A lock may not succeed if there isn't enough room
  24. bool Lock( int nMaxSizeInBytes = 0 );
  25. void Unlock();
  26. // returns the number of vertices
  27. int VertexCount() const;
  28. // returns the total # of vertices in the entire buffer
  29. int GetBufferVertexCount() const;
  30. // Call this to move forward a vertex
  31. void AdvanceVertex();
  32. IRenderContext *GetRenderContext() { return m_pRenderContext; }
  33. // Call this to detach ownership of the vertex buffer. Caller is responsible
  34. // for deleting it now
  35. HRenderBuffer TakeOwnership();
  36. // Allows us to iterate on this algorithm at a later date
  37. FORCEINLINE T* operator->() { return &m_Scratch; }
  38. FORCEINLINE const T* operator->() const { return &m_Scratch; }
  39. protected:
  40. enum
  41. {
  42. BUFFER_OFFSET_UNINITIALIZED = 0xFFFFFFFF
  43. };
  44. void Release();
  45. // The temporary memory we're writing into
  46. T m_Scratch;
  47. // The mesh we're modifying
  48. T* m_pMemory;
  49. // The current vertex
  50. int m_nVertexCount;
  51. // Amount to increase the vertex count each time (0 if there was a lock failure)
  52. int m_nVertexIncrement;
  53. IRenderContext* m_pRenderContext;
  54. HRenderBuffer m_hVertexBuffer;
  55. int m_nMaxVertexCount;
  56. int m_nBufferVertexCount : 31;
  57. int m_bShouldDeallocate : 1;
  58. };
  59. //-----------------------------------------------------------------------------
  60. //
  61. // Inline methods related to CVertexData
  62. //
  63. //-----------------------------------------------------------------------------
  64. //-----------------------------------------------------------------------------
  65. // Constructor
  66. //-----------------------------------------------------------------------------
  67. template< class T >
  68. inline CVertexData<T>::CVertexData( IRenderContext* pRenderContext, HRenderBuffer hVertexBuffer )
  69. {
  70. m_pRenderContext = pRenderContext;
  71. m_hVertexBuffer = hVertexBuffer;
  72. m_bShouldDeallocate = false;
  73. BufferDesc_t desc;
  74. pRenderContext->GetDevice()->GetVertexBufferDesc( hVertexBuffer, &desc );
  75. m_nBufferVertexCount = desc.m_nElementCount;
  76. #ifdef _DEBUG
  77. // Initialize the vertex fields to NAN
  78. memset( &m_Scratch, 0xFF, sizeof(m_Scratch) );
  79. m_nVertexCount = 0;
  80. m_nMaxVertexCount = 0;
  81. m_pMemory = NULL;
  82. m_nVertexIncrement = 0;
  83. #endif
  84. }
  85. template< class T >
  86. inline CVertexData<T>::CVertexData( IRenderContext* pRenderContext, RenderBufferType_t nType, int nVertexCount, const char *pDebugName, const char *pBudgetGroup )
  87. {
  88. m_pRenderContext = pRenderContext;
  89. BufferDesc_t vertexDesc;
  90. vertexDesc.m_nElementSizeInBytes = sizeof(T);
  91. vertexDesc.m_nElementCount = nVertexCount;
  92. vertexDesc.m_pDebugName = pDebugName;
  93. vertexDesc.m_pBudgetGroupName = pBudgetGroup;
  94. m_hVertexBuffer = pRenderContext->GetDevice()->CreateVertexBuffer( nType, vertexDesc );
  95. m_nBufferVertexCount = nVertexCount;
  96. m_bShouldDeallocate = true;
  97. ResourceAddRef( m_hVertexBuffer );
  98. #ifdef _DEBUG
  99. // Initialize the vertex fields to NAN
  100. memset( &m_Scratch, 0xFF, sizeof(m_Scratch) );
  101. m_nVertexCount = 0;
  102. m_nMaxVertexCount = 0;
  103. m_pMemory = NULL;
  104. m_nVertexIncrement = 0;
  105. #endif
  106. }
  107. template< class T >
  108. inline CVertexData<T>::~CVertexData()
  109. {
  110. // If this assertion fails, you forgot to unlock
  111. Assert( !m_pMemory );
  112. Release();
  113. }
  114. //-----------------------------------------------------------------------------
  115. // Release
  116. //-----------------------------------------------------------------------------
  117. template< class T >
  118. void CVertexData<T>::Release()
  119. {
  120. if ( m_bShouldDeallocate && ( m_hVertexBuffer != RENDER_BUFFER_HANDLE_INVALID ) )
  121. {
  122. ResourceRelease( m_hVertexBuffer );
  123. m_pRenderContext->GetDevice()->DestroyVertexBuffer( m_hVertexBuffer );
  124. m_hVertexBuffer = RENDER_BUFFER_HANDLE_INVALID;
  125. m_bShouldDeallocate = false;
  126. }
  127. }
  128. //-----------------------------------------------------------------------------
  129. // Call this to take ownership of the vertex buffer
  130. //-----------------------------------------------------------------------------
  131. template< class T >
  132. inline HRenderBuffer CVertexData<T>::TakeOwnership()
  133. {
  134. if ( m_bShouldDeallocate )
  135. {
  136. ResourceRelease( m_hVertexBuffer );
  137. }
  138. m_bShouldDeallocate = false;
  139. return m_hVertexBuffer;
  140. }
  141. //-----------------------------------------------------------------------------
  142. // Returns the buffer vertex count
  143. //-----------------------------------------------------------------------------
  144. template< class T >
  145. inline int CVertexData<T>::GetBufferVertexCount() const
  146. {
  147. return m_nBufferVertexCount;
  148. }
  149. //-----------------------------------------------------------------------------
  150. // Begins, ends modification of the vertex buffer
  151. //-----------------------------------------------------------------------------
  152. template< class T >
  153. inline bool CVertexData<T>::Lock( int nMaxVertexCount )
  154. {
  155. if ( nMaxVertexCount == 0 )
  156. {
  157. nMaxVertexCount = m_nBufferVertexCount;
  158. }
  159. // Lock the vertex buffer
  160. LockDesc_t desc;
  161. bool bOk = m_pRenderContext->LockVertexBuffer( m_hVertexBuffer, nMaxVertexCount * sizeof(T), &desc );
  162. m_nVertexIncrement = bOk ? 1 : 0;
  163. m_nMaxVertexCount = nMaxVertexCount * m_nVertexIncrement;
  164. m_nVertexCount = 0;
  165. m_pMemory = (T*)desc.m_pMemory;
  166. return bOk;
  167. }
  168. template< class T >
  169. inline void CVertexData<T>::Unlock()
  170. {
  171. LockDesc_t desc;
  172. desc.m_pMemory = m_pMemory;
  173. m_pRenderContext->UnlockVertexBuffer( m_hVertexBuffer, m_nVertexCount * sizeof(T), &desc );
  174. #ifdef _DEBUG
  175. m_nVertexCount = 0;
  176. m_nMaxVertexCount = 0;
  177. m_pMemory = 0;
  178. m_nVertexIncrement = 0;
  179. #endif
  180. }
  181. //-----------------------------------------------------------------------------
  182. // returns the number of vertices
  183. //-----------------------------------------------------------------------------
  184. template< class T >
  185. inline int CVertexData<T>::VertexCount() const
  186. {
  187. return m_nVertexCount;
  188. }
  189. //-----------------------------------------------------------------------------
  190. // NOTE: This version is the one you really want to achieve write-combining;
  191. // Write combining only works if you write in 4 bytes chunks.
  192. //-----------------------------------------------------------------------------
  193. template< class T >
  194. inline void CVertexData<T>::AdvanceVertex()
  195. {
  196. Assert( ( m_nVertexIncrement == 0 ) || ( m_nVertexCount < m_nMaxVertexCount ) );
  197. T *pDest = &m_pMemory[ m_nVertexCount ];
  198. T *pSrc = &m_Scratch;
  199. #if defined( COMPILER_MSVC32 )
  200. if ( sizeof(T) == 16 )
  201. {
  202. __asm
  203. {
  204. mov esi, pSrc
  205. mov edi, pDest
  206. movaps xmm0, [esi + 0]
  207. movntps [edi + 0], xmm0
  208. }
  209. }
  210. else if ( sizeof(T) == 32 )
  211. {
  212. __asm
  213. {
  214. mov esi, pSrc
  215. mov edi, pDest
  216. movaps xmm0, [esi + 0]
  217. movaps xmm1, [esi + 16]
  218. movntps [edi + 0], xmm0
  219. movntps [edi + 16], xmm1
  220. }
  221. }
  222. else if ( sizeof(T) == 48 )
  223. {
  224. __asm
  225. {
  226. mov esi, pSrc
  227. mov edi, pDest
  228. movaps xmm0, [esi + 0]
  229. movaps xmm1, [esi + 16]
  230. movaps xmm2, [esi + 32]
  231. movntps [edi + 0], xmm0
  232. movntps [edi + 16], xmm1
  233. movntps [edi + 32], xmm2
  234. }
  235. }
  236. else if ( sizeof(T) == 64 )
  237. {
  238. __asm
  239. {
  240. mov esi, pSrc
  241. mov edi, pDest
  242. movaps xmm0, [esi + 0]
  243. movaps xmm1, [esi + 16]
  244. movaps xmm2, [esi + 32]
  245. movaps xmm3, [esi + 48]
  246. movntps [edi + 0], xmm0
  247. movntps [edi + 16], xmm1
  248. movntps [edi + 32], xmm2
  249. movntps [edi + 48], xmm3
  250. }
  251. }
  252. else
  253. #elif defined ( PLATFORM_X360 )
  254. if ( sizeof(T) == 16 )
  255. {
  256. __vector4 v4Read = __lvx( pSrc, 0 );
  257. __stvx( v4Read, pDest, 0 );
  258. }
  259. else if ( sizeof(T) == 32 )
  260. {
  261. __vector4 v4Read0 = __lvx( pSrc, 0 );
  262. __vector4 v4Read1 = __lvx( pSrc, 16 );
  263. __stvx( v4Read0, pDest, 0 );
  264. __stvx( v4Read1, pDest, 16 );
  265. }
  266. else if ( sizeof(T) == 48 )
  267. {
  268. __vector4 v4Read0 = __lvx( pSrc, 0 );
  269. __vector4 v4Read1 = __lvx( pSrc, 16 );
  270. __vector4 v4Read2 = __lvx( pSrc, 32 );
  271. __stvx( v4Read0, pDest, 0 );
  272. __stvx( v4Read1, pDest, 16 );
  273. __stvx( v4Read2, pDest, 32 );
  274. }
  275. else if ( sizeof(T) == 64 )
  276. {
  277. __vector4 v4Read0 = __lvx( pSrc, 0 );
  278. __vector4 v4Read1 = __lvx( pSrc, 16 );
  279. __vector4 v4Read2 = __lvx( pSrc, 32 );
  280. __vector4 v4Read3 = __lvx( pSrc, 48 );
  281. __stvx( v4Read0, pDest, 0 );
  282. __stvx( v4Read1, pDest, 16 );
  283. __stvx( v4Read2, pDest, 32 );
  284. __stvx( v4Read3, pDest, 48 );
  285. }
  286. else
  287. #endif
  288. *pDest = *pSrc;
  289. m_nVertexCount += m_nVertexIncrement;
  290. }
  291. //-----------------------------------------------------------------------------
  292. // Dynamic vertex field creation
  293. // NOTE: Draw call must occur prior to destruction of this class!
  294. //-----------------------------------------------------------------------------
  295. enum VertexDataStrideType_t
  296. {
  297. VD_STRIDE_ZERO = 0,
  298. VD_STRIDE_DEFAULT,
  299. };
  300. template< class T > class ALIGN16 CDynamicVertexData : public CVertexData< T >
  301. {
  302. typedef CVertexData< T > BaseClass;
  303. public:
  304. CDynamicVertexData( IRenderContext* pRenderContext, int nVertexCount, const char *pDebugName, const char *pBudgetGroup );
  305. ~CDynamicVertexData();
  306. void Release();
  307. // Begins, ends modification of the vertex buffer (returns true if the lock succeeded)
  308. // A lock may not succeed if there isn't enough room
  309. bool Lock( );
  310. // Binds the vb to a particular slot using a particular offset
  311. void Bind( int nSlot, int nOffset, VertexDataStrideType_t nStride = VD_STRIDE_DEFAULT );
  312. };
  313. //-----------------------------------------------------------------------------
  314. //
  315. // Inline methods related to CDynamicVertexData
  316. //
  317. //-----------------------------------------------------------------------------
  318. //-----------------------------------------------------------------------------
  319. // Constructor
  320. //-----------------------------------------------------------------------------
  321. template< class T >
  322. inline CDynamicVertexData<T>::CDynamicVertexData( IRenderContext* pRenderContext, int nVertexCount, const char *pDebugName, const char *pBudgetGroup ) :
  323. BaseClass( pRenderContext, RENDER_BUFFER_HANDLE_INVALID )
  324. {
  325. BufferDesc_t vertexDesc;
  326. vertexDesc.m_nElementSizeInBytes = sizeof(T);
  327. vertexDesc.m_nElementCount = nVertexCount;
  328. vertexDesc.m_pDebugName = pDebugName;
  329. vertexDesc.m_pBudgetGroupName = pBudgetGroup;
  330. this->m_hVertexBuffer = pRenderContext->CreateDynamicVertexBuffer( vertexDesc );
  331. this->m_nBufferVertexCount = nVertexCount;
  332. ResourceAddRef( this->m_hVertexBuffer );
  333. }
  334. template< class T >
  335. inline CDynamicVertexData<T>::~CDynamicVertexData()
  336. {
  337. Release();
  338. }
  339. //-----------------------------------------------------------------------------
  340. // Release
  341. //-----------------------------------------------------------------------------
  342. template< class T >
  343. void CDynamicVertexData<T>::Release()
  344. {
  345. if ( this->m_hVertexBuffer != RENDER_BUFFER_HANDLE_INVALID )
  346. {
  347. this->m_pRenderContext->DestroyDynamicVertexBuffer( this->m_hVertexBuffer );
  348. ResourceRelease( this->m_hVertexBuffer );
  349. this->m_hVertexBuffer = RENDER_BUFFER_HANDLE_INVALID;
  350. }
  351. }
  352. //-----------------------------------------------------------------------------
  353. // Begins, ends modification of the buffer
  354. //-----------------------------------------------------------------------------
  355. template< class T >
  356. inline bool CDynamicVertexData<T>::Lock( )
  357. {
  358. Assert( this->m_hVertexBuffer != RENDER_BUFFER_HANDLE_INVALID );
  359. return BaseClass::Lock( );
  360. }
  361. //-----------------------------------------------------------------------------
  362. // Binds the vb to a particular stream using a particular offset
  363. //-----------------------------------------------------------------------------
  364. template< class T >
  365. inline void CDynamicVertexData<T>::Bind( int nSlot, int nOffset, VertexDataStrideType_t nStrideType )
  366. {
  367. int nStride = ( nStrideType == VD_STRIDE_DEFAULT ) ? sizeof( T ) : 0;
  368. this->m_pRenderContext->BindVertexBuffer( nSlot, this->m_hVertexBuffer, nOffset, nStride );
  369. }
  370. #endif // VERTEXDATA_H