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.

3783 lines
116 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Vertex/Pixel Shaders
  4. //
  5. //===========================================================================//
  6. #define DISABLE_PROTECTED_THINGS
  7. #if ( defined(_WIN32) && !defined( _X360 ) )
  8. #elif POSIX
  9. #include <sys/types.h>
  10. #include <sys/socket.h>
  11. #include <netdb.h>
  12. #include <netinet/in.h>
  13. #include <netinet/tcp.h>
  14. #include <errno.h>
  15. #include <sys/ioctl.h>
  16. #define closesocket close
  17. #define WSAGetLastError() errno
  18. #undef SOCKET
  19. typedef int SOCKET;
  20. #define SOCKET_ERROR (-1)
  21. #define SD_SEND 0x01
  22. #define INVALID_SOCKET (~0)
  23. #endif
  24. #include "togl/rendermechanism.h"
  25. #include "vertexshaderdx8.h"
  26. #include "tier1/utlsymbol.h"
  27. #include "tier1/utlvector.h"
  28. #include "tier1/utldict.h"
  29. #include "tier1/utllinkedlist.h"
  30. #include "tier1/utlbuffer.h"
  31. #include "tier1/UtlStringMap.h"
  32. #include "locald3dtypes.h"
  33. #include "shaderapidx8_global.h"
  34. #include "recording.h"
  35. #include "tier0/vprof.h"
  36. #include "materialsystem/imaterialsystem.h"
  37. #include "materialsystem/imaterialsystemhardwareconfig.h"
  38. #include "KeyValues.h"
  39. #include "shaderapidx8.h"
  40. #include "materialsystem/IShader.h"
  41. #include "IShaderSystem.h"
  42. #include "tier0/fasttimer.h"
  43. #include <sys/stat.h>
  44. #include <time.h>
  45. #include <stdlib.h>
  46. #include "filesystem.h"
  47. #include "convar.h"
  48. #include "materialsystem/shader_vcs_version.h"
  49. #include "tier1/lzmaDecoder.h"
  50. #include "tier1/utlmap.h"
  51. #include "datacache/idatacache.h"
  52. #include "tier1/diff.h"
  53. #include "shaderdevicedx8.h"
  54. #include "filesystem/IQueuedLoader.h"
  55. #include "tier2/tier2.h"
  56. #include "shaderapi/ishaderutil.h"
  57. #include "tier0/icommandline.h"
  58. #include "Color.h"
  59. #include "tier0/dbg.h"
  60. #ifdef REMOTE_DYNAMIC_SHADER_COMPILE
  61. # if defined (POSIX)
  62. # include <sys/types.h>
  63. # include <sys/socket.h>
  64. # else
  65. # include <winsock2.h>
  66. # include <ws2tcpip.h>
  67. # endif
  68. #endif
  69. // NOTE: This has to be the last file included!
  70. #include "tier0/memdbgon.h"
  71. // It currently includes windows.h and we don't want that.
  72. #ifdef USE_ACTUAL_DX
  73. #include "../utils/bzip2/bzlib.h"
  74. #else
  75. int BZ2_bzBuffToBuffDecompress(
  76. char* dest,
  77. unsigned int* destLen,
  78. char* source,
  79. unsigned int sourceLen,
  80. int small,
  81. int verbosity
  82. )
  83. {
  84. return 0;
  85. }
  86. #endif
  87. static ConVar mat_remoteshadercompile( "mat_remoteshadercompile", "127.0.0.1", FCVAR_CHEAT );
  88. //#define PROFILE_SHADER_CREATE
  89. //#define NO_AMBIENT_CUBE
  90. #define MAX_BONES 3
  91. // debugging aid
  92. #define MAX_SHADER_HISTORY 16
  93. #if !defined( _X360 )
  94. #define SHADER_FNAME_EXTENSION ".vcs"
  95. #else
  96. #define SHADER_FNAME_EXTENSION ".360.vcs"
  97. #endif
  98. #ifdef DYNAMIC_SHADER_COMPILE
  99. volatile static char s_ShaderCompileString[]="dynamic_shader_compile_is_on";
  100. #endif
  101. #ifdef DYNAMIC_SHADER_COMPILE
  102. static void MatFlushShaders( void );
  103. #endif
  104. // D3D to OpenGL translator
  105. //static D3DToGL_ASM sg_D3DToOpenGLTranslator; // Remove the _ASM to switch to the new translator
  106. //static D3DToGL sg_NewD3DToOpenGLTranslator; // Remove the _ASM to switch to the new translator
  107. static const char *GetLightTypeName( VertexShaderLightTypes_t type )
  108. {
  109. static const char *s_VertexShaderLightTypeNames[] =
  110. {
  111. "LIGHT_NONE",
  112. "LIGHT_SPOT",
  113. "LIGHT_POINT",
  114. "LIGHT_DIRECTIONAL",
  115. "LIGHT_STATIC",
  116. "LIGHT_AMBIENTCUBE",
  117. };
  118. return s_VertexShaderLightTypeNames[type+1];
  119. }
  120. #ifdef PROFILE_SHADER_CREATE
  121. static FILE *GetDebugFileHandle( void )
  122. {
  123. static FILE *fp = NULL;
  124. if( !fp )
  125. {
  126. fp = fopen( "shadercreate.txt", "w" );
  127. Assert( fp );
  128. }
  129. return fp;
  130. }
  131. #endif // PROFILE_SHADER_CREATE
  132. #ifdef DX_TO_GL_ABSTRACTION
  133. // mat_autoload_glshaders instructs the engine to load a cached shader table at startup
  134. // it will try for glshaders.cfg first, then fall back to glbaseshaders.cfg if not found
  135. ConVar mat_autoload_glshaders( "mat_autoload_glshaders", "1" );
  136. // mat_autosave_glshaders instructs the engine to save out the shader table at key points
  137. // to the filename glshaders.cfg
  138. //
  139. ConVar mat_autosave_glshaders( "mat_autosave_glshaders", "1" );
  140. #endif
  141. //-----------------------------------------------------------------------------
  142. // Explicit instantiation of shader buffer implementation
  143. //-----------------------------------------------------------------------------
  144. template class CShaderBuffer< ID3DXBuffer >;
  145. //-----------------------------------------------------------------------------
  146. // Used to find unique shaders
  147. //-----------------------------------------------------------------------------
  148. #ifdef MEASURE_DRIVER_ALLOCATIONS
  149. static CUtlMap< CRC32_t, int, int > s_UniqueVS( 0, 0, DefLessFunc( CRC32_t ) );
  150. static CUtlMap< CRC32_t, int, int > s_UniquePS( 0, 0, DefLessFunc( CRC32_t ) );
  151. static CUtlMap< IDirect3DVertexShader9*, CRC32_t, int > s_VSLookup( 0, 0, DefLessFunc( IDirect3DVertexShader9* ) );
  152. static CUtlMap< IDirect3DPixelShader9*, CRC32_t, int > s_PSLookup( 0, 0, DefLessFunc( IDirect3DPixelShader9* ) );
  153. #endif
  154. static int s_NumPixelShadersCreated = 0;
  155. static int s_NumVertexShadersCreated = 0;
  156. static void RegisterVS( const void* pShaderBits, int nShaderSize, IDirect3DVertexShader9* pShader )
  157. {
  158. #ifdef MEASURE_DRIVER_ALLOCATIONS
  159. CRC32_t crc;
  160. CRC32_Init( &crc );
  161. CRC32_ProcessBuffer( &crc, pShaderBits, nShaderSize );
  162. CRC32_Final( &crc );
  163. s_VSLookup.Insert( pShader, crc );
  164. int nIndex = s_UniqueVS.Find( crc );
  165. if ( nIndex != s_UniqueVS.InvalidIndex() )
  166. {
  167. ++s_UniqueVS[nIndex];
  168. }
  169. else
  170. {
  171. int nMemUsed = 23 * 1024;
  172. s_UniqueVS.Insert( crc, 1 );
  173. VPROF_INCREMENT_GROUP_COUNTER( "unique vs count", COUNTER_GROUP_NO_RESET, 1 );
  174. VPROF_INCREMENT_GROUP_COUNTER( "vs driver mem", COUNTER_GROUP_NO_RESET, nMemUsed );
  175. VPROF_INCREMENT_GROUP_COUNTER( "total driver mem", COUNTER_GROUP_NO_RESET, nMemUsed );
  176. }
  177. #endif
  178. }
  179. static void RegisterPS( const void* pShaderBits, int nShaderSize, IDirect3DPixelShader9* pShader )
  180. {
  181. #ifdef MEASURE_DRIVER_ALLOCATIONS
  182. CRC32_t crc;
  183. CRC32_Init( &crc );
  184. CRC32_ProcessBuffer( &crc, pShaderBits, nShaderSize );
  185. CRC32_Final( &crc );
  186. s_PSLookup.Insert( pShader, crc );
  187. int nIndex = s_UniquePS.Find( crc );
  188. if ( nIndex != s_UniquePS.InvalidIndex() )
  189. {
  190. ++s_UniquePS[nIndex];
  191. }
  192. else
  193. {
  194. int nMemUsed = 400;
  195. s_UniquePS.Insert( crc, 1 );
  196. VPROF_INCREMENT_GROUP_COUNTER( "unique ps count", COUNTER_GROUP_NO_RESET, 1 );
  197. VPROF_INCREMENT_GROUP_COUNTER( "ps driver mem", COUNTER_GROUP_NO_RESET, nMemUsed );
  198. VPROF_INCREMENT_GROUP_COUNTER( "total driver mem", COUNTER_GROUP_NO_RESET, nMemUsed );
  199. }
  200. #endif
  201. }
  202. static void UnregisterVS( IDirect3DVertexShader9* pShader )
  203. {
  204. #ifdef MEASURE_DRIVER_ALLOCATIONS
  205. int nCRCIndex = s_VSLookup.Find( pShader );
  206. if ( nCRCIndex == s_VSLookup.InvalidIndex() )
  207. return;
  208. CRC32_t crc = s_VSLookup[nCRCIndex];
  209. s_VSLookup.RemoveAt( nCRCIndex );
  210. int nIndex = s_UniqueVS.Find( crc );
  211. if ( nIndex != s_UniqueVS.InvalidIndex() )
  212. {
  213. if ( --s_UniqueVS[nIndex] <= 0 )
  214. {
  215. int nMemUsed = 23 * 1024;
  216. VPROF_INCREMENT_GROUP_COUNTER( "unique vs count", COUNTER_GROUP_NO_RESET, -1 );
  217. VPROF_INCREMENT_GROUP_COUNTER( "vs driver mem", COUNTER_GROUP_NO_RESET, -nMemUsed );
  218. VPROF_INCREMENT_GROUP_COUNTER( "total driver mem", COUNTER_GROUP_NO_RESET, -nMemUsed );
  219. s_UniqueVS.Remove( nIndex );
  220. }
  221. }
  222. #endif
  223. }
  224. static void UnregisterPS( IDirect3DPixelShader9* pShader )
  225. {
  226. #ifdef MEASURE_DRIVER_ALLOCATIONS
  227. int nCRCIndex = s_PSLookup.Find( pShader );
  228. if ( nCRCIndex == s_PSLookup.InvalidIndex() )
  229. return;
  230. CRC32_t crc = s_PSLookup[nCRCIndex];
  231. s_PSLookup.RemoveAt( nCRCIndex );
  232. int nIndex = s_UniquePS.Find( crc );
  233. if ( nIndex != s_UniquePS.InvalidIndex() )
  234. {
  235. if ( --s_UniquePS[nIndex] <= 0 )
  236. {
  237. int nMemUsed = 400;
  238. VPROF_INCREMENT_GROUP_COUNTER( "unique ps count", COUNTER_GROUP_NO_RESET, -1 );
  239. VPROF_INCREMENT_GROUP_COUNTER( "ps driver mem", COUNTER_GROUP_NO_RESET, -nMemUsed );
  240. VPROF_INCREMENT_GROUP_COUNTER( "total driver mem", COUNTER_GROUP_NO_RESET, -nMemUsed );
  241. s_UniquePS.Remove( nIndex );
  242. }
  243. }
  244. #endif
  245. }
  246. //-----------------------------------------------------------------------------
  247. // The lovely low-level dx call to create a vertex shader
  248. //-----------------------------------------------------------------------------
  249. static HardwareShader_t CreateD3DVertexShader( DWORD *pByteCode, int numBytes, const char *pShaderName, char *debugLabel = NULL )
  250. {
  251. MEM_ALLOC_D3D_CREDIT();
  252. if ( !pByteCode )
  253. {
  254. Assert( 0 );
  255. return INVALID_HARDWARE_SHADER;
  256. }
  257. // Compute the vertex specification
  258. HardwareShader_t hShader;
  259. #ifdef DX_TO_GL_ABSTRACTION
  260. HRESULT hr = Dx9Device()->CreateVertexShader( pByteCode, (IDirect3DVertexShader9 **)&hShader, pShaderName, debugLabel );
  261. #else
  262. if ( IsEmulatingGL() )
  263. {
  264. DWORD dwVersion = D3DXGetShaderVersion( pByteCode );
  265. REFERENCE( dwVersion );
  266. Assert ( D3DSHADER_VERSION_MAJOR( dwVersion ) == 2 );
  267. }
  268. #if defined(_X360) || !defined(DX_TO_GL_ABSTRACTION)
  269. HRESULT hr = Dx9Device()->CreateVertexShader( pByteCode, (IDirect3DVertexShader9 **)&hShader );
  270. #else
  271. HRESULT hr = Dx9Device()->CreateVertexShader( pByteCode, (IDirect3DVertexShader9 **)&hShader, pShaderName );
  272. #endif
  273. #endif
  274. // NOTE: This isn't recorded before the CreateVertexShader because
  275. // we don't know the value of shader until after the CreateVertexShader.
  276. RECORD_COMMAND( DX8_CREATE_VERTEX_SHADER, 3 );
  277. RECORD_INT( ( int )hShader ); // hack hack hack
  278. RECORD_INT( numBytes );
  279. RECORD_STRUCT( pByteCode, numBytes );
  280. if ( FAILED( hr ) )
  281. {
  282. Assert( 0 );
  283. hShader = INVALID_HARDWARE_SHADER;
  284. }
  285. else
  286. {
  287. s_NumVertexShadersCreated++;
  288. RegisterVS( pByteCode, numBytes, (IDirect3DVertexShader9 *)hShader );
  289. }
  290. return hShader;
  291. }
  292. static void PatchPixelShaderForAtiMsaaHack(DWORD *pShader, DWORD dwTexCoordMask)
  293. {
  294. if ( IsPC() )
  295. {
  296. bool bIsSampler, bIsTexCoord;
  297. // Should be able to patch only ps2.0
  298. if (*pShader != 0xFFFF0200)
  299. return;
  300. pShader++;
  301. while (pShader)
  302. {
  303. switch (*pShader & D3DSI_OPCODE_MASK)
  304. {
  305. case D3DSIO_COMMENT:
  306. // Process comment
  307. pShader = pShader + (*pShader >> 16) + 1;
  308. break;
  309. case D3DSIO_END:
  310. // End of shader
  311. return;
  312. case D3DSIO_DCL:
  313. bIsSampler = (*(pShader + 1) & D3DSP_TEXTURETYPE_MASK) != D3DSTT_UNKNOWN;
  314. bIsTexCoord = (((*(pShader + 2) & D3DSP_REGTYPE_MASK) >> D3DSP_REGTYPE_SHIFT) +
  315. ((*(pShader + 2) & D3DSP_REGTYPE_MASK2) >> D3DSP_REGTYPE_SHIFT2)) == D3DSPR_TEXTURE;
  316. if (!bIsSampler && bIsTexCoord)
  317. {
  318. DWORD dwTexCoord = *(pShader + 2) & D3DSP_REGNUM_MASK;
  319. DWORD mask = 0x01;
  320. for (DWORD i = 0; i < 16; i++)
  321. {
  322. if (((dwTexCoordMask & mask) == mask) && (dwTexCoord == i))
  323. {
  324. // If found -- patch and get out
  325. // *(pShader + 2) |= D3DSPDM_PARTIALPRECISION;
  326. *(pShader + 2) |= D3DSPDM_MSAMPCENTROID;
  327. break;
  328. }
  329. mask <<= 1;
  330. }
  331. }
  332. // Intentionally fall through...
  333. default:
  334. // Skip instruction
  335. pShader = pShader + ((*pShader & D3DSI_INSTLENGTH_MASK) >> D3DSI_INSTLENGTH_SHIFT) + 1;
  336. }
  337. }
  338. }
  339. }
  340. static ConVar mat_force_ps_patch( "mat_force_ps_patch", "0" );
  341. static ConVar mat_disable_ps_patch( "mat_disable_ps_patch", "0", FCVAR_ALLOWED_IN_COMPETITIVE );
  342. //-----------------------------------------------------------------------------
  343. // The lovely low-level dx call to create a pixel shader
  344. //-----------------------------------------------------------------------------
  345. static HardwareShader_t CreateD3DPixelShader( DWORD *pByteCode, unsigned int nCentroidMask, int numBytes, const char* pShaderName, char *debugLabel = NULL )
  346. {
  347. MEM_ALLOC_D3D_CREDIT();
  348. if ( !pByteCode )
  349. return INVALID_HARDWARE_SHADER;
  350. if ( IsPC() && nCentroidMask &&
  351. ( HardwareConfig()->NeedsATICentroidHack() ||
  352. mat_force_ps_patch.GetInt() ) )
  353. {
  354. if ( !mat_disable_ps_patch.GetInt() )
  355. {
  356. PatchPixelShaderForAtiMsaaHack( pByteCode, nCentroidMask );
  357. }
  358. }
  359. HardwareShader_t shader;
  360. #if defined( DX_TO_GL_ABSTRACTION )
  361. #if defined( OSX )
  362. HRESULT hr = Dx9Device()->CreatePixelShader( pByteCode, ( IDirect3DPixelShader ** )&shader, pShaderName, debugLabel );
  363. #else
  364. HRESULT hr = Dx9Device()->CreatePixelShader( pByteCode, ( IDirect3DPixelShader ** )&shader, pShaderName, debugLabel, &nCentroidMask );
  365. #endif
  366. #else
  367. if ( IsEmulatingGL() )
  368. {
  369. DWORD dwVersion;
  370. dwVersion = D3DXGetShaderVersion( pByteCode );
  371. Assert ( D3DSHADER_VERSION_MAJOR( dwVersion ) == 2 );
  372. }
  373. #if defined(_X360) || !defined(DX_TO_GL_ABSTRACTION)
  374. HRESULT hr = Dx9Device()->CreatePixelShader( pByteCode, ( IDirect3DPixelShader ** )&shader );
  375. #else
  376. HRESULT hr = Dx9Device()->CreatePixelShader( pByteCode, ( IDirect3DPixelShader ** )&shader, pShaderName );
  377. #endif
  378. #endif
  379. // NOTE: We have to do this after creating the pixel shader since we don't know
  380. // lookup.m_PixelShader yet!!!!!!!
  381. RECORD_COMMAND( DX8_CREATE_PIXEL_SHADER, 3 );
  382. RECORD_INT( ( int )shader ); // hack hack hack
  383. RECORD_INT( numBytes );
  384. RECORD_STRUCT( pByteCode, numBytes );
  385. if ( FAILED( hr ) )
  386. {
  387. Assert(0);
  388. shader = INVALID_HARDWARE_SHADER;
  389. }
  390. else
  391. {
  392. s_NumPixelShadersCreated++;
  393. RegisterPS( pByteCode, numBytes, ( IDirect3DPixelShader9* )shader );
  394. }
  395. return shader;
  396. }
  397. template<class T> int BinarySearchCombos( uint32 nStaticComboID, int nCombos, T const *pRecords )
  398. {
  399. // Use binary search - data is sorted
  400. int nLowerIdx = 1;
  401. int nUpperIdx = nCombos;
  402. for (;;)
  403. {
  404. if ( nUpperIdx < nLowerIdx )
  405. return -1;
  406. int nMiddleIndex = ( nLowerIdx + nUpperIdx ) / 2;
  407. uint32 nProbe = pRecords[nMiddleIndex-1].m_nStaticComboID;
  408. if ( nStaticComboID < nProbe )
  409. {
  410. nUpperIdx = nMiddleIndex - 1;
  411. }
  412. else
  413. {
  414. if ( nStaticComboID > nProbe )
  415. nLowerIdx = nMiddleIndex + 1;
  416. else
  417. return nMiddleIndex - 1;
  418. }
  419. }
  420. }
  421. inline int FindShaderStaticCombo( uint32 nStaticComboID, const ShaderHeader_t& header, StaticComboRecord_t *pRecords )
  422. {
  423. if ( header.m_nVersion < 5 )
  424. return -1;
  425. return BinarySearchCombos( nStaticComboID, header.m_nNumStaticCombos, pRecords );
  426. }
  427. // cache redundant i/o fetched components of the vcs files
  428. struct ShaderFileCache_t
  429. {
  430. CUtlSymbol m_Name;
  431. CUtlSymbol m_Filename;
  432. ShaderHeader_t m_Header;
  433. bool m_bVertexShader;
  434. // valid for diff version only - contains the microcode used as the reference for diff algorithm
  435. CUtlBuffer m_ReferenceCombo;
  436. // valid for ver5 only - contains the directory
  437. CUtlVector< StaticComboRecord_t > m_StaticComboRecords;
  438. CUtlVector< StaticComboAliasRecord_t > m_StaticComboDupRecords;
  439. ShaderFileCache_t()
  440. {
  441. // invalid until version established
  442. m_Header.m_nVersion = 0;
  443. }
  444. bool IsValid() const
  445. {
  446. return m_Header.m_nVersion != 0;
  447. }
  448. bool IsOldVersion() const
  449. {
  450. return m_Header.m_nVersion < 5;
  451. }
  452. int IsVersion6() const
  453. {
  454. return ( m_Header.m_nVersion == 6 );
  455. }
  456. int FindCombo( uint32 nStaticComboID )
  457. {
  458. int nSearchAliases = BinarySearchCombos( nStaticComboID, m_StaticComboDupRecords.Count(), m_StaticComboDupRecords.Base() );
  459. if ( nSearchAliases != -1 )
  460. nStaticComboID = m_StaticComboDupRecords[nSearchAliases].m_nSourceStaticCombo;
  461. return FindShaderStaticCombo( nStaticComboID, m_Header, m_StaticComboRecords.Base() );
  462. }
  463. bool operator==( const ShaderFileCache_t& a ) const
  464. {
  465. return m_Name == a.m_Name && m_bVertexShader == a.m_bVertexShader;
  466. }
  467. };
  468. //-----------------------------------------------------------------------------
  469. // Vertex + pixel shader manager
  470. //-----------------------------------------------------------------------------
  471. class CShaderManager : public IShaderManager
  472. {
  473. public:
  474. CShaderManager();
  475. virtual ~CShaderManager();
  476. // Methods of IShaderManager
  477. virtual void Init();
  478. virtual void Shutdown();
  479. virtual IShaderBuffer *CompileShader( const char *pProgram, size_t nBufLen, const char *pShaderVersion );
  480. virtual VertexShaderHandle_t CreateVertexShader( IShaderBuffer* pShaderBuffer );
  481. virtual void DestroyVertexShader( VertexShaderHandle_t hShader );
  482. virtual PixelShaderHandle_t CreatePixelShader( IShaderBuffer* pShaderBuffer );
  483. virtual void DestroyPixelShader( PixelShaderHandle_t hShader );
  484. virtual VertexShader_t CreateVertexShader( const char *pVertexShaderFile, int nStaticVshIndex = 0, char *debugLabel = NULL );
  485. virtual PixelShader_t CreatePixelShader( const char *pPixelShaderFile, int nStaticPshIndex = 0, char *debugLabel = NULL );
  486. virtual void SetVertexShader( VertexShader_t shader );
  487. virtual void SetPixelShader( PixelShader_t shader );
  488. virtual void BindVertexShader( VertexShaderHandle_t shader );
  489. virtual void BindPixelShader( PixelShaderHandle_t shader );
  490. virtual void *GetCurrentVertexShader();
  491. virtual void *GetCurrentPixelShader();
  492. virtual void ResetShaderState();
  493. void FlushShaders();
  494. virtual void ClearVertexAndPixelShaderRefCounts();
  495. virtual void PurgeUnusedVertexAndPixelShaders();
  496. void SpewVertexAndPixelShaders();
  497. const char *GetActiveVertexShaderName();
  498. const char *GetActivePixelShaderName();
  499. bool CreateDynamicCombos_Ver4( void *pContext, uint8 *pComboBuffer );
  500. bool CreateDynamicCombos_Ver5( void *pContext, uint8 *pComboBuffer, char *debugLabel = NULL );
  501. #if defined( DX_TO_GL_ABSTRACTION )
  502. virtual void DoStartupShaderPreloading();
  503. #endif
  504. static void QueuedLoaderCallback( void *pContext, void *pContext2, const void *pData, int nSize, LoaderError_t loaderError );
  505. private:
  506. typedef CUtlFixedLinkedList< IDirect3DVertexShader9* >::IndexType_t VertexShaderIndex_t;
  507. typedef CUtlFixedLinkedList< IDirect3DPixelShader9* >::IndexType_t PixelShaderIndex_t;
  508. struct ShaderStaticCombos_t
  509. {
  510. int m_nCount;
  511. // Can't use CUtlVector here since you CUtlLinkedList<CUtlVector<>> doesn't work.
  512. HardwareShader_t *m_pHardwareShaders;
  513. struct ShaderCreationData_t
  514. {
  515. CUtlVector<uint8> ByteCode;
  516. uint32 iCentroidMask;
  517. };
  518. ShaderCreationData_t *m_pCreationData;
  519. };
  520. struct ShaderLookup_t
  521. {
  522. CUtlSymbol m_Name;
  523. int m_nStaticIndex;
  524. ShaderStaticCombos_t m_ShaderStaticCombos;
  525. DWORD m_Flags;
  526. int m_nRefCount;
  527. unsigned int m_hShaderFileCache;
  528. // for queued loading, bias an aligned optimal buffer forward to correct location
  529. int m_nDataOffset;
  530. // diff version, valid during load only
  531. ShaderDictionaryEntry_t *m_pComboDictionary;
  532. ShaderLookup_t()
  533. {
  534. m_Flags = 0;
  535. m_nRefCount = 0;
  536. m_ShaderStaticCombos.m_nCount = 0;
  537. m_ShaderStaticCombos.m_pHardwareShaders = 0;
  538. m_ShaderStaticCombos.m_pCreationData = 0;
  539. m_pComboDictionary = NULL;
  540. }
  541. void IncRefCount()
  542. {
  543. m_nRefCount++;
  544. }
  545. bool operator==( const ShaderLookup_t& a ) const
  546. {
  547. return m_Name == a.m_Name && m_nStaticIndex == a.m_nStaticIndex;
  548. }
  549. };
  550. #ifdef DYNAMIC_SHADER_COMPILE
  551. struct Combo_t
  552. {
  553. CUtlSymbol m_ComboName;
  554. int m_nMin;
  555. int m_nMax;
  556. };
  557. struct ShaderCombos_t
  558. {
  559. CUtlVector<Combo_t> m_StaticCombos;
  560. CUtlVector<Combo_t> m_DynamicCombos;
  561. int GetNumDynamicCombos( void ) const
  562. {
  563. int combos = 1;
  564. int i;
  565. for( i = 0; i < m_DynamicCombos.Count(); i++ )
  566. {
  567. combos *= ( m_DynamicCombos[i].m_nMax - m_DynamicCombos[i].m_nMin + 1 );
  568. }
  569. return combos;
  570. }
  571. int GetNumStaticCombos( void ) const
  572. {
  573. int combos = 1;
  574. int i;
  575. for( i = 0; i < m_StaticCombos.Count(); i++ )
  576. {
  577. combos *= ( m_StaticCombos[i].m_nMax - m_StaticCombos[i].m_nMin + 1 );
  578. }
  579. return combos;
  580. }
  581. };
  582. #endif
  583. private:
  584. void CreateStaticShaders();
  585. void DestroyStaticShaders();
  586. #if defined ( DYNAMIC_SHADER_COMPILE ) && defined( REMOTE_DYNAMIC_SHADER_COMPILE )
  587. void InitRemoteShaderCompile();
  588. void DeinitRemoteShaderCompile();
  589. #endif
  590. // The low-level dx call to set the vertex shader state
  591. void SetVertexShaderState( HardwareShader_t shader, DataCacheHandle_t hCachedShader = DC_INVALID_HANDLE );
  592. // The low-level dx call to set the pixel shader state
  593. void SetPixelShaderState( HardwareShader_t shader, DataCacheHandle_t hCachedShader = DC_INVALID_HANDLE );
  594. // Destroys all shaders
  595. void DestroyAllShaders();
  596. // Destroy a particular vertex shader
  597. void DestroyVertexShader( VertexShader_t shader );
  598. // Destroy a particular pixel shader
  599. void DestroyPixelShader( PixelShader_t shader );
  600. bool LoadAndCreateShaders( ShaderLookup_t &lookup, bool bVertexShader, char *debugLabel = NULL );
  601. FileHandle_t OpenFileAndLoadHeader( const char *pFileName, ShaderHeader_t *pHeader );
  602. #ifdef DYNAMIC_SHADER_COMPILE
  603. bool LoadAndCreateShaders_Dynamic( ShaderLookup_t &lookup, bool bVertexShader );
  604. const ShaderCombos_t *FindOrCreateShaderCombos( const char *pShaderName );
  605. HardwareShader_t CompileShader( const char *pShaderName, int nStaticIndex, int nDynamicIndex, bool bVertexShader );
  606. #endif
  607. void DisassembleShader( ShaderLookup_t *pLookup, int dynamicCombo, uint8 *pByteCode );
  608. void WriteTranslatedFile( ShaderLookup_t *pLookup, int dynamicCombo, char *pFileContents, char *pFileExtension );
  609. // DX_TO_GL_ABSTRACTION only, no-op otherwise
  610. void SaveShaderCache( char *cacheName ); // query GLM pair cache for all active shader pairs and write them to disk in named file
  611. bool LoadShaderCache( char *cacheName ); // read named file, establish compiled shader sets for each vertex+static and pixel+static, then link pairs as listed in table
  612. // return true on success, false if file not found
  613. // old void WarmShaderCache();
  614. CUtlFixedLinkedList< ShaderLookup_t > m_VertexShaderDict;
  615. CUtlFixedLinkedList< ShaderLookup_t > m_PixelShaderDict;
  616. CUtlSymbolTable m_ShaderSymbolTable;
  617. #ifdef DYNAMIC_SHADER_COMPILE
  618. typedef HRESULT (__stdcall *ShaderCompileFromFileFunc_t)( LPCSTR pSrcFile, CONST D3DXMACRO* pDefines,
  619. LPD3DXINCLUDE pInclude, LPCSTR pFunctionName, LPCSTR pProfile, DWORD Flags,
  620. LPD3DXBUFFER* ppShader, LPD3DXBUFFER * ppErrorMsgs, LPD3DXCONSTANTTABLE * ppConstantTable );
  621. CUtlStringMap<ShaderCombos_t> m_ShaderNameToCombos;
  622. CSysModule *m_pShaderCompiler30;
  623. ShaderCompileFromFileFunc_t m_ShaderCompileFileFunc30;
  624. #endif
  625. // The current vertex and pixel shader
  626. HardwareShader_t m_HardwareVertexShader;
  627. HardwareShader_t m_HardwarePixelShader;
  628. CUtlFixedLinkedList< IDirect3DVertexShader9* > m_RawVertexShaderDict;
  629. CUtlFixedLinkedList< IDirect3DPixelShader9* > m_RawPixelShaderDict;
  630. CUtlFixedLinkedList< ShaderFileCache_t > m_ShaderFileCache;
  631. // false, creates during init.
  632. // true, creates on access, helps reduce d3d memory for tools, but causes i/o hitches.
  633. bool m_bCreateShadersOnDemand;
  634. #if defined( _DEBUG )
  635. // for debugging (can't resolve UtlSym)
  636. // need some history because 360 d3d has rips related to sequencing
  637. char vshDebugName[MAX_SHADER_HISTORY][64];
  638. int vshDebugIndex;
  639. char pshDebugName[MAX_SHADER_HISTORY][64];
  640. int pshDebugIndex;
  641. #endif
  642. #if defined ( DYNAMIC_SHADER_COMPILE ) && defined( REMOTE_DYNAMIC_SHADER_COMPILE )
  643. SOCKET m_RemoteShaderCompileSocket;
  644. #endif
  645. };
  646. //-----------------------------------------------------------------------------
  647. // Singleton accessor
  648. //-----------------------------------------------------------------------------
  649. static CShaderManager s_ShaderManager;
  650. IShaderManager *g_pShaderManager = &s_ShaderManager;
  651. //-----------------------------------------------------------------------------
  652. // Constructor, destructor
  653. //-----------------------------------------------------------------------------
  654. CShaderManager::CShaderManager() :
  655. m_ShaderSymbolTable( 0, 32, true /* caseInsensitive */ ),
  656. m_VertexShaderDict( 32 ),
  657. m_PixelShaderDict( 32 ),
  658. m_ShaderFileCache( 32 )
  659. {
  660. m_bCreateShadersOnDemand = false;
  661. #ifdef DYNAMIC_SHADER_COMPILE
  662. m_pShaderCompiler30 = 0;
  663. m_ShaderCompileFileFunc30 = 0;
  664. #ifdef REMOTE_DYNAMIC_SHADER_COMPILE
  665. m_RemoteShaderCompileSocket = INVALID_SOCKET;
  666. #endif
  667. #endif
  668. #ifdef _DEBUG
  669. vshDebugIndex = 0;
  670. pshDebugIndex = 0;
  671. #endif
  672. }
  673. CShaderManager::~CShaderManager()
  674. {
  675. #if defined ( DYNAMIC_SHADER_COMPILE ) && defined( REMOTE_DYNAMIC_SHADER_COMPILE )
  676. DeinitRemoteShaderCompile();
  677. #endif
  678. }
  679. #define REMOTE_SHADER_COMPILE_PORT "20000"
  680. #if defined ( DYNAMIC_SHADER_COMPILE ) && defined( REMOTE_DYNAMIC_SHADER_COMPILE )
  681. void CShaderManager::InitRemoteShaderCompile()
  682. {
  683. DeinitRemoteShaderCompile();
  684. int nResult = 0;
  685. #ifdef _WIN32
  686. WSADATA wsaData;
  687. nResult = WSAStartup( 0x101, &wsaData );
  688. if ( nResult != 0 )
  689. {
  690. Warning( "CShaderManager::Init - Could not init socket for remote dynamic shader compilation\n" );
  691. }
  692. #endif
  693. struct addrinfo hints;
  694. ZeroMemory( &hints, sizeof(hints) );
  695. hints.ai_family = AF_UNSPEC;
  696. hints.ai_socktype = SOCK_STREAM;
  697. hints.ai_protocol = IPPROTO_TCP;
  698. // Resolve the server address and port
  699. struct addrinfo *result = NULL;
  700. nResult = getaddrinfo( mat_remoteshadercompile.GetString(), REMOTE_SHADER_COMPILE_PORT, &hints, &result );
  701. if ( nResult != 0 )
  702. {
  703. Warning( "getaddrinfo failed: %d\n", nResult );
  704. #ifdef _WIN32
  705. WSACleanup();
  706. #endif
  707. Assert( 0 );
  708. }
  709. // Attempt to connect to an address until one succeeds
  710. for( struct addrinfo *ptr = result; ptr != NULL; ptr = ptr->ai_next )
  711. {
  712. // Create a SOCKET for connecting to remote shader compilation server
  713. m_RemoteShaderCompileSocket = socket( ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol );
  714. if ( m_RemoteShaderCompileSocket == INVALID_SOCKET )
  715. {
  716. Warning( "Error at socket(): %ld\n", WSAGetLastError() );
  717. freeaddrinfo( result );
  718. #ifdef _WIN32
  719. WSACleanup();
  720. #endif
  721. Assert( 0 );
  722. continue;
  723. }
  724. // Connect to server.
  725. nResult = connect( m_RemoteShaderCompileSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
  726. if ( nResult == SOCKET_ERROR )
  727. {
  728. closesocket( m_RemoteShaderCompileSocket );
  729. m_RemoteShaderCompileSocket = INVALID_SOCKET;
  730. continue;
  731. }
  732. break;
  733. }
  734. freeaddrinfo( result );
  735. if ( m_RemoteShaderCompileSocket == INVALID_SOCKET )
  736. {
  737. Warning( "Unable to connect to remote shader compilation server!\n" );
  738. #ifdef _WIN32
  739. WSACleanup();
  740. #endif
  741. Assert ( 0 );
  742. }
  743. }
  744. void CShaderManager::DeinitRemoteShaderCompile()
  745. {
  746. if ( m_RemoteShaderCompileSocket != INVALID_SOCKET )
  747. {
  748. if ( shutdown( m_RemoteShaderCompileSocket, SD_SEND ) == SOCKET_ERROR )
  749. {
  750. Warning( "Remote shader compilation shutdown failed: %d\n", WSAGetLastError() );
  751. }
  752. closesocket( m_RemoteShaderCompileSocket );
  753. m_RemoteShaderCompileSocket = INVALID_SOCKET;
  754. }
  755. }
  756. #endif // defined ( DYNAMIC_SHADER_COMPILE ) && defined( REMOTE_DYNAMIC_SHADER_COMPILE )
  757. //-----------------------------------------------------------------------------
  758. // Initialization, shutdown
  759. //-----------------------------------------------------------------------------
  760. void CShaderManager::Init()
  761. {
  762. // incompatible with the 360, violates loading system
  763. // only used by PC to help tools reduce d3d footprint
  764. m_bCreateShadersOnDemand = IsPC() && ( ShaderUtil()->InEditorMode() || CommandLine()->CheckParm( "-shadersondemand" ) );
  765. #ifdef DYNAMIC_SHADER_COMPILE
  766. if( !IsX360() )
  767. {
  768. #ifdef REMOTE_DYNAMIC_SHADER_COMPILE
  769. InitRemoteShaderCompile();
  770. #else // REMOTE_DYNAMIC_SHADER_COMPILE
  771. #ifdef _DEBUG
  772. m_pShaderCompiler30 = Sys_LoadModule( "d3dx9d_33.dll" );
  773. #endif
  774. if (!m_pShaderCompiler30)
  775. {
  776. m_pShaderCompiler30 = Sys_LoadModule( "d3dx9_33.dll" );
  777. }
  778. if ( m_pShaderCompiler30 )
  779. {
  780. m_ShaderCompileFileFunc30 = (ShaderCompileFromFileFunc_t)GetProcAddress( (HMODULE)m_pShaderCompiler30, "D3DXCompileShaderFromFileA" );
  781. }
  782. #endif
  783. }
  784. #endif // DYNAMIC_SHADER_COMPILE
  785. CreateStaticShaders();
  786. }
  787. void CShaderManager::Shutdown()
  788. {
  789. #ifdef DYNAMIC_SHADER_COMPILE
  790. if ( m_pShaderCompiler30 )
  791. {
  792. Sys_UnloadModule( m_pShaderCompiler30 );
  793. m_pShaderCompiler30 = 0;
  794. m_ShaderCompileFileFunc30 = 0;
  795. }
  796. #endif
  797. #ifdef DX_TO_GL_ABSTRACTION
  798. if (mat_autosave_glshaders.GetInt())
  799. {
  800. SaveShaderCache("glshaders.cfg");
  801. }
  802. #endif
  803. DestroyAllShaders();
  804. DestroyStaticShaders();
  805. }
  806. //-----------------------------------------------------------------------------
  807. // Compiles shaders
  808. //-----------------------------------------------------------------------------
  809. IShaderBuffer *CShaderManager::CompileShader( const char *pProgram, size_t nBufLen, const char *pShaderVersion )
  810. {
  811. int nCompileFlags = D3DXSHADER_AVOID_FLOW_CONTROL;
  812. #ifdef _DEBUG
  813. nCompileFlags |= D3DXSHADER_DEBUG;
  814. #endif
  815. LPD3DXBUFFER pCompiledShader, pErrorMessages;
  816. HRESULT hr = D3DXCompileShader( pProgram, nBufLen,
  817. NULL, NULL, "main", pShaderVersion, nCompileFlags,
  818. &pCompiledShader, &pErrorMessages, NULL );
  819. if ( FAILED( hr ) )
  820. {
  821. if ( pErrorMessages )
  822. {
  823. const char *pErrorMessage = (const char *)pErrorMessages->GetBufferPointer();
  824. Warning( "Shader compilation failed! Reported the following errors:\n%s\n", pErrorMessage );
  825. pErrorMessages->Release();
  826. }
  827. return NULL;
  828. }
  829. // NOTE: This uses small block heap allocator; so I'm not going
  830. // to bother creating a memory pool.
  831. CShaderBuffer< ID3DXBuffer > *pShaderBuffer = new CShaderBuffer< ID3DXBuffer >( pCompiledShader );
  832. if ( pErrorMessages )
  833. {
  834. pErrorMessages->Release();
  835. }
  836. return pShaderBuffer;
  837. }
  838. VertexShaderHandle_t CShaderManager::CreateVertexShader( IShaderBuffer* pShaderBuffer )
  839. {
  840. // Create the vertex shader
  841. IDirect3DVertexShader9 *pVertexShader = NULL;
  842. #if defined(_X360) || !defined(DX_TO_GL_ABSTRACTION)
  843. HRESULT hr = Dx9Device()->CreateVertexShader( (const DWORD*)pShaderBuffer->GetBits(), &pVertexShader );
  844. #else
  845. HRESULT hr = Dx9Device()->CreateVertexShader( (const DWORD*)pShaderBuffer->GetBits(), &pVertexShader, NULL );
  846. #endif
  847. if ( FAILED( hr ) || !pVertexShader )
  848. return VERTEX_SHADER_HANDLE_INVALID;
  849. s_NumVertexShadersCreated++;
  850. RegisterVS( pShaderBuffer->GetBits(), pShaderBuffer->GetSize(), pVertexShader );
  851. // Insert the shader into the dictionary of shaders
  852. VertexShaderIndex_t i = m_RawVertexShaderDict.AddToTail( pVertexShader );
  853. return (VertexShaderHandle_t)i;
  854. }
  855. void CShaderManager::DestroyVertexShader( VertexShaderHandle_t hShader )
  856. {
  857. if ( hShader == VERTEX_SHADER_HANDLE_INVALID )
  858. return;
  859. VertexShaderIndex_t i = (VertexShaderIndex_t)hShader;
  860. IDirect3DVertexShader9 *pVertexShader = m_RawVertexShaderDict[ i ];
  861. UnregisterVS( pVertexShader );
  862. VerifyEquals( (int)pVertexShader->Release(), 0 );
  863. m_RawVertexShaderDict.Remove( i );
  864. }
  865. PixelShaderHandle_t CShaderManager::CreatePixelShader( IShaderBuffer* pShaderBuffer )
  866. {
  867. // Create the vertex shader
  868. IDirect3DPixelShader9 *pPixelShader = NULL;
  869. #if defined(_X360) || !defined(DX_TO_GL_ABSTRACTION)
  870. HRESULT hr = Dx9Device()->CreatePixelShader( (const DWORD*)pShaderBuffer->GetBits(), &pPixelShader );
  871. #else
  872. HRESULT hr = Dx9Device()->CreatePixelShader( (const DWORD*)pShaderBuffer->GetBits(), &pPixelShader, NULL );
  873. #endif
  874. if ( FAILED( hr ) || !pPixelShader )
  875. return PIXEL_SHADER_HANDLE_INVALID;
  876. s_NumPixelShadersCreated++;
  877. RegisterPS( pShaderBuffer->GetBits(), pShaderBuffer->GetSize(), pPixelShader );
  878. // Insert the shader into the dictionary of shaders
  879. PixelShaderIndex_t i = m_RawPixelShaderDict.AddToTail( pPixelShader );
  880. return (PixelShaderHandle_t)i;
  881. }
  882. void CShaderManager::DestroyPixelShader( PixelShaderHandle_t hShader )
  883. {
  884. if ( hShader == PIXEL_SHADER_HANDLE_INVALID )
  885. return;
  886. PixelShaderIndex_t i = (PixelShaderIndex_t)hShader;
  887. IDirect3DPixelShader9 *pPixelShader = m_RawPixelShaderDict[ i ];
  888. UnregisterPS( pPixelShader );
  889. VerifyEquals( (int)pPixelShader->Release(), 0 );
  890. m_RawPixelShaderDict.Remove( i );
  891. }
  892. //-----------------------------------------------------------------------------
  893. // Globals
  894. //-----------------------------------------------------------------------------
  895. HardwareShader_t s_pIllegalMaterialPS = INVALID_HARDWARE_SHADER;
  896. //-----------------------------------------------------------------------------
  897. // Static methods
  898. //-----------------------------------------------------------------------------
  899. void CShaderManager::CreateStaticShaders()
  900. {
  901. MEM_ALLOC_D3D_CREDIT();
  902. if ( !HardwareConfig()->SupportsVertexAndPixelShaders() )
  903. {
  904. return;
  905. }
  906. if ( IsPC() )
  907. {
  908. // GR - hack for illegal materials
  909. const DWORD psIllegalMaterial[] =
  910. {
  911. #ifdef DX_TO_GL_ABSTRACTION
  912. // Use a PS 2.0 binary shader on DX_TO_GL_ABSTRACTION
  913. 0xffff0200, 0x05000051, 0xa00f0000, 0x3f800000,
  914. 0x00000000, 0x3f800000, 0x3f800000, 0x02000001,
  915. 0x800f0000, 0xa0e40000, 0x02000001, 0x800f0800,
  916. 0x80e40000, 0x0000ffff
  917. #else
  918. 0xffff0101, 0x00000051, 0xa00f0000, 0x00000000, 0x3f800000, 0x00000000,
  919. 0x3f800000, 0x00000001, 0x800f0000, 0xa0e40000, 0x0000ffff
  920. #endif
  921. };
  922. // create default shader
  923. #if defined(_X360) || !defined(DX_TO_GL_ABSTRACTION)
  924. Dx9Device()->CreatePixelShader( psIllegalMaterial, ( IDirect3DPixelShader9 ** )&s_pIllegalMaterialPS );
  925. #else
  926. Dx9Device()->CreatePixelShader( psIllegalMaterial, ( IDirect3DPixelShader9 ** )&s_pIllegalMaterialPS, NULL );
  927. #endif
  928. }
  929. }
  930. void CShaderManager::DestroyStaticShaders()
  931. {
  932. // GR - invalid material hack
  933. // destroy internal shader
  934. if ( s_pIllegalMaterialPS != INVALID_HARDWARE_SHADER )
  935. {
  936. ( ( IDirect3DPixelShader9 * )s_pIllegalMaterialPS )->Release();
  937. s_pIllegalMaterialPS = INVALID_HARDWARE_SHADER;
  938. }
  939. }
  940. #ifdef DYNAMIC_SHADER_COMPILE
  941. static const char *GetShaderSourcePath( void )
  942. {
  943. static char shaderDir[MAX_PATH];
  944. // GR - just in case init this...
  945. static bool bHaveShaderDir = false;
  946. if( !bHaveShaderDir )
  947. {
  948. bHaveShaderDir = true;
  949. # if ( defined( DYNAMIC_SHADER_COMPILE_CUSTOM_PATH ) )
  950. {
  951. Q_strncpy( shaderDir, DYNAMIC_SHADER_COMPILE_CUSTOM_PATH, MAX_PATH );
  952. }
  953. # else
  954. {
  955. # if ( defined( _X360 ) )
  956. {
  957. char hostName[128] = "";
  958. const char *pHostName = CommandLine()->ParmValue( "-host" );
  959. if ( !pHostName )
  960. {
  961. // the 360 machine name must be <HostPC>_360
  962. DWORD length = sizeof( hostName );
  963. DmGetXboxName( hostName, &length );
  964. char *p = strstr( hostName, "_360" );
  965. *p = '\0';
  966. pHostName = hostName;
  967. }
  968. Q_snprintf( shaderDir, MAX_PATH, "net:\\smb\\%s\\stdshaders", pHostName );
  969. }
  970. # else
  971. {
  972. Q_strncpy( shaderDir, __FILE__, MAX_PATH );
  973. Q_StripFilename( shaderDir );
  974. Q_StripLastDir( shaderDir, MAX_PATH );
  975. Q_strncat( shaderDir, "stdshaders", MAX_PATH, COPY_ALL_CHARACTERS );
  976. }
  977. # endif
  978. }
  979. # endif
  980. }
  981. return shaderDir;
  982. }
  983. #endif
  984. #ifdef DYNAMIC_SHADER_COMPILE
  985. const CShaderManager::ShaderCombos_t *CShaderManager::FindOrCreateShaderCombos( const char *pShaderName )
  986. {
  987. if( m_ShaderNameToCombos.Defined( pShaderName ) )
  988. {
  989. return &m_ShaderNameToCombos[pShaderName];
  990. }
  991. ShaderCombos_t &combos = m_ShaderNameToCombos[pShaderName];
  992. char filename[MAX_PATH];
  993. // try the vsh dir first.
  994. Q_strncpy( filename, GetShaderSourcePath(), MAX_PATH );
  995. Q_strncat( filename, "\\", MAX_PATH, COPY_ALL_CHARACTERS );
  996. Q_strncat( filename, pShaderName, MAX_PATH, COPY_ALL_CHARACTERS );
  997. Q_strncat( filename, ".vsh", MAX_PATH, COPY_ALL_CHARACTERS );
  998. CUtlInplaceBuffer bffr( 0, 0, CUtlInplaceBuffer::TEXT_BUFFER );
  999. bool bOpenResult = g_pFullFileSystem->ReadFile( filename, NULL, bffr );
  1000. if ( bOpenResult )
  1001. {
  1002. NULL;
  1003. }
  1004. else
  1005. {
  1006. // try the fxc dir.
  1007. Q_strncpy( filename, GetShaderSourcePath(), MAX_PATH );
  1008. Q_strncat( filename, "\\", MAX_PATH, COPY_ALL_CHARACTERS );
  1009. Q_strncat( filename, pShaderName, MAX_PATH, COPY_ALL_CHARACTERS );
  1010. Q_strncat( filename, ".fxc", MAX_PATH, COPY_ALL_CHARACTERS );
  1011. bOpenResult = g_pFullFileSystem->ReadFile( filename, NULL, bffr );
  1012. if ( !bOpenResult )
  1013. {
  1014. // Maybe this is a specific version [20 & 20b] -> [2x]
  1015. if ( Q_strlen( pShaderName ) >= 3 )
  1016. {
  1017. char *pszEndFilename = filename + strlen( filename );
  1018. if ( !Q_stricmp( pszEndFilename - 6, "30.fxc" ) )
  1019. {
  1020. // Total hack. Who knows what builds that 30 shader?
  1021. strcpy( pszEndFilename - 6, "20b.fxc" );
  1022. bOpenResult = g_pFullFileSystem->ReadFile( filename, NULL, bffr );
  1023. if ( !bOpenResult )
  1024. {
  1025. strcpy( pszEndFilename - 6, "2x.fxc" );
  1026. bOpenResult = g_pFullFileSystem->ReadFile( filename, NULL, bffr );
  1027. }
  1028. if ( !bOpenResult )
  1029. {
  1030. strcpy( pszEndFilename - 6, "20.fxc" );
  1031. bOpenResult = g_pFullFileSystem->ReadFile( filename, NULL, bffr );
  1032. }
  1033. }
  1034. else
  1035. {
  1036. if ( !stricmp( pszEndFilename - 6, "20.fxc" ) )
  1037. {
  1038. pszEndFilename[ -5 ] = 'x';
  1039. }
  1040. else if ( !stricmp( pszEndFilename - 7, "20b.fxc" ) )
  1041. {
  1042. strcpy( pszEndFilename - 7, "2x.fxc" );
  1043. --pszEndFilename;
  1044. }
  1045. else if ( !stricmp( pszEndFilename - 6, "11.fxc" ) )
  1046. {
  1047. strcpy( pszEndFilename - 6, "xx.fxc" );
  1048. }
  1049. bOpenResult = g_pFullFileSystem->ReadFile( filename, NULL, bffr );
  1050. if ( !bOpenResult )
  1051. {
  1052. if ( !stricmp( pszEndFilename - 6, "2x.fxc" ) )
  1053. {
  1054. pszEndFilename[ -6 ] = 'x';
  1055. bOpenResult = g_pFullFileSystem->ReadFile( filename, NULL, bffr );
  1056. }
  1057. }
  1058. }
  1059. }
  1060. }
  1061. if ( !bOpenResult )
  1062. {
  1063. Assert( 0 );
  1064. return NULL;
  1065. }
  1066. }
  1067. while( char *line = bffr.InplaceGetLinePtr() )
  1068. {
  1069. // dear god perl is better at this kind of shit!
  1070. int begin = 0;
  1071. int end = 0;
  1072. // check if the line starts with '//'
  1073. if( line[0] != '/' || line[1] != '/' )
  1074. {
  1075. continue;
  1076. }
  1077. // Check if line intended for platform lines
  1078. if( IsX360() )
  1079. {
  1080. if ( Q_stristr( line, "[PC]" ) )
  1081. continue;
  1082. }
  1083. else
  1084. {
  1085. if ( Q_stristr( line, "[360]" ) || Q_stristr( line, "[XBOX]" ) )
  1086. continue;
  1087. }
  1088. // Skip any lines intended for other shader version
  1089. if ( Q_stristr( pShaderName, "_ps20" ) && !Q_stristr( pShaderName, "_ps20b" ) &&
  1090. Q_stristr( line, "[ps" ) && !Q_stristr( line, "[ps20]" ) )
  1091. continue;
  1092. if ( Q_stristr( pShaderName, "_ps20b" ) &&
  1093. Q_stristr( line, "[ps" ) && !Q_stristr( line, "[ps20b]" ) )
  1094. continue;
  1095. if ( Q_stristr( pShaderName, "_ps30" ) &&
  1096. Q_stristr( line, "[ps" ) && !Q_stristr( line, "[ps30]" ) )
  1097. continue;
  1098. if ( Q_stristr( pShaderName, "_vs20" ) &&
  1099. Q_stristr( line, "[vs" ) && !Q_stristr( line, "[vs20]" ) )
  1100. continue;
  1101. if ( Q_stristr( pShaderName, "_vs30" ) &&
  1102. Q_stristr( line, "[vs" ) && !Q_stristr( line, "[vs30]" ) )
  1103. continue;
  1104. char *pScan = &line[2];
  1105. while( *pScan == ' ' || *pScan == '\t' )
  1106. {
  1107. pScan++;
  1108. }
  1109. bool bDynamic;
  1110. if( Q_strncmp( pScan, "DYNAMIC", 7 ) == 0 )
  1111. {
  1112. bDynamic = true;
  1113. pScan += 7;
  1114. }
  1115. else if( Q_strncmp( pScan, "STATIC", 6 ) == 0 )
  1116. {
  1117. bDynamic = false;
  1118. pScan += 6;
  1119. }
  1120. else
  1121. {
  1122. continue;
  1123. }
  1124. // skip whitespace
  1125. while( *pScan == ' ' || *pScan == '\t' )
  1126. {
  1127. pScan++;
  1128. }
  1129. // check for colon
  1130. if( *pScan != ':' )
  1131. {
  1132. continue;
  1133. }
  1134. pScan++;
  1135. // skip whitespace
  1136. while( *pScan == ' ' || *pScan == '\t' )
  1137. {
  1138. pScan++;
  1139. }
  1140. // check for quote
  1141. if( *pScan != '\"' )
  1142. {
  1143. continue;
  1144. }
  1145. pScan++;
  1146. char *pBeginningOfName = pScan;
  1147. while( 1 )
  1148. {
  1149. if( *pScan == '\0' )
  1150. {
  1151. break;
  1152. }
  1153. if( *pScan == '\"' )
  1154. {
  1155. break;
  1156. }
  1157. pScan++;
  1158. }
  1159. if( *pScan == '\0' )
  1160. {
  1161. continue;
  1162. }
  1163. // must have hit a quote. .done with string.
  1164. // slam a NULL at the end quote of the string so that we have the string at pBeginningOfName.
  1165. *pScan = '\0';
  1166. pScan++;
  1167. // skip whitespace
  1168. while( *pScan == ' ' || *pScan == '\t' )
  1169. {
  1170. pScan++;
  1171. }
  1172. // check for quote
  1173. if( *pScan != '\"' )
  1174. {
  1175. continue;
  1176. }
  1177. pScan++;
  1178. // make sure that we have a number after the quote.
  1179. if( !isdigit( *pScan ) )
  1180. {
  1181. continue;
  1182. }
  1183. while( isdigit( *pScan ) )
  1184. {
  1185. begin = begin * 10 + ( *pScan - '0' );
  1186. pScan++;
  1187. }
  1188. if( pScan[0] != '.' || pScan[1] != '.' )
  1189. {
  1190. continue;
  1191. }
  1192. pScan += 2;
  1193. // make sure that we have a number
  1194. if( !isdigit( *pScan ) )
  1195. {
  1196. continue;
  1197. }
  1198. while( isdigit( *pScan ) )
  1199. {
  1200. end = end * 10 + ( *pScan - '0' );
  1201. pScan++;
  1202. }
  1203. if( pScan[0] != '\"' )
  1204. {
  1205. continue;
  1206. }
  1207. // sweet freaking jesus. .done parsing the line.
  1208. // char buf[1024];
  1209. // sprintf( buf, "\"%s\" \"%s\" %d %d\n", bDynamic ? "DYNAMIC" : "STATIC", pBeginningOfName, begin, end );
  1210. // Plat_DebugString( buf );
  1211. Combo_t *pCombo = NULL;
  1212. if( bDynamic )
  1213. {
  1214. pCombo = &combos.m_DynamicCombos[combos.m_DynamicCombos.AddToTail()];
  1215. }
  1216. else
  1217. {
  1218. pCombo = &combos.m_StaticCombos[combos.m_StaticCombos.AddToTail()];
  1219. }
  1220. pCombo->m_ComboName = m_ShaderSymbolTable.AddString( pBeginningOfName );
  1221. pCombo->m_nMin = begin;
  1222. pCombo->m_nMax = end;
  1223. }
  1224. return &combos;
  1225. }
  1226. #endif // DYNAMIC_SHADER_COMPILE
  1227. #ifdef DYNAMIC_SHADER_COMPILE
  1228. #ifndef DX_TO_GL_ABSTRACTION
  1229. //-----------------------------------------------------------------------------
  1230. // Used to deal with include files
  1231. //-----------------------------------------------------------------------------
  1232. class CDxInclude : public ID3DXInclude
  1233. {
  1234. public:
  1235. CDxInclude( const char *pMainFileName );
  1236. #if defined( _X360 )
  1237. virtual HRESULT WINAPI Open( D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID * ppData, UINT * pBytes, LPSTR pFullPath, DWORD cbFullPath );
  1238. #else
  1239. STDMETHOD(Open)(THIS_ D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID *ppData, UINT *pBytes);
  1240. #endif
  1241. STDMETHOD(Close)(THIS_ LPCVOID pData);
  1242. private:
  1243. char m_pBasePath[MAX_PATH];
  1244. #if defined( _X360 )
  1245. char m_pFullPath[MAX_PATH];
  1246. #endif
  1247. };
  1248. CDxInclude::CDxInclude( const char *pMainFileName )
  1249. {
  1250. Q_ExtractFilePath( pMainFileName, m_pBasePath, sizeof(m_pBasePath) );
  1251. }
  1252. #if defined( _X360 )
  1253. HRESULT CDxInclude::Open( D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID * ppData, UINT * pBytes, LPSTR pFullPath, DWORD cbFullPath )
  1254. #else
  1255. HRESULT CDxInclude::Open( D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID * ppData, UINT * pBytes )
  1256. #endif
  1257. {
  1258. char pTemp[MAX_PATH];
  1259. if ( !Q_IsAbsolutePath( pFileName ) && ( IncludeType == D3DXINC_LOCAL ) )
  1260. {
  1261. Q_ComposeFileName( m_pBasePath, pFileName, pTemp, sizeof(pTemp) );
  1262. pFileName = pTemp;
  1263. }
  1264. CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  1265. if ( !g_pFullFileSystem->ReadFile( pFileName, NULL, buf ) )
  1266. return E_FAIL;
  1267. *pBytes = buf.TellMaxPut();
  1268. void *pMem = malloc( *pBytes );
  1269. memcpy( pMem, buf.Base(), *pBytes );
  1270. *ppData = pMem;
  1271. # if ( defined( _X360 ) )
  1272. {
  1273. Q_ComposeFileName( m_pBasePath, pFileName, m_pFullPath, sizeof(m_pFullPath) );
  1274. pFullPath = m_pFullPath;
  1275. cbFullPath = MAX_PATH;
  1276. }
  1277. # endif
  1278. return S_OK;
  1279. }
  1280. HRESULT CDxInclude::Close( LPCVOID pData )
  1281. {
  1282. void *pMem = const_cast<void*>( pData );
  1283. free( pMem );
  1284. return S_OK;
  1285. }
  1286. #endif // not DX_TO_GL_ABSTRACTION
  1287. static const char *FileNameToShaderModel( const char *pShaderName, bool bVertexShader )
  1288. {
  1289. // Figure out the shader model
  1290. const char *pShaderModel = NULL;
  1291. if( bVertexShader )
  1292. {
  1293. if( Q_stristr( pShaderName, "vs20" ) )
  1294. {
  1295. pShaderModel = "vs_2_0";
  1296. bVertexShader = true;
  1297. }
  1298. else if( Q_stristr( pShaderName, "vs11" ) )
  1299. {
  1300. pShaderModel = "vs_1_1";
  1301. bVertexShader = true;
  1302. }
  1303. else if( Q_stristr( pShaderName, "vs14" ) )
  1304. {
  1305. pShaderModel = "vs_1_1";
  1306. bVertexShader = true;
  1307. }
  1308. else if( Q_stristr( pShaderName, "vs30" ) )
  1309. {
  1310. pShaderModel = "vs_3_0";
  1311. bVertexShader = true;
  1312. }
  1313. else
  1314. {
  1315. #ifdef _DEBUG
  1316. Error( "Failed dynamic shader compiled\nBuild shaderapidx9.dll in debug to find problem\n" );
  1317. #else
  1318. Assert( 0 );
  1319. #endif
  1320. }
  1321. }
  1322. else
  1323. {
  1324. if( Q_stristr( pShaderName, "ps20b" ) )
  1325. {
  1326. pShaderModel = "ps_2_b";
  1327. }
  1328. else if( Q_stristr( pShaderName, "ps20" ) )
  1329. {
  1330. pShaderModel = "ps_2_0";
  1331. }
  1332. else if( Q_stristr( pShaderName, "ps11" ) )
  1333. {
  1334. pShaderModel = "ps_1_1";
  1335. }
  1336. else if( Q_stristr( pShaderName, "ps14" ) )
  1337. {
  1338. pShaderModel = "ps_1_4";
  1339. }
  1340. else if( Q_stristr( pShaderName, "ps30" ) )
  1341. {
  1342. pShaderModel = "ps_3_0";
  1343. }
  1344. else
  1345. {
  1346. #ifdef _DEBUG
  1347. Error( "Failed dynamic shader compiled\nBuild shaderapidx9.dll in debug to find problem\n" );
  1348. #else
  1349. Assert( 0 );
  1350. #endif
  1351. }
  1352. }
  1353. return pShaderModel;
  1354. }
  1355. #endif
  1356. #ifdef DYNAMIC_SHADER_COMPILE
  1357. #if defined( _X360 )
  1358. static ConVar mat_flushshaders_generate_updbs( "mat_flushshaders_generate_updbs", "0", 0, "Generates UPDBs whenever you flush shaders." );
  1359. #endif
  1360. HardwareShader_t CShaderManager::CompileShader( const char *pShaderName,
  1361. int nStaticIndex, int nDynamicIndex, bool bVertexShader )
  1362. {
  1363. VPROF_BUDGET( "CompileShader", "CompileShader" );
  1364. Assert( m_ShaderNameToCombos.Defined( pShaderName ) );
  1365. if( !m_ShaderNameToCombos.Defined( pShaderName ) )
  1366. {
  1367. return INVALID_HARDWARE_SHADER;
  1368. }
  1369. const ShaderCombos_t &combos = m_ShaderNameToCombos[pShaderName];
  1370. #ifdef _DEBUG
  1371. int numStaticCombos = combos.GetNumStaticCombos();
  1372. int numDynamicCombos = combos.GetNumDynamicCombos();
  1373. #endif
  1374. Assert( nStaticIndex % numDynamicCombos == 0 );
  1375. Assert( ( nStaticIndex % numDynamicCombos ) >= 0 && ( nStaticIndex % numDynamicCombos ) < numStaticCombos );
  1376. Assert( nDynamicIndex >= 0 && nDynamicIndex < numDynamicCombos );
  1377. # ifdef DYNAMIC_SHADER_COMPILE_VERBOSE
  1378. //Warning( "Compiling %s %s\n\tdynamic:", bVertexShader ? "vsh" : "psh", pShaderName );
  1379. Warning( "Compiling " );
  1380. if ( bVertexShader )
  1381. ConColorMsg( Color( 0, 255, 0, 255 ), "vsh - %s ", pShaderName );
  1382. else
  1383. ConColorMsg( Color( 0, 255, 255, 255 ), "psh - %s ", pShaderName );
  1384. Warning( "\n\tdynamic:" );
  1385. # endif
  1386. CUtlVector<D3DXMACRO> macros;
  1387. // plus 1 for null termination, plus 1 for #define SHADER_MODEL_*, and plus 1 for #define _X360 on 360
  1388. macros.SetCount( combos.m_DynamicCombos.Count() + combos.m_StaticCombos.Count() + 2 + ( IsX360() ? 1 : 0 ) );
  1389. int nCombo = nStaticIndex + nDynamicIndex;
  1390. int macroIndex = 0;
  1391. int i;
  1392. for( i = 0; i < combos.m_DynamicCombos.Count(); i++ )
  1393. {
  1394. int countForCombo = combos.m_DynamicCombos[i].m_nMax - combos.m_DynamicCombos[i].m_nMin + 1;
  1395. int val = nCombo % countForCombo + combos.m_DynamicCombos[i].m_nMin;
  1396. nCombo /= countForCombo;
  1397. macros[macroIndex].Name = m_ShaderSymbolTable.String( combos.m_DynamicCombos[i].m_ComboName );
  1398. char buf[16];
  1399. sprintf( buf, "%d", val );
  1400. CUtlSymbol valSymbol( buf );
  1401. macros[macroIndex].Definition = valSymbol.String();
  1402. # ifdef DYNAMIC_SHADER_COMPILE_VERBOSE
  1403. Warning( " %s=%s", macros[macroIndex].Name, macros[macroIndex].Definition );
  1404. # endif
  1405. macroIndex++;
  1406. }
  1407. # ifdef DYNAMIC_SHADER_COMPILE_VERBOSE
  1408. Warning( "\n\tstatic:" );
  1409. # endif
  1410. for( i = 0; i < combos.m_StaticCombos.Count(); i++ )
  1411. {
  1412. int countForCombo = combos.m_StaticCombos[i].m_nMax - combos.m_StaticCombos[i].m_nMin + 1;
  1413. int val = nCombo % countForCombo + combos.m_StaticCombos[i].m_nMin;
  1414. nCombo /= countForCombo;
  1415. macros[macroIndex].Name = m_ShaderSymbolTable.String( combos.m_StaticCombos[i].m_ComboName );
  1416. char buf[16];
  1417. sprintf( buf, "%d", val );
  1418. CUtlSymbol valSymbol( buf );
  1419. macros[macroIndex].Definition = valSymbol.String();
  1420. # ifdef DYNAMIC_SHADER_COMPILE_VERBOSE
  1421. Warning( " %s=%s", macros[macroIndex].Name, macros[macroIndex].Definition );
  1422. # endif
  1423. macroIndex++;
  1424. }
  1425. # ifdef DYNAMIC_SHADER_COMPILE_VERBOSE
  1426. Warning( "\n" );
  1427. # endif
  1428. char filename[MAX_PATH];
  1429. Q_strncpy( filename, GetShaderSourcePath(), MAX_PATH );
  1430. Q_strncat( filename, "\\", MAX_PATH, COPY_ALL_CHARACTERS );
  1431. Q_strncat( filename, pShaderName, MAX_PATH, COPY_ALL_CHARACTERS );
  1432. Q_strncat( filename, ".fxc", MAX_PATH, COPY_ALL_CHARACTERS );
  1433. const char *pShaderModel = FileNameToShaderModel( pShaderName, bVertexShader );
  1434. // define the shader model
  1435. char shaderModelDefineString[1024];
  1436. Q_snprintf( shaderModelDefineString, 1024, "SHADER_MODEL_%s", pShaderModel );
  1437. Q_strupr( shaderModelDefineString );
  1438. macros[macroIndex].Name = shaderModelDefineString;
  1439. macros[macroIndex].Definition = "1";
  1440. macroIndex++;
  1441. char x360DefineString[1024];
  1442. if( IsX360() )
  1443. {
  1444. Q_snprintf( x360DefineString, 1024, "_X360", pShaderModel );
  1445. Q_strupr( x360DefineString );
  1446. macros[macroIndex].Name = x360DefineString;
  1447. macros[macroIndex].Definition = "1";
  1448. macroIndex++;
  1449. }
  1450. // NULL terminate.
  1451. macros[macroIndex].Name = NULL;
  1452. macros[macroIndex].Definition = NULL;
  1453. // Instead of erroring out, infinite-loop on shader compilation
  1454. // (i.e. give developers a chance to fix the shader code w/out restarting the game)
  1455. #ifndef _DEBUG
  1456. int retriesLeft = 20;
  1457. retry_compile:
  1458. #endif
  1459. // Try and open the file to see if it exists
  1460. FileHandle_t fp = g_pFullFileSystem->Open( filename, "r" );
  1461. if ( fp == FILESYSTEM_INVALID_HANDLE )
  1462. {
  1463. // Maybe this is a specific version [20 & 20b] -> [2x]
  1464. if ( strlen( pShaderName ) >= 3 )
  1465. {
  1466. char *pszEndFilename = filename + strlen( filename );
  1467. if ( !Q_stricmp( pszEndFilename - 6, "30.fxc" ) )
  1468. {
  1469. strcpy( pszEndFilename - 6, "20b.fxc" );
  1470. fp = g_pFullFileSystem->Open( filename, "r" );
  1471. if ( fp == FILESYSTEM_INVALID_HANDLE )
  1472. {
  1473. strcpy( pszEndFilename - 6, "2x.fxc" );
  1474. fp = g_pFullFileSystem->Open( filename, "r" );
  1475. }
  1476. if ( fp == FILESYSTEM_INVALID_HANDLE )
  1477. {
  1478. strcpy( pszEndFilename - 6, "20.fxc" );
  1479. fp = g_pFullFileSystem->Open( filename, "r" );
  1480. }
  1481. }
  1482. else
  1483. {
  1484. if ( !Q_stricmp( pszEndFilename - 6, "20.fxc" ) )
  1485. {
  1486. pszEndFilename[ -5 ] = 'x';
  1487. fp = g_pFullFileSystem->Open( filename, "r" );
  1488. }
  1489. else if ( !Q_stricmp( pszEndFilename - 7, "20b.fxc" ) )
  1490. {
  1491. strcpy( pszEndFilename - 7, "2x.fxc" );
  1492. fp = g_pFullFileSystem->Open( filename, "r" );
  1493. }
  1494. else if ( !stricmp( pszEndFilename - 6, "11.fxc" ) )
  1495. {
  1496. strcpy( pszEndFilename - 6, "xx.fxc" );
  1497. fp = g_pFullFileSystem->Open( filename, "r" );
  1498. }
  1499. if ( fp == FILESYSTEM_INVALID_HANDLE )
  1500. {
  1501. if ( !stricmp( pszEndFilename - 6, "2x.fxc" ) )
  1502. {
  1503. pszEndFilename[ -6 ] = 'x';
  1504. fp = g_pFullFileSystem->Open( filename, "r" );
  1505. }
  1506. }
  1507. }
  1508. }
  1509. }
  1510. if ( fp != FILESYSTEM_INVALID_HANDLE )
  1511. {
  1512. g_pFullFileSystem->Close( fp );
  1513. }
  1514. #ifdef REMOTE_DYNAMIC_SHADER_COMPILE
  1515. #define SEND_BUF_SIZE 40000
  1516. #define RECV_BUF_SIZE 40000
  1517. // Remotely-compiled shader code
  1518. uint32 *pRemotelyCompiledShader = NULL;
  1519. uint32 nRemotelyCompiledShaderLength = 0;
  1520. if ( m_RemoteShaderCompileSocket == INVALID_SOCKET )
  1521. {
  1522. InitRemoteShaderCompile();
  1523. }
  1524. // In this case, we're going to use a remote service to do our compiling
  1525. if ( m_RemoteShaderCompileSocket != INVALID_SOCKET )
  1526. {
  1527. // Build up command list for remote shader compiler
  1528. char pSendbuf[SEND_BUF_SIZE], pRecvbuf[RECV_BUF_SIZE], pFixedFilename[MAX_PATH], buf[MAX_PATH];
  1529. V_FixupPathName( pFixedFilename, MAX_PATH, filename );
  1530. V_FileBase( pFixedFilename, buf, MAX_PATH ); // Just find base filename
  1531. V_strncat( buf, ".fxc", MAX_PATH );
  1532. V_snprintf( pSendbuf, SEND_BUF_SIZE, "%s\n", buf );
  1533. V_strncat( pSendbuf, pShaderModel, SEND_BUF_SIZE );
  1534. V_strncat( pSendbuf, "\n", SEND_BUF_SIZE );
  1535. V_snprintf( buf, MAX_PATH, "%d\n", macros.Count() );
  1536. V_strncat( pSendbuf, buf, SEND_BUF_SIZE );
  1537. for ( int i=0; i < macros.Count(); i++ )
  1538. {
  1539. V_snprintf( buf, MAX_PATH, "%s\n%s\n", macros[i].Name, macros[i].Definition );
  1540. V_strncat( pSendbuf, buf, SEND_BUF_SIZE );
  1541. }
  1542. V_strncat( pSendbuf, "", SEND_BUF_SIZE );
  1543. // Send commands to remote shader compiler
  1544. int nResult = send( m_RemoteShaderCompileSocket, pSendbuf, (int)strlen( pSendbuf ), 0 );
  1545. if ( nResult == SOCKET_ERROR )
  1546. {
  1547. Warning( "send failed: %d\n", WSAGetLastError() );
  1548. DeinitRemoteShaderCompile();
  1549. }
  1550. if ( m_RemoteShaderCompileSocket != INVALID_SOCKET )
  1551. {
  1552. // Block here until we get a result back from the server
  1553. nResult = recv( m_RemoteShaderCompileSocket, pRecvbuf, RECV_BUF_SIZE, 0 );
  1554. if ( nResult == 0 )
  1555. {
  1556. Warning( "Connection closed\n" );
  1557. DeinitRemoteShaderCompile();
  1558. }
  1559. else if ( nResult < 0 )
  1560. {
  1561. Warning( "recv failed: %d\n", WSAGetLastError() );
  1562. DeinitRemoteShaderCompile();
  1563. }
  1564. if ( m_RemoteShaderCompileSocket != INVALID_SOCKET )
  1565. {
  1566. // Grab the first 32 bits, which tell us what the rest of the data is
  1567. uint32 nCompileResultCode;
  1568. memcpy( &nCompileResultCode, pRecvbuf, sizeof( nCompileResultCode ) );
  1569. // If is zero, we have an error, so the rest of the data is a text string from the compiler
  1570. if ( nCompileResultCode == 0x00000000 )
  1571. {
  1572. Warning( "Remote shader compile error: %s\n", pRecvbuf+4 );
  1573. }
  1574. else // we have an actual binary shader blob coming back
  1575. {
  1576. nRemotelyCompiledShaderLength = nCompileResultCode;
  1577. pRemotelyCompiledShader = (uint32 *) pRecvbuf;
  1578. pRemotelyCompiledShader++;
  1579. }
  1580. }
  1581. }
  1582. } // End using remote compile service
  1583. #endif // REMOTE_DYNAMIC_SHADER_COMPILE
  1584. #if defined( DYNAMIC_SHADER_COMPILE )
  1585. bool bShadersNeedFlush = false;
  1586. #endif
  1587. #if defined( DYNAMIC_SHADER_COMPILE ) && !defined( REMOTE_DYNAMIC_SHADER_COMPILE )
  1588. LPD3DXBUFFER pShader = NULL;
  1589. LPD3DXBUFFER pErrorMessages = NULL;
  1590. HRESULT hr = S_OK;
  1591. bool b30Shader = !Q_stricmp( pShaderModel, "vs_3_0" ) || !Q_stricmp( pShaderModel, "ps_3_0" );
  1592. if ( m_ShaderCompileFileFunc30 && b30Shader )
  1593. {
  1594. CDxInclude dxInclude( filename );
  1595. hr = m_ShaderCompileFileFunc30( filename, macros.Base(), &dxInclude,
  1596. "main", pShaderModel, 0 /* DWORD Flags */, &pShader, &pErrorMessages, NULL /* LPD3DXCONSTANTTABLE *ppConstantTable */ );
  1597. }
  1598. else
  1599. {
  1600. # if ( !defined( _X360 ) )
  1601. {
  1602. if ( b30Shader )
  1603. {
  1604. Warning( "Compiling with a stale version of d3dx. Should have d3d9x_33.dll installed (Apr 2007)\n" );
  1605. }
  1606. hr = D3DXCompileShaderFromFile( filename, macros.Base(), NULL /* LPD3DXINCLUDE */,
  1607. "main", pShaderModel, 0 /* DWORD Flags */, &pShader, &pErrorMessages, NULL /* LPD3DXCONSTANTTABLE *ppConstantTable */ );
  1608. #ifdef REMOTE_DYNAMIC_SHADER_COMPILE
  1609. // If we're using the remote compiling service, let's double-check against a local compile
  1610. if ( ( m_RemoteShaderCompileSocket != INVALID_SOCKET ) && pRemotelyCompiledShader )
  1611. {
  1612. if ( ( memcmp( pRemotelyCompiledShader, pShader->GetBufferPointer(), pShader->GetBufferSize() ) != 0 ) ||
  1613. ( pShader->GetBufferSize() != nRemotelyCompiledShaderLength) )
  1614. {
  1615. Warning( "Remote and local shaders don't match!\n" );
  1616. return INVALID_HARDWARE_SHADER;
  1617. }
  1618. }
  1619. #endif // REMOTE_DYNAMIC_SHADER_COMPILE
  1620. }
  1621. # else
  1622. {
  1623. D3DXSHADER_COMPILE_PARAMETERS compileParams;
  1624. memset( &compileParams, 0, sizeof( compileParams ) );
  1625. char pUPDBOutputFile[MAX_PATH] = ""; //where we write the file
  1626. char pUPDBPIXLookup[MAX_PATH] = ""; //where PIX (on a pc) looks for the file
  1627. compileParams.Flags |= D3DXSHADEREX_OPTIMIZE_UCODE;
  1628. if( mat_flushshaders_generate_updbs.GetBool() )
  1629. {
  1630. //UPDB generation for PIX debugging
  1631. compileParams.Flags |= D3DXSHADEREX_GENERATE_UPDB;
  1632. compileParams.UPDBPath = pUPDBPIXLookup;
  1633. Q_snprintf( pUPDBOutputFile, MAX_PATH, "%s\\UPDB_X360\\%s_S%d_D%d.updb", GetShaderSourcePath(), pShaderName, nStaticIndex, nDynamicIndex );
  1634. //replace "net:\smb" with another "\" turning the xbox network address format into the pc network address format
  1635. V_strcpy_safe( pUPDBPIXLookup, &pUPDBOutputFile[7] );
  1636. pUPDBPIXLookup[0] = '\\';
  1637. }
  1638. hr = D3DXCompileShaderFromFileEx( filename, macros.Base(), NULL /* LPD3DXINCLUDE */,
  1639. "main", pShaderModel, 0 /* DWORD Flags */, &pShader, &pErrorMessages, NULL /* LPD3DXCONSTANTTABLE *ppConstantTable */, &compileParams );
  1640. if( (pUPDBOutputFile[0] != '\0') && compileParams.pUPDBBuffer ) //Did we generate a updb?
  1641. {
  1642. CUtlBuffer outbuffer;
  1643. DWORD dataSize = compileParams.pUPDBBuffer->GetBufferSize();
  1644. outbuffer.EnsureCapacity( dataSize );
  1645. memcpy( outbuffer.Base(), compileParams.pUPDBBuffer->GetBufferPointer(), dataSize );
  1646. outbuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, dataSize );
  1647. g_pFullFileSystem->WriteFile( pUPDBOutputFile, NULL, outbuffer );
  1648. compileParams.pUPDBBuffer->Release();
  1649. }
  1650. }
  1651. # endif
  1652. }
  1653. if ( hr != D3D_OK )
  1654. {
  1655. const char *pErrorMessageString = ( const char * )pErrorMessages->GetBufferPointer();
  1656. Plat_DebugString( pErrorMessageString );
  1657. Plat_DebugString( "\n" );
  1658. #ifndef _DEBUG
  1659. if ( retriesLeft-- > 0 )
  1660. {
  1661. DevMsg( 0, "Failed dynamic shader compiled - fix the shader while the debugger is at the breakpoint, then continue\n" );
  1662. DebuggerBreakIfDebugging();
  1663. #if defined( DYNAMIC_SHADER_COMPILE )
  1664. bShadersNeedFlush = true;
  1665. #endif
  1666. goto retry_compile;
  1667. }
  1668. if( !IsX360() ) //errors make the 360 puke and die. We have a better solution for this particular error
  1669. Error( "Failed dynamic shader compile\nBuild shaderapidx9.dll in debug to find problem\n" );
  1670. #else
  1671. Assert( 0 );
  1672. #endif // _DEBUG
  1673. return INVALID_HARDWARE_SHADER;
  1674. }
  1675. else
  1676. #endif // #if defined( DYNAMIC_SHADER_COMPILE ) && !defined( REMOTE_DYNAMIC_SHADER_COMPILE )
  1677. {
  1678. #ifdef DYNAMIC_SHADER_COMPILE_WRITE_ASSEMBLY
  1679. // enable to dump the disassembly for shader validation
  1680. char exampleCommandLine[2048];
  1681. Q_strncpy( exampleCommandLine, "// Run from stdshaders\n// ..\\..\\dx9sdk\\utilities\\fxc.exe ", sizeof( exampleCommandLine ) );
  1682. int i;
  1683. for( i = 0; macros[i].Name; i++ )
  1684. {
  1685. Q_strncat( exampleCommandLine, "/D", sizeof( exampleCommandLine ) );
  1686. Q_strncat( exampleCommandLine, macros[i].Name, sizeof( exampleCommandLine ) );
  1687. Q_strncat( exampleCommandLine, "=", sizeof( exampleCommandLine ) );
  1688. Q_strncat( exampleCommandLine, macros[i].Definition, sizeof( exampleCommandLine ) );
  1689. Q_strncat( exampleCommandLine, " ", sizeof( exampleCommandLine ) );
  1690. }
  1691. Q_strncat( exampleCommandLine, "/T", sizeof( exampleCommandLine ) );
  1692. Q_strncat( exampleCommandLine, pShaderModel, sizeof( exampleCommandLine ) );
  1693. Q_strncat( exampleCommandLine, " ", sizeof( exampleCommandLine ) );
  1694. Q_strncat( exampleCommandLine, filename, sizeof( exampleCommandLine ) );
  1695. Q_strncat( exampleCommandLine, "\n", sizeof( exampleCommandLine ) );
  1696. ID3DXBuffer *pd3dxBuffer;
  1697. HRESULT hr;
  1698. hr = D3DXDisassembleShader( ( DWORD* )pShader->GetBufferPointer(), false, NULL, &pd3dxBuffer );
  1699. Assert( hr == D3D_OK );
  1700. CUtlBuffer tempBuffer;
  1701. tempBuffer.SetBufferType( true, false );
  1702. int exampleCommandLineLength = strlen( exampleCommandLine );
  1703. tempBuffer.EnsureCapacity( pd3dxBuffer->GetBufferSize() + exampleCommandLineLength );
  1704. memcpy( tempBuffer.Base(), exampleCommandLine, exampleCommandLineLength );
  1705. memcpy( ( char * )tempBuffer.Base() + exampleCommandLineLength, pd3dxBuffer->GetBufferPointer(), pd3dxBuffer->GetBufferSize() );
  1706. tempBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, pd3dxBuffer->GetBufferSize() + exampleCommandLineLength );
  1707. char filename[MAX_PATH];
  1708. sprintf( filename, "%s_%d_%d.asm", pShaderName, nStaticIndex, nDynamicIndex );
  1709. g_pFullFileSystem->WriteFile( filename, "DEFAULT_WRITE_PATH", tempBuffer );
  1710. #endif
  1711. #ifdef REMOTE_DYNAMIC_SHADER_COMPILE
  1712. if ( bVertexShader )
  1713. {
  1714. return CreateD3DVertexShader( ( DWORD * )pRemotelyCompiledShader, nRemotelyCompiledShaderLength, pShaderName );
  1715. }
  1716. else
  1717. {
  1718. return CreateD3DPixelShader( ( DWORD * )pRemotelyCompiledShader, 0, nRemotelyCompiledShaderLength, pShaderName ); // hack hack hack! need to get centroid info from the source
  1719. }
  1720. #else // local compile, not remote
  1721. if ( bVertexShader )
  1722. {
  1723. return CreateD3DVertexShader( ( DWORD * )pShader->GetBufferPointer(), pShader->GetBufferSize(), pShaderName );
  1724. }
  1725. else
  1726. {
  1727. return CreateD3DPixelShader( ( DWORD * )pShader->GetBufferPointer(), 0, pShader->GetBufferSize(), pShaderName ); // hack hack hack! need to get centroid info from the source
  1728. }
  1729. #endif
  1730. #if defined( DYNAMIC_SHADER_COMPILE )
  1731. // We keep up with whether we hit a compile error above. If we did, then we likely need to recompile everything again since we could have changed global code.
  1732. if ( bShadersNeedFlush )
  1733. {
  1734. MatFlushShaders();
  1735. }
  1736. #endif
  1737. }
  1738. #ifndef REMOTE_DYNAMIC_SHADER_COMPILE
  1739. if ( pShader )
  1740. {
  1741. pShader->Release();
  1742. }
  1743. #endif
  1744. #if defined( DYNAMIC_SHADER_COMPILE ) && !defined( REMOTE_DYNAMIC_SHADER_COMPILE )
  1745. if ( pErrorMessages )
  1746. {
  1747. pErrorMessages->Release();
  1748. }
  1749. #endif
  1750. }
  1751. #endif
  1752. #ifdef DYNAMIC_SHADER_COMPILE
  1753. bool CShaderManager::LoadAndCreateShaders_Dynamic( ShaderLookup_t &lookup, bool bVertexShader )
  1754. {
  1755. const char *pName = m_ShaderSymbolTable.String( lookup.m_Name );
  1756. const ShaderCombos_t *pCombos = FindOrCreateShaderCombos( pName );
  1757. if ( !pCombos )
  1758. {
  1759. return false;
  1760. }
  1761. int numDynamicCombos = pCombos->GetNumDynamicCombos();
  1762. lookup.m_ShaderStaticCombos.m_pHardwareShaders = new HardwareShader_t[numDynamicCombos];
  1763. lookup.m_ShaderStaticCombos.m_nCount = numDynamicCombos;
  1764. lookup.m_ShaderStaticCombos.m_pCreationData = new ShaderStaticCombos_t::ShaderCreationData_t[numDynamicCombos];
  1765. int i;
  1766. for( i = 0; i < numDynamicCombos; i++ )
  1767. {
  1768. lookup.m_ShaderStaticCombos.m_pHardwareShaders[i] = INVALID_HARDWARE_SHADER;
  1769. }
  1770. return true;
  1771. }
  1772. #endif
  1773. //-----------------------------------------------------------------------------
  1774. // Open the shader file, optionally gets the header
  1775. //-----------------------------------------------------------------------------
  1776. FileHandle_t CShaderManager::OpenFileAndLoadHeader( const char *pFileName, ShaderHeader_t *pHeader )
  1777. {
  1778. FileHandle_t fp = g_pFullFileSystem->Open( pFileName, "rb", "GAME" );
  1779. if ( fp == FILESYSTEM_INVALID_HANDLE )
  1780. {
  1781. return FILESYSTEM_INVALID_HANDLE;
  1782. }
  1783. if ( pHeader )
  1784. {
  1785. // read the header
  1786. g_pFullFileSystem->Read( pHeader, sizeof( ShaderHeader_t ), fp );
  1787. switch ( pHeader->m_nVersion )
  1788. {
  1789. case 4:
  1790. // version with combos done as diffs vs a reference combo
  1791. // vsh/psh or older fxc
  1792. break;
  1793. case 5:
  1794. case 6:
  1795. // version with optimal dictionary and compressed combo block
  1796. break;
  1797. default:
  1798. Assert( 0 );
  1799. Warning( "Shader %s is the wrong version %d, expecting %d\n", pFileName, pHeader->m_nVersion, SHADER_VCS_VERSION_NUMBER );
  1800. g_pFullFileSystem->Close( fp );
  1801. return FILESYSTEM_INVALID_HANDLE;
  1802. }
  1803. }
  1804. return fp;
  1805. }
  1806. //---------------------------------------------------------------------------------------------------------
  1807. // Writes text files named for looked-up shaders. Used by GL shader translator to dump code for debugging
  1808. //---------------------------------------------------------------------------------------------------------
  1809. void CShaderManager::WriteTranslatedFile( ShaderLookup_t *pLookup, int dynamicCombo, char *pFileContents, char *pFileExtension )
  1810. {
  1811. const char *pName = m_ShaderSymbolTable.String( pLookup->m_Name );
  1812. int nNumChars = V_strlen( pFileContents );
  1813. CUtlBuffer tempBuffer;
  1814. tempBuffer.SetBufferType( true, false );
  1815. tempBuffer.EnsureCapacity( nNumChars );
  1816. memcpy( ( char * )tempBuffer.Base(), pFileContents, nNumChars );
  1817. tempBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, nNumChars );
  1818. char filename[MAX_PATH];
  1819. sprintf( filename, "%s_%d_%d.%s", pName, pLookup->m_nStaticIndex, dynamicCombo, pFileExtension );
  1820. g_pFullFileSystem->WriteFile( filename, "DEFAULT_WRITE_PATH", tempBuffer );
  1821. }
  1822. //-----------------------------------------------------------------------------
  1823. // Disassemble a shader for debugging. Writes .asm files.
  1824. //-----------------------------------------------------------------------------
  1825. void CShaderManager::DisassembleShader( ShaderLookup_t *pLookup, int dynamicCombo, uint8 *pByteCode )
  1826. {
  1827. #if defined( WRITE_ASSEMBLY )
  1828. const char *pName = m_ShaderSymbolTable.String( pLookup->m_Name );
  1829. ID3DXBuffer *pd3dxBuffer;
  1830. HRESULT hr;
  1831. hr = D3DXDisassembleShader( (DWORD*)pByteCode, false, NULL, &pd3dxBuffer );
  1832. Assert( hr == D3D_OK );
  1833. CUtlBuffer tempBuffer;
  1834. tempBuffer.SetBufferType( true, false );
  1835. tempBuffer.EnsureCapacity( pd3dxBuffer->GetBufferSize() );
  1836. memcpy( ( char * )tempBuffer.Base(), pd3dxBuffer->GetBufferPointer(), pd3dxBuffer->GetBufferSize() );
  1837. tempBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, pd3dxBuffer->GetBufferSize() );
  1838. char filename[MAX_PATH];
  1839. sprintf( filename, "%s_%d_%d.asm", pName, pLookup->m_nStaticIndex, dynamicCombo );
  1840. g_pFullFileSystem->WriteFile( filename, "DEFAULT_WRITE_PATH", tempBuffer );
  1841. #endif
  1842. }
  1843. //-----------------------------------------------------------------------------
  1844. // Create dynamic combos
  1845. //-----------------------------------------------------------------------------
  1846. bool CShaderManager::CreateDynamicCombos_Ver4( void *pContext, uint8 *pComboBuffer )
  1847. {
  1848. ShaderLookup_t* pLookup = (ShaderLookup_t *)pContext;
  1849. ShaderFileCache_t *pFileCache = &m_ShaderFileCache[pLookup->m_hShaderFileCache];
  1850. ShaderHeader_t *pHeader = &pFileCache->m_Header;
  1851. int nReferenceComboSizeForDiffs = ((ShaderHeader_t_v4 *)pHeader)->m_nDiffReferenceSize;
  1852. uint8 *pReferenceShader = NULL;
  1853. uint8 *pDiffOutputBuffer = NULL;
  1854. if ( nReferenceComboSizeForDiffs )
  1855. {
  1856. // reference combo is *always* the largest combo, so safe worst case size for uncompression buffer
  1857. pReferenceShader = (uint8 *)pFileCache->m_ReferenceCombo.Base();
  1858. pDiffOutputBuffer = (uint8 *)_alloca( nReferenceComboSizeForDiffs );
  1859. }
  1860. // build this shader's dynamic combos
  1861. bool bOK = true;
  1862. int nStartingOffset = 0;
  1863. for ( int i = 0; i < pHeader->m_nDynamicCombos; i++ )
  1864. {
  1865. if ( pLookup->m_pComboDictionary[i].m_Offset == -1 )
  1866. {
  1867. // skipped
  1868. continue;
  1869. }
  1870. if ( !nStartingOffset )
  1871. {
  1872. nStartingOffset = pLookup->m_pComboDictionary[i].m_Offset;
  1873. }
  1874. // offsets better be sequentially ascending
  1875. Assert( nStartingOffset <= pLookup->m_pComboDictionary[i].m_Offset );
  1876. if ( pLookup->m_pComboDictionary[i].m_Size <= 0 )
  1877. {
  1878. // skipped
  1879. continue;
  1880. }
  1881. // get the right byte code from the monolithic buffer
  1882. uint8 *pByteCode = (uint8 *)pComboBuffer + pLookup->m_nDataOffset + pLookup->m_pComboDictionary[i].m_Offset - nStartingOffset;
  1883. int nByteCodeSize = pLookup->m_pComboDictionary[i].m_Size;
  1884. if ( pReferenceShader )
  1885. {
  1886. // reference combo better be the largest combo, otherwise memory corruption
  1887. Assert( nReferenceComboSizeForDiffs >= nByteCodeSize );
  1888. // use the differencing algorithm to recover the full shader
  1889. int nOriginalSize;
  1890. ApplyDiffs(
  1891. pReferenceShader,
  1892. pByteCode,
  1893. nReferenceComboSizeForDiffs,
  1894. nByteCodeSize,
  1895. nOriginalSize,
  1896. pDiffOutputBuffer,
  1897. nReferenceComboSizeForDiffs );
  1898. pByteCode = pDiffOutputBuffer;
  1899. nByteCodeSize = nOriginalSize;
  1900. }
  1901. #if defined( WRITE_ASSEMBLY )
  1902. DisassembleShader( pLookup, i, pByteCode );
  1903. #endif
  1904. HardwareShader_t hardwareShader = INVALID_HARDWARE_SHADER;
  1905. if ( IsPC() && m_bCreateShadersOnDemand )
  1906. {
  1907. // cache the code off for later
  1908. pLookup->m_ShaderStaticCombos.m_pCreationData[i].ByteCode.SetSize( nByteCodeSize );
  1909. V_memcpy( pLookup->m_ShaderStaticCombos.m_pCreationData[i].ByteCode.Base(), pByteCode, nByteCodeSize );
  1910. pLookup->m_ShaderStaticCombos.m_pCreationData[i].iCentroidMask = pFileCache->m_bVertexShader ? 0 : pHeader->m_nCentroidMask;
  1911. }
  1912. else
  1913. {
  1914. const char *pShaderName = m_ShaderSymbolTable.String( pLookup->m_Name );
  1915. if ( pFileCache->m_bVertexShader )
  1916. {
  1917. hardwareShader = CreateD3DVertexShader( reinterpret_cast< DWORD *>( pByteCode ), nByteCodeSize, pShaderName );
  1918. }
  1919. else
  1920. {
  1921. hardwareShader = CreateD3DPixelShader( reinterpret_cast< DWORD *>( pByteCode ), pHeader->m_nCentroidMask, nByteCodeSize, pShaderName );
  1922. }
  1923. if ( hardwareShader == INVALID_HARDWARE_SHADER )
  1924. {
  1925. Assert( 0 );
  1926. bOK = false;
  1927. break;
  1928. }
  1929. }
  1930. pLookup->m_ShaderStaticCombos.m_pHardwareShaders[i] = hardwareShader;
  1931. }
  1932. delete [] pLookup->m_pComboDictionary;
  1933. pLookup->m_pComboDictionary = NULL;
  1934. return bOK;
  1935. }
  1936. //-----------------------------------------------------------------------------
  1937. // Create dynamic combos
  1938. //-----------------------------------------------------------------------------
  1939. static uint32 NextULONG( uint8 * &pData )
  1940. {
  1941. // handle unaligned read
  1942. uint32 nRet;
  1943. memcpy( &nRet, pData, sizeof( nRet ) );
  1944. pData += sizeof( nRet );
  1945. return nRet;
  1946. }
  1947. bool CShaderManager::CreateDynamicCombos_Ver5( void *pContext, uint8 *pComboBuffer, char *debugLabel )
  1948. {
  1949. ShaderLookup_t* pLookup = (ShaderLookup_t *)pContext;
  1950. ShaderFileCache_t *pFileCache = &m_ShaderFileCache[pLookup->m_hShaderFileCache];
  1951. uint8 *pCompressedShaders = pComboBuffer + pLookup->m_nDataOffset;
  1952. uint8 *pUnpackBuffer = new uint8[MAX_SHADER_UNPACKED_BLOCK_SIZE];
  1953. char *debugLabelPtr = debugLabel; // can be moved to point at something else if need be
  1954. // now, loop through all blocks
  1955. bool bOK = true;
  1956. while ( bOK )
  1957. {
  1958. uint32 nBlockSize = NextULONG( pCompressedShaders );
  1959. if ( nBlockSize == 0xffffffff )
  1960. {
  1961. // any more blocks?
  1962. break;
  1963. }
  1964. switch( nBlockSize & 0xc0000000 )
  1965. {
  1966. case 0: // bzip2
  1967. {
  1968. // uncompress
  1969. uint32 nOutsize = MAX_SHADER_UNPACKED_BLOCK_SIZE;
  1970. int nRslt = BZ2_bzBuffToBuffDecompress(
  1971. reinterpret_cast<char *>( pUnpackBuffer ),
  1972. &nOutsize,
  1973. reinterpret_cast<char *>( pCompressedShaders ),
  1974. nBlockSize, 1, 0 );
  1975. if ( nRslt < 0 )
  1976. {
  1977. // errors are negative for bzip
  1978. Assert( 0 );
  1979. Warning( "BZIP Error (%d) decompressing shader", nRslt );
  1980. bOK = false;
  1981. }
  1982. pCompressedShaders += nBlockSize;
  1983. nBlockSize = nOutsize; // how much data there is
  1984. }
  1985. break;
  1986. case 0x80000000: // uncompressed
  1987. {
  1988. // not compressed, as is
  1989. nBlockSize &= 0x3fffffff;
  1990. memcpy( pUnpackBuffer, pCompressedShaders, nBlockSize );
  1991. pCompressedShaders += nBlockSize;
  1992. }
  1993. break;
  1994. case 0x40000000: // lzma compressed
  1995. {
  1996. nBlockSize &= 0x3fffffff;
  1997. size_t nOutsize = CLZMA::Uncompress(
  1998. reinterpret_cast<uint8 *>( pCompressedShaders ),
  1999. pUnpackBuffer );
  2000. pCompressedShaders += nBlockSize;
  2001. nBlockSize = nOutsize; // how much data there is
  2002. }
  2003. break;
  2004. default:
  2005. {
  2006. Assert( 0 );
  2007. Error(" unrecognized shader compression type = file corrupt?");
  2008. bOK = false;
  2009. }
  2010. }
  2011. uint8 *pReadPtr = pUnpackBuffer;
  2012. while ( pReadPtr < pUnpackBuffer+nBlockSize )
  2013. {
  2014. uint32 nCombo_ID = NextULONG( pReadPtr );
  2015. uint32 nShaderSize = NextULONG( pReadPtr );
  2016. #if defined( WRITE_ASSEMBLY )
  2017. DisassembleShader( pLookup, nCombo_ID, pReadPtr );
  2018. #endif
  2019. HardwareShader_t hardwareShader = INVALID_HARDWARE_SHADER;
  2020. int iIndex = nCombo_ID;
  2021. if ( iIndex >= pLookup->m_nStaticIndex )
  2022. iIndex -= pLookup->m_nStaticIndex; // ver5 stores combos as full combo, ver6 as dynamic combo # only
  2023. if ( IsPC() && m_bCreateShadersOnDemand )
  2024. {
  2025. // cache the code off for later
  2026. pLookup->m_ShaderStaticCombos.m_pCreationData[iIndex].ByteCode.SetSize( nShaderSize );
  2027. V_memcpy( pLookup->m_ShaderStaticCombos.m_pCreationData[iIndex].ByteCode.Base(), pReadPtr, nShaderSize );
  2028. pLookup->m_ShaderStaticCombos.m_pCreationData[iIndex].iCentroidMask = pFileCache->m_bVertexShader ? 0 : pFileCache->m_Header.m_nCentroidMask;
  2029. }
  2030. else
  2031. {
  2032. const char *pShaderName = m_ShaderSymbolTable.String( pLookup->m_Name );
  2033. if ( pFileCache->m_bVertexShader )
  2034. {
  2035. #if 0
  2036. // this is all test code
  2037. CUtlBuffer bufGLCode( 1000, 50000, CUtlBuffer::TEXT_BUFFER );
  2038. CUtlBuffer bufNewGLCode( 1000, 50000, CUtlBuffer::TEXT_BUFFER );
  2039. CUtlBuffer bufGLSLCode( 1000, 50000, CUtlBuffer::TEXT_BUFFER );
  2040. bool bVertexShader;
  2041. uint32 nOptions = 0;
  2042. nOptions |= D3DToGL_OptionUseEnvParams;
  2043. nOptions |= D3DToGL_OptionDoFixupZ;
  2044. nOptions |= D3DToGL_OptionDoFixupY;
  2045. //options |= D3DToGL_OptionSpew;
  2046. // sg_D3DToOpenGLTranslator.TranslateShader( (uint32 *) pReadPtr, (char *)bufGLCode.Base(), bufGLCode.Size(), &bVertexShader, nOptions, -1, debugLabel );
  2047. // sg_NewD3DToOpenGLTranslator.TranslateShader( (uint32 *) pReadPtr, &bufNewGLCode, &bVertexShader, nOptions, -1, debugLabel );
  2048. // bool bDumpGLSL = false;
  2049. // if ( !stricmp( "vs-file vertexlit_and_unlit_generic_bump_vs20 vs-index 144", debugLabel ) && ( iIndex == 0 ) )
  2050. // {
  2051. // DisassembleShader( pLookup, iIndex, pReadPtr ); // Direct3D
  2052. // bDumpGLSL = true;
  2053. // }
  2054. // GLSL options
  2055. nOptions |= D3DToGL_OptionGLSL; // | D3DToGL_AddHexComments | D3DToGL_PutHexCommentsAfterLines;
  2056. if ( !IsOSX() )
  2057. {
  2058. nOptions |= D3DToGL_OptionAllowStaticControlFlow;
  2059. }
  2060. sg_NewD3DToOpenGLTranslator.TranslateShader( (uint32 *) pReadPtr, &bufGLSLCode, &bVertexShader, nOptions, -1, 0, debugLabel );
  2061. Assert( bVertexShader );
  2062. // Test to make sure these are identical
  2063. // if ( bDumpGLSL )//V_strcmp( (char *)bufGLCode.Base(), (char *)bufNewGLCode.Base() ) )
  2064. // {
  2065. // WriteTranslatedFile( pLookup, iIndex, (char *)bufGLCode.Base(), "avp" ); // Old
  2066. // WriteTranslatedFile( pLookup, iIndex, (char *)bufNewGLCode.Base(), "avp2" ); // New
  2067. WriteTranslatedFile( pLookup, iIndex, (char *)bufGLSLCode.Base(), "glsl_v" ); // GLSL
  2068. // DisassembleShader( pLookup, iIndex, pReadPtr ); // Direct3D
  2069. // }
  2070. #if defined( WRITE_ASSEMBLY )
  2071. WriteTranslatedFile( pLookup, iIndex, (char *)bufGLCode.Base(), "avp" );
  2072. #endif
  2073. #endif // 0
  2074. #ifdef DX_TO_GL_ABSTRACTION
  2075. // munge the debug label a bit to aid in decoding... catenate the iIndex on the end
  2076. char temp[1024];
  2077. sprintf(temp, "%s vs-combo %d", (debugLabel)?debugLabel:"none", iIndex );
  2078. debugLabelPtr = temp;
  2079. #endif
  2080. // pass binary code to d3d interface, on GL it will invoke the translator back to asm
  2081. hardwareShader = CreateD3DVertexShader( reinterpret_cast< DWORD *>( pReadPtr ), nShaderSize, pShaderName, debugLabelPtr );
  2082. }
  2083. else
  2084. {
  2085. #if 0
  2086. // this is all test code
  2087. // CUtlBuffer bufGLCode( 1000, 50000, CUtlBuffer::TEXT_BUFFER );
  2088. // CUtlBuffer bufNewGLCode( 1000, 50000, CUtlBuffer::TEXT_BUFFER );
  2089. CUtlBuffer bufGLSLCode( 1000, 50000, CUtlBuffer::TEXT_BUFFER );
  2090. bool bVertexShader;
  2091. uint32 nOptions = D3DToGL_OptionUseEnvParams;
  2092. // sg_D3DToOpenGLTranslator.TranslateShader( (uint32 *) pReadPtr, (char *)bufGLCode.Base(), bufGLCode.Size(), &bVertexShader, D3DToGL_OptionUseEnvParams, -1, debugLabel );
  2093. // sg_NewD3DToOpenGLTranslator.TranslateShader( (uint32 *) pReadPtr, &bufNewGLCode, &bVertexShader, D3DToGL_OptionUseEnvParams, -1, debugLabel );
  2094. // GLSL options
  2095. nOptions |= D3DToGL_OptionGLSL;// | D3DToGL_OptionSRGBWriteSuffix | D3DToGL_AddHexComments | D3DToGL_PutHexCommentsAfterLines;
  2096. if ( !IsOSX() )
  2097. {
  2098. nOptions |= D3DToGL_OptionAllowStaticControlFlow;
  2099. }
  2100. sg_NewD3DToOpenGLTranslator.TranslateShader( (uint32 *) pReadPtr, &bufGLSLCode, &bVertexShader, nOptions, -1, 0, debugLabel );
  2101. Assert( !bVertexShader );
  2102. // Test to make sure these are identical
  2103. // if ( V_strcmp( (char *)bufGLCode.Base(), (char *)bufNewGLCode.Base() ) )
  2104. // {
  2105. // WriteTranslatedFile( pLookup, iIndex, (char *)bufGLCode.Base(), "afp" ); // Old
  2106. // WriteTranslatedFile( pLookup, iIndex, (char *)bufNewGLCode.Base(), "afp2" ); // New
  2107. WriteTranslatedFile( pLookup, iIndex, (char *)bufGLSLCode.Base(), "glsl_p" ); // GLSL
  2108. // DisassembleShader( pLookup, iIndex, pReadPtr ); // Direct3D
  2109. // }
  2110. #if defined( WRITE_ASSEMBLY )
  2111. WriteTranslatedFile( pLookup, iIndex, (char *)bufGLCode.Base(), "afp" );
  2112. #endif
  2113. #endif // 0
  2114. #ifdef DX_TO_GL_ABSTRACTION
  2115. // munge the debug label a bit to aid in decoding... catenate the iIndex on the end
  2116. char temp[1024];
  2117. sprintf(temp, "%s ps-combo %d", (debugLabel)?debugLabel:"", iIndex );
  2118. debugLabelPtr = temp;
  2119. #endif
  2120. // pass binary code to d3d interface, on GL it will invoke the translator back to asm
  2121. hardwareShader = CreateD3DPixelShader( reinterpret_cast< DWORD *>( pReadPtr ), pFileCache->m_Header.m_nCentroidMask, nShaderSize, pShaderName, debugLabelPtr );
  2122. }
  2123. if ( hardwareShader == INVALID_HARDWARE_SHADER )
  2124. {
  2125. Warning( "failed to create shader\n" );
  2126. Assert( 0 );
  2127. bOK = false;
  2128. break;
  2129. }
  2130. }
  2131. pLookup->m_ShaderStaticCombos.m_pHardwareShaders[iIndex] = hardwareShader;
  2132. pReadPtr += nShaderSize;
  2133. }
  2134. }
  2135. delete[] pUnpackBuffer;
  2136. return bOK;
  2137. }
  2138. //-----------------------------------------------------------------------------
  2139. // Static method, called by thread, don't call anything non-threadsafe from handler!!!
  2140. //-----------------------------------------------------------------------------
  2141. void CShaderManager::QueuedLoaderCallback( void *pContext, void *pContext2, const void *pData, int nSize, LoaderError_t loaderError )
  2142. {
  2143. ShaderLookup_t* pLookup = (ShaderLookup_t *)pContext;
  2144. bool bOK = ( loaderError == LOADERERROR_NONE );
  2145. if ( bOK )
  2146. {
  2147. if ( pContext2 )
  2148. {
  2149. // presence denotes diff version
  2150. bOK = s_ShaderManager.CreateDynamicCombos_Ver4( pContext, (uint8 *)pData );
  2151. }
  2152. else
  2153. {
  2154. bOK = s_ShaderManager.CreateDynamicCombos_Ver5( pContext, (uint8 *)pData );
  2155. }
  2156. }
  2157. if ( !bOK )
  2158. {
  2159. pLookup->m_Flags |= SHADER_FAILED_LOAD;
  2160. }
  2161. }
  2162. //-----------------------------------------------------------------------------
  2163. // Loads all shaders
  2164. //-----------------------------------------------------------------------------
  2165. bool CShaderManager::LoadAndCreateShaders( ShaderLookup_t &lookup, bool bVertexShader, char *debugLabel )
  2166. {
  2167. const char *pName = m_ShaderSymbolTable.String( lookup.m_Name );
  2168. // find it in the cache
  2169. // a cache hit prevents costly i/o for static components, i.e. header, ref combo, etc.
  2170. ShaderFileCache_t fileCacheLookup;
  2171. fileCacheLookup.m_Name = lookup.m_Name;
  2172. fileCacheLookup.m_bVertexShader = bVertexShader;
  2173. int fileCacheIndex = m_ShaderFileCache.Find( fileCacheLookup );
  2174. if ( fileCacheIndex == m_ShaderFileCache.InvalidIndex() )
  2175. {
  2176. // not found, create a new entry
  2177. fileCacheIndex = m_ShaderFileCache.AddToTail();
  2178. }
  2179. lookup.m_hShaderFileCache = fileCacheIndex;
  2180. // fetch from cache
  2181. ShaderFileCache_t *pFileCache = &m_ShaderFileCache[fileCacheIndex];
  2182. ShaderHeader_t *pHeader = &pFileCache->m_Header;
  2183. FileHandle_t hFile = FILESYSTEM_INVALID_HANDLE;
  2184. if ( pFileCache->IsValid() )
  2185. {
  2186. // using cached header, just open file, no read of header needed
  2187. hFile = OpenFileAndLoadHeader( m_ShaderSymbolTable.String( pFileCache->m_Filename ), NULL );
  2188. if ( hFile == FILESYSTEM_INVALID_HANDLE )
  2189. {
  2190. // shouldn't happen
  2191. Assert( 0 );
  2192. return false;
  2193. }
  2194. }
  2195. else
  2196. {
  2197. V_memset( pHeader, 0, sizeof( ShaderHeader_t ) );
  2198. // try the vsh/psh dir first
  2199. char filename[MAX_PATH];
  2200. Q_snprintf( filename, MAX_PATH, "shaders\\%s\\%s" SHADER_FNAME_EXTENSION, bVertexShader ? "vsh" : "psh", pName );
  2201. hFile = OpenFileAndLoadHeader( filename, pHeader );
  2202. if ( hFile == FILESYSTEM_INVALID_HANDLE )
  2203. {
  2204. #ifdef DYNAMIC_SHADER_COMPILE
  2205. // Dynamically compile if it's HLSL.
  2206. if ( LoadAndCreateShaders_Dynamic( lookup, bVertexShader ) )
  2207. {
  2208. return true;
  2209. }
  2210. else
  2211. {
  2212. return false;
  2213. }
  2214. #endif
  2215. // next, try the fxc dir
  2216. Q_snprintf( filename, MAX_PATH, "shaders\\fxc\\%s" SHADER_FNAME_EXTENSION, pName );
  2217. hFile = OpenFileAndLoadHeader( filename, pHeader );
  2218. if ( hFile == FILESYSTEM_INVALID_HANDLE )
  2219. {
  2220. lookup.m_Flags |= SHADER_FAILED_LOAD;
  2221. Warning( "Couldn't load %s shader %s\n", bVertexShader ? "vertex" : "pixel", pName );
  2222. return false;
  2223. }
  2224. }
  2225. lookup.m_Flags = pHeader->m_nFlags;
  2226. pFileCache->m_Name = lookup.m_Name;
  2227. pFileCache->m_Filename = m_ShaderSymbolTable.AddString( filename );
  2228. pFileCache->m_bVertexShader = bVertexShader;
  2229. if ( pFileCache->IsOldVersion() )
  2230. {
  2231. int referenceComboSize = ((ShaderHeader_t_v4 *)pHeader)->m_nDiffReferenceSize;
  2232. if ( referenceComboSize )
  2233. {
  2234. // cache the reference combo
  2235. pFileCache->m_ReferenceCombo.EnsureCapacity( referenceComboSize );
  2236. g_pFullFileSystem->Read( pFileCache->m_ReferenceCombo.Base(), referenceComboSize, hFile );
  2237. }
  2238. }
  2239. else
  2240. {
  2241. // cache the dictionary
  2242. pFileCache->m_StaticComboRecords.EnsureCount( pHeader->m_nNumStaticCombos );
  2243. g_pFullFileSystem->Read( pFileCache->m_StaticComboRecords.Base(), pHeader->m_nNumStaticCombos * sizeof( StaticComboRecord_t ), hFile );
  2244. if ( pFileCache->IsVersion6() )
  2245. {
  2246. // read static combo alias records
  2247. int nNumDups;
  2248. g_pFullFileSystem->Read( &nNumDups, sizeof( nNumDups ), hFile );
  2249. if ( nNumDups )
  2250. {
  2251. pFileCache->m_StaticComboDupRecords.EnsureCount( nNumDups );
  2252. g_pFullFileSystem->Read( pFileCache->m_StaticComboDupRecords.Base(), nNumDups * sizeof( StaticComboAliasRecord_t ), hFile );
  2253. }
  2254. }
  2255. }
  2256. }
  2257. // FIXME: should make lookup and ShaderStaticCombos_t are pool allocated.
  2258. int i;
  2259. lookup.m_ShaderStaticCombos.m_nCount = pHeader->m_nDynamicCombos;
  2260. lookup.m_ShaderStaticCombos.m_pHardwareShaders = new HardwareShader_t[pHeader->m_nDynamicCombos];
  2261. if ( IsPC() && m_bCreateShadersOnDemand )
  2262. {
  2263. lookup.m_ShaderStaticCombos.m_pCreationData = new ShaderStaticCombos_t::ShaderCreationData_t[pHeader->m_nDynamicCombos];
  2264. }
  2265. for ( i = 0; i < pHeader->m_nDynamicCombos; i++ )
  2266. {
  2267. lookup.m_ShaderStaticCombos.m_pHardwareShaders[i] = INVALID_HARDWARE_SHADER;
  2268. }
  2269. int nStartingOffset = 0;
  2270. int nEndingOffset = 0;
  2271. if ( pFileCache->IsOldVersion() )
  2272. {
  2273. int nDictionaryOffset = sizeof( ShaderHeader_t ) + ((ShaderHeader_t_v4 *)pHeader)->m_nDiffReferenceSize;
  2274. // read in shader's dynamic combos directory
  2275. lookup.m_pComboDictionary = new ShaderDictionaryEntry_t[pHeader->m_nDynamicCombos];
  2276. g_pFullFileSystem->Seek( hFile, nDictionaryOffset + lookup.m_nStaticIndex * sizeof( ShaderDictionaryEntry_t ), FILESYSTEM_SEEK_HEAD );
  2277. g_pFullFileSystem->Read( lookup.m_pComboDictionary, pHeader->m_nDynamicCombos * sizeof( ShaderDictionaryEntry_t ), hFile );
  2278. // want single read of all this shader's dynamic combos into a target buffer
  2279. // shaders are written sequentially, determine starting offset and length
  2280. for ( i = 0; i < pHeader->m_nDynamicCombos; i++ )
  2281. {
  2282. if ( lookup.m_pComboDictionary[i].m_Offset == -1 )
  2283. {
  2284. // skipped
  2285. continue;
  2286. }
  2287. // ensure offsets are in fact sequentially ascending
  2288. Assert( lookup.m_pComboDictionary[i].m_Offset >= nStartingOffset && lookup.m_pComboDictionary[i].m_Size >= 0 );
  2289. if ( !nStartingOffset )
  2290. {
  2291. nStartingOffset = lookup.m_pComboDictionary[i].m_Offset;
  2292. }
  2293. nEndingOffset = lookup.m_pComboDictionary[i].m_Offset + lookup.m_pComboDictionary[i].m_Size;
  2294. }
  2295. if ( !nStartingOffset )
  2296. {
  2297. g_pFullFileSystem->Close( hFile );
  2298. Warning( "Shader '%s' - All dynamic combos skipped. This is bad!\n", m_ShaderSymbolTable.String( pFileCache->m_Filename ) );
  2299. return false;
  2300. }
  2301. }
  2302. else
  2303. {
  2304. int nStaticComboIdx = pFileCache->FindCombo( lookup.m_nStaticIndex / pFileCache->m_Header.m_nDynamicCombos );
  2305. if ( nStaticComboIdx == -1 )
  2306. {
  2307. g_pFullFileSystem->Close( hFile );
  2308. lookup.m_Flags |= SHADER_FAILED_LOAD;
  2309. Warning( "Shader '%s' - Couldn't load combo %d of shader (dyn=%d)\n", m_ShaderSymbolTable.String( pFileCache->m_Filename ), lookup.m_nStaticIndex, pFileCache->m_Header.m_nDynamicCombos );
  2310. return false;
  2311. }
  2312. nStartingOffset = pFileCache->m_StaticComboRecords[nStaticComboIdx].m_nFileOffset;
  2313. nEndingOffset = pFileCache->m_StaticComboRecords[nStaticComboIdx+1].m_nFileOffset;
  2314. }
  2315. // align offsets for unbuffered optimal i/o - fastest i/o possible
  2316. unsigned nOffsetAlign, nSizeAlign, nBufferAlign;
  2317. g_pFullFileSystem->GetOptimalIOConstraints( hFile, &nOffsetAlign, &nSizeAlign, &nBufferAlign );
  2318. unsigned int nAlignedOffset = AlignValue( ( nStartingOffset - nOffsetAlign ) + 1, nOffsetAlign );
  2319. unsigned int nAlignedBytesToRead = AlignValue( nEndingOffset - nAlignedOffset, nSizeAlign );
  2320. // used for adjusting provided buffer to actual data
  2321. lookup.m_nDataOffset = nStartingOffset - nAlignedOffset;
  2322. bool bOK = true;
  2323. if ( IsX360() && g_pQueuedLoader->IsMapLoading() )
  2324. {
  2325. LoaderJob_t loaderJob;
  2326. loaderJob.m_pFilename = m_ShaderSymbolTable.String( pFileCache->m_Filename );
  2327. loaderJob.m_pPathID = "GAME";
  2328. loaderJob.m_pCallback = QueuedLoaderCallback;
  2329. loaderJob.m_pContext = (void *)&lookup;
  2330. loaderJob.m_pContext2 = (void *)pFileCache->IsOldVersion();
  2331. loaderJob.m_Priority = LOADERPRIORITY_DURINGPRELOAD;
  2332. loaderJob.m_nBytesToRead = nAlignedBytesToRead;
  2333. loaderJob.m_nStartOffset = nAlignedOffset;
  2334. g_pQueuedLoader->AddJob( &loaderJob );
  2335. }
  2336. else
  2337. {
  2338. //printf("\n CShaderManager::LoadAndCreateShaders - reading %d bytes from file offset %d", nAlignedBytesToRead, nAlignedOffset);
  2339. // single optimal read of all dynamic combos into monolithic buffer
  2340. uint8 *pOptimalBuffer = (uint8 *)g_pFullFileSystem->AllocOptimalReadBuffer( hFile, nAlignedBytesToRead, nAlignedOffset );
  2341. g_pFullFileSystem->Seek( hFile, nAlignedOffset, FILESYSTEM_SEEK_HEAD );
  2342. g_pFullFileSystem->Read( pOptimalBuffer, nAlignedBytesToRead, hFile );
  2343. if ( pFileCache->IsOldVersion() )
  2344. {
  2345. bOK = CreateDynamicCombos_Ver4( &lookup, pOptimalBuffer );
  2346. }
  2347. else
  2348. {
  2349. bOK = CreateDynamicCombos_Ver5( &lookup, pOptimalBuffer, debugLabel );
  2350. }
  2351. g_pFullFileSystem->FreeOptimalReadBuffer( pOptimalBuffer );
  2352. }
  2353. g_pFullFileSystem->Close( hFile );
  2354. if ( !bOK )
  2355. {
  2356. lookup.m_Flags |= SHADER_FAILED_LOAD;
  2357. }
  2358. return bOK;
  2359. }
  2360. //----------------------------------------------------------------------------------old code
  2361. #if 0
  2362. // Set this convar internally to build or add to the shader cache file
  2363. // We really only expect this to work on DX_TO_GL_ABSTRACTION
  2364. ConVar mat_cacheshaders( "mat_cacheshaders", "0", FCVAR_DEVELOPMENTONLY );
  2365. #define SHADER_CACHE_FILE "shader_cache.cfg"
  2366. #define PROGRAM_CACHE_FILE "program_cache.cfg"
  2367. static void WriteToShaderCache( const char *pShaderName, const int nIndex )
  2368. {
  2369. #ifndef DX_TO_GL_ABSTRACTION
  2370. return;
  2371. #endif
  2372. KeyValues *pShaderCache = new KeyValues( "shadercache" );
  2373. // we don't load anything, it starts empty.. pShaderCache->LoadFromFile( g_pFullFileSystem, SHADER_CACHE_FILE, "MOD" );
  2374. if ( !pShaderCache )
  2375. {
  2376. Warning( "Could not write to shader cache file!\n" );
  2377. return;
  2378. }
  2379. // Subkey for specific shader
  2380. KeyValues *pShaderKey = pShaderCache->FindKey( pShaderName, true );
  2381. Assert( pShaderKey );
  2382. bool bFound = false;
  2383. int nKeys = 0;
  2384. char szIndex[8];
  2385. FOR_EACH_VALUE( pShaderKey, pValues )
  2386. {
  2387. if ( pValues->GetInt() == nIndex )
  2388. {
  2389. bFound = true;
  2390. }
  2391. nKeys++;
  2392. }
  2393. if ( !bFound )
  2394. {
  2395. V_snprintf( szIndex, 8, "%d", nKeys );
  2396. pShaderKey->SetInt( szIndex, nIndex );
  2397. }
  2398. pShaderCache->SaveToFile( g_pFullFileSystem, SHADER_CACHE_FILE, "MOD" );
  2399. pShaderCache->deleteThis();
  2400. }
  2401. void CShaderManager::WarmShaderCache()
  2402. {
  2403. #ifndef DX_TO_GL_ABSTRACTION
  2404. return;
  2405. #endif
  2406. // Don't access the cache if we're building it!
  2407. if ( mat_cacheshaders.GetBool() )
  2408. return;
  2409. // Don't warm the cache if we're just going to monkey with the shaders anyway
  2410. #ifdef DYNAMIC_SHADER_COMPILE
  2411. return;
  2412. #endif
  2413. double st = Sys_FloatTime();
  2414. //
  2415. // First we warm SHADERS ===============================================
  2416. //
  2417. KeyValues *pShaderCache = new KeyValues( "shadercache" );
  2418. pShaderCache->LoadFromFile( g_pFullFileSystem, SHADER_CACHE_FILE, "MOD" );
  2419. if ( !pShaderCache )
  2420. {
  2421. Warning( "Could not find shader cache file!\n" );
  2422. return;
  2423. }
  2424. // Run through each shader in the cache
  2425. FOR_EACH_SUBKEY( pShaderCache, pShaderKey )
  2426. {
  2427. const char *pShaderName = pShaderKey->GetName();
  2428. bool bVertexShader = Q_stristr( pShaderName, "_vs20" ) || Q_stristr( pShaderName, "_vs30" );
  2429. FOR_EACH_VALUE( pShaderKey, pValue )
  2430. {
  2431. char temp[1024];
  2432. int staticIndex = pValue->GetInt();
  2433. if ( bVertexShader )
  2434. {
  2435. V_snprintf( temp, sizeof(temp), "vs-file %s vs-index %d", pShaderName, staticIndex );
  2436. CreateVertexShader( pShaderName, staticIndex, temp );
  2437. }
  2438. else
  2439. {
  2440. V_snprintf( temp, sizeof(temp), "ps-file %s ps-index %d", pShaderName, staticIndex );
  2441. CreatePixelShader( pShaderName, staticIndex, temp );
  2442. }
  2443. }
  2444. }
  2445. pShaderCache->deleteThis();
  2446. //
  2447. // Next, we warm PROGRAMS (which are pairs of shaders) =================
  2448. //
  2449. KeyValues *pProgramCache = new KeyValues( "programcache" );
  2450. pProgramCache->LoadFromFile( g_pFullFileSystem, PROGRAM_CACHE_FILE, "MOD" );
  2451. if ( !pProgramCache )
  2452. {
  2453. Warning( "Could not find program cache file!\n" );
  2454. return;
  2455. }
  2456. // Run through each program in the cache
  2457. FOR_EACH_SUBKEY( pProgramCache, pProgramKey )
  2458. {
  2459. KeyValues *pValue = pProgramKey->GetFirstValue();
  2460. const char *pVertexShaderName = pValue->GetString();
  2461. pValue = pValue->GetNextValue();
  2462. const char *pPixelShaderName = pValue->GetString();
  2463. pValue = pValue->GetNextValue();
  2464. int nVertexShaderStaticIndex = pValue->GetInt();
  2465. pValue = pValue->GetNextValue();
  2466. int nPixelShaderStaticIndex = pValue->GetInt();
  2467. pValue = pValue->GetNextValue();
  2468. int nVertexShaderDynamicIndex = pValue->GetInt();
  2469. pValue = pValue->GetNextValue();
  2470. int nPixelShaderDynamicIndex = pValue->GetInt();
  2471. ShaderLookup_t vshLookup;
  2472. vshLookup.m_Name = m_ShaderSymbolTable.AddString( pVertexShaderName ); // TODO: use String() here and catch this odd case
  2473. vshLookup.m_nStaticIndex = nVertexShaderStaticIndex;
  2474. VertexShader_t vertexShader = m_VertexShaderDict.Find( vshLookup );
  2475. ShaderLookup_t pshLookup;
  2476. pshLookup.m_Name = m_ShaderSymbolTable.AddString( pPixelShaderName );
  2477. pshLookup.m_nStaticIndex = nPixelShaderStaticIndex;
  2478. PixelShader_t pixelShader = m_PixelShaderDict.Find( pshLookup );
  2479. // If we found both shaders, do the link!
  2480. if ( ( vertexShader != m_VertexShaderDict.InvalidIndex() ) && ( pixelShader != m_PixelShaderDict.InvalidIndex() ) )
  2481. {
  2482. #ifdef DX_TO_GL_ABSTRACTION
  2483. //HardwareShader_t hardwareVertexShader = vshLookup.m_ShaderStaticCombos.m_pHardwareShaders[nVertexShaderDynamicIndex];
  2484. //HardwareShader_t hardwarePixelShader = pshLookup.m_ShaderStaticCombos.m_pHardwareShaders[nPixelShaderDynamicIndex];
  2485. HardwareShader_t hardwareVertexShader = m_VertexShaderDict[vertexShader].m_ShaderStaticCombos.m_pHardwareShaders[nVertexShaderDynamicIndex];
  2486. HardwareShader_t hardwarePixelShader = m_PixelShaderDict[pixelShader].m_ShaderStaticCombos.m_pHardwareShaders[nPixelShaderDynamicIndex];
  2487. if ( ( hardwareVertexShader != INVALID_HARDWARE_SHADER ) && ( hardwarePixelShader != INVALID_HARDWARE_SHADER ) )
  2488. {
  2489. if ( S_OK != Dx9Device()->LinkShaderPair( (IDirect3DVertexShader9 *)hardwareVertexShader, (IDirect3DPixelShader9 *)hardwarePixelShader ) )
  2490. {
  2491. Warning( "Could not link OpenGL shaders: %s (%d, %d) : %s (%d, %d)\n", pVertexShaderName, nVertexShaderStaticIndex, nVertexShaderDynamicIndex, pPixelShaderName, nPixelShaderStaticIndex, nPixelShaderDynamicIndex );
  2492. }
  2493. }
  2494. #endif
  2495. }
  2496. else
  2497. {
  2498. Warning( "Invalid shader linkage: %s (%d, %d) : %s (%d, %d)\n", pVertexShaderName, nVertexShaderStaticIndex, nVertexShaderDynamicIndex, pPixelShaderName, nPixelShaderStaticIndex, nPixelShaderDynamicIndex );
  2499. }
  2500. }
  2501. pProgramCache->deleteThis();
  2502. float elapsed = ( float )( Sys_FloatTime() - st ) * 1000.0;
  2503. DevMsg( "WarmShaderCache took %.3f msec\n", elapsed );
  2504. }
  2505. #endif
  2506. //----------------------------------------------------------------------------------old code
  2507. #ifdef DX_TO_GL_ABSTRACTION
  2508. // if shaders are changed in a way that requires the client-side cache to be invalidated,
  2509. // increment this string - such changes include combo changes (skips, adding combos)
  2510. const char *k_pszShaderCacheRootKey = "glshadercachev002";
  2511. #endif
  2512. void CShaderManager::SaveShaderCache( char *cacheName )
  2513. {
  2514. #ifdef DX_TO_GL_ABSTRACTION // must ifdef, it uses calls which don't exist in the real DX9 interface
  2515. KeyValues *pProgramCache = new KeyValues( k_pszShaderCacheRootKey );
  2516. if ( !pProgramCache )
  2517. {
  2518. Warning( "Could not write to program cache file!\n" );
  2519. return;
  2520. }
  2521. int i=0;
  2522. GLMShaderPairInfo info;
  2523. do
  2524. {
  2525. Dx9Device()->QueryShaderPair( i, &info );
  2526. if (info.m_status==1)
  2527. {
  2528. // found one
  2529. // extract values of interest which represent a pair of shaders
  2530. if (info.m_vsName[0] && info.m_psName[0] && (info.m_vsDynamicIndex > -1) && (info.m_psDynamicIndex > -1) )
  2531. {
  2532. // make up a key - this thing is really a list of tuples, so need not be keyed by anything particular
  2533. KeyValues *pProgramKey = pProgramCache->CreateNewKey();
  2534. Assert( pProgramKey );
  2535. pProgramKey->SetString ( "vs", info.m_vsName );
  2536. pProgramKey->SetString ( "ps", info.m_psName );
  2537. pProgramKey->SetInt ( "vs_static", info.m_vsStaticIndex );
  2538. pProgramKey->SetInt ( "ps_static", info.m_psStaticIndex );
  2539. pProgramKey->SetInt ( "vs_dynamic", info.m_vsDynamicIndex );
  2540. pProgramKey->SetInt ( "ps_dynamic", info.m_psDynamicIndex );
  2541. }
  2542. }
  2543. i++;
  2544. } while( info.m_status >= 0 );
  2545. pProgramCache->SaveToFile( g_pFullFileSystem, cacheName, "MOD" );
  2546. pProgramCache->deleteThis();
  2547. // done! whew
  2548. #endif
  2549. }
  2550. bool CShaderManager::LoadShaderCache( char *cacheName )
  2551. {
  2552. #ifdef DX_TO_GL_ABSTRACTION
  2553. KeyValues *pProgramCache = new KeyValues( "" );
  2554. bool found = pProgramCache->LoadFromFile( g_pFullFileSystem, cacheName, "MOD" );
  2555. if ( !found )
  2556. {
  2557. Warning( "Could not load program cache file %s\n", cacheName );
  2558. return false;
  2559. }
  2560. if ( Q_stricmp( pProgramCache->GetName(), k_pszShaderCacheRootKey ) )
  2561. {
  2562. Warning( "Ignoring out-of-date shader cache (%s) with root key %s\n", cacheName, pProgramCache->GetName() );
  2563. return false;
  2564. }
  2565. int nTotalLinkedShaders = 0;
  2566. int nTotalKeyValues = 0;
  2567. // walk the table..
  2568. FOR_EACH_SUBKEY( pProgramCache, pProgramKey )
  2569. {
  2570. nTotalKeyValues++;
  2571. // extract values decribing the specific active pair
  2572. // then see if either stage needs a compilation done
  2573. // then proceed to link
  2574. KeyValues *pValue = pProgramKey->GetFirstValue();
  2575. if (!pValue)
  2576. continue;
  2577. const char *pVertexShaderName = pValue->GetString();
  2578. pValue = pValue->GetNextValue();
  2579. if (!pValue)
  2580. continue;
  2581. const char *pPixelShaderName = pValue->GetString();
  2582. pValue = pValue->GetNextValue();
  2583. if (!pValue)
  2584. continue;
  2585. int nVertexShaderStaticIndex = pValue->GetInt();
  2586. pValue = pValue->GetNextValue();
  2587. if (!pValue)
  2588. continue;
  2589. int nPixelShaderStaticIndex = pValue->GetInt();
  2590. pValue = pValue->GetNextValue();
  2591. if (!pValue)
  2592. continue;
  2593. int nVertexShaderDynamicIndex = pValue->GetInt();
  2594. pValue = pValue->GetNextValue();
  2595. if (!pValue)
  2596. continue;
  2597. int nPixelShaderDynamicIndex = pValue->GetInt();
  2598. ShaderLookup_t vshLookup;
  2599. vshLookup.m_Name = m_ShaderSymbolTable.AddString( pVertexShaderName ); // TODO: use String() here and catch this odd case
  2600. vshLookup.m_nStaticIndex = nVertexShaderStaticIndex;
  2601. VertexShader_t vertexShader = m_VertexShaderDict.Find( vshLookup );
  2602. // if the VS was not found - now is the time to build it
  2603. if( vertexShader == m_VertexShaderDict.InvalidIndex())
  2604. {
  2605. char temp[1024];
  2606. V_snprintf( temp, sizeof(temp), "vs-file %s vs-index %d", pVertexShaderName, nVertexShaderStaticIndex );
  2607. CreateVertexShader( pVertexShaderName, nVertexShaderStaticIndex, temp );
  2608. // this one should not fail
  2609. vertexShader = m_VertexShaderDict.Find( vshLookup );
  2610. Assert( vertexShader != m_VertexShaderDict.InvalidIndex());
  2611. }
  2612. ShaderLookup_t pshLookup;
  2613. pshLookup.m_Name = m_ShaderSymbolTable.AddString( pPixelShaderName );
  2614. pshLookup.m_nStaticIndex = nPixelShaderStaticIndex;
  2615. PixelShader_t pixelShader = m_PixelShaderDict.Find( pshLookup );
  2616. if( pixelShader == m_PixelShaderDict.InvalidIndex())
  2617. {
  2618. char temp[1024];
  2619. V_snprintf( temp, sizeof(temp), "ps-file %s ps-index %d", pPixelShaderName, nPixelShaderStaticIndex );
  2620. CreatePixelShader( pPixelShaderName, nPixelShaderStaticIndex, temp );
  2621. // this one should not fail
  2622. pixelShader = m_PixelShaderDict.Find( pshLookup );
  2623. Assert( pixelShader != m_PixelShaderDict.InvalidIndex());
  2624. }
  2625. // If we found both shaders, do the link!
  2626. if ( ( vertexShader != m_VertexShaderDict.InvalidIndex() ) && ( pixelShader != m_PixelShaderDict.InvalidIndex() ) )
  2627. {
  2628. // double check that the hardware shader arrays are actually instantiated.. bail on the attempt if not (odd...)
  2629. if (m_VertexShaderDict[vertexShader].m_ShaderStaticCombos.m_pHardwareShaders && m_PixelShaderDict[pixelShader].m_ShaderStaticCombos.m_pHardwareShaders)
  2630. {
  2631. // and sanity check the indices..
  2632. if ( (nVertexShaderDynamicIndex>=0) && (nPixelShaderDynamicIndex>=0) )
  2633. {
  2634. HardwareShader_t hardwareVertexShader = m_VertexShaderDict[vertexShader].m_ShaderStaticCombos.m_pHardwareShaders[nVertexShaderDynamicIndex];
  2635. HardwareShader_t hardwarePixelShader = m_PixelShaderDict[pixelShader].m_ShaderStaticCombos.m_pHardwareShaders[nPixelShaderDynamicIndex];
  2636. if ( ( hardwareVertexShader != INVALID_HARDWARE_SHADER ) && ( hardwarePixelShader != INVALID_HARDWARE_SHADER ) )
  2637. {
  2638. if ( S_OK != Dx9Device()->LinkShaderPair( (IDirect3DVertexShader9 *)hardwareVertexShader, (IDirect3DPixelShader9 *)hardwarePixelShader ) )
  2639. {
  2640. Warning( "Could not link OpenGL shaders: %s (%d, %d) : %s (%d, %d)\n", pVertexShaderName, nVertexShaderStaticIndex, nVertexShaderDynamicIndex, pPixelShaderName, nPixelShaderStaticIndex, nPixelShaderDynamicIndex );
  2641. }
  2642. else
  2643. {
  2644. nTotalLinkedShaders++;
  2645. }
  2646. }
  2647. }
  2648. else
  2649. {
  2650. Warning( "nVertexShaderDynamicIndex or nPixelShaderDynamicIndex was negative\n" );
  2651. }
  2652. }
  2653. else
  2654. {
  2655. Warning( "m_pHardwareShaders was null\n" );
  2656. }
  2657. }
  2658. else
  2659. {
  2660. Warning( "Invalid shader linkage: %s (%d, %d) : %s (%d, %d)\n", pVertexShaderName, nVertexShaderStaticIndex, nVertexShaderDynamicIndex, pPixelShaderName, nPixelShaderStaticIndex, nPixelShaderDynamicIndex );
  2661. }
  2662. }
  2663. Msg( "Loaded program cache file \"%s\", total keyvalues: %i, total successfully linked: %i\n", cacheName, nTotalKeyValues, nTotalLinkedShaders );
  2664. return true;
  2665. #else
  2666. return false; // have to return a value on Windows build to appease compiler
  2667. #endif
  2668. }
  2669. //-----------------------------------------------------------------------------
  2670. // Creates and destroys vertex shaders
  2671. //-----------------------------------------------------------------------------
  2672. VertexShader_t CShaderManager::CreateVertexShader( const char *pFileName, int nStaticVshIndex, char *debugLabel )
  2673. {
  2674. MEM_ALLOC_CREDIT();
  2675. if ( !pFileName )
  2676. {
  2677. return INVALID_SHADER;
  2678. }
  2679. #if 0 //old
  2680. if ( mat_cacheshaders.GetBool() )
  2681. {
  2682. WriteToShaderCache( pFileName, nStaticVshIndex );
  2683. }
  2684. #endif
  2685. VertexShader_t shader;
  2686. ShaderLookup_t lookup;
  2687. lookup.m_Name = m_ShaderSymbolTable.AddString( pFileName );
  2688. lookup.m_nStaticIndex = nStaticVshIndex;
  2689. shader = m_VertexShaderDict.Find( lookup );
  2690. if ( shader == m_VertexShaderDict.InvalidIndex() )
  2691. {
  2692. //printf("\nCShaderManager::CreateVertexShader( filename = %s, staticVshIndex = %d - not in cache", pFileName, nStaticVshIndex );
  2693. shader = m_VertexShaderDict.AddToTail( lookup );
  2694. if ( !LoadAndCreateShaders( m_VertexShaderDict[shader], true, debugLabel ) )
  2695. {
  2696. return INVALID_SHADER;
  2697. }
  2698. }
  2699. m_VertexShaderDict[shader].IncRefCount();
  2700. return shader;
  2701. }
  2702. //-----------------------------------------------------------------------------
  2703. // Create pixel shader
  2704. //-----------------------------------------------------------------------------
  2705. PixelShader_t CShaderManager::CreatePixelShader( const char *pFileName, int nStaticPshIndex, char *debugLabel )
  2706. {
  2707. MEM_ALLOC_CREDIT();
  2708. if ( !pFileName )
  2709. {
  2710. return INVALID_SHADER;
  2711. }
  2712. #if 0 //old
  2713. if ( mat_cacheshaders.GetBool() )
  2714. {
  2715. WriteToShaderCache( pFileName, nStaticPshIndex );
  2716. }
  2717. #endif
  2718. PixelShader_t shader;
  2719. ShaderLookup_t lookup;
  2720. lookup.m_Name = m_ShaderSymbolTable.AddString( pFileName );
  2721. lookup.m_nStaticIndex = nStaticPshIndex;
  2722. shader = m_PixelShaderDict.Find( lookup );
  2723. if ( shader == m_PixelShaderDict.InvalidIndex() )
  2724. {
  2725. shader = m_PixelShaderDict.AddToTail( lookup );
  2726. if ( !LoadAndCreateShaders( m_PixelShaderDict[shader], false, debugLabel ) )
  2727. {
  2728. return INVALID_SHADER;
  2729. }
  2730. }
  2731. m_PixelShaderDict[shader].IncRefCount();
  2732. return shader;
  2733. }
  2734. //-----------------------------------------------------------------------------
  2735. // Clear the refCounts to zero
  2736. //-----------------------------------------------------------------------------
  2737. void CShaderManager::ClearVertexAndPixelShaderRefCounts()
  2738. {
  2739. for ( VertexShader_t vshIndex = m_VertexShaderDict.Head();
  2740. vshIndex != m_VertexShaderDict.InvalidIndex();
  2741. vshIndex = m_VertexShaderDict.Next( vshIndex ) )
  2742. {
  2743. m_VertexShaderDict[vshIndex].m_nRefCount = 0;
  2744. }
  2745. for ( PixelShader_t pshIndex = m_PixelShaderDict.Head();
  2746. pshIndex != m_PixelShaderDict.InvalidIndex();
  2747. pshIndex = m_PixelShaderDict.Next( pshIndex ) )
  2748. {
  2749. m_PixelShaderDict[pshIndex].m_nRefCount = 0;
  2750. }
  2751. }
  2752. //-----------------------------------------------------------------------------
  2753. // Destroy all shaders that have no reference
  2754. //-----------------------------------------------------------------------------
  2755. void CShaderManager::PurgeUnusedVertexAndPixelShaders()
  2756. {
  2757. #ifdef DX_TO_GL_ABSTRACTION
  2758. if (mat_autosave_glshaders.GetInt())
  2759. {
  2760. SaveShaderCache("glshaders.cfg");
  2761. }
  2762. return; // don't purge shaders, it's too costly to put them back
  2763. #endif
  2764. // iterate vertex shaders
  2765. for ( VertexShader_t vshIndex = m_VertexShaderDict.Head(); vshIndex != m_VertexShaderDict.InvalidIndex(); )
  2766. {
  2767. Assert( m_VertexShaderDict[vshIndex].m_nRefCount >= 0 );
  2768. // Get the next one before we potentially delete the current one.
  2769. VertexShader_t next = m_VertexShaderDict.Next( vshIndex );
  2770. if ( m_VertexShaderDict[vshIndex].m_nRefCount <= 0 )
  2771. {
  2772. DestroyVertexShader( vshIndex );
  2773. }
  2774. vshIndex = next;
  2775. }
  2776. // iterate pixel shaders
  2777. for ( PixelShader_t pshIndex = m_PixelShaderDict.Head(); pshIndex != m_PixelShaderDict.InvalidIndex(); )
  2778. {
  2779. Assert( m_PixelShaderDict[pshIndex].m_nRefCount >= 0 );
  2780. // Get the next one before we potentially delete the current one.
  2781. PixelShader_t next = m_PixelShaderDict.Next( pshIndex );
  2782. if ( m_PixelShaderDict[pshIndex].m_nRefCount <= 0 )
  2783. {
  2784. DestroyPixelShader( pshIndex );
  2785. }
  2786. pshIndex = next;
  2787. }
  2788. }
  2789. void* CShaderManager::GetCurrentVertexShader()
  2790. {
  2791. return (void*)m_HardwareVertexShader;
  2792. }
  2793. void* CShaderManager::GetCurrentPixelShader()
  2794. {
  2795. return (void*)m_HardwarePixelShader;
  2796. }
  2797. //-----------------------------------------------------------------------------
  2798. // The low-level dx call to set the vertex shader state
  2799. //-----------------------------------------------------------------------------
  2800. void CShaderManager::SetVertexShaderState( HardwareShader_t shader, DataCacheHandle_t hCachedShader )
  2801. {
  2802. if ( m_HardwareVertexShader != shader )
  2803. {
  2804. RECORD_COMMAND( DX8_SET_VERTEX_SHADER, 1 );
  2805. RECORD_INT( ( int )shader ); // hack hack hack
  2806. Dx9Device()->SetVertexShader( (IDirect3DVertexShader9*)shader );
  2807. m_HardwareVertexShader = shader;
  2808. }
  2809. }
  2810. void CShaderManager::BindVertexShader( VertexShaderHandle_t hVertexShader )
  2811. {
  2812. HardwareShader_t hHardwareShader = m_RawVertexShaderDict[ (VertexShaderIndex_t)hVertexShader] ;
  2813. SetVertexShaderState( hHardwareShader );
  2814. }
  2815. //-----------------------------------------------------------------------------
  2816. // Sets a particular vertex shader as the current shader
  2817. //-----------------------------------------------------------------------------
  2818. void CShaderManager::SetVertexShader( VertexShader_t shader )
  2819. {
  2820. // Determine which vertex shader to use...
  2821. if ( shader == INVALID_SHADER )
  2822. {
  2823. SetVertexShaderState( 0 );
  2824. return;
  2825. }
  2826. int vshIndex = m_nVertexShaderIndex;
  2827. Assert( vshIndex >= 0 );
  2828. if( vshIndex < 0 )
  2829. {
  2830. vshIndex = 0;
  2831. }
  2832. ShaderLookup_t &vshLookup = m_VertexShaderDict[shader];
  2833. // Warning( "vsh: %s static: %d dynamic: %d\n", m_ShaderSymbolTable.String( vshLookup.m_Name ),
  2834. // vshLookup.m_nStaticIndex, m_nVertexShaderIndex );
  2835. #ifdef DYNAMIC_SHADER_COMPILE
  2836. HardwareShader_t &dxshader = m_VertexShaderDict[shader].m_ShaderStaticCombos.m_pHardwareShaders[vshIndex];
  2837. if ( dxshader == INVALID_HARDWARE_SHADER )
  2838. {
  2839. // compile it since we haven't already!
  2840. dxshader = CompileShader( m_ShaderSymbolTable.String( vshLookup.m_Name ), vshLookup.m_nStaticIndex, vshIndex, true );
  2841. Assert( dxshader != INVALID_HARDWARE_SHADER );
  2842. if( IsX360() )
  2843. {
  2844. //360 does not respond well at all to bad shaders or Error() calls. So we're staying here until we get something that compiles
  2845. while( dxshader == INVALID_HARDWARE_SHADER )
  2846. {
  2847. Warning( "A dynamically compiled vertex shader has failed to build. Pausing for 5 seconds and attempting rebuild.\n" );
  2848. #ifdef _WIN32
  2849. Sleep( 5000 );
  2850. #elif POSIX
  2851. usleep( 5000 );
  2852. #endif
  2853. dxshader = CompileShader( m_ShaderSymbolTable.String( vshLookup.m_Name ), vshLookup.m_nStaticIndex, vshIndex, true );
  2854. }
  2855. }
  2856. }
  2857. #else
  2858. if ( vshLookup.m_Flags & SHADER_FAILED_LOAD )
  2859. {
  2860. Assert( 0 );
  2861. return;
  2862. }
  2863. #ifdef _DEBUG
  2864. vshDebugIndex = (vshDebugIndex + 1) % MAX_SHADER_HISTORY;
  2865. Q_strncpy( vshDebugName[vshDebugIndex], m_ShaderSymbolTable.String( vshLookup.m_Name ), sizeof( vshDebugName[0] ) );
  2866. #endif
  2867. Assert( vshIndex < vshLookup.m_ShaderStaticCombos.m_nCount );
  2868. HardwareShader_t dxshader = vshLookup.m_ShaderStaticCombos.m_pHardwareShaders[vshIndex];
  2869. #endif
  2870. if ( IsPC() && ( dxshader == INVALID_HARDWARE_SHADER ) && m_bCreateShadersOnDemand )
  2871. {
  2872. #ifdef DYNAMIC_SHADER_COMPILE
  2873. ShaderStaticCombos_t::ShaderCreationData_t *pCreationData = &m_VertexShaderDict[shader].m_ShaderStaticCombos.m_pCreationData[vshIndex];
  2874. #else
  2875. ShaderStaticCombos_t::ShaderCreationData_t *pCreationData = &vshLookup.m_ShaderStaticCombos.m_pCreationData[vshIndex];
  2876. #endif
  2877. dxshader = CreateD3DVertexShader( ( DWORD * )pCreationData->ByteCode.Base(), pCreationData->ByteCode.Count(), m_ShaderSymbolTable.String( vshLookup.m_Name ) );
  2878. #ifdef DYNAMIC_SHADER_COMPILE
  2879. // copy the compiled shader handle back to wherever it's supposed to be stored
  2880. m_VertexShaderDict[shader].m_ShaderStaticCombos.m_pHardwareShaders[vshIndex] = dxshader;
  2881. #else
  2882. vshLookup.m_ShaderStaticCombos.m_pHardwareShaders[vshIndex] = dxshader;
  2883. #endif
  2884. }
  2885. Assert( dxshader );
  2886. #ifndef DYNAMIC_SHADER_COMPILE
  2887. if( !dxshader )
  2888. {
  2889. Error( "!!!!!Using invalid shader combo!!!!! Consult a programmer and tell them to build debug materialsystem.dll and stdshader*.dll. Run with \"mat_bufferprimitives 0\" and look for CMaterial in the call stack and see what m_pDebugName is. You are likely using a shader combo that has been skipped.\n" );
  2890. }
  2891. #endif
  2892. SetVertexShaderState( dxshader );
  2893. }
  2894. //-----------------------------------------------------------------------------
  2895. // The low-level dx call to set the pixel shader state
  2896. //-----------------------------------------------------------------------------
  2897. void CShaderManager::SetPixelShaderState( HardwareShader_t shader, DataCacheHandle_t hCachedShader )
  2898. {
  2899. if ( m_HardwarePixelShader != shader )
  2900. {
  2901. Dx9Device()->SetPixelShader( (IDirect3DPixelShader*)shader );
  2902. m_HardwarePixelShader = shader;
  2903. }
  2904. }
  2905. void CShaderManager::BindPixelShader( PixelShaderHandle_t hPixelShader )
  2906. {
  2907. HardwareShader_t hHardwareShader = m_RawPixelShaderDict[ (PixelShaderIndex_t)hPixelShader ];
  2908. SetPixelShaderState( hHardwareShader );
  2909. }
  2910. //-----------------------------------------------------------------------------
  2911. // Sets a particular pixel shader as the current shader
  2912. //-----------------------------------------------------------------------------
  2913. void CShaderManager::SetPixelShader( PixelShader_t shader )
  2914. {
  2915. if ( shader == INVALID_SHADER )
  2916. {
  2917. SetPixelShaderState( 0 );
  2918. return;
  2919. }
  2920. int pshIndex = m_nPixelShaderIndex;
  2921. Assert( pshIndex >= 0 );
  2922. ShaderLookup_t &pshLookup = m_PixelShaderDict[shader];
  2923. // Warning( "psh: %s static: %d dynamic: %d\n", m_ShaderSymbolTable.String( pshLookup.m_Name ),
  2924. // pshLookup.m_nStaticIndex, m_nPixelShaderIndex );
  2925. #ifdef DYNAMIC_SHADER_COMPILE
  2926. HardwareShader_t &dxshader = m_PixelShaderDict[shader].m_ShaderStaticCombos.m_pHardwareShaders[pshIndex];
  2927. if ( dxshader == INVALID_HARDWARE_SHADER )
  2928. {
  2929. // compile it since we haven't already!
  2930. dxshader = CompileShader( m_ShaderSymbolTable.String( pshLookup.m_Name ), pshLookup.m_nStaticIndex, pshIndex, false );
  2931. // Assert( dxshader != INVALID_HARDWARE_SHADER );
  2932. if( IsX360() )
  2933. {
  2934. //360 does not respond well at all to bad shaders or Error() calls. So we're staying here until we get something that compiles
  2935. while( dxshader == INVALID_HARDWARE_SHADER )
  2936. {
  2937. Warning( "A dynamically compiled pixel shader has failed to build. Pausing for 5 seconds and attempting rebuild.\n" );
  2938. #ifdef _WIN32
  2939. Sleep( 5000 );
  2940. #elif POSIX
  2941. usleep( 5000 );
  2942. #endif
  2943. dxshader = CompileShader( m_ShaderSymbolTable.String( pshLookup.m_Name ), pshLookup.m_nStaticIndex, pshIndex, false );
  2944. }
  2945. }
  2946. }
  2947. #else
  2948. if ( pshLookup.m_Flags & SHADER_FAILED_LOAD )
  2949. {
  2950. Assert( 0 );
  2951. return;
  2952. }
  2953. #ifdef _DEBUG
  2954. pshDebugIndex = (pshDebugIndex + 1) % MAX_SHADER_HISTORY;
  2955. Q_strncpy( pshDebugName[pshDebugIndex], m_ShaderSymbolTable.String( pshLookup.m_Name ), sizeof( pshDebugName[0] ) );
  2956. #endif
  2957. HardwareShader_t dxshader = pshLookup.m_ShaderStaticCombos.m_pHardwareShaders[pshIndex];
  2958. #endif
  2959. if ( IsPC() && ( dxshader == INVALID_HARDWARE_SHADER ) && m_bCreateShadersOnDemand )
  2960. {
  2961. #ifdef DYNAMIC_SHADER_COMPILE
  2962. ShaderStaticCombos_t::ShaderCreationData_t *pCreationData = &m_PixelShaderDict[shader].m_ShaderStaticCombos.m_pCreationData[pshIndex];
  2963. #else
  2964. ShaderStaticCombos_t::ShaderCreationData_t *pCreationData = &pshLookup.m_ShaderStaticCombos.m_pCreationData[pshIndex];
  2965. #endif
  2966. const char *pShaderName = m_ShaderSymbolTable.String( pshLookup.m_Name );
  2967. dxshader = CreateD3DPixelShader( ( DWORD * )pCreationData->ByteCode.Base(), pCreationData->iCentroidMask, pCreationData->ByteCode.Count(), pShaderName );
  2968. #ifdef DYNAMIC_SHADER_COMPILE
  2969. // copy the compiled shader handle back to wherever it's supposed to be stored
  2970. m_PixelShaderDict[shader].m_ShaderStaticCombos.m_pHardwareShaders[pshIndex] = dxshader;
  2971. #else
  2972. pshLookup.m_ShaderStaticCombos.m_pHardwareShaders[pshIndex] = dxshader;
  2973. #endif
  2974. }
  2975. AssertMsg( dxshader != INVALID_HARDWARE_SHADER, "Failed to set pixel shader." );
  2976. SetPixelShaderState( dxshader );
  2977. }
  2978. //-----------------------------------------------------------------------------
  2979. // Resets the shader state
  2980. //-----------------------------------------------------------------------------
  2981. void CShaderManager::ResetShaderState()
  2982. {
  2983. // This will force the calls to SetVertexShader + SetPixelShader to actually set the state
  2984. m_HardwareVertexShader = (HardwareShader_t)-1;
  2985. m_HardwarePixelShader = (HardwareShader_t)-1;
  2986. SetVertexShader( INVALID_SHADER );
  2987. SetPixelShader( INVALID_SHADER );
  2988. }
  2989. //-----------------------------------------------------------------------------
  2990. // Destroy a particular vertex shader
  2991. //-----------------------------------------------------------------------------
  2992. void CShaderManager::DestroyVertexShader( VertexShader_t shader )
  2993. {
  2994. ShaderStaticCombos_t &combos = m_VertexShaderDict[shader].m_ShaderStaticCombos;
  2995. int i;
  2996. for ( i = 0; i < combos.m_nCount; i++ )
  2997. {
  2998. if ( combos.m_pHardwareShaders[i] != INVALID_HARDWARE_SHADER )
  2999. {
  3000. IDirect3DVertexShader9* pShader = ( IDirect3DVertexShader9 * )combos.m_pHardwareShaders[i];
  3001. UnregisterVS( pShader );
  3002. #ifdef DBGFLAG_ASSERT
  3003. int nRetVal =
  3004. #endif
  3005. pShader->Release();
  3006. Assert( nRetVal == 0 );
  3007. }
  3008. }
  3009. delete [] combos.m_pHardwareShaders;
  3010. combos.m_pHardwareShaders = NULL;
  3011. if ( combos.m_pCreationData != NULL )
  3012. {
  3013. delete [] combos.m_pCreationData;
  3014. combos.m_pCreationData = NULL;
  3015. }
  3016. m_VertexShaderDict.Remove( shader );
  3017. }
  3018. //-----------------------------------------------------------------------------
  3019. // Destroy a particular pixel shader
  3020. //-----------------------------------------------------------------------------
  3021. void CShaderManager::DestroyPixelShader( PixelShader_t pixelShader )
  3022. {
  3023. ShaderStaticCombos_t &combos = m_PixelShaderDict[pixelShader].m_ShaderStaticCombos;
  3024. int i;
  3025. for ( i = 0; i < combos.m_nCount; i++ )
  3026. {
  3027. if ( combos.m_pHardwareShaders[i] != INVALID_HARDWARE_SHADER )
  3028. {
  3029. IDirect3DPixelShader* pShader = ( IDirect3DPixelShader * )combos.m_pHardwareShaders[i];
  3030. UnregisterPS( pShader );
  3031. #ifdef DBGFLAG_ASSERT
  3032. int nRetVal =
  3033. #endif
  3034. pShader->Release();
  3035. Assert( nRetVal == 0 );
  3036. }
  3037. }
  3038. delete [] combos.m_pHardwareShaders;
  3039. combos.m_pHardwareShaders = NULL;
  3040. if ( combos.m_pCreationData != NULL )
  3041. {
  3042. delete [] combos.m_pCreationData;
  3043. combos.m_pCreationData = NULL;
  3044. }
  3045. m_PixelShaderDict.Remove( pixelShader );
  3046. }
  3047. //-----------------------------------------------------------------------------
  3048. // Destroys all shaders
  3049. //-----------------------------------------------------------------------------
  3050. void CShaderManager::DestroyAllShaders( void )
  3051. {
  3052. // Remarking this out because it's conflicting with dxabstract's shutdown resource leak detection code (we leak thousands of shaders at shutdown with this in place).
  3053. // I see no reason why we would want to do this in D3D9 but not GL?
  3054. //#ifdef DX_TO_GL_ABSTRACTION
  3055. // return;
  3056. //#endif
  3057. for ( VertexShader_t vshIndex = m_VertexShaderDict.Head();
  3058. vshIndex != m_VertexShaderDict.InvalidIndex(); )
  3059. {
  3060. Assert( m_VertexShaderDict[vshIndex].m_nRefCount >= 0 );
  3061. VertexShader_t next = m_VertexShaderDict.Next( vshIndex );
  3062. DestroyVertexShader( vshIndex );
  3063. vshIndex = next;
  3064. }
  3065. for ( PixelShader_t pshIndex = m_PixelShaderDict.Head();
  3066. pshIndex != m_PixelShaderDict.InvalidIndex(); )
  3067. {
  3068. Assert( m_PixelShaderDict[pshIndex].m_nRefCount >= 0 );
  3069. PixelShader_t next = m_PixelShaderDict.Next( pshIndex );
  3070. DestroyPixelShader( pshIndex );
  3071. pshIndex = next;
  3072. }
  3073. // invalidate the file cache
  3074. m_ShaderFileCache.Purge();
  3075. }
  3076. //-----------------------------------------------------------------------------
  3077. // print all vertex and pixel shaders along with refcounts to the console
  3078. //-----------------------------------------------------------------------------
  3079. void CShaderManager::SpewVertexAndPixelShaders( void )
  3080. {
  3081. // only spew a populated shader file cache
  3082. Msg( "\nShader File Cache:\n" );
  3083. for ( int cacheIndex = m_ShaderFileCache.Head();
  3084. cacheIndex != m_ShaderFileCache.InvalidIndex();
  3085. cacheIndex = m_ShaderFileCache.Next( cacheIndex ) )
  3086. {
  3087. ShaderFileCache_t *pCache = &m_ShaderFileCache[cacheIndex];
  3088. Msg( "Total Combos:%9d Static:%9d Dynamic:%7d SeekTable:%7d Ver:%d '%s'\n",
  3089. pCache->m_Header.m_nTotalCombos,
  3090. pCache->m_Header.m_nTotalCombos/pCache->m_Header.m_nDynamicCombos,
  3091. pCache->m_Header.m_nDynamicCombos,
  3092. pCache->IsOldVersion() ? 0 : pCache->m_Header.m_nNumStaticCombos,
  3093. pCache->m_Header.m_nVersion,
  3094. m_ShaderSymbolTable.String( pCache->m_Filename ) );
  3095. }
  3096. Msg( "\n" );
  3097. // spew vertex shader dictionary
  3098. int totalVertexShaders = 0;
  3099. int totalVertexShaderSets = 0;
  3100. for ( VertexShader_t vshIndex = m_VertexShaderDict.Head();
  3101. vshIndex != m_VertexShaderDict.InvalidIndex();
  3102. vshIndex = m_VertexShaderDict.Next( vshIndex ) )
  3103. {
  3104. const ShaderLookup_t &lookup = m_VertexShaderDict[vshIndex];
  3105. const char *pName = m_ShaderSymbolTable.String( lookup.m_Name );
  3106. Msg( "vsh 0x%8.8x: static combo:%9d dynamic combos:%6d refcount:%4d \"%s\"\n", vshIndex,
  3107. ( int )lookup.m_nStaticIndex, ( int )lookup.m_ShaderStaticCombos.m_nCount,
  3108. lookup.m_nRefCount, pName );
  3109. totalVertexShaders += lookup.m_ShaderStaticCombos.m_nCount;
  3110. totalVertexShaderSets++;
  3111. }
  3112. // spew pixel shader dictionary
  3113. int totalPixelShaders = 0;
  3114. int totalPixelShaderSets = 0;
  3115. for ( PixelShader_t pshIndex = m_PixelShaderDict.Head();
  3116. pshIndex != m_PixelShaderDict.InvalidIndex();
  3117. pshIndex = m_PixelShaderDict.Next( pshIndex ) )
  3118. {
  3119. const ShaderLookup_t &lookup = m_PixelShaderDict[pshIndex];
  3120. const char *pName = m_ShaderSymbolTable.String( lookup.m_Name );
  3121. Msg( "psh 0x%8.8x: static combo:%9d dynamic combos:%6d refcount:%4d \"%s\"\n", pshIndex,
  3122. ( int )lookup.m_nStaticIndex, ( int )lookup.m_ShaderStaticCombos.m_nCount,
  3123. lookup.m_nRefCount, pName );
  3124. totalPixelShaders += lookup.m_ShaderStaticCombos.m_nCount;
  3125. totalPixelShaderSets++;
  3126. }
  3127. Msg( "Total unique vertex shaders: %d\n", totalVertexShaders );
  3128. Msg( "Total vertex shader sets: %d\n", totalVertexShaderSets );
  3129. Msg( "Total unique pixel shaders: %d\n", totalPixelShaders );
  3130. Msg( "Total pixel shader sets: %d\n", totalPixelShaderSets );
  3131. }
  3132. CON_COMMAND( mat_spewvertexandpixelshaders, "Print all vertex and pixel shaders currently loaded to the console" )
  3133. {
  3134. ( ( CShaderManager * )ShaderManager() )->SpewVertexAndPixelShaders();
  3135. }
  3136. const char *CShaderManager::GetActiveVertexShaderName()
  3137. {
  3138. #if !defined( _DEBUG )
  3139. return "";
  3140. #else
  3141. if ( !m_HardwareVertexShader )
  3142. {
  3143. return "NULL";
  3144. }
  3145. return vshDebugName[vshDebugIndex];
  3146. #endif
  3147. }
  3148. const char *CShaderManager::GetActivePixelShaderName()
  3149. {
  3150. #if !defined( _DEBUG )
  3151. return "";
  3152. #else
  3153. if ( !m_HardwarePixelShader )
  3154. {
  3155. return "NULL";
  3156. }
  3157. return pshDebugName[pshDebugIndex];
  3158. #endif
  3159. }
  3160. #ifdef DYNAMIC_SHADER_COMPILE
  3161. void CShaderManager::FlushShaders( void )
  3162. {
  3163. for( VertexShader_t shader = m_VertexShaderDict.Head();
  3164. shader != m_VertexShaderDict.InvalidIndex();
  3165. shader = m_VertexShaderDict.Next( shader ) )
  3166. {
  3167. int i;
  3168. ShaderStaticCombos_t &combos = m_VertexShaderDict[shader].m_ShaderStaticCombos;
  3169. for( i = 0; i < combos.m_nCount; i++ )
  3170. {
  3171. if( combos.m_pHardwareShaders[i] != INVALID_HARDWARE_SHADER )
  3172. {
  3173. #ifdef _DEBUG
  3174. int nRetVal=
  3175. #endif
  3176. ( ( IDirect3DVertexShader9 * )combos.m_pHardwareShaders[i] )->Release();
  3177. Assert( nRetVal == 0 );
  3178. }
  3179. combos.m_pHardwareShaders[i] = INVALID_HARDWARE_SHADER;
  3180. }
  3181. }
  3182. for( PixelShader_t shader = m_PixelShaderDict.Head();
  3183. shader != m_PixelShaderDict.InvalidIndex();
  3184. shader = m_PixelShaderDict.Next( shader ) )
  3185. {
  3186. int i;
  3187. ShaderStaticCombos_t &combos = m_PixelShaderDict[shader].m_ShaderStaticCombos;
  3188. for( i = 0; i < combos.m_nCount; i++ )
  3189. {
  3190. if( combos.m_pHardwareShaders[i] != INVALID_HARDWARE_SHADER )
  3191. {
  3192. #ifdef _DEBUG
  3193. int nRetVal =
  3194. #endif
  3195. ( ( IDirect3DPixelShader * )combos.m_pHardwareShaders[i] )->Release();
  3196. Assert( nRetVal == 0 );
  3197. }
  3198. combos.m_pHardwareShaders[i] = INVALID_HARDWARE_SHADER;
  3199. }
  3200. }
  3201. // invalidate the file cache
  3202. m_ShaderFileCache.Purge();
  3203. }
  3204. #endif
  3205. #ifdef DYNAMIC_SHADER_COMPILE
  3206. static void MatFlushShaders( void )
  3207. {
  3208. #if defined( _X360 )
  3209. XBX_rSyncShaderCache();
  3210. #endif
  3211. ( ( CShaderManager * )ShaderManager() )->FlushShaders();
  3212. }
  3213. #endif
  3214. #ifdef DYNAMIC_SHADER_COMPILE
  3215. CON_COMMAND( mat_flushshaders, "flush all hardware shaders when using DYNAMIC_SHADER_COMPILE" )
  3216. {
  3217. MatFlushShaders();
  3218. }
  3219. #endif
  3220. CON_COMMAND( mat_shadercount, "display count of all shaders and reset that count" )
  3221. {
  3222. Warning( "Num Pixel Shaders = %d Vertex Shaders=%d\n", s_NumPixelShadersCreated, s_NumVertexShadersCreated );
  3223. s_NumVertexShadersCreated = 0;
  3224. s_NumPixelShadersCreated = 0;
  3225. }
  3226. #if defined( DX_TO_GL_ABSTRACTION )
  3227. void CShaderManager::DoStartupShaderPreloading()
  3228. {
  3229. if (mat_autoload_glshaders.GetInt())
  3230. {
  3231. double flStartTime = Plat_FloatTime();
  3232. s_NumVertexShadersCreated = s_NumPixelShadersCreated = 0;
  3233. // try base file
  3234. #ifdef OSX
  3235. if ( !LoadShaderCache("glbaseshaders_osx.cfg") ) // factory cache
  3236. #else
  3237. if ( !LoadShaderCache("glbaseshaders.cfg") ) // factory cache
  3238. #endif
  3239. {
  3240. Warning( "Could not find base GL shader cache file\n" );
  3241. }
  3242. if ( !LoadShaderCache("glshaders.cfg") ) // user mutable cache
  3243. {
  3244. Warning( "Could not find user GL shader cache file\n" );
  3245. }
  3246. double flEndTime = Plat_FloatTime();
  3247. Msg( "Precache: Took %d ms, Vertex %d, Pixel %d\n", ( int )( ( flEndTime - flStartTime ) * 1000.0 ), s_NumVertexShadersCreated, s_NumPixelShadersCreated );
  3248. }
  3249. }
  3250. #endif