Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4708 lines
144 KiB

  1. //==== Copyright (c) 1996-2009, 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 defined( POSIX ) && !defined( _PS3 )
  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/utlcommon.h"
  27. #include "tier1/utlsymbol.h"
  28. #include "tier1/utlvector.h"
  29. #include "tier1/utldict.h"
  30. #include "tier1/utllinkedlist.h"
  31. #include "tier1/utlbuffer.h"
  32. #include "tier1/UtlStringMap.h"
  33. #include "locald3dtypes.h"
  34. #include "shaderapidx8_global.h"
  35. #include "recording.h"
  36. #include "tier0/vprof.h"
  37. #include "materialsystem/imaterialsystem.h"
  38. #include "materialsystem/imaterialsystemhardwareconfig.h"
  39. #include "keyvalues.h"
  40. #include "shaderapidx8.h"
  41. #include "materialsystem/IShader.h"
  42. #include "materialsystem/ishadersystem.h"
  43. #include "tier0/fasttimer.h"
  44. #include <sys/stat.h>
  45. #include <time.h>
  46. #include <stdlib.h>
  47. #include "filesystem.h"
  48. #include "convar.h"
  49. #include "materialsystem/shader_vcs_version.h"
  50. #include "tier1/lzmaDecoder.h"
  51. #include "tier1/utlmap.h"
  52. #include "shaderlib/shadercombosemantics.h"
  53. #include "datacache/idatacache.h"
  54. #include "tier1/diff.h"
  55. #include "shaderdevicedx8.h"
  56. #include "filesystem/IQueuedLoader.h"
  57. #include "tier2/tier2.h"
  58. #include "shaderapi/ishaderutil.h"
  59. #include "tier0/icommandline.h"
  60. #include "tier1/utlintrusivelist.h"
  61. #include "color.h"
  62. #include "tier0/dbg.h"
  63. #if defined( _X360 )
  64. #include "xbox/xbox_console.h"
  65. #endif
  66. #ifdef REMOTE_DYNAMIC_SHADER_COMPILE
  67. #if defined( POSIX )
  68. #include <sys/types.h>
  69. #include <sys/socket.h>
  70. #elif ( defined(_WIN32) && !defined( _X360 ) )
  71. #include <winsock2.h>
  72. #include <ws2tcpip.h>
  73. #endif
  74. #endif
  75. #if defined( DYNAMIC_SHADER_COMPILE ) && defined( _PS3 )
  76. // The CGC library is used to compile shaders at runtime.
  77. #include <cg/cgc.h>
  78. #pragma comment(lib, "cgc" )
  79. #endif
  80. // NOTE: This has to be the last file included!
  81. #include "tier0/memdbgon.h"
  82. // mapping from vcs file basename to shader combo semantics information.
  83. static CUtlStringMap<const ShaderComboSemantics_t *> s_ShaderComboInfoByName;
  84. // It currently includes windows.h and we don't want that.
  85. #ifdef USE_ACTUAL_DX
  86. #include "../utils/bzip2/bzlib.h"
  87. #else
  88. int BZ2_bzBuffToBuffDecompress(
  89. char* dest,
  90. unsigned int* destLen,
  91. char* source,
  92. unsigned int sourceLen,
  93. int small,
  94. int verbosity
  95. )
  96. {
  97. return 0;
  98. }
  99. #endif
  100. static ConVar mat_remoteshadercompile( "mat_remoteshadercompile", "127.0.0.1", FCVAR_CHEAT );
  101. #ifdef DYNAMIC_SHADER_COMPILE
  102. static ConVar mat_dynamic_shader_compile_force_reload( "mat_dynamic_shader_compile_force_reload", "0" );
  103. #endif
  104. #ifdef DYNAMIC_SHADER_COMPILE_VERBOSE
  105. static ConVar mat_dynamic_shader_substring( "mat_dynamic_shader_substring", "" );
  106. #endif
  107. //#define PROFILE_SHADER_CREATE
  108. #define SHADER_COMBO_SPEW_VERBOSE 1
  109. //#define NO_AMBIENT_CUBE
  110. #define MAX_BONES 3
  111. // debugging aid
  112. #define MAX_SHADER_HISTORY 16
  113. #define SHADER_FNAME_EXTENSION PLATFORM_EXT ".vcs"
  114. #ifdef DYNAMIC_SHADER_COMPILE
  115. volatile static char s_ShaderCompileString[]="dynamic_shader_compile_is_on";
  116. #endif
  117. #ifdef DYNAMIC_SHADER_COMPILE
  118. static void MatFlushShaders( void );
  119. #endif
  120. #if 0
  121. #ifndef _PS3
  122. // D3D to OpenGL translator
  123. static D3DToGL sg_D3DToOpenGLTranslator;
  124. #endif
  125. #endif // !_PS3
  126. #ifdef PROFILE_SHADER_CREATE
  127. static FILE *GetDebugFileHandle( void )
  128. {
  129. static FILE *fp = NULL;
  130. if( !fp )
  131. {
  132. fp = fopen( "shadercreate.txt", "w" );
  133. Assert( fp );
  134. }
  135. return fp;
  136. }
  137. #endif // PROFILE_SHADER_CREATE
  138. #ifdef DX_TO_GL_ABSTRACTION
  139. // mat_autoload_glshaders instructs the engine to load a cached shader table at startup
  140. // it will try for glshaders.cfg first, then fall back to glbaseshaders.cfg if not found
  141. ConVar mat_autoload_glshaders( "mat_autoload_glshaders", "1" );
  142. // mat_autosave_glshaders instructs the engine to save out the shader table at key points
  143. // to the filename glshaders.cfg
  144. //
  145. ConVar mat_autosave_glshaders( "mat_autosave_glshaders", "1" );
  146. #endif
  147. //-----------------------------------------------------------------------------
  148. // Explicit instantiation of shader buffer implementation
  149. //-----------------------------------------------------------------------------
  150. template class CShaderBuffer< ID3DXBuffer >;
  151. //-----------------------------------------------------------------------------
  152. bool ToolsEnabled()
  153. {
  154. static bool bToolsMode = ( CommandLine()->CheckParm( "-tools" ) != NULL );
  155. return bToolsMode;
  156. }
  157. //-----------------------------------------------------------------------------
  158. // Used to find unique shaders
  159. //-----------------------------------------------------------------------------
  160. #ifdef MEASURE_DRIVER_ALLOCATIONS
  161. static CUtlMap< CRC32_t, int, int > s_UniqueVS( 0, 0, DefLessFunc( CRC32_t ) );
  162. static CUtlMap< CRC32_t, int, int > s_UniquePS( 0, 0, DefLessFunc( CRC32_t ) );
  163. static CUtlMap< IDirect3DVertexShader9*, CRC32_t, int > s_VSLookup( 0, 0, DefLessFunc( IDirect3DVertexShader9* ) );
  164. static CUtlMap< IDirect3DPixelShader9*, CRC32_t, int > s_PSLookup( 0, 0, DefLessFunc( IDirect3DPixelShader9* ) );
  165. #endif
  166. static int s_NumPixelShadersCreated = 0;
  167. static int s_NumVertexShadersCreated = 0;
  168. static void RegisterVS( const void* pShaderBits, int nShaderSize, IDirect3DVertexShader9* pShader )
  169. {
  170. #ifdef MEASURE_DRIVER_ALLOCATIONS
  171. CRC32_t crc;
  172. CRC32_Init( &crc );
  173. CRC32_ProcessBuffer( &crc, pShaderBits, nShaderSize );
  174. CRC32_Final( &crc );
  175. s_VSLookup.Insert( pShader, crc );
  176. int nIndex = s_UniqueVS.Find( crc );
  177. if ( nIndex != s_UniqueVS.InvalidIndex() )
  178. {
  179. ++s_UniqueVS[nIndex];
  180. }
  181. else
  182. {
  183. int nMemUsed = 23 * 1024;
  184. s_UniqueVS.Insert( crc, 1 );
  185. VPROF_INCREMENT_GROUP_COUNTER( "unique vs count", COUNTER_GROUP_NO_RESET, 1 );
  186. VPROF_INCREMENT_GROUP_COUNTER( "vs driver mem", COUNTER_GROUP_NO_RESET, nMemUsed );
  187. VPROF_INCREMENT_GROUP_COUNTER( "total driver mem", COUNTER_GROUP_NO_RESET, nMemUsed );
  188. }
  189. #endif
  190. }
  191. static void RegisterPS( const void* pShaderBits, int nShaderSize, IDirect3DPixelShader9* pShader )
  192. {
  193. #ifdef MEASURE_DRIVER_ALLOCATIONS
  194. CRC32_t crc;
  195. CRC32_Init( &crc );
  196. CRC32_ProcessBuffer( &crc, pShaderBits, nShaderSize );
  197. CRC32_Final( &crc );
  198. s_PSLookup.Insert( pShader, crc );
  199. int nIndex = s_UniquePS.Find( crc );
  200. if ( nIndex != s_UniquePS.InvalidIndex() )
  201. {
  202. ++s_UniquePS[nIndex];
  203. }
  204. else
  205. {
  206. int nMemUsed = 400;
  207. s_UniquePS.Insert( crc, 1 );
  208. VPROF_INCREMENT_GROUP_COUNTER( "unique ps count", COUNTER_GROUP_NO_RESET, 1 );
  209. VPROF_INCREMENT_GROUP_COUNTER( "ps driver mem", COUNTER_GROUP_NO_RESET, nMemUsed );
  210. VPROF_INCREMENT_GROUP_COUNTER( "total driver mem", COUNTER_GROUP_NO_RESET, nMemUsed );
  211. }
  212. #endif
  213. }
  214. static void UnregisterVS( IDirect3DVertexShader9* pShader )
  215. {
  216. #ifdef MEASURE_DRIVER_ALLOCATIONS
  217. int nCRCIndex = s_VSLookup.Find( pShader );
  218. if ( nCRCIndex == s_VSLookup.InvalidIndex() )
  219. return;
  220. CRC32_t crc = s_VSLookup[nCRCIndex];
  221. s_VSLookup.RemoveAt( nCRCIndex );
  222. int nIndex = s_UniqueVS.Find( crc );
  223. if ( nIndex != s_UniqueVS.InvalidIndex() )
  224. {
  225. if ( --s_UniqueVS[nIndex] <= 0 )
  226. {
  227. int nMemUsed = 23 * 1024;
  228. VPROF_INCREMENT_GROUP_COUNTER( "unique vs count", COUNTER_GROUP_NO_RESET, -1 );
  229. VPROF_INCREMENT_GROUP_COUNTER( "vs driver mem", COUNTER_GROUP_NO_RESET, -nMemUsed );
  230. VPROF_INCREMENT_GROUP_COUNTER( "total driver mem", COUNTER_GROUP_NO_RESET, -nMemUsed );
  231. s_UniqueVS.Remove( nIndex );
  232. }
  233. }
  234. #endif
  235. }
  236. static void UnregisterPS( IDirect3DPixelShader9* pShader )
  237. {
  238. #ifdef MEASURE_DRIVER_ALLOCATIONS
  239. int nCRCIndex = s_PSLookup.Find( pShader );
  240. if ( nCRCIndex == s_PSLookup.InvalidIndex() )
  241. return;
  242. CRC32_t crc = s_PSLookup[nCRCIndex];
  243. s_PSLookup.RemoveAt( nCRCIndex );
  244. int nIndex = s_UniquePS.Find( crc );
  245. if ( nIndex != s_UniquePS.InvalidIndex() )
  246. {
  247. if ( --s_UniquePS[nIndex] <= 0 )
  248. {
  249. int nMemUsed = 400;
  250. VPROF_INCREMENT_GROUP_COUNTER( "unique ps count", COUNTER_GROUP_NO_RESET, -1 );
  251. VPROF_INCREMENT_GROUP_COUNTER( "ps driver mem", COUNTER_GROUP_NO_RESET, -nMemUsed );
  252. VPROF_INCREMENT_GROUP_COUNTER( "total driver mem", COUNTER_GROUP_NO_RESET, -nMemUsed );
  253. s_UniquePS.Remove( nIndex );
  254. }
  255. }
  256. #endif
  257. }
  258. //-----------------------------------------------------------------------------
  259. // The lovely low-level dx call to create a vertex shader
  260. //-----------------------------------------------------------------------------
  261. static HardwareShader_t CreateD3DVertexShader( DWORD *pByteCode, int numBytes, const char *pShaderName, char *debugLabel = NULL )
  262. {
  263. MEM_ALLOC_D3D_CREDIT();
  264. if ( !pByteCode )
  265. {
  266. Assert( 0 );
  267. return INVALID_HARDWARE_SHADER;
  268. }
  269. // Compute the vertex specification
  270. HardwareShader_t hShader;
  271. #if defined( _PS3 )
  272. HRESULT hr = Dx9Device()->CreateVertexShader( pByteCode, (IDirect3DVertexShader9 **)&hShader, debugLabel );
  273. #elif defined( DX_TO_GL_ABSTRACTION )
  274. HRESULT hr = Dx9Device()->CreateVertexShader( pByteCode, (IDirect3DVertexShader9 **)&hShader, pShaderName, debugLabel );
  275. #else
  276. #ifdef _GAMECONSOLE
  277. HRESULT hr = Dx9Device()->CreateVertexShader( pByteCode, (IDirect3DVertexShader9 **)&hShader );
  278. #else
  279. HRESULT hr = Dx9Device()->CreateVertexShader( pByteCode, (IDirect3DVertexShader9 **)&hShader, pShaderName );
  280. #endif
  281. #endif
  282. // NOTE: This isn't recorded before the CreateVertexShader because
  283. // we don't know the value of shader until after the CreateVertexShader.
  284. RECORD_COMMAND( DX8_CREATE_VERTEX_SHADER, 3 );
  285. RECORD_INT( ( int )hShader ); // hack hack hack
  286. RECORD_INT( numBytes );
  287. RECORD_STRUCT( pByteCode, numBytes );
  288. if ( FAILED( hr ) )
  289. {
  290. Assert( 0 );
  291. hShader = INVALID_HARDWARE_SHADER;
  292. }
  293. else
  294. {
  295. s_NumVertexShadersCreated++;
  296. RegisterVS( pByteCode, numBytes, (IDirect3DVertexShader9 *)hShader );
  297. }
  298. return hShader;
  299. }
  300. static void PatchPixelShaderForAtiMsaaHack(DWORD *pShader, DWORD dwTexCoordMask)
  301. {
  302. if ( IsPC() )
  303. {
  304. bool bIsSampler, bIsTexCoord;
  305. // Should be able to patch only ps2.0
  306. if (*pShader != 0xFFFF0200)
  307. return;
  308. pShader++;
  309. while (pShader)
  310. {
  311. switch (*pShader & D3DSI_OPCODE_MASK)
  312. {
  313. case D3DSIO_COMMENT:
  314. // Process comment
  315. pShader = pShader + (*pShader >> 16) + 1;
  316. break;
  317. case D3DSIO_END:
  318. // End of shader
  319. return;
  320. case D3DSIO_DCL:
  321. bIsSampler = (*(pShader + 1) & D3DSP_TEXTURETYPE_MASK) != D3DSTT_UNKNOWN;
  322. bIsTexCoord = (((*(pShader + 2) & D3DSP_REGTYPE_MASK) >> D3DSP_REGTYPE_SHIFT) +
  323. ((*(pShader + 2) & D3DSP_REGTYPE_MASK2) >> D3DSP_REGTYPE_SHIFT2)) == D3DSPR_TEXTURE;
  324. if (!bIsSampler && bIsTexCoord)
  325. {
  326. DWORD dwTexCoord = *(pShader + 2) & D3DSP_REGNUM_MASK;
  327. DWORD mask = 0x01;
  328. for (DWORD i = 0; i < 16; i++)
  329. {
  330. if (((dwTexCoordMask & mask) == mask) && (dwTexCoord == i))
  331. {
  332. // If found -- patch and get out
  333. // *(pShader + 2) |= D3DSPDM_PARTIALPRECISION;
  334. *(pShader + 2) |= D3DSPDM_MSAMPCENTROID;
  335. break;
  336. }
  337. mask <<= 1;
  338. }
  339. }
  340. // Intentionally fall through...
  341. default:
  342. // Skip instruction
  343. pShader = pShader + ((*pShader & D3DSI_INSTLENGTH_MASK) >> D3DSI_INSTLENGTH_SHIFT) + 1;
  344. }
  345. }
  346. }
  347. }
  348. //-----------------------------------------------------------------------------
  349. // The lovely low-level dx call to create a pixel shader
  350. //-----------------------------------------------------------------------------
  351. static HardwareShader_t CreateD3DPixelShader( DWORD *pByteCode, unsigned int nCentroidMask, int numBytes, const char* pShaderName, char *debugLabel = NULL )
  352. {
  353. MEM_ALLOC_D3D_CREDIT();
  354. if ( !pByteCode )
  355. return INVALID_HARDWARE_SHADER;
  356. // if ( nCentroidMask )
  357. // {
  358. // ConColorMsg( Color( 255, 187, 73, 255 ), "Centroid Mask for %s: 0x%x\n", pShaderName, nCentroidMask );
  359. // }
  360. if ( IsPC() && nCentroidMask &&
  361. HardwareConfig()->NeedsATICentroidHack() &&
  362. !HardwareConfig()->SuppressPixelShaderCentroidHackFixup() )
  363. {
  364. PatchPixelShaderForAtiMsaaHack( pByteCode, nCentroidMask );
  365. }
  366. HardwareShader_t shader;
  367. #if defined( DX_TO_GL_ABSTRACTION )
  368. #if defined( OSX )
  369. HRESULT hr = Dx9Device()->CreatePixelShader( pByteCode, ( IDirect3DPixelShader ** )&shader, pShaderName, debugLabel );
  370. #else
  371. HRESULT hr = Dx9Device()->CreatePixelShader( pByteCode, ( IDirect3DPixelShader ** )&shader, pShaderName, debugLabel, &nCentroidMask );
  372. #endif
  373. #else
  374. #if defined(_X360)
  375. HRESULT hr = Dx9Device()->CreatePixelShader( pByteCode, ( IDirect3DPixelShader ** )&shader );
  376. #else
  377. HRESULT hr = Dx9Device()->CreatePixelShader( pByteCode, ( IDirect3DPixelShader ** )&shader, pShaderName );
  378. #endif
  379. #endif
  380. // NOTE: We have to do this after creating the pixel shader since we don't know
  381. // lookup.m_PixelShader yet!!!!!!!
  382. RECORD_COMMAND( DX8_CREATE_PIXEL_SHADER, 3 );
  383. RECORD_INT( ( int )shader ); // hack hack hack
  384. RECORD_INT( numBytes );
  385. RECORD_STRUCT( pByteCode, numBytes );
  386. if ( FAILED( hr ) )
  387. {
  388. Assert(0);
  389. shader = INVALID_HARDWARE_SHADER;
  390. }
  391. else
  392. {
  393. s_NumPixelShadersCreated++;
  394. RegisterPS( pByteCode, numBytes, ( IDirect3DPixelShader9* )shader );
  395. }
  396. return shader;
  397. }
  398. template<class T> int BinarySearchCombos( uint32 nStaticComboID, int nCombos, T const *pRecords )
  399. {
  400. // Use binary search - data is sorted
  401. int nLowerIdx = 1;
  402. int nUpperIdx = nCombos;
  403. for (;;)
  404. {
  405. if ( nUpperIdx < nLowerIdx )
  406. return -1;
  407. int nMiddleIndex = ( nLowerIdx + nUpperIdx ) / 2;
  408. uint32 nProbe = pRecords[nMiddleIndex-1].m_nStaticComboID;
  409. if ( nStaticComboID < nProbe )
  410. {
  411. nUpperIdx = nMiddleIndex - 1;
  412. }
  413. else
  414. {
  415. if ( nStaticComboID > nProbe )
  416. nLowerIdx = nMiddleIndex + 1;
  417. else
  418. return nMiddleIndex - 1;
  419. }
  420. }
  421. }
  422. inline int FindShaderStaticCombo( uint32 nStaticComboID, const ShaderHeader_t& header, StaticComboRecord_t *pRecords )
  423. {
  424. if ( header.m_nVersion < 5 )
  425. return -1;
  426. return BinarySearchCombos( nStaticComboID, header.m_nNumStaticCombos, pRecords );
  427. }
  428. // cache redundant i/o fetched components of the vcs files
  429. struct ShaderFileCache_t
  430. {
  431. CUtlSymbol m_Name;
  432. CUtlSymbol m_Filename;
  433. ShaderHeader_t m_Header;
  434. bool m_bVertexShader;
  435. // valid for diff version only - contains the microcode used as the reference for diff algorithm
  436. CUtlBuffer m_ReferenceCombo;
  437. // valid for ver5 only - contains the directory
  438. CUtlVector< StaticComboRecord_t > m_StaticComboRecords;
  439. CUtlVector< StaticComboAliasRecord_t > m_StaticComboDupRecords;
  440. ShaderFileCache_t()
  441. {
  442. // invalid until version established
  443. m_Header.m_nVersion = 0;
  444. }
  445. bool IsValid() const
  446. {
  447. return m_Header.m_nVersion != 0;
  448. }
  449. bool IsOldVersion() const
  450. {
  451. return m_Header.m_nVersion < 5;
  452. }
  453. int IsVersion6() const
  454. {
  455. return ( m_Header.m_nVersion == 6 );
  456. }
  457. int FindCombo( uint32 nStaticComboID )
  458. {
  459. int nSearchAliases = BinarySearchCombos( nStaticComboID, m_StaticComboDupRecords.Count(), m_StaticComboDupRecords.Base() );
  460. if ( nSearchAliases != -1 )
  461. nStaticComboID = m_StaticComboDupRecords[nSearchAliases].m_nSourceStaticCombo;
  462. return FindShaderStaticCombo( nStaticComboID, m_Header, m_StaticComboRecords.Base() );
  463. }
  464. bool operator==( const ShaderFileCache_t& a ) const
  465. {
  466. return m_Name == a.m_Name && m_bVertexShader == a.m_bVertexShader;
  467. }
  468. };
  469. //-----------------------------------------------------------------------------
  470. // Vertex + pixel shader manager
  471. //-----------------------------------------------------------------------------
  472. class CShaderManager : public IShaderManager
  473. {
  474. public:
  475. CShaderManager();
  476. virtual ~CShaderManager();
  477. // Methods of IShaderManager
  478. virtual void Init();
  479. virtual void Shutdown();
  480. virtual IShaderBuffer *CompileShader( const char *pProgram, size_t nBufLen, const char *pShaderVersion );
  481. virtual VertexShaderHandle_t CreateVertexShader( IShaderBuffer* pShaderBuffer );
  482. virtual void DestroyVertexShader( VertexShaderHandle_t hShader );
  483. virtual PixelShaderHandle_t CreatePixelShader( IShaderBuffer* pShaderBuffer );
  484. virtual void DestroyPixelShader( PixelShaderHandle_t hShader );
  485. virtual VertexShader_t CreateVertexShader( const char *pVertexShaderFile, int nStaticVshIndex = 0, char *debugLabel = NULL );
  486. virtual PixelShader_t CreatePixelShader( const char *pPixelShaderFile, int nStaticPshIndex = 0, char *debugLabel = NULL );
  487. virtual void SetVertexShader( VertexShader_t shader );
  488. virtual void SetPixelShader( PixelShader_t shader );
  489. virtual void BindVertexShader( VertexShaderHandle_t shader );
  490. virtual void BindPixelShader( PixelShaderHandle_t shader );
  491. virtual void *GetCurrentVertexShader();
  492. virtual void *GetCurrentPixelShader();
  493. virtual void ResetShaderState();
  494. virtual void FlushShaders();
  495. virtual void ClearVertexAndPixelShaderRefCounts();
  496. virtual void PurgeUnusedVertexAndPixelShaders();
  497. void SpewVertexAndPixelShaders();
  498. const char *GetActiveVertexShaderName();
  499. const char *GetActivePixelShaderName();
  500. bool CreateDynamicCombos_Ver4( void *pContext, uint8 *pComboBuffer );
  501. bool CreateDynamicCombos_Ver5( void *pContext, uint8 *pComboBuffer, char *debugLabel = NULL );
  502. static void QueuedLoaderCallback( void *pContext, void *pContext2, const void *pData, int nSize, LoaderError_t loaderError );
  503. virtual HardwareShader_t GetVertexShader( VertexShader_t vs, int dynIdx );
  504. virtual HardwareShader_t GetPixelShader( PixelShader_t ps, int dynIdx );
  505. // Destroys all shaders
  506. void DestroyAllShaders();
  507. virtual void AddShaderComboInformation( const ShaderComboSemantics_t *pSemantics );
  508. #if defined( DX_TO_GL_ABSTRACTION )
  509. virtual void DoStartupShaderPreloading();
  510. #endif
  511. private:
  512. typedef CUtlFixedLinkedList< IDirect3DVertexShader9* >::IndexType_t VertexShaderIndex_t;
  513. typedef CUtlFixedLinkedList< IDirect3DPixelShader9* >::IndexType_t PixelShaderIndex_t;
  514. struct ShaderStaticCombos_t
  515. {
  516. int m_nCount;
  517. int m_nNumDynamicCombosAfterSkips;
  518. // Can't use CUtlVector here since you CUtlLinkedList<CUtlVector<>> doesn't work.
  519. HardwareShader_t *m_pHardwareShaders;
  520. struct ShaderCreationData_t
  521. {
  522. CUtlVector<uint8> ByteCode;
  523. uint32 iCentroidMask;
  524. };
  525. ShaderCreationData_t *m_pCreationData;
  526. };
  527. struct ShaderLookup_t
  528. {
  529. CUtlSymbol m_Name;
  530. int m_nStaticIndex;
  531. ShaderStaticCombos_t m_ShaderStaticCombos;
  532. DWORD m_Flags;
  533. int m_nRefCount;
  534. intp m_hShaderFileCache;
  535. #ifdef DYNAMIC_SHADER_COMPILE
  536. uint32 m_nVcsCrc32;
  537. #endif
  538. // for queued loading, bias an aligned optimal buffer forward to correct location
  539. int m_nDataOffset;
  540. // diff version, valid during load only
  541. ShaderDictionaryEntry_t *m_pComboDictionary;
  542. ShaderLookup_t()
  543. {
  544. m_Flags = 0;
  545. m_nRefCount = 0;
  546. m_ShaderStaticCombos.m_nCount = 0;
  547. m_ShaderStaticCombos.m_pHardwareShaders = 0;
  548. m_ShaderStaticCombos.m_pCreationData = 0;
  549. m_ShaderStaticCombos.m_nNumDynamicCombosAfterSkips = 0;
  550. m_pComboDictionary = NULL;
  551. }
  552. void IncRefCount()
  553. {
  554. m_nRefCount++;
  555. }
  556. bool operator==( const ShaderLookup_t& a ) const
  557. {
  558. return m_Name == a.m_Name && m_nStaticIndex == a.m_nStaticIndex;
  559. }
  560. };
  561. #ifdef DYNAMIC_SHADER_COMPILE
  562. struct Combo_t
  563. {
  564. CUtlSymbol m_ComboName;
  565. int m_nMin;
  566. int m_nMax;
  567. };
  568. struct ShaderCombos_t
  569. {
  570. CUtlVector<Combo_t> m_StaticCombos;
  571. CUtlVector<Combo_t> m_DynamicCombos;
  572. unsigned int GetNumDynamicCombos( void ) const
  573. {
  574. unsigned int combos = 1;
  575. int i;
  576. for( i = 0; i < m_DynamicCombos.Count(); i++ )
  577. {
  578. combos *= ( m_DynamicCombos[i].m_nMax - m_DynamicCombos[i].m_nMin + 1 );
  579. }
  580. return combos;
  581. }
  582. unsigned int GetNumStaticCombos( void ) const
  583. {
  584. unsigned int combos = 1;
  585. int i;
  586. for( i = 0; i < m_StaticCombos.Count(); i++ )
  587. {
  588. combos *= ( m_StaticCombos[i].m_nMax - m_StaticCombos[i].m_nMin + 1 );
  589. }
  590. return combos;
  591. }
  592. };
  593. #endif
  594. virtual void SetPixelShaderState_Internal( HardwareShader_t shader, DataCacheHandle_t hCachedShader );
  595. virtual void SetVertexShaderState_Internal( HardwareShader_t shader, DataCacheHandle_t hCachedShader );
  596. private:
  597. void CreateStaticShaders();
  598. void DestroyStaticShaders();
  599. #if defined ( DYNAMIC_SHADER_COMPILE ) && defined( REMOTE_DYNAMIC_SHADER_COMPILE )
  600. void InitRemoteShaderCompile();
  601. void DeinitRemoteShaderCompile();
  602. #endif
  603. // The low-level dx call to set the vertex shader state
  604. inline void SetVertexShaderState( HardwareShader_t shader, DataCacheHandle_t hCachedShader = DC_INVALID_HANDLE )
  605. {
  606. if ( m_HardwareVertexShader != shader )
  607. {
  608. SetVertexShaderState_Internal( shader, hCachedShader );
  609. }
  610. }
  611. // The low-level dx call to set the pixel shader state
  612. inline void SetPixelShaderState( HardwareShader_t shader, DataCacheHandle_t hCachedShader = DC_INVALID_HANDLE )
  613. {
  614. if ( m_HardwarePixelShader != shader )
  615. {
  616. SetPixelShaderState_Internal( shader, hCachedShader );
  617. }
  618. }
  619. // Destroy a particular vertex shader
  620. void DestroyVertexShader( VertexShader_t shader );
  621. // Destroy a particular pixel shader
  622. void DestroyPixelShader( PixelShader_t shader );
  623. bool LoadAndCreateShaders( ShaderLookup_t &lookup, bool bVertexShader, char *debugLabel = NULL );
  624. bool DoesShaderCRCMatchSourceCode( const char *pFileName, uint32 crc32, uint32 &sourceCRC );
  625. FileHandle_t OpenFileAndLoadHeader( const char *pFileName, ShaderHeader_t *pHeader );
  626. #ifdef DYNAMIC_SHADER_COMPILE
  627. bool ReadShaderSourceWithIncludes( const char *pShaderName, CUtlBuffer &bffr, bool bTryVshDirectory );
  628. bool LoadAndCreateShaders_Dynamic( ShaderLookup_t &lookup, bool bVertexShader );
  629. const ShaderCombos_t *FindOrCreateShaderCombos( const char *pShaderName );
  630. #ifdef _PS3
  631. bool CompileShaderPS3( const char *pShaderFilename, const char *pShaderModelForD3DX, const CUtlVector<D3DXMACRO> &macros, CUtlVector< uint8 > &compiledShader );
  632. #endif
  633. HardwareShader_t CompileShader( const char *pShaderName, unsigned int nStaticIndex, unsigned int nDynamicIndex, bool bVertexShader );
  634. #endif
  635. void DisassembleShader( ShaderLookup_t *pLookup, int dynamicCombo, uint8 *pByteCode );
  636. void WriteTranslatedFile( ShaderLookup_t *pLookup, int dynamicCombo, char *pFileContents, char *pFileExtension );
  637. // OSX only, no-op otherwise
  638. void SaveShaderCache( char *cacheName ); // query GLM pair cache for all active shader pairs and write them to disk in named file
  639. 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
  640. CUtlFixedLinkedList< ShaderLookup_t > m_VertexShaderDict;
  641. CUtlFixedLinkedList< ShaderLookup_t > m_PixelShaderDict;
  642. CUtlSymbolTable m_ShaderSymbolTable;
  643. #ifdef DYNAMIC_SHADER_COMPILE
  644. typedef HRESULT (__stdcall *ShaderCompileFromFileFunc_t)( LPCSTR pSrcFile, CONST D3DXMACRO* pDefines,
  645. LPD3DXINCLUDE pInclude, LPCSTR pFunctionName, LPCSTR pProfile, DWORD Flags,
  646. LPD3DXBUFFER* ppShader, LPD3DXBUFFER * ppErrorMsgs, LPD3DXCONSTANTTABLE * ppConstantTable );
  647. CUtlStringMap<ShaderCombos_t> m_ShaderNameToCombos;
  648. CSysModule *m_pShaderCompiler30;
  649. ShaderCompileFromFileFunc_t m_ShaderCompileFileFunc30;
  650. #endif
  651. // The current vertex and pixel shader
  652. HardwareShader_t m_HardwareVertexShader;
  653. HardwareShader_t m_HardwarePixelShader;
  654. CUtlFixedLinkedList< IDirect3DVertexShader9* > m_RawVertexShaderDict;
  655. CUtlFixedLinkedList< IDirect3DPixelShader9* > m_RawPixelShaderDict;
  656. CUtlFixedLinkedList< ShaderFileCache_t > m_ShaderFileCache;
  657. // false, creates during init.
  658. // true, creates on access, helps reduce d3d memory for tools, but causes i/o hitches.
  659. bool m_bCreateShadersOnDemand;
  660. #if defined( _DEBUG )
  661. // for debugging (can't resolve UtlSym)
  662. // need some history because 360 d3d has rips related to sequencing
  663. char vshDebugName[MAX_SHADER_HISTORY][64];
  664. int vshDebugIndex;
  665. char pshDebugName[MAX_SHADER_HISTORY][64];
  666. int pshDebugIndex;
  667. #endif
  668. #if defined ( DYNAMIC_SHADER_COMPILE ) && defined( REMOTE_DYNAMIC_SHADER_COMPILE )
  669. SOCKET m_RemoteShaderCompileSocket;
  670. #endif
  671. };
  672. //-----------------------------------------------------------------------------
  673. // Singleton accessor
  674. //-----------------------------------------------------------------------------
  675. static CShaderManager s_ShaderManager;
  676. IShaderManager *g_pShaderManager = &s_ShaderManager;
  677. //-----------------------------------------------------------------------------
  678. // Constructor, destructor
  679. //-----------------------------------------------------------------------------
  680. CShaderManager::CShaderManager() :
  681. m_ShaderSymbolTable( 0, 32, true /* caseInsensitive */ ),
  682. m_VertexShaderDict( 32 ),
  683. m_PixelShaderDict( 32 ),
  684. m_ShaderFileCache( 32 )
  685. {
  686. m_bCreateShadersOnDemand = false;
  687. #ifdef DYNAMIC_SHADER_COMPILE
  688. m_pShaderCompiler30 = 0;
  689. m_ShaderCompileFileFunc30 = 0;
  690. #ifdef REMOTE_DYNAMIC_SHADER_COMPILE
  691. m_RemoteShaderCompileSocket = INVALID_SOCKET;
  692. #endif
  693. #endif
  694. #ifdef _DEBUG
  695. vshDebugIndex = 0;
  696. pshDebugIndex = 0;
  697. #endif
  698. }
  699. CShaderManager::~CShaderManager()
  700. {
  701. #if defined ( DYNAMIC_SHADER_COMPILE ) && defined( REMOTE_DYNAMIC_SHADER_COMPILE )
  702. DeinitRemoteShaderCompile();
  703. #endif
  704. }
  705. #define REMOTE_SHADER_COMPILE_PORT "20000"
  706. #if defined ( DYNAMIC_SHADER_COMPILE ) && defined( REMOTE_DYNAMIC_SHADER_COMPILE )
  707. void CShaderManager::InitRemoteShaderCompile()
  708. {
  709. DeinitRemoteShaderCompile();
  710. struct addrinfo hints;
  711. ZeroMemory( &hints, sizeof(hints) );
  712. hints.ai_family = AF_UNSPEC;
  713. hints.ai_socktype = SOCK_STREAM;
  714. hints.ai_protocol = IPPROTO_TCP;
  715. // Resolve the server address and port
  716. struct addrinfo *result = NULL;
  717. int nResult = getaddrinfo( mat_remoteshadercompile.GetString(), REMOTE_SHADER_COMPILE_PORT, &hints, &result );
  718. if ( nResult != 0 )
  719. {
  720. DevWarning( "getaddrinfo failed: %d\n", nResult );
  721. Assert( 0 );
  722. }
  723. // Attempt to connect to an address until one succeeds
  724. for( struct addrinfo *ptr = result; ptr != NULL; ptr = ptr->ai_next )
  725. {
  726. // Create a SOCKET for connecting to remote shader compilation server
  727. m_RemoteShaderCompileSocket = socket( ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol );
  728. if ( m_RemoteShaderCompileSocket == INVALID_SOCKET )
  729. {
  730. DevWarning( "Error at socket(): %ld\n", WSAGetLastError() );
  731. freeaddrinfo( result );
  732. Assert( 0 );
  733. continue;
  734. }
  735. // Connect to server.
  736. nResult = connect( m_RemoteShaderCompileSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
  737. if ( nResult == SOCKET_ERROR )
  738. {
  739. closesocket( m_RemoteShaderCompileSocket );
  740. m_RemoteShaderCompileSocket = INVALID_SOCKET;
  741. continue;
  742. }
  743. break;
  744. }
  745. freeaddrinfo( result );
  746. if ( m_RemoteShaderCompileSocket == INVALID_SOCKET )
  747. {
  748. DevWarning( "Unable to connect to remote shader compilation server!\n" );
  749. Assert ( 0 );
  750. }
  751. }
  752. void CShaderManager::DeinitRemoteShaderCompile()
  753. {
  754. if ( m_RemoteShaderCompileSocket != INVALID_SOCKET )
  755. {
  756. if ( shutdown( m_RemoteShaderCompileSocket, SD_SEND ) == SOCKET_ERROR )
  757. {
  758. DevWarning( "Remote shader compilation shutdown failed: %d\n", WSAGetLastError() );
  759. }
  760. closesocket( m_RemoteShaderCompileSocket );
  761. m_RemoteShaderCompileSocket = INVALID_SOCKET;
  762. }
  763. }
  764. #endif
  765. //-----------------------------------------------------------------------------
  766. // Syncs shader cache directory
  767. //-----------------------------------------------------------------------------
  768. #ifdef DYNAMIC_SHADER_COMPILE
  769. static void SyncShaderCache()
  770. {
  771. #if defined( _X360 )
  772. XBX_rSyncShaderCache();
  773. #elif defined ( _PS3 )
  774. // Nothing needs to be done here - we're using a junction link to map src\materialsystem\stdshaders to the bdvd\stdshaders directory.
  775. #endif
  776. }
  777. #endif // DYNAMIC_SHADER_COMPILE
  778. //-----------------------------------------------------------------------------
  779. // Initialization, shutdown
  780. //-----------------------------------------------------------------------------
  781. void CShaderManager::Init()
  782. {
  783. // incompatible with the 360, violates loading system
  784. // only used by PC to help tools reduce d3d footprint
  785. m_bCreateShadersOnDemand = IsPC() && ( ShaderUtil()->InEditorMode() || CommandLine()->CheckParm( "-shadersondemand" ) );
  786. #ifdef DYNAMIC_SHADER_COMPILE
  787. #ifndef PLATFORM_PS3
  788. if( !IsX360() )
  789. {
  790. #if !defined( DX_TO_GL_ABSTRACTION )
  791. #ifdef _DEBUG
  792. m_pShaderCompiler30 = Sys_LoadModule( "d3dx9d_43.dll" );
  793. #endif
  794. if (!m_pShaderCompiler30)
  795. {
  796. m_pShaderCompiler30 = Sys_LoadModule( "d3dx9_43.dll" );
  797. }
  798. if ( m_pShaderCompiler30 )
  799. {
  800. m_ShaderCompileFileFunc30 = (ShaderCompileFromFileFunc_t)GetProcAddress( (HMODULE)m_pShaderCompiler30, "D3DXCompileShaderFromFileA" );
  801. }
  802. #else
  803. m_pShaderCompiler30 = NULL;
  804. m_ShaderCompileFileFunc30 = NULL;
  805. #endif
  806. #ifdef REMOTE_DYNAMIC_SHADER_COMPILE
  807. InitRemoteShaderCompile();
  808. #endif // REMOTE_DYNAMIC_SHADER_COMPILE
  809. }
  810. #endif
  811. #endif // DYNAMIC_SHADER_COMPILE
  812. CreateStaticShaders();
  813. #if defined( DYNAMIC_SHADER_COMPILE )
  814. // sync the shader cache in case dynamic shader compile is enabled
  815. SyncShaderCache();
  816. #endif
  817. }
  818. void CShaderManager::Shutdown()
  819. {
  820. #if defined( DYNAMIC_SHADER_COMPILE ) && !defined( DX_TO_GL_ABSTRACTION )
  821. if ( m_pShaderCompiler30 )
  822. {
  823. Sys_UnloadModule( m_pShaderCompiler30 );
  824. m_pShaderCompiler30 = 0;
  825. m_ShaderCompileFileFunc30 = 0;
  826. }
  827. #endif
  828. #ifdef DX_TO_GL_ABSTRACTION
  829. if (mat_autosave_glshaders.GetInt())
  830. {
  831. #if defined( OSX )
  832. SaveShaderCache("glshaders_OSX.cfg");
  833. #else
  834. SaveShaderCache("glshaders.cfg");
  835. #endif
  836. }
  837. #endif
  838. DestroyAllShaders();
  839. DestroyStaticShaders();
  840. }
  841. //-----------------------------------------------------------------------------
  842. // Compiles shaders
  843. //-----------------------------------------------------------------------------
  844. IShaderBuffer *CShaderManager::CompileShader( const char *pProgram, size_t nBufLen, const char *pShaderVersion )
  845. {
  846. #if defined( DYNAMIC_SHADER_COMPILE ) || !defined( _X360 )
  847. int nCompileFlags = D3DXSHADER_AVOID_FLOW_CONTROL;
  848. #ifdef _DEBUG
  849. nCompileFlags |= D3DXSHADER_DEBUG;
  850. #endif
  851. LPD3DXBUFFER pCompiledShader, pErrorMessages;
  852. HRESULT hr = D3DXCompileShader( pProgram, nBufLen,
  853. NULL, NULL, "main", pShaderVersion, nCompileFlags,
  854. &pCompiledShader, &pErrorMessages, NULL );
  855. if ( FAILED( hr ) )
  856. {
  857. if ( pErrorMessages )
  858. {
  859. const char *pErrorMessage = (const char *)pErrorMessages->GetBufferPointer();
  860. DevWarning( "Shader compilation failed! Reported the following errors:\n%s\n", pErrorMessage );
  861. pErrorMessages->Release();
  862. }
  863. return NULL;
  864. }
  865. // NOTE: This uses small block heap allocator; so I'm not going
  866. // to bother creating a memory pool.
  867. CShaderBuffer< ID3DXBuffer > *pShaderBuffer = new CShaderBuffer< ID3DXBuffer >( pCompiledShader );
  868. if ( pErrorMessages )
  869. {
  870. pErrorMessages->Release();
  871. }
  872. return pShaderBuffer;
  873. #else // !DYNAMIC_SHADER_COMPILE && _X360
  874. DevWarning( "ERROR: CompileShader called in a non-DYNAMIC_SHADER_COMPILE build!\n" );
  875. DebuggerBreak();
  876. return NULL;
  877. #endif // DYNAMIC_SHADER_COMPILE || !_X360
  878. }
  879. VertexShaderHandle_t CShaderManager::CreateVertexShader( IShaderBuffer* pShaderBuffer )
  880. {
  881. // Create the vertex shader
  882. IDirect3DVertexShader9 *pVertexShader = NULL;
  883. #ifdef _X360
  884. HRESULT hr = Dx9Device()->CreateVertexShader( (const DWORD*)pShaderBuffer->GetBits(), &pVertexShader );
  885. #else
  886. HRESULT hr = Dx9Device()->CreateVertexShader( (const DWORD*)pShaderBuffer->GetBits(), &pVertexShader, NULL );
  887. #endif
  888. if ( FAILED( hr ) || !pVertexShader )
  889. return VERTEX_SHADER_HANDLE_INVALID;
  890. s_NumVertexShadersCreated++;
  891. RegisterVS( pShaderBuffer->GetBits(), pShaderBuffer->GetSize(), pVertexShader );
  892. // Insert the shader into the dictionary of shaders
  893. VertexShaderIndex_t i = m_RawVertexShaderDict.AddToTail( pVertexShader );
  894. return (VertexShaderHandle_t)i;
  895. }
  896. void CShaderManager::DestroyVertexShader( VertexShaderHandle_t hShader )
  897. {
  898. if ( hShader == VERTEX_SHADER_HANDLE_INVALID )
  899. return;
  900. VertexShaderIndex_t i = (VertexShaderIndex_t)hShader;
  901. IDirect3DVertexShader9 *pVertexShader = m_RawVertexShaderDict[ i ];
  902. UnregisterVS( pVertexShader );
  903. VerifyEquals( pVertexShader->Release(), 0 );
  904. m_RawVertexShaderDict.Remove( i );
  905. }
  906. PixelShaderHandle_t CShaderManager::CreatePixelShader( IShaderBuffer* pShaderBuffer )
  907. {
  908. // Create the vertex shader
  909. IDirect3DPixelShader9 *pPixelShader = NULL;
  910. #if defined(_X360)
  911. HRESULT hr = Dx9Device()->CreatePixelShader( (const DWORD*)pShaderBuffer->GetBits(), &pPixelShader );
  912. #else
  913. HRESULT hr = Dx9Device()->CreatePixelShader( (const DWORD*)pShaderBuffer->GetBits(), &pPixelShader, NULL );
  914. #endif
  915. if ( FAILED( hr ) || !pPixelShader )
  916. return PIXEL_SHADER_HANDLE_INVALID;
  917. s_NumPixelShadersCreated++;
  918. RegisterPS( pShaderBuffer->GetBits(), pShaderBuffer->GetSize(), pPixelShader );
  919. // Insert the shader into the dictionary of shaders
  920. PixelShaderIndex_t i = m_RawPixelShaderDict.AddToTail( pPixelShader );
  921. return (PixelShaderHandle_t)i;
  922. }
  923. void CShaderManager::DestroyPixelShader( PixelShaderHandle_t hShader )
  924. {
  925. if ( hShader == PIXEL_SHADER_HANDLE_INVALID )
  926. return;
  927. PixelShaderIndex_t i = (PixelShaderIndex_t)hShader;
  928. IDirect3DPixelShader9 *pPixelShader = m_RawPixelShaderDict[ i ];
  929. UnregisterPS( pPixelShader );
  930. VerifyEquals( pPixelShader->Release(), 0 );
  931. m_RawPixelShaderDict.Remove( i );
  932. }
  933. //-----------------------------------------------------------------------------
  934. // Globals
  935. //-----------------------------------------------------------------------------
  936. HardwareShader_t s_pIllegalMaterialPS = INVALID_HARDWARE_SHADER;
  937. //-----------------------------------------------------------------------------
  938. // Static methods
  939. //-----------------------------------------------------------------------------
  940. void CShaderManager::CreateStaticShaders()
  941. {
  942. MEM_ALLOC_D3D_CREDIT();
  943. if ( IsPC() )
  944. {
  945. // GR - hack for illegal materials
  946. const DWORD psIllegalMaterial[] =
  947. {
  948. #ifdef DX_TO_GL_ABSTRACTION
  949. // Use a PS 2.0 binary shader on POSIX
  950. 0xffff0200, 0x05000051, 0xa00f0000, 0x3f800000,
  951. 0x00000000, 0x3f800000, 0x3f800000, 0x02000001,
  952. 0x800f0000, 0xa0e40000, 0x02000001, 0x800f0800,
  953. 0x80e40000, 0x0000ffff
  954. #else
  955. 0xffff0101, 0x00000051, 0xa00f0000, 0x00000000, 0x3f800000, 0x00000000,
  956. 0x3f800000, 0x00000001, 0x800f0000, 0xa0e40000, 0x0000ffff
  957. #endif
  958. };
  959. // create default shader
  960. #if defined(_X360)
  961. Dx9Device()->CreatePixelShader( psIllegalMaterial, ( IDirect3DPixelShader9 ** )&s_pIllegalMaterialPS );
  962. #else
  963. Dx9Device()->CreatePixelShader( psIllegalMaterial, ( IDirect3DPixelShader9 ** )&s_pIllegalMaterialPS, NULL );
  964. #endif
  965. }
  966. }
  967. void CShaderManager::DestroyStaticShaders()
  968. {
  969. // GR - invalid material hack
  970. // destroy internal shader
  971. if ( s_pIllegalMaterialPS != INVALID_HARDWARE_SHADER )
  972. {
  973. ( ( IDirect3DPixelShader9 * )s_pIllegalMaterialPS )->Release();
  974. s_pIllegalMaterialPS = INVALID_HARDWARE_SHADER;
  975. }
  976. }
  977. #ifdef DYNAMIC_SHADER_COMPILE
  978. static const char *GetShaderSourcePath( void )
  979. {
  980. static char shaderDir[MAX_PATH];
  981. // GR - just in case init this...
  982. static bool bHaveShaderDir = false;
  983. if( !bHaveShaderDir )
  984. {
  985. bHaveShaderDir = true;
  986. # if ( defined( DYNAMIC_SHADER_COMPILE_CUSTOM_PATH ) )
  987. {
  988. Q_strncpy( shaderDir, DYNAMIC_SHADER_COMPILE_CUSTOM_PATH, MAX_PATH );
  989. }
  990. # else
  991. {
  992. # if ( defined( _X360 ) )
  993. {
  994. Q_snprintf( shaderDir, MAX_PATH, "d:\\shadercache" );
  995. }
  996. # elif ( defined (_PS3) )
  997. {
  998. Q_snprintf( shaderDir, MAX_PATH, "/app_home/src/materialsystem/stdshaders" );
  999. }
  1000. # else
  1001. {
  1002. Q_strncpy( shaderDir, __FILE__, MAX_PATH );
  1003. Q_StripFilename( shaderDir );
  1004. Q_StripLastDir( shaderDir, MAX_PATH );
  1005. Q_strncat( shaderDir, "stdshaders", MAX_PATH, COPY_ALL_CHARACTERS );
  1006. }
  1007. # endif
  1008. }
  1009. # endif
  1010. }
  1011. return shaderDir;
  1012. }
  1013. #endif // DYNAMIC_SHADER_COMPILE
  1014. #ifdef DYNAMIC_SHADER_COMPILE
  1015. #define MAX_INCLUDE_STACK_DEPTH 10
  1016. // for linked lists of strings
  1017. struct StringNode_t
  1018. {
  1019. StringNode_t *m_pNext;
  1020. StringNode_t *m_pPrev;
  1021. char m_Text[1]; // the string data
  1022. };
  1023. static StringNode_t *MakeStrNode( char const *pStr )
  1024. {
  1025. int nLen = strlen( pStr );
  1026. StringNode_t *nRet = ( StringNode_t * ) new uint8[sizeof( StringNode_t ) + nLen ];
  1027. strcpy( nRet->m_Text, pStr );
  1028. return nRet;
  1029. }
  1030. static bool ReadTextFile( const char *pFilename, const char *pPath, CUtlBuffer &buffer )
  1031. {
  1032. bool bSuccess;
  1033. buffer.SetBufferType( true, false );
  1034. #ifdef PLATFORM_PS3
  1035. CUtlBuffer tmpBuf;
  1036. tmpBuf.SetBufferType( true, true );
  1037. bSuccess = g_pFullFileSystem->ReadFile( pFilename, pPath, tmpBuf );
  1038. if ( bSuccess )
  1039. {
  1040. if ( !tmpBuf.ConvertCRLF( buffer ) )
  1041. {
  1042. buffer = tmpBuf;
  1043. }
  1044. }
  1045. #else
  1046. bSuccess = g_pFullFileSystem->ReadFile( pFilename, pPath, buffer );
  1047. #endif
  1048. return bSuccess;
  1049. }
  1050. // read a whole file into a cutlbuffer while expanding #includes.
  1051. // FIXME: Could be moved to common code to be generally useful, but needs more thought put into include paths.
  1052. static bool ReadTextFileWithIncludes( const char *pFilename, const char *pPath, CUtlBuffer &buffer )
  1053. {
  1054. CUtlBuffer pFileStack[MAX_INCLUDE_STACK_DEPTH];
  1055. int nSP = ARRAYSIZE( pFileStack );
  1056. CUtlIntrusiveDListWithTailPtr<StringNode_t> fileLines; // tail ptr for fast adds
  1057. int nTotalFileBytes = 0;
  1058. // push
  1059. nSP--;
  1060. if ( !ReadTextFile( pFilename, pPath, pFileStack[nSP] ) )
  1061. return false;
  1062. while( nSP < ARRAYSIZE( pFileStack ) )
  1063. {
  1064. // read lines
  1065. for(;;)
  1066. {
  1067. char lineBuffer[2048];
  1068. pFileStack[nSP].GetLine( lineBuffer, sizeof( lineBuffer ) );
  1069. if ( !pFileStack[nSP].IsValid() )
  1070. {
  1071. break;
  1072. }
  1073. char *ln = lineBuffer;
  1074. ln += strspn( ln, "\t " ); // skip white space
  1075. if ( memcmp( ln, "#include", 8 ) == 0 )
  1076. {
  1077. // omg, an include
  1078. ln += 8;
  1079. ln += strspn( ln, " \t\"<" ); // skip whitespace, ", and <
  1080. int nPathNameLength = strcspn( ln, " \t\">\n" );
  1081. if ( !nPathNameLength )
  1082. {
  1083. Error( "bad include %s via %s\n", lineBuffer, pFilename );
  1084. }
  1085. ln[nPathNameLength] = 0; // kill everything after end of filename
  1086. char incfilename[MAX_PATH];
  1087. V_strncpy( incfilename, GetShaderSourcePath(), sizeof( incfilename ) );
  1088. V_strncat( incfilename, CORRECT_PATH_SEPARATOR_S, sizeof( incfilename ) );
  1089. V_strncat( incfilename, ln, sizeof( incfilename ) );
  1090. nSP--;
  1091. if ( !ReadTextFile( incfilename, pPath, pFileStack[nSP] ) )
  1092. {
  1093. Error( "can't open #include of %s\n", ln );
  1094. }
  1095. if ( !nSP )
  1096. {
  1097. Error( "include nesting too deep via %s", pFilename );
  1098. }
  1099. }
  1100. else
  1101. {
  1102. int nLen = strlen( lineBuffer );
  1103. nTotalFileBytes += nLen;
  1104. StringNode_t *pNewLine = MakeStrNode( lineBuffer );
  1105. fileLines.AddToTail( pNewLine );
  1106. }
  1107. }
  1108. pFileStack[nSP].Purge();
  1109. pFileStack[nSP].SetBufferType( true, false );
  1110. nSP++; // pop stack
  1111. }
  1112. buffer.EnsureCapacity( nTotalFileBytes + 1); // and NULL
  1113. // copy all strings and null terminate
  1114. int nLine = 0;
  1115. for( StringNode_t *i = fileLines.m_pHead; i ; i = i->m_pNext )
  1116. {
  1117. int nLen = strlen( i->m_Text );
  1118. buffer.Put( i->m_Text, nLen );
  1119. nLine++;
  1120. }
  1121. buffer.Put( "\0", 1 );
  1122. fileLines.Purge();
  1123. return true;
  1124. }
  1125. bool CShaderManager::ReadShaderSourceWithIncludes( const char *pShaderName, CUtlBuffer &bffr, bool bTryVshDirectory )
  1126. {
  1127. char filename[MAX_PATH];
  1128. bffr.SetBufferType( true, false );
  1129. if ( bTryVshDirectory )
  1130. {
  1131. // try the vsh dir first.
  1132. Q_strncpy( filename, GetShaderSourcePath(), MAX_PATH );
  1133. Q_strncat( filename, CORRECT_PATH_SEPARATOR_S, MAX_PATH, COPY_ALL_CHARACTERS );
  1134. Q_strncat( filename, pShaderName, MAX_PATH, COPY_ALL_CHARACTERS );
  1135. Q_strncat( filename, ".vsh", MAX_PATH, COPY_ALL_CHARACTERS );
  1136. if ( ReadTextFileWithIncludes( filename, NULL, bffr ) )
  1137. return true;
  1138. }
  1139. // try the fxc dir.
  1140. Q_strncpy( filename, GetShaderSourcePath(), MAX_PATH );
  1141. Q_strncat( filename, CORRECT_PATH_SEPARATOR_S, MAX_PATH, COPY_ALL_CHARACTERS );
  1142. Q_strncat( filename, pShaderName, MAX_PATH, COPY_ALL_CHARACTERS );
  1143. Q_strncat( filename, ".fxc", MAX_PATH, COPY_ALL_CHARACTERS );
  1144. if ( ReadTextFileWithIncludes( filename, NULL, bffr ) )
  1145. return true;
  1146. // Maybe this is a specific version [20 & 20b] -> [2x]
  1147. if ( Q_strlen( pShaderName ) >= 3 )
  1148. {
  1149. char *pszEndFilename = filename + strlen( filename );
  1150. if ( !Q_stricmp( pszEndFilename - 6, "30.fxc" ) )
  1151. {
  1152. // Total hack. Who knows what builds that 30 shader?
  1153. strcpy( pszEndFilename - 6, "20b.fxc" );
  1154. if ( ReadTextFileWithIncludes( filename, NULL, bffr ) )
  1155. return true;
  1156. strcpy( pszEndFilename - 6, "2x.fxc" );
  1157. if ( ReadTextFileWithIncludes( filename, NULL, bffr ) )
  1158. return true;
  1159. strcpy( pszEndFilename - 6, "20.fxc" );
  1160. if ( ReadTextFileWithIncludes( filename, NULL, bffr ) )
  1161. return true;
  1162. }
  1163. else
  1164. {
  1165. if ( !stricmp( pszEndFilename - 6, "20.fxc" ) )
  1166. {
  1167. pszEndFilename[ -5 ] = 'x';
  1168. }
  1169. else if ( !stricmp( pszEndFilename - 7, "20b.fxc" ) )
  1170. {
  1171. strcpy( pszEndFilename - 7, "2x.fxc" );
  1172. --pszEndFilename;
  1173. }
  1174. else if ( !stricmp( pszEndFilename - 6, "11.fxc" ) )
  1175. {
  1176. strcpy( pszEndFilename - 6, "xx.fxc" );
  1177. }
  1178. if ( ReadTextFileWithIncludes( filename, NULL, bffr ) )
  1179. return true;
  1180. if ( !stricmp( pszEndFilename - 6, "2x.fxc" ) )
  1181. {
  1182. pszEndFilename[ -6 ] = 'x';
  1183. if ( ReadTextFileWithIncludes( filename, NULL, bffr ) )
  1184. return true;
  1185. }
  1186. }
  1187. }
  1188. return false;
  1189. }
  1190. const CShaderManager::ShaderCombos_t *CShaderManager::FindOrCreateShaderCombos( const char *pShaderName )
  1191. {
  1192. if( m_ShaderNameToCombos.Defined( pShaderName ) )
  1193. {
  1194. return &m_ShaderNameToCombos[pShaderName];
  1195. }
  1196. ShaderCombos_t &combos = m_ShaderNameToCombos[pShaderName];
  1197. char filename[MAX_PATH];
  1198. // try the vsh dir first.
  1199. Q_strncpy( filename, GetShaderSourcePath(), MAX_PATH );
  1200. Q_strncat( filename, CORRECT_PATH_SEPARATOR_S, MAX_PATH, COPY_ALL_CHARACTERS );
  1201. Q_strncat( filename, pShaderName, MAX_PATH, COPY_ALL_CHARACTERS );
  1202. Q_strncat( filename, ".vsh", MAX_PATH, COPY_ALL_CHARACTERS );
  1203. CUtlInplaceBuffer bffr( 0, 0, CUtlInplaceBuffer::TEXT_BUFFER );
  1204. bool bOpenResult = ReadTextFileWithIncludes( filename, NULL, bffr );
  1205. if ( bOpenResult )
  1206. {
  1207. NULL;
  1208. }
  1209. else
  1210. {
  1211. // try the fxc dir.
  1212. Q_strncpy( filename, GetShaderSourcePath(), MAX_PATH );
  1213. Q_strncat( filename, CORRECT_PATH_SEPARATOR_S, MAX_PATH, COPY_ALL_CHARACTERS );
  1214. Q_strncat( filename, pShaderName, MAX_PATH, COPY_ALL_CHARACTERS );
  1215. Q_strncat( filename, ".fxc", MAX_PATH, COPY_ALL_CHARACTERS );
  1216. bOpenResult = ReadTextFileWithIncludes( filename, NULL, bffr );
  1217. if ( !bOpenResult )
  1218. {
  1219. // Maybe this is a specific version [20 & 20b] -> [2x]
  1220. if ( Q_strlen( pShaderName ) >= 3 )
  1221. {
  1222. char *pszEndFilename = filename + strlen( filename );
  1223. if ( !Q_stricmp( pszEndFilename - 6, "30.fxc" ) )
  1224. {
  1225. // Total hack. Who knows what builds that 30 shader?
  1226. strcpy( pszEndFilename - 6, "20b.fxc" );
  1227. bOpenResult = ReadTextFileWithIncludes( filename, NULL, bffr );
  1228. if ( !bOpenResult )
  1229. {
  1230. strcpy( pszEndFilename - 6, "2x.fxc" );
  1231. bOpenResult = ReadTextFileWithIncludes( filename, NULL, bffr );
  1232. }
  1233. if ( !bOpenResult )
  1234. {
  1235. strcpy( pszEndFilename - 6, "20.fxc" );
  1236. bOpenResult = ReadTextFileWithIncludes( filename, NULL, bffr );
  1237. }
  1238. }
  1239. else
  1240. {
  1241. if ( !stricmp( pszEndFilename - 6, "20.fxc" ) )
  1242. {
  1243. pszEndFilename[ -5 ] = 'x';
  1244. }
  1245. else if ( !stricmp( pszEndFilename - 7, "20b.fxc" ) )
  1246. {
  1247. strcpy( pszEndFilename - 7, "2x.fxc" );
  1248. --pszEndFilename;
  1249. }
  1250. else if ( !stricmp( pszEndFilename - 6, "11.fxc" ) )
  1251. {
  1252. strcpy( pszEndFilename - 6, "xx.fxc" );
  1253. }
  1254. bOpenResult = ReadTextFileWithIncludes( filename, NULL, bffr );
  1255. if ( !bOpenResult )
  1256. {
  1257. if ( !stricmp( pszEndFilename - 6, "2x.fxc" ) )
  1258. {
  1259. pszEndFilename[ -6 ] = 'x';
  1260. bOpenResult = ReadTextFileWithIncludes( filename, NULL, bffr );
  1261. }
  1262. }
  1263. }
  1264. }
  1265. }
  1266. if ( !bOpenResult )
  1267. {
  1268. Assert( 0 );
  1269. return NULL;
  1270. }
  1271. }
  1272. while( char *line = bffr.InplaceGetLinePtr() )
  1273. {
  1274. // dear god perl is better at this kind of shit!
  1275. int begin = 0;
  1276. int end = 0;
  1277. // check if the line starts with '//'
  1278. if( line[0] != '/' || line[1] != '/' )
  1279. {
  1280. continue;
  1281. }
  1282. // Check if line intended for platform lines
  1283. if ( IsGameConsole() )
  1284. {
  1285. if ( Q_stristr( line, "[PC]" ) )
  1286. continue;
  1287. if ( IsPS3() )
  1288. {
  1289. if ( Q_stristr( line, "[360]" ) || Q_stristr( line, "[XBOX]" ) || Q_stristr( line, "[!SONYPS3]" ) )
  1290. continue;
  1291. }
  1292. else if ( IsX360() )
  1293. {
  1294. if ( Q_stristr( line, "[SONYPS3]" ) )
  1295. continue;
  1296. }
  1297. }
  1298. else
  1299. {
  1300. if ( Q_stristr( line, "[360]" ) || Q_stristr( line, "[XBOX]" ) || Q_stristr( line, "[SONYPS3]" ) || Q_stristr( line, "[CONSOLE]" ) )
  1301. continue;
  1302. }
  1303. // Skip SFM combos
  1304. if ( 1 ) // Change this to 0 if fxc_prep.pl disables [SFM]
  1305. {
  1306. // [SFM] enabled in fxc_prep.pl
  1307. if ( Q_stristr( line, "[!SFM]" ) )
  1308. {
  1309. continue;
  1310. }
  1311. }
  1312. else
  1313. {
  1314. // [SFM] disabled in fxc_prep.pl
  1315. if ( Q_stristr( line, "[SFM]" ) )
  1316. {
  1317. continue;
  1318. }
  1319. }
  1320. // Skip any lines intended for other shader version
  1321. if ( Q_stristr( pShaderName, "_ps20" ) && !Q_stristr( pShaderName, "_ps20b" ) &&
  1322. Q_stristr( line, "[ps" ) && !Q_stristr( line, "[ps20]" ) )
  1323. continue;
  1324. if ( Q_stristr( pShaderName, "_ps20b" ) &&
  1325. Q_stristr( line, "[ps" ) && !Q_stristr( line, "[ps20b]" ) )
  1326. continue;
  1327. if ( Q_stristr( pShaderName, "_ps30" ) &&
  1328. Q_stristr( line, "[ps" ) && !Q_stristr( line, "[ps30]" ) )
  1329. continue;
  1330. if ( Q_stristr( pShaderName, "_vs20" ) &&
  1331. Q_stristr( line, "[vs" ) && !Q_stristr( line, "[vs20]" ) )
  1332. continue;
  1333. if ( Q_stristr( pShaderName, "_vs30" ) &&
  1334. Q_stristr( line, "[vs" ) && !Q_stristr( line, "[vs30]" ) )
  1335. continue;
  1336. char *pScan = &line[2];
  1337. while( *pScan == ' ' || *pScan == '\t' )
  1338. {
  1339. pScan++;
  1340. }
  1341. bool bDynamic;
  1342. if( Q_strncmp( pScan, "DYNAMIC", 7 ) == 0 )
  1343. {
  1344. bDynamic = true;
  1345. pScan += 7;
  1346. }
  1347. else if( Q_strncmp( pScan, "STATIC", 6 ) == 0 )
  1348. {
  1349. bDynamic = false;
  1350. pScan += 6;
  1351. }
  1352. else
  1353. {
  1354. continue;
  1355. }
  1356. // skip whitespace
  1357. while( *pScan == ' ' || *pScan == '\t' )
  1358. {
  1359. pScan++;
  1360. }
  1361. // check for colon
  1362. if( *pScan != ':' )
  1363. {
  1364. continue;
  1365. }
  1366. pScan++;
  1367. // skip whitespace
  1368. while( *pScan == ' ' || *pScan == '\t' )
  1369. {
  1370. pScan++;
  1371. }
  1372. // check for quote
  1373. if( *pScan != '\"' )
  1374. {
  1375. continue;
  1376. }
  1377. pScan++;
  1378. char *pBeginningOfName = pScan;
  1379. while( 1 )
  1380. {
  1381. if( *pScan == '\0' )
  1382. {
  1383. break;
  1384. }
  1385. if( *pScan == '\"' )
  1386. {
  1387. break;
  1388. }
  1389. pScan++;
  1390. }
  1391. if( *pScan == '\0' )
  1392. {
  1393. continue;
  1394. }
  1395. // must have hit a quote. .done with string.
  1396. // slam a NULL at the end quote of the string so that we have the string at pBeginningOfName.
  1397. *pScan = '\0';
  1398. pScan++;
  1399. // skip whitespace
  1400. while( *pScan == ' ' || *pScan == '\t' )
  1401. {
  1402. pScan++;
  1403. }
  1404. // check for quote
  1405. if( *pScan != '\"' )
  1406. {
  1407. continue;
  1408. }
  1409. pScan++;
  1410. // make sure that we have a number after the quote.
  1411. if( !V_isdigit( *pScan ) )
  1412. {
  1413. continue;
  1414. }
  1415. while( V_isdigit( *pScan ) )
  1416. {
  1417. begin = begin * 10 + ( *pScan - '0' );
  1418. pScan++;
  1419. }
  1420. if( pScan[0] != '.' || pScan[1] != '.' )
  1421. {
  1422. continue;
  1423. }
  1424. pScan += 2;
  1425. // make sure that we have a number
  1426. if( !V_isdigit( *pScan ) )
  1427. {
  1428. continue;
  1429. }
  1430. while( V_isdigit( *pScan ) )
  1431. {
  1432. end = end * 10 + ( *pScan - '0' );
  1433. pScan++;
  1434. }
  1435. if( pScan[0] != '\"' )
  1436. {
  1437. continue;
  1438. }
  1439. // sweet freaking jesus. .done parsing the line.
  1440. // char buf[1024];
  1441. // sprintf( buf, "\"%s\" \"%s\" %d %d\n", bDynamic ? "DYNAMIC" : "STATIC", pBeginningOfName, begin, end );
  1442. // Plat_DebugString( buf );
  1443. Combo_t *pCombo = NULL;
  1444. if( bDynamic )
  1445. {
  1446. pCombo = &combos.m_DynamicCombos[combos.m_DynamicCombos.AddToTail()];
  1447. }
  1448. else
  1449. {
  1450. pCombo = &combos.m_StaticCombos[combos.m_StaticCombos.AddToTail()];
  1451. }
  1452. pCombo->m_ComboName = m_ShaderSymbolTable.AddString( pBeginningOfName );
  1453. pCombo->m_nMin = begin;
  1454. pCombo->m_nMax = end;
  1455. }
  1456. return &combos;
  1457. }
  1458. #endif // DYNAMIC_SHADER_COMPILE
  1459. #ifdef DYNAMIC_SHADER_COMPILE
  1460. #ifndef DX_TO_GL_ABSTRACTION
  1461. //-----------------------------------------------------------------------------
  1462. // Used to deal with include files
  1463. //-----------------------------------------------------------------------------
  1464. class CDxInclude : public ID3DXInclude
  1465. {
  1466. public:
  1467. CDxInclude( const char *pMainFileName );
  1468. #if defined( _X360 )
  1469. virtual HRESULT WINAPI Open( D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID * ppData, UINT * pBytes, LPSTR pFullPath, DWORD cbFullPath );
  1470. #else
  1471. virtual HRESULT WINAPI Open( D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID * ppData, UINT * pBytes );
  1472. #endif
  1473. virtual HRESULT WINAPI Close( LPCVOID pData );
  1474. private:
  1475. char m_pBasePath[MAX_PATH];
  1476. #if defined( _X360 )
  1477. char m_pFullPath[MAX_PATH];
  1478. #endif
  1479. };
  1480. CDxInclude::CDxInclude( const char *pMainFileName )
  1481. {
  1482. Q_ExtractFilePath( pMainFileName, m_pBasePath, sizeof(m_pBasePath) );
  1483. }
  1484. #if defined( _X360 )
  1485. HRESULT CDxInclude::Open( D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID * ppData, UINT * pBytes, LPSTR pFullPath, DWORD cbFullPath )
  1486. #else
  1487. HRESULT CDxInclude::Open( D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID * ppData, UINT * pBytes )
  1488. #endif
  1489. {
  1490. char pTemp[MAX_PATH];
  1491. if ( !Q_IsAbsolutePath( pFileName ) && ( IncludeType == D3DXINC_LOCAL ) )
  1492. {
  1493. Q_ComposeFileName( m_pBasePath, pFileName, pTemp, sizeof(pTemp) );
  1494. pFileName = pTemp;
  1495. }
  1496. CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  1497. if ( !g_pFullFileSystem->ReadFile( pFileName, NULL, buf ) )
  1498. return E_FAIL;
  1499. *pBytes = buf.TellMaxPut();
  1500. void *pMem = malloc( *pBytes );
  1501. memcpy( pMem, buf.Base(), *pBytes );
  1502. *ppData = pMem;
  1503. # if ( defined( _X360 ) )
  1504. {
  1505. Q_ComposeFileName( m_pBasePath, pFileName, m_pFullPath, sizeof(m_pFullPath) );
  1506. pFullPath = m_pFullPath;
  1507. cbFullPath = MAX_PATH;
  1508. }
  1509. # endif
  1510. return S_OK;
  1511. }
  1512. HRESULT CDxInclude::Close( LPCVOID pData )
  1513. {
  1514. void *pMem = const_cast<void*>( pData );
  1515. free( pMem );
  1516. return S_OK;
  1517. }
  1518. #endif // not POSIX
  1519. static const char *FileNameToShaderModel( const char *pShaderName, bool bVertexShader )
  1520. {
  1521. // Figure out the shader model
  1522. const char *pShaderModel = NULL;
  1523. if( bVertexShader )
  1524. {
  1525. if( Q_stristr( pShaderName, "vs20" ) )
  1526. {
  1527. pShaderModel = "vs_2_0";
  1528. bVertexShader = true;
  1529. }
  1530. else if( Q_stristr( pShaderName, "vs11" ) )
  1531. {
  1532. pShaderModel = "vs_1_1";
  1533. bVertexShader = true;
  1534. }
  1535. else if( Q_stristr( pShaderName, "vs14" ) )
  1536. {
  1537. pShaderModel = "vs_1_1";
  1538. bVertexShader = true;
  1539. }
  1540. else if( Q_stristr( pShaderName, "vs30" ) )
  1541. {
  1542. pShaderModel = "vs_3_0";
  1543. bVertexShader = true;
  1544. }
  1545. else
  1546. {
  1547. #ifdef _DEBUG
  1548. Error( "Failed dynamic shader compiled\nBuild shaderapidx9.dll in debug to find problem\n" );
  1549. #else
  1550. Assert( 0 );
  1551. #endif
  1552. }
  1553. }
  1554. else
  1555. {
  1556. if( Q_stristr( pShaderName, "ps20b" ) )
  1557. {
  1558. pShaderModel = "ps_2_b";
  1559. }
  1560. else if( Q_stristr( pShaderName, "ps20" ) )
  1561. {
  1562. pShaderModel = "ps_2_0";
  1563. }
  1564. else if( Q_stristr( pShaderName, "ps11" ) )
  1565. {
  1566. pShaderModel = "ps_1_1";
  1567. }
  1568. else if( Q_stristr( pShaderName, "ps14" ) )
  1569. {
  1570. pShaderModel = "ps_1_4";
  1571. }
  1572. else if( Q_stristr( pShaderName, "ps30" ) )
  1573. {
  1574. pShaderModel = "ps_3_0";
  1575. }
  1576. else
  1577. {
  1578. #ifdef _DEBUG
  1579. Error( "Failed dynamic shader compiled\nBuild shaderapidx9.dll in debug to find problem\n" );
  1580. #else
  1581. Assert( 0 );
  1582. #endif
  1583. }
  1584. }
  1585. return pShaderModel;
  1586. }
  1587. #endif // DYNAMIC_SHADER_COMPILE
  1588. #ifdef DYNAMIC_SHADER_COMPILE
  1589. #if defined( _X360 )
  1590. static ConVar mat_flushshaders_generate_updbs( "mat_flushshaders_generate_updbs", "1", 0, "Generates UPDBs whenever you flush shaders." );
  1591. #endif
  1592. #ifdef _PS3
  1593. int CgcIncludeOpen( SCECGC_INCLUDE_TYPE type,
  1594. const char* filename,
  1595. char** data, size_t* size )
  1596. {
  1597. // We manually expand out all #include's form the shader source, so it's not necessary to do anything here.
  1598. *data = NULL;
  1599. *size = 0;
  1600. return 0;
  1601. }
  1602. int CgcIncludeClose( const char* data )
  1603. {
  1604. return 1;
  1605. }
  1606. int g_nCgAllocated;
  1607. void* CgMalloc( void* arg, size_t size ) // Memory allocation callback
  1608. {
  1609. g_nCgAllocated += size;
  1610. uint * pData = (uint*)malloc( size + sizeof( uint ) );
  1611. *pData = size;
  1612. return pData + 1;
  1613. }
  1614. void CgFree( void* arg, void* ptr ) // Memory freeing callback
  1615. {
  1616. uint * pData = ( ( uint* ) ptr ) - 1;
  1617. g_nCgAllocated -= *pData;
  1618. free( pData );
  1619. }
  1620. class CgContextWrapper
  1621. {
  1622. public:
  1623. CGCcontext *m_cgc;
  1624. CgContextWrapper( CGCmem *pMem )
  1625. {
  1626. m_cgc = sceCgcNewContext( pMem );
  1627. }
  1628. ~CgContextWrapper()
  1629. {
  1630. sceCgcDeleteContext( m_cgc );
  1631. }
  1632. operator CGCcontext * () { return m_cgc ; }
  1633. };
  1634. bool CShaderManager::CompileShaderPS3( const char *pShaderFilename, const char *pShaderModelForD3DX, const CUtlVector<D3DXMACRO> &macros, CUtlVector< uint8 > &compiledShader )
  1635. {
  1636. CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  1637. bool bReadShader = ReadShaderSourceWithIncludes( pShaderFilename, buf, false );
  1638. if ( !bReadShader )
  1639. {
  1640. DevMsg( 0, "Failed reading source shader file: %s\n", pShaderFilename );
  1641. DebuggerBreak();
  1642. return false;
  1643. }
  1644. char *pShaderSource = (char *)malloc( buf.Size() + 1 );
  1645. memcpy( pShaderSource, buf.Base(), buf.Size() );
  1646. pShaderSource[buf.Size()] = '\0';
  1647. CUtlVector< CUtlString > options;
  1648. for ( int i=0; i < ( macros.Count() - 1 ); i++ )
  1649. {
  1650. char buf[256];
  1651. V_snprintf( buf, sizeof( buf ), "-D%s=%s", macros[i].Name, macros[i].Definition );
  1652. options.AddToTail( CUtlString( buf ) );
  1653. }
  1654. options.AddToTail( CUtlString( "-O1" ) );
  1655. options.AddToTail( CUtlString( "-fastmath" ) );
  1656. options.AddToTail( CUtlString( "-inline" ) );
  1657. options.AddToTail( CUtlString( "all" ) );
  1658. const char ** ppOptions = (const char**)stackalloc( sizeof(char*) * ( options.Count() + 1 ) );
  1659. for( int i = 0; i < options.Count(); ++i )
  1660. ppOptions[i] = options[i].Get();
  1661. ppOptions[ options.Count() ] = NULL;
  1662. const char * pRsxProfile = pShaderModelForD3DX;
  1663. if( pShaderModelForD3DX[0] == 'v' )
  1664. {
  1665. pRsxProfile = "sce_vp_rsx";
  1666. }
  1667. else if( pShaderModelForD3DX[0] == 'p' )
  1668. {
  1669. pRsxProfile = "sce_fp_rsx";
  1670. }
  1671. CGCmem mem;
  1672. mem.malloc = CgMalloc;
  1673. mem.free = CgFree;
  1674. mem.arg = NULL;
  1675. CGCinclude incWrap;
  1676. incWrap.open = CgcIncludeOpen;
  1677. incWrap.close = CgcIncludeClose;
  1678. CgContextWrapper cgContext( &mem );
  1679. CGCbin *pCgCompiledShader = sceCgcNewBin( &mem );
  1680. CGCbin *pCgMessages = sceCgcNewBin( &mem );
  1681. CGCbin *pCgAcsiiOutput = sceCgcNewBin( &mem );
  1682. int nStatus = sceCgcCompileString( cgContext.m_cgc, pShaderSource, pRsxProfile, "main", ppOptions, pCgCompiledShader, pCgMessages, pCgAcsiiOutput, &incWrap );
  1683. if ( nStatus != SCECGC_OK )
  1684. {
  1685. DevMsg( 0, "Failed dynamic shader compiled - fix the shader while the debugger is at the breakpoint, then continue. (sceCgcCompileString status=%i.)\n", nStatus );
  1686. DevMsg( "Compiler messages:\n%s\n", (char*)sceCgcGetBinData( pCgMessages ) );
  1687. }
  1688. else
  1689. {
  1690. if ( sceCgcGetBinSize( pCgMessages ) > 1 )
  1691. {
  1692. DevMsg( "Compilation succeeded with compiler messages:\n%s\n", (char*)sceCgcGetBinData( pCgMessages ) );
  1693. }
  1694. compiledShader.SetCount( sceCgcGetBinSize( pCgCompiledShader ) );
  1695. memcpy( &compiledShader[0], sceCgcGetBinData( pCgCompiledShader ), sceCgcGetBinSize( pCgCompiledShader ) );
  1696. }
  1697. sceCgcDeleteBin( pCgCompiledShader );
  1698. pCgCompiledShader = NULL;
  1699. sceCgcDeleteBin( pCgMessages );
  1700. pCgMessages = NULL;
  1701. sceCgcDeleteBin( pCgAcsiiOutput );
  1702. pCgAcsiiOutput = NULL;
  1703. return nStatus == SCECGC_OK;
  1704. }
  1705. #endif // _PS3
  1706. HardwareShader_t CShaderManager::CompileShader( const char *pShaderName,
  1707. unsigned int nStaticIndex,
  1708. unsigned int nDynamicIndex,
  1709. bool bVertexShader )
  1710. {
  1711. VPROF_BUDGET( "CompileShader", "CompileShader" );
  1712. if ( !m_ShaderNameToCombos.Defined( pShaderName ) )
  1713. {
  1714. FindOrCreateShaderCombos( pShaderName );
  1715. }
  1716. const ShaderCombos_t &combos = m_ShaderNameToCombos[pShaderName];
  1717. #ifdef _DEBUG
  1718. unsigned int numStaticCombos = combos.GetNumStaticCombos();
  1719. unsigned int numDynamicCombos = combos.GetNumDynamicCombos();
  1720. Assert( nStaticIndex % numDynamicCombos == 0 );
  1721. Assert( ( nStaticIndex % numDynamicCombos ) >= 0 && ( nStaticIndex % numDynamicCombos ) < numStaticCombos );
  1722. Assert( nDynamicIndex >= 0 && nDynamicIndex < numDynamicCombos );
  1723. #endif
  1724. #ifdef DYNAMIC_SHADER_COMPILE_VERBOSE
  1725. bool bVerbose = true;
  1726. if ( V_strlen( mat_dynamic_shader_substring.GetString() ) > 0 )
  1727. {
  1728. if ( V_stristr( pShaderName, mat_dynamic_shader_substring.GetString() ) == NULL ) // If didn't find a match
  1729. {
  1730. bVerbose = false;
  1731. }
  1732. }
  1733. if ( bVerbose )
  1734. {
  1735. if ( bVertexShader )
  1736. ConColorMsg( Color( 0, 187, 255, 255 ), "Compiling VS - %s\n", pShaderName );
  1737. else
  1738. ConColorMsg( Color( 67, 217, 87, 255 ), "Compiling PS - %s\n", pShaderName );
  1739. }
  1740. #endif
  1741. CUtlVector<D3DXMACRO> macros;
  1742. // plus 1 for null termination, plus 1 for #define SHADER_MODEL_*, and plus 1 for #define _X360 on 360
  1743. macros.SetCount( combos.m_DynamicCombos.Count() + combos.m_StaticCombos.Count() + 2 + ( ( IsX360() || IsPS3() ) ? 1 : 0 ) );
  1744. // Loop over all dynamic combos first
  1745. unsigned int nCombo = nStaticIndex + nDynamicIndex;
  1746. int macroIndex = 0;
  1747. int i;
  1748. for ( i = 0; i < combos.m_DynamicCombos.Count(); i++ )
  1749. {
  1750. unsigned int countForCombo = combos.m_DynamicCombos[i].m_nMax - combos.m_DynamicCombos[i].m_nMin + 1;
  1751. unsigned int val = nCombo % countForCombo + combos.m_DynamicCombos[i].m_nMin;
  1752. nCombo /= countForCombo;
  1753. macros[macroIndex].Name = m_ShaderSymbolTable.String( combos.m_DynamicCombos[i].m_ComboName );
  1754. char buf[16];
  1755. sprintf( buf, "%d", val );
  1756. CUtlSymbol valSymbol( buf );
  1757. macros[macroIndex].Definition = valSymbol.String();
  1758. macroIndex++;
  1759. }
  1760. // Loop over all static combos and print combo info
  1761. #ifdef DYNAMIC_SHADER_COMPILE_VERBOSE
  1762. if ( bVerbose )
  1763. ConColorMsg( Color( 200, 200, 200, 255 ), "\tStatic:" );
  1764. #endif
  1765. for ( i = 0; i < combos.m_StaticCombos.Count(); i++ )
  1766. {
  1767. unsigned int countForCombo = combos.m_StaticCombos[i].m_nMax - combos.m_StaticCombos[i].m_nMin + 1;
  1768. unsigned int val = nCombo % countForCombo + combos.m_StaticCombos[i].m_nMin;
  1769. nCombo /= countForCombo;
  1770. macros[macroIndex].Name = m_ShaderSymbolTable.String( combos.m_StaticCombos[i].m_ComboName );
  1771. char buf[16];
  1772. sprintf( buf, "%d", val );
  1773. CUtlSymbol valSymbol( buf );
  1774. macros[macroIndex].Definition = valSymbol.String();
  1775. #ifdef DYNAMIC_SHADER_COMPILE_VERBOSE
  1776. if ( bVerbose )
  1777. {
  1778. #ifdef DYNAMIC_SHADER_COMPILE_THIN
  1779. if ( V_strcmp( macros[macroIndex].Definition, "0" ) != 0 ) // If not set to 0
  1780. #endif
  1781. {
  1782. if ( V_strcmp( macros[macroIndex].Definition, "0" ) == 0 )
  1783. {
  1784. ConColorMsg( Color( 200, 200, 200, 255 ), " %s=0", macros[macroIndex].Name );
  1785. }
  1786. else
  1787. {
  1788. ConColorMsg( Color( 255, 100, 100, 255 ), " %s", macros[macroIndex].Name );
  1789. ConColorMsg( Color( 200, 200, 200, 255 ), "=" );
  1790. ConColorMsg( Color( 255, 255, 255, 255 ), "%s", macros[macroIndex].Definition );
  1791. }
  1792. }
  1793. }
  1794. #endif
  1795. macroIndex++;
  1796. }
  1797. // Now print dynamic combo info
  1798. #ifdef DYNAMIC_SHADER_COMPILE_VERBOSE
  1799. if ( bVerbose )
  1800. {
  1801. ConColorMsg( Color( 200, 200, 200, 255 ), "\n\tDynamic:" );
  1802. for ( i = 0; i < combos.m_DynamicCombos.Count(); i++ )
  1803. {
  1804. int macroIndex = i;
  1805. #ifdef DYNAMIC_SHADER_COMPILE_THIN
  1806. if ( V_strcmp( macros[macroIndex].Definition, "0" ) != 0 ) // If not set to 0
  1807. #endif
  1808. {
  1809. if ( V_strcmp( macros[macroIndex].Definition, "0" ) == 0 )
  1810. {
  1811. ConColorMsg( Color( 200, 200, 200, 255 ), " %s=0", macros[macroIndex].Name );
  1812. }
  1813. else
  1814. {
  1815. ConColorMsg( Color( 255, 100, 100, 255 ), " %s", macros[macroIndex].Name );
  1816. ConColorMsg( Color( 200, 200, 200, 255 ), "=" );
  1817. ConColorMsg( Color( 255, 255, 255, 255 ), "%s", macros[macroIndex].Definition );
  1818. }
  1819. }
  1820. }
  1821. ConColorMsg( Color( 200, 200, 200, 255 ), "\n" );
  1822. }
  1823. #endif
  1824. char filename[MAX_PATH];
  1825. Q_strncpy( filename, GetShaderSourcePath(), MAX_PATH );
  1826. Q_strncat( filename, CORRECT_PATH_SEPARATOR_S, MAX_PATH, COPY_ALL_CHARACTERS );
  1827. Q_strncat( filename, pShaderName, MAX_PATH, COPY_ALL_CHARACTERS );
  1828. Q_strncat( filename, ".fxc", MAX_PATH, COPY_ALL_CHARACTERS );
  1829. const char *pShaderModel = FileNameToShaderModel( pShaderName, bVertexShader );
  1830. const char *pShaderModelForD3DX = pShaderModel;
  1831. if ( 0 == V_strcmp( pShaderModelForD3DX, "ps_2_0" ) )
  1832. {
  1833. // We compile the ps20 path with ps_2_b these days since we don't support ps20 anymore. Still want to get the perf and combo reduction of this path for low end.
  1834. pShaderModelForD3DX = "ps_2_b";
  1835. }
  1836. // define the shader model
  1837. char shaderModelDefineString[1024];
  1838. Q_snprintf( shaderModelDefineString, 1024, "SHADER_MODEL_%s", pShaderModel );
  1839. Q_strupr( shaderModelDefineString );
  1840. macros[macroIndex].Name = shaderModelDefineString;
  1841. macros[macroIndex].Definition = "1";
  1842. macroIndex++;
  1843. char platformDefineString[1024];
  1844. if( IsX360() || IsPS3() )
  1845. {
  1846. Q_snprintf( platformDefineString, 1024, IsPS3() ? "_PS3" : "_X360" );
  1847. Q_strupr( platformDefineString );
  1848. macros[macroIndex].Name = platformDefineString;
  1849. macros[macroIndex].Definition = "1";
  1850. macroIndex++;
  1851. }
  1852. // NULL terminate.
  1853. macros[macroIndex].Name = NULL;
  1854. macros[macroIndex].Definition = NULL;
  1855. // Instead of erroring out, infinite-loop on shader compilation
  1856. // (i.e. give developers a chance to fix the shader code w/out restarting the game)
  1857. int retriesLeft = 20;
  1858. retriesLeft;
  1859. #if defined( PLATFORM_PS3 ) || ( !defined( POSIX ) && !defined( _DEBUG ) )
  1860. retry_compile:
  1861. #endif
  1862. // Try and open the file to see if it exists
  1863. FileHandle_t fp = g_pFullFileSystem->Open( filename, "r" );
  1864. if ( fp == FILESYSTEM_INVALID_HANDLE )
  1865. {
  1866. // Maybe this is a specific version [20 & 20b] -> [2x]
  1867. if ( strlen( pShaderName ) >= 3 )
  1868. {
  1869. char *pszEndFilename = filename + strlen( filename );
  1870. if ( !Q_stricmp( pszEndFilename - 6, "30.fxc" ) )
  1871. {
  1872. strcpy( pszEndFilename - 6, "20b.fxc" );
  1873. fp = g_pFullFileSystem->Open( filename, "r" );
  1874. if ( fp == FILESYSTEM_INVALID_HANDLE )
  1875. {
  1876. strcpy( pszEndFilename - 6, "2x.fxc" );
  1877. fp = g_pFullFileSystem->Open( filename, "r" );
  1878. }
  1879. if ( fp == FILESYSTEM_INVALID_HANDLE )
  1880. {
  1881. strcpy( pszEndFilename - 6, "20.fxc" );
  1882. fp = g_pFullFileSystem->Open( filename, "r" );
  1883. }
  1884. }
  1885. else
  1886. {
  1887. if ( !Q_stricmp( pszEndFilename - 6, "20.fxc" ) )
  1888. {
  1889. pszEndFilename[ -5 ] = 'x';
  1890. fp = g_pFullFileSystem->Open( filename, "r" );
  1891. }
  1892. else if ( !Q_stricmp( pszEndFilename - 7, "20b.fxc" ) )
  1893. {
  1894. strcpy( pszEndFilename - 7, "2x.fxc" );
  1895. fp = g_pFullFileSystem->Open( filename, "r" );
  1896. }
  1897. else if ( !stricmp( pszEndFilename - 6, "11.fxc" ) )
  1898. {
  1899. strcpy( pszEndFilename - 6, "xx.fxc" );
  1900. fp = g_pFullFileSystem->Open( filename, "r" );
  1901. }
  1902. if ( fp == FILESYSTEM_INVALID_HANDLE )
  1903. {
  1904. if ( !stricmp( pszEndFilename - 6, "2x.fxc" ) )
  1905. {
  1906. pszEndFilename[ -6 ] = 'x';
  1907. fp = g_pFullFileSystem->Open( filename, "r" );
  1908. }
  1909. }
  1910. }
  1911. }
  1912. }
  1913. if ( fp != FILESYSTEM_INVALID_HANDLE )
  1914. {
  1915. g_pFullFileSystem->Close( fp );
  1916. }
  1917. #ifdef REMOTE_DYNAMIC_SHADER_COMPILE
  1918. #define SEND_BUF_SIZE 40000
  1919. #define RECV_BUF_SIZE 40000
  1920. // Remotely-compiled shader code
  1921. uint32 *pRemotelyCompiledShader = NULL;
  1922. uint32 nRemotelyCompiledShaderLength = 0;
  1923. static char pSendbuf[SEND_BUF_SIZE], pRecvbuf[RECV_BUF_SIZE], pFixedFilename[MAX_PATH], buf[MAX_PATH];
  1924. if ( m_RemoteShaderCompileSocket == INVALID_SOCKET )
  1925. {
  1926. InitRemoteShaderCompile();
  1927. }
  1928. // In this case, we're going to use a remote service to do our compiling
  1929. if ( m_RemoteShaderCompileSocket != INVALID_SOCKET )
  1930. {
  1931. // Build up command list for remote shader compiler
  1932. V_FixupPathName( pFixedFilename, MAX_PATH, filename );
  1933. V_FileBase( pFixedFilename, buf, MAX_PATH ); // Just find base filename
  1934. V_strncat( buf, ".fxc", MAX_PATH );
  1935. V_snprintf( pSendbuf, SEND_BUF_SIZE, "%s\n", buf );
  1936. V_strncat( pSendbuf, pShaderModel, SEND_BUF_SIZE );
  1937. V_strncat( pSendbuf, "\n", SEND_BUF_SIZE );
  1938. V_snprintf( buf, MAX_PATH, "%d\n", macros.Count() );
  1939. V_strncat( pSendbuf, buf, SEND_BUF_SIZE );
  1940. for ( int i=0; i < macros.Count(); i++ )
  1941. {
  1942. V_snprintf( buf, MAX_PATH, "%s\n%s\n", macros[i].Name, macros[i].Definition );
  1943. V_strncat( pSendbuf, buf, SEND_BUF_SIZE );
  1944. }
  1945. V_strncat( pSendbuf, "", SEND_BUF_SIZE );
  1946. // Send commands to remote shader compiler
  1947. int nResult = send( m_RemoteShaderCompileSocket, pSendbuf, (int)strlen( pSendbuf ), 0 );
  1948. if ( nResult == SOCKET_ERROR )
  1949. {
  1950. DevWarning( "send failed: %d\n", WSAGetLastError() );
  1951. DeinitRemoteShaderCompile();
  1952. }
  1953. if ( m_RemoteShaderCompileSocket != INVALID_SOCKET )
  1954. {
  1955. // Block here until we get a result back from the server
  1956. nResult = recv( m_RemoteShaderCompileSocket, pRecvbuf, RECV_BUF_SIZE, 0 );
  1957. if ( nResult == 0 )
  1958. {
  1959. DevWarning( "Connection closed\n" );
  1960. DeinitRemoteShaderCompile();
  1961. }
  1962. else if ( nResult < 0 )
  1963. {
  1964. DevWarning( "recv failed: %d\n", WSAGetLastError() );
  1965. DeinitRemoteShaderCompile();
  1966. }
  1967. if ( m_RemoteShaderCompileSocket != INVALID_SOCKET )
  1968. {
  1969. // Grab the first 32 bits, which tell us what the rest of the data is
  1970. uint32 nCompileResultCode;
  1971. memcpy( &nCompileResultCode, pRecvbuf, sizeof( nCompileResultCode ) );
  1972. // If is zero, we have an error, so the rest of the data is a text string from the compiler
  1973. if ( nCompileResultCode == 0x00000000 )
  1974. {
  1975. DevWarning( "Remote shader compile error: %s\n", pRecvbuf+4 );
  1976. }
  1977. else // we have an actual binary shader blob coming back
  1978. {
  1979. while ( nResult != ( nCompileResultCode + 4 ) )
  1980. {
  1981. nResult += recv( m_RemoteShaderCompileSocket, pRecvbuf + nResult, RECV_BUF_SIZE - nResult, 0 );
  1982. }
  1983. nRemotelyCompiledShaderLength = nCompileResultCode;
  1984. pRemotelyCompiledShader = (uint32 *) pRecvbuf;
  1985. pRemotelyCompiledShader++;
  1986. }
  1987. }
  1988. }
  1989. } // End using remote compile service
  1990. #endif // REMOTE_DYNAMIC_SHADER_COMPILE
  1991. #if defined( DYNAMIC_SHADER_COMPILE )
  1992. bool bShadersNeedFlush = false;
  1993. #endif
  1994. LPD3DXBUFFER pShader = NULL;
  1995. LPD3DXBUFFER pErrorMessages = NULL;
  1996. #if defined( PLATFORM_PS3 )
  1997. CUtlVector< uint8 > compiledShaderPS3;
  1998. bool nSucceeded = CompileShaderPS3(pShaderName, pShaderModelForD3DX, macros, compiledShaderPS3);
  1999. if (!nSucceeded)
  2000. {
  2001. bShadersNeedFlush = true;
  2002. if (retriesLeft-- > 0)
  2003. {
  2004. // Dynamic shader compile has failed! Fix the shader before continuing in the debugger.
  2005. DebuggerBreak();
  2006. SyncShaderCache();
  2007. // Compilation failed, and if we're debugging the user has already continued. Retry compiling the shader.
  2008. goto retry_compile;
  2009. }
  2010. return INVALID_HARDWARE_SHADER;
  2011. }
  2012. #elif !defined( DX_TO_GL_ABSTRACTION )
  2013. HRESULT hr;
  2014. bool b30Shader = !Q_stricmp( pShaderModel, "vs_3_0" ) || !Q_stricmp( pShaderModel, "ps_3_0" );
  2015. if ( m_ShaderCompileFileFunc30 && b30Shader )
  2016. {
  2017. CDxInclude dxInclude( filename );
  2018. hr = m_ShaderCompileFileFunc30( filename, macros.Base(), &dxInclude,
  2019. "main", pShaderModelForD3DX, 0 /* DWORD Flags */, &pShader, &pErrorMessages, NULL /* LPD3DXCONSTANTTABLE *ppConstantTable */ );
  2020. }
  2021. else
  2022. {
  2023. #if ( !defined( _X360 ) )
  2024. {
  2025. if ( b30Shader )
  2026. {
  2027. DevWarning( "Compiling with a stale version of d3dx. Should have d3d9x_33.dll installed (Apr 2007)\n" );
  2028. }
  2029. hr = D3DXCompileShaderFromFile( filename, macros.Base(), NULL /* LPD3DXINCLUDE */,
  2030. "main", pShaderModelForD3DX, 0 /* DWORD Flags */, &pShader, &pErrorMessages, NULL /* LPD3DXCONSTANTTABLE *ppConstantTable */ );
  2031. #ifdef REMOTE_DYNAMIC_SHADER_COMPILE
  2032. // If we're using the remote compiling service, let's double-check against a local compile
  2033. if ( ( m_RemoteShaderCompileSocket != INVALID_SOCKET ) && pRemotelyCompiledShader )
  2034. {
  2035. if ( ( memcmp( pRemotelyCompiledShader, pShader->GetBufferPointer(), pShader->GetBufferSize() ) != 0 ) ||
  2036. ( pShader->GetBufferSize() != nRemotelyCompiledShaderLength) )
  2037. {
  2038. DevWarning( "Remote and local shaders don't match!\n" );
  2039. return INVALID_HARDWARE_SHADER;
  2040. }
  2041. }
  2042. #endif // REMOTE_DYNAMIC_SHADER_COMPILE
  2043. }
  2044. #else // _X360 path
  2045. {
  2046. D3DXSHADER_COMPILE_PARAMETERS compileParams;
  2047. memset( &compileParams, 0, sizeof( compileParams ) );
  2048. char pUPDBOutputFile[MAX_PATH] = ""; //where we write the file
  2049. char pUPDBPIXLookup[MAX_PATH] = ""; //where PIX (on a pc) looks for the file
  2050. compileParams.Flags |= D3DXSHADEREX_OPTIMIZE_UCODE;
  2051. if( mat_flushshaders_generate_updbs.GetBool() )
  2052. {
  2053. //UPDB generation for PIX debugging
  2054. compileParams.Flags |= D3DXSHADEREX_GENERATE_UPDB;
  2055. compileParams.UPDBPath = pUPDBPIXLookup;
  2056. // *** IMPORTANT ***
  2057. // To get UPDBs working, you need to ensure that the UPDB_X360 directory is created underneath your mod folder on the Xbox 360.
  2058. // You must also replace DEPLOYMENT_ROOT with your mod path.
  2059. // This should probably be cleaned up, except that very few people use this feature and I'm not sure how to get the mod path properly in shaderapidx9.dll.
  2060. #define DEPLOYMENT_ROOT "xe:\\csgo"
  2061. char outputFileOnly[MAX_PATH];
  2062. const char *pOutputFileStart = &outputFileOnly[0];
  2063. Q_snprintf( outputFileOnly, MAX_PATH, "%s_S%d_D%d.updb", pShaderName, nStaticIndex, nDynamicIndex );
  2064. int nOutputFileNameLen = Q_strlen( outputFileOnly );
  2065. if ( nOutputFileNameLen >= 40 )
  2066. {
  2067. // X360 has a ~41 character filename limit
  2068. pOutputFileStart += ( nOutputFileNameLen - 40 );
  2069. }
  2070. Q_snprintf( pUPDBOutputFile, MAX_PATH, "d:\\UPDB_X360\\%s", pOutputFileStart );
  2071. Q_strncpy( pUPDBPIXLookup, DEPLOYMENT_ROOT, MAX_PATH );
  2072. // Skip past the "d:" part of the output file path
  2073. Q_strncat( pUPDBPIXLookup, pUPDBOutputFile + 2, MAX_PATH );
  2074. }
  2075. hr = D3DXCompileShaderFromFileEx( filename, macros.Base(), NULL /* LPD3DXINCLUDE */,
  2076. "main", pShaderModelForD3DX, 0 /* DWORD Flags */, &pShader, &pErrorMessages, NULL /* LPD3DXCONSTANTTABLE *ppConstantTable */, &compileParams );
  2077. if( (pUPDBOutputFile[0] != '\0') && compileParams.pUPDBBuffer ) //Did we generate a updb?
  2078. {
  2079. CUtlBuffer outbuffer;
  2080. DWORD dataSize = compileParams.pUPDBBuffer->GetBufferSize();
  2081. outbuffer.EnsureCapacity( dataSize );
  2082. memcpy( outbuffer.Base(), compileParams.pUPDBBuffer->GetBufferPointer(), dataSize );
  2083. outbuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, dataSize );
  2084. CreateDirectoryA( "d:\\UPDB_X360", NULL );
  2085. g_pFullFileSystem->WriteFile( pUPDBOutputFile, NULL, outbuffer );
  2086. compileParams.pUPDBBuffer->Release();
  2087. }
  2088. }
  2089. #endif // ( !defined( _X360 ) )
  2090. }
  2091. if ( hr != D3D_OK )
  2092. {
  2093. if ( pErrorMessages )
  2094. {
  2095. const char *pErrorMessageString = (const char *)pErrorMessages->GetBufferPointer();
  2096. Plat_DebugString( pErrorMessageString );
  2097. Plat_DebugString( "\n" );
  2098. }
  2099. #ifndef _DEBUG
  2100. if ( retriesLeft-- > 0 )
  2101. {
  2102. DevMsg( 0, "Failed dynamic shader compiled - fix the shader while the debugger is at the breakpoint, then continue\n" );
  2103. DebuggerBreakIfDebugging();
  2104. #if defined( DYNAMIC_SHADER_COMPILE )
  2105. // We probably changed code to fix the error, so go ahead and sync the shader cache from the PC to the 360.
  2106. SyncShaderCache();
  2107. #endif
  2108. #if defined( DYNAMIC_SHADER_COMPILE )
  2109. bShadersNeedFlush = true;
  2110. #endif
  2111. goto retry_compile;
  2112. }
  2113. if( !IsX360() ) //errors make the 360 puke and die. We have a better solution for this particular error
  2114. Error( "Failed dynamic shader compile\nBuild shaderapidx9.dll in debug to find problem\n" );
  2115. #else // _DEBUG
  2116. Assert( 0 );
  2117. #if defined( DYNAMIC_SHADER_COMPILE )
  2118. // We probably changed code to fix the error, so go ahead and sync the shader cache from the PC to the 360.
  2119. SyncShaderCache();
  2120. #endif
  2121. #if defined( DYNAMIC_SHADER_COMPILE )
  2122. bShadersNeedFlush = true;
  2123. #endif
  2124. #endif // _DEBUG
  2125. return INVALID_HARDWARE_SHADER;
  2126. }
  2127. else
  2128. #endif // not DX_TO_GL_ABSTRACTION
  2129. {
  2130. // Output number of instructions
  2131. #if defined( DYNAMIC_SHADER_COMPILE_VERBOSE ) && !defined( PLATFORM_PS3 ) && !defined( DX_TO_GL_ABSTRACTION )
  2132. if ( bVerbose )
  2133. {
  2134. LPD3DXBUFFER pDisassembly = NULL;
  2135. #ifdef _X360
  2136. D3DXDisassembleShaderEx( static_cast<DWORD*>( pShader->GetBufferPointer() ), D3DXDISASSEMBLER_SHOW_TIMING_ESTIMATE, NULL, &pDisassembly );
  2137. #else
  2138. D3DXDisassembleShader( static_cast<DWORD*>( pShader->GetBufferPointer() ), false, NULL, &pDisassembly );
  2139. #endif
  2140. const char *pString = ( pDisassembly != NULL ) ? ( const char * )pDisassembly->GetBufferPointer() : "Error!";
  2141. const char *pInstructions;
  2142. if ( IsX360() )
  2143. {
  2144. pInstructions = strstr( pString, "// Shader Timing Estimate" );
  2145. }
  2146. else
  2147. {
  2148. pInstructions = strstr( pString, "// approximately " );
  2149. }
  2150. if ( pInstructions != NULL )
  2151. {
  2152. if ( IsX360() )
  2153. {
  2154. ConColorMsg( Color( 255, 255, 100, 255 ), "%s\n", pInstructions );
  2155. }
  2156. else
  2157. {
  2158. ConColorMsg( Color( 255, 255, 100, 255 ), "\t%s\n", &( pInstructions[ V_strlen( "// approximately " ) ] ) );
  2159. }
  2160. }
  2161. if ( pDisassembly != NULL)
  2162. pDisassembly->Release();
  2163. }
  2164. #endif
  2165. #ifdef DYNAMIC_SHADER_COMPILE_WRITE_ASSEMBLY
  2166. {
  2167. // enable to dump the disassembly for shader validation
  2168. char exampleCommandLine[2048];
  2169. Q_strncpy( exampleCommandLine, "// Run from stdshaders\n// ..\\..\\dx9sdk\\utilities\\fxc.exe ", sizeof( exampleCommandLine ) );
  2170. int i;
  2171. for( i = 0; macros[i].Name; i++ )
  2172. {
  2173. Q_strncat( exampleCommandLine, "/D", sizeof( exampleCommandLine ) );
  2174. Q_strncat( exampleCommandLine, macros[i].Name, sizeof( exampleCommandLine ) );
  2175. Q_strncat( exampleCommandLine, "=", sizeof( exampleCommandLine ) );
  2176. Q_strncat( exampleCommandLine, macros[i].Definition, sizeof( exampleCommandLine ) );
  2177. Q_strncat( exampleCommandLine, " ", sizeof( exampleCommandLine ) );
  2178. }
  2179. Q_strncat( exampleCommandLine, "/T", sizeof( exampleCommandLine ) );
  2180. Q_strncat( exampleCommandLine, pShaderModelForD3DX, sizeof( exampleCommandLine ) );
  2181. Q_strncat( exampleCommandLine, " ", sizeof( exampleCommandLine ) );
  2182. Q_strncat( exampleCommandLine, filename, sizeof( exampleCommandLine ) );
  2183. Q_strncat( exampleCommandLine, "\n", sizeof( exampleCommandLine ) );
  2184. ID3DXBuffer *pd3dxBuffer;
  2185. HRESULT hr;
  2186. hr = D3DXDisassembleShader( ( DWORD* )pShader->GetBufferPointer(), false, NULL, &pd3dxBuffer );
  2187. Assert( hr == D3D_OK );
  2188. CUtlBuffer tempBuffer;
  2189. tempBuffer.SetBufferType( true, false );
  2190. int exampleCommandLineLength = strlen( exampleCommandLine );
  2191. tempBuffer.EnsureCapacity( pd3dxBuffer->GetBufferSize() + exampleCommandLineLength );
  2192. memcpy( tempBuffer.Base(), exampleCommandLine, exampleCommandLineLength );
  2193. memcpy( ( char * )tempBuffer.Base() + exampleCommandLineLength, pd3dxBuffer->GetBufferPointer(), pd3dxBuffer->GetBufferSize() );
  2194. tempBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, pd3dxBuffer->GetBufferSize() + exampleCommandLineLength );
  2195. char filename[MAX_PATH];
  2196. sprintf( filename, "%s_%d_%d.asm", pShaderName, nStaticIndex, nDynamicIndex );
  2197. g_pFullFileSystem->WriteFile( filename, "DEFAULT_WRITE_PATH", tempBuffer );
  2198. }
  2199. #endif
  2200. #ifdef REMOTE_DYNAMIC_SHADER_COMPILE
  2201. {
  2202. if ( bVertexShader )
  2203. {
  2204. return CreateD3DVertexShader( ( DWORD * )pRemotelyCompiledShader, nRemotelyCompiledShaderLength, pShaderName );
  2205. }
  2206. else
  2207. {
  2208. return CreateD3DPixelShader( ( DWORD * )pRemotelyCompiledShader, 0, nRemotelyCompiledShaderLength, pShaderName ); // hack hack hack! need to get centroid info from the source
  2209. }
  2210. }
  2211. #elif defined( PLATFORM_PS3 )
  2212. {
  2213. if ( bVertexShader )
  2214. {
  2215. return CreateD3DVertexShader( ( DWORD * )compiledShaderPS3.Base(), compiledShaderPS3.Count(), pShaderName );
  2216. }
  2217. else
  2218. {
  2219. return CreateD3DPixelShader( ( DWORD * )compiledShaderPS3.Base(), 0, compiledShaderPS3.Count(), pShaderName ); // hack hack hack! need to get centroid info from the source
  2220. }
  2221. }
  2222. #else // local compile, not remote
  2223. {
  2224. if ( bVertexShader )
  2225. {
  2226. return CreateD3DVertexShader( ( DWORD * )pShader->GetBufferPointer(), pShader->GetBufferSize(), pShaderName );
  2227. }
  2228. else
  2229. {
  2230. return CreateD3DPixelShader( ( DWORD * )pShader->GetBufferPointer(), 0, pShader->GetBufferSize(), pShaderName ); // hack hack hack! need to get centroid info from the source
  2231. }
  2232. }
  2233. #endif
  2234. #if defined( DYNAMIC_SHADER_COMPILE )
  2235. {
  2236. // 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.
  2237. if ( bShadersNeedFlush )
  2238. {
  2239. MatFlushShaders();
  2240. }
  2241. }
  2242. #endif
  2243. }
  2244. #if !defined( REMOTE_DYNAMIC_SHADER_COMPILE ) && !defined( PLATFORM_PS3 )
  2245. {
  2246. if ( pShader )
  2247. {
  2248. pShader->Release();
  2249. }
  2250. }
  2251. #endif
  2252. #ifdef DYNAMIC_SHADER_COMPILE_VERBOSE
  2253. if ( pErrorMessages )
  2254. {
  2255. pErrorMessages->Release();
  2256. }
  2257. #endif
  2258. }
  2259. #endif
  2260. #ifdef DYNAMIC_SHADER_COMPILE
  2261. bool CShaderManager::LoadAndCreateShaders_Dynamic( ShaderLookup_t &lookup, bool bVertexShader )
  2262. {
  2263. const char *pName = m_ShaderSymbolTable.String( lookup.m_Name );
  2264. const ShaderCombos_t *pCombos = FindOrCreateShaderCombos( pName );
  2265. if ( !pCombos )
  2266. {
  2267. return false;
  2268. }
  2269. int numDynamicCombos = pCombos->GetNumDynamicCombos();
  2270. lookup.m_ShaderStaticCombos.m_pHardwareShaders = new HardwareShader_t[numDynamicCombos];
  2271. lookup.m_ShaderStaticCombos.m_nCount = numDynamicCombos;
  2272. lookup.m_ShaderStaticCombos.m_pCreationData = new ShaderStaticCombos_t::ShaderCreationData_t[numDynamicCombos];
  2273. int i;
  2274. for( i = 0; i < numDynamicCombos; i++ )
  2275. {
  2276. lookup.m_ShaderStaticCombos.m_pHardwareShaders[i] = INVALID_HARDWARE_SHADER;
  2277. }
  2278. return true;
  2279. }
  2280. #endif
  2281. //-----------------------------------------------------------------------------
  2282. // Open the shader file, optionally gets the header
  2283. //-----------------------------------------------------------------------------
  2284. FileHandle_t CShaderManager::OpenFileAndLoadHeader( const char *pFileName, ShaderHeader_t *pHeader )
  2285. {
  2286. FileHandle_t fp = g_pFullFileSystem->Open( pFileName, "rb", "PLATFORM" );
  2287. if ( fp == FILESYSTEM_INVALID_HANDLE )
  2288. {
  2289. return FILESYSTEM_INVALID_HANDLE;
  2290. }
  2291. if ( pHeader )
  2292. {
  2293. // read the header
  2294. g_pFullFileSystem->Read( pHeader, sizeof( ShaderHeader_t ), fp );
  2295. switch ( pHeader->m_nVersion )
  2296. {
  2297. case 4:
  2298. // version with combos done as diffs vs a reference combo
  2299. // vsh/psh or older fxc
  2300. break;
  2301. case 5:
  2302. case 6:
  2303. // version with optimal dictionary and compressed combo block
  2304. break;
  2305. default:
  2306. Assert( 0 );
  2307. DevWarning( "Shader %s is the wrong version %d, expecting %d\n", pFileName, pHeader->m_nVersion, SHADER_VCS_VERSION_NUMBER );
  2308. g_pFullFileSystem->Close( fp );
  2309. return FILESYSTEM_INVALID_HANDLE;
  2310. }
  2311. }
  2312. return fp;
  2313. }
  2314. //---------------------------------------------------------------------------------------------------------
  2315. // Writes text files named for looked-up shaders. Used by GL shader translator to dump code for debugging
  2316. //---------------------------------------------------------------------------------------------------------
  2317. void CShaderManager::WriteTranslatedFile( ShaderLookup_t *pLookup, int dynamicCombo, char *pFileContents, char *pFileExtension )
  2318. {
  2319. const char *pName = m_ShaderSymbolTable.String( pLookup->m_Name );
  2320. int nNumChars = V_strlen( pFileContents );
  2321. CUtlBuffer tempBuffer;
  2322. tempBuffer.SetBufferType( true, false );
  2323. tempBuffer.EnsureCapacity( nNumChars );
  2324. memcpy( ( char * )tempBuffer.Base(), pFileContents, nNumChars );
  2325. tempBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, nNumChars );
  2326. char filename[MAX_PATH];
  2327. sprintf( filename, "%s_%d_%d.%s", pName, pLookup->m_nStaticIndex, dynamicCombo, pFileExtension );
  2328. g_pFullFileSystem->WriteFile( filename, "DEFAULT_WRITE_PATH", tempBuffer );
  2329. }
  2330. //-----------------------------------------------------------------------------
  2331. // Disassemble a shader for debugging. Writes .asm files.
  2332. //-----------------------------------------------------------------------------
  2333. void CShaderManager::DisassembleShader( ShaderLookup_t *pLookup, int dynamicCombo, uint8 *pByteCode )
  2334. {
  2335. #if defined( WRITE_ASSEMBLY )
  2336. const char *pName = m_ShaderSymbolTable.String( pLookup->m_Name );
  2337. ID3DXBuffer *pd3dxBuffer;
  2338. HRESULT hr;
  2339. hr = D3DXDisassembleShader( (DWORD*)pByteCode, false, NULL, &pd3dxBuffer );
  2340. Assert( hr == D3D_OK );
  2341. CUtlBuffer tempBuffer;
  2342. tempBuffer.SetBufferType( true, false );
  2343. tempBuffer.EnsureCapacity( pd3dxBuffer->GetBufferSize() );
  2344. memcpy( ( char * )tempBuffer.Base(), pd3dxBuffer->GetBufferPointer(), pd3dxBuffer->GetBufferSize() );
  2345. tempBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, pd3dxBuffer->GetBufferSize() );
  2346. char filename[MAX_PATH];
  2347. sprintf( filename, "%s_%d_%d.asm", pName, pLookup->m_nStaticIndex, dynamicCombo );
  2348. g_pFullFileSystem->WriteFile( filename, "DEFAULT_WRITE_PATH", tempBuffer );
  2349. #endif
  2350. }
  2351. //-----------------------------------------------------------------------------
  2352. // Create dynamic combos
  2353. //-----------------------------------------------------------------------------
  2354. bool CShaderManager::CreateDynamicCombos_Ver4( void *pContext, uint8 *pComboBuffer )
  2355. {
  2356. ShaderLookup_t* pLookup = (ShaderLookup_t *)pContext;
  2357. ShaderFileCache_t *pFileCache = &m_ShaderFileCache[pLookup->m_hShaderFileCache];
  2358. ShaderHeader_t *pHeader = &pFileCache->m_Header;
  2359. int nReferenceComboSizeForDiffs = ((ShaderHeader_t_v4 *)pHeader)->m_nDiffReferenceSize;
  2360. uint8 *pReferenceShader = NULL;
  2361. uint8 *pDiffOutputBuffer = NULL;
  2362. if ( nReferenceComboSizeForDiffs )
  2363. {
  2364. // reference combo is *always* the largest combo, so safe worst case size for uncompression buffer
  2365. pReferenceShader = (uint8 *)pFileCache->m_ReferenceCombo.Base();
  2366. pDiffOutputBuffer = (uint8 *)stackalloc( nReferenceComboSizeForDiffs );
  2367. }
  2368. // build this shader's dynamic combos
  2369. bool bOK = true;
  2370. int nStartingOffset = 0;
  2371. for ( int i = 0; i < pHeader->m_nDynamicCombos; i++ )
  2372. {
  2373. if ( pLookup->m_pComboDictionary[i].m_Offset == -1 )
  2374. {
  2375. // skipped
  2376. continue;
  2377. }
  2378. if ( !nStartingOffset )
  2379. {
  2380. nStartingOffset = pLookup->m_pComboDictionary[i].m_Offset;
  2381. }
  2382. // offsets better be sequentially ascending
  2383. Assert( nStartingOffset <= pLookup->m_pComboDictionary[i].m_Offset );
  2384. if ( pLookup->m_pComboDictionary[i].m_Size <= 0 )
  2385. {
  2386. // skipped
  2387. continue;
  2388. }
  2389. // get the right byte code from the monolithic buffer
  2390. uint8 *pByteCode = (uint8 *)pComboBuffer + pLookup->m_nDataOffset + pLookup->m_pComboDictionary[i].m_Offset - nStartingOffset;
  2391. int nByteCodeSize = pLookup->m_pComboDictionary[i].m_Size;
  2392. if ( pReferenceShader )
  2393. {
  2394. // reference combo better be the largest combo, otherwise memory corruption
  2395. Assert( nReferenceComboSizeForDiffs >= nByteCodeSize );
  2396. // use the differencing algorithm to recover the full shader
  2397. int nOriginalSize;
  2398. ApplyDiffs(
  2399. pReferenceShader,
  2400. pByteCode,
  2401. nReferenceComboSizeForDiffs,
  2402. nByteCodeSize,
  2403. nOriginalSize,
  2404. pDiffOutputBuffer,
  2405. nReferenceComboSizeForDiffs );
  2406. pByteCode = pDiffOutputBuffer;
  2407. nByteCodeSize = nOriginalSize;
  2408. }
  2409. #if defined( WRITE_ASSEMBLY )
  2410. DisassembleShader( pLookup, i, pByteCode );
  2411. #endif
  2412. HardwareShader_t hardwareShader = INVALID_HARDWARE_SHADER;
  2413. if ( IsPC() && m_bCreateShadersOnDemand )
  2414. {
  2415. // cache the code off for later
  2416. pLookup->m_ShaderStaticCombos.m_pCreationData[i].ByteCode.SetSize( nByteCodeSize );
  2417. V_memcpy( pLookup->m_ShaderStaticCombos.m_pCreationData[i].ByteCode.Base(), pByteCode, nByteCodeSize );
  2418. pLookup->m_ShaderStaticCombos.m_pCreationData[i].iCentroidMask = pFileCache->m_bVertexShader ? 0 : pHeader->m_nCentroidMask;
  2419. }
  2420. else
  2421. {
  2422. const char *pShaderName = m_ShaderSymbolTable.String( pLookup->m_Name );
  2423. if ( pFileCache->m_bVertexShader )
  2424. {
  2425. hardwareShader = CreateD3DVertexShader( reinterpret_cast< DWORD *>( pByteCode ), nByteCodeSize, pShaderName );
  2426. }
  2427. else
  2428. {
  2429. hardwareShader = CreateD3DPixelShader( reinterpret_cast< DWORD *>( pByteCode ), pHeader->m_nCentroidMask, nByteCodeSize, pShaderName );
  2430. }
  2431. if ( hardwareShader == INVALID_HARDWARE_SHADER )
  2432. {
  2433. Assert( 0 );
  2434. bOK = false;
  2435. break;
  2436. }
  2437. }
  2438. pLookup->m_ShaderStaticCombos.m_pHardwareShaders[i] = hardwareShader;
  2439. }
  2440. delete [] pLookup->m_pComboDictionary;
  2441. pLookup->m_pComboDictionary = NULL;
  2442. return bOK;
  2443. }
  2444. //-----------------------------------------------------------------------------
  2445. // Create dynamic combos
  2446. //-----------------------------------------------------------------------------
  2447. static uint32 NextULONG( uint8 * &pData )
  2448. {
  2449. // handle unaligned read
  2450. uint32 nRet;
  2451. memcpy( &nRet, pData, sizeof( nRet ) );
  2452. pData += sizeof( nRet );
  2453. return nRet;
  2454. }
  2455. bool CShaderManager::CreateDynamicCombos_Ver5( void *pContext, uint8 *pComboBuffer, char *debugLabel )
  2456. {
  2457. ShaderLookup_t* pLookup = (ShaderLookup_t *)pContext;
  2458. ShaderFileCache_t *pFileCache = &m_ShaderFileCache[pLookup->m_hShaderFileCache];
  2459. uint8 *pCompressedShaders = pComboBuffer + pLookup->m_nDataOffset;
  2460. uint8 *pUnpackBuffer = new uint8[MAX_SHADER_UNPACKED_BLOCK_SIZE];
  2461. char *debugLabelPtr = debugLabel; // can be moved to point at something else if need be
  2462. // now, loop through all blocks
  2463. bool bOK = true;
  2464. while ( bOK )
  2465. {
  2466. uint32 nBlockSize = NextULONG( pCompressedShaders );
  2467. if ( nBlockSize == 0xffffffff )
  2468. {
  2469. // any more blocks?
  2470. break;
  2471. }
  2472. switch( nBlockSize & 0xc0000000 )
  2473. {
  2474. case 0: // bzip2
  2475. {
  2476. // uncompress
  2477. uint32 nOutsize = MAX_SHADER_UNPACKED_BLOCK_SIZE;
  2478. int nRslt = BZ2_bzBuffToBuffDecompress(
  2479. reinterpret_cast<char *>( pUnpackBuffer ),
  2480. &nOutsize,
  2481. reinterpret_cast<char *>( pCompressedShaders ),
  2482. nBlockSize, 1, 0 );
  2483. if ( nRslt < 0 )
  2484. {
  2485. // errors are negative for bzip
  2486. Assert( 0 );
  2487. DevWarning( "BZIP Error (%d) decompressing shader", nRslt );
  2488. bOK = false;
  2489. }
  2490. pCompressedShaders += nBlockSize;
  2491. nBlockSize = nOutsize; // how much data there is
  2492. }
  2493. break;
  2494. case 0x80000000: // uncompressed
  2495. {
  2496. // not compressed, as is
  2497. nBlockSize &= 0x3fffffff;
  2498. memcpy( pUnpackBuffer, pCompressedShaders, nBlockSize );
  2499. pCompressedShaders += nBlockSize;
  2500. }
  2501. break;
  2502. case 0x40000000: // lzma compressed
  2503. {
  2504. CLZMA lzDecoder;
  2505. nBlockSize &= 0x3fffffff;
  2506. size_t nOutsize = lzDecoder.Uncompress(
  2507. reinterpret_cast<uint8 *>( pCompressedShaders ),
  2508. pUnpackBuffer );
  2509. pCompressedShaders += nBlockSize;
  2510. nBlockSize = nOutsize; // how much data there is
  2511. }
  2512. break;
  2513. default:
  2514. {
  2515. Assert( 0 );
  2516. Error(" unrecognized shader compression type = file corrupt?");
  2517. bOK = false;
  2518. }
  2519. }
  2520. uint8 *pReadPtr = pUnpackBuffer;
  2521. while ( pReadPtr < pUnpackBuffer+nBlockSize )
  2522. {
  2523. uint32 nCombo_ID = NextULONG( pReadPtr );
  2524. uint32 nShaderSize = NextULONG( pReadPtr );
  2525. #if defined( WRITE_ASSEMBLY )
  2526. DisassembleShader( pLookup, nCombo_ID, pReadPtr );
  2527. #endif
  2528. HardwareShader_t hardwareShader = INVALID_HARDWARE_SHADER;
  2529. int iIndex = nCombo_ID;
  2530. if ( iIndex >= pLookup->m_nStaticIndex )
  2531. iIndex -= pLookup->m_nStaticIndex; // ver5 stores combos as full combo, ver6 as dynamic combo # only
  2532. if ( IsPC() && m_bCreateShadersOnDemand )
  2533. {
  2534. // cache the code off for later
  2535. pLookup->m_ShaderStaticCombos.m_pCreationData[iIndex].ByteCode.SetSize( nShaderSize );
  2536. V_memcpy( pLookup->m_ShaderStaticCombos.m_pCreationData[iIndex].ByteCode.Base(), pReadPtr, nShaderSize );
  2537. pLookup->m_ShaderStaticCombos.m_pCreationData[iIndex].iCentroidMask = pFileCache->m_bVertexShader ? 0 : pFileCache->m_Header.m_nCentroidMask;
  2538. }
  2539. else
  2540. {
  2541. const char *pShaderName = m_ShaderSymbolTable.String( pLookup->m_Name );
  2542. if ( pFileCache->m_bVertexShader )
  2543. {
  2544. #if 0
  2545. // this is all test code
  2546. CUtlBuffer bufGLSLCode( 1000, 50000, CUtlBuffer::TEXT_BUFFER );
  2547. bool bVertexShader;
  2548. uint32 nOptions = 0;
  2549. nOptions |= D3DToGL_OptionUseEnvParams;
  2550. nOptions |= D3DToGL_OptionDoFixupZ;
  2551. nOptions |= D3DToGL_OptionDoFixupY;
  2552. //options |= D3DToGL_OptionSpew;
  2553. // GLSL options
  2554. nOptions |= D3DToGL_OptionGLSL;// | D3DToGL_OptionAllowStaticControlFlow | D3DToGL_AddHexComments | D3DToGL_PutHexCommentsAfterLines;
  2555. sg_NewD3DToOpenGLTranslator.TranslateShader( (uint32 *) pReadPtr, &bufGLSLCode, &bVertexShader, nOptions, -1, 0, debugLabel );
  2556. nOptions |= D3DToGL_OptionGLSL; // | D3DToGL_AddHexComments | D3DToGL_PutHexCommentsAfterLines;
  2557. //if ( !IsOSX() )
  2558. {
  2559. nOptions |= D3DToGL_OptionAllowStaticControlFlow;
  2560. }
  2561. sg_NewD3DToOpenGLTranslator.TranslateShader( (uint32 *) pReadPtr, &bufGLSLCode, &bVertexShader, nOptions, -1, 0, debugLabel );
  2562. nOptions |= D3DToGL_OptionGLSL;// | D3DToGL_AddHexComments | D3DToGL_PutHexCommentsAfterLines;
  2563. sg_D3DToOpenGLTranslator.TranslateShader( (uint32 *) pReadPtr, &bufGLSLCode, &bVertexShader, nOptions, -1, 0, debugLabel );
  2564. Assert( bVertexShader );
  2565. WriteTranslatedFile( pLookup, iIndex, (char *)bufGLSLCode.Base(), "glsl_v" ); // GLSL
  2566. #endif
  2567. #ifdef DX_TO_GL_ABSTRACTION
  2568. // munge the debug label a bit to aid in decoding... catenate the iIndex on the end
  2569. char temp[1024];
  2570. sprintf(temp, "%s vs-combo %d", (debugLabel)?debugLabel:"none", iIndex );
  2571. debugLabelPtr = temp;
  2572. #endif
  2573. // pass binary code to d3d interface, on GL it will invoke the translator back to asm
  2574. hardwareShader = CreateD3DVertexShader( reinterpret_cast< DWORD *>( pReadPtr ), nShaderSize, pShaderName, debugLabelPtr );
  2575. }
  2576. else
  2577. {
  2578. #if 0
  2579. // this is all test code
  2580. CUtlBuffer bufGLSLCode( 1000, 50000, CUtlBuffer::TEXT_BUFFER );
  2581. bool bVertexShader;
  2582. uint32 nOptions = D3DToGL_OptionUseEnvParams;
  2583. // GLSL options
  2584. nOptions |= D3DToGL_OptionGLSL; // | D3DToGL_OptionSRGBWriteSuffix | D3DToGL_AddHexComments | D3DToGL_PutHexCommentsAfterLines;
  2585. //if ( !IsOSX() )
  2586. {
  2587. nOptions |= D3DToGL_OptionAllowStaticControlFlow;
  2588. }
  2589. sg_D3DToOpenGLTranslator.TranslateShader( (uint32 *) pReadPtr, &bufGLSLCode, &bVertexShader, nOptions, -1, 0, debugLabel );
  2590. Assert( !bVertexShader );
  2591. WriteTranslatedFile( pLookup, iIndex, (char *)bufGLSLCode.Base(), "glsl_p" ); // GLSL
  2592. #endif
  2593. #ifdef DX_TO_GL_ABSTRACTION
  2594. // munge the debug label a bit to aid in decoding... catenate the iIndex on the end
  2595. char temp[1024];
  2596. sprintf(temp, "%s ps-combo %d", (debugLabel)?debugLabel:"", iIndex );
  2597. debugLabelPtr = temp;
  2598. #endif
  2599. // pass binary code to d3d interface, on GL it will invoke the translator back to asm
  2600. hardwareShader = CreateD3DPixelShader( reinterpret_cast< DWORD *>( pReadPtr ), pFileCache->m_Header.m_nCentroidMask, nShaderSize, pShaderName, debugLabelPtr );
  2601. }
  2602. if ( hardwareShader == INVALID_HARDWARE_SHADER )
  2603. {
  2604. DevWarning( "failed to create shader\n" );
  2605. Assert( 0 );
  2606. bOK = false;
  2607. break;
  2608. }
  2609. pLookup->m_ShaderStaticCombos.m_nNumDynamicCombosAfterSkips++;
  2610. }
  2611. pLookup->m_ShaderStaticCombos.m_pHardwareShaders[iIndex] = hardwareShader;
  2612. pReadPtr += nShaderSize;
  2613. }
  2614. }
  2615. delete[] pUnpackBuffer;
  2616. return bOK;
  2617. }
  2618. //-----------------------------------------------------------------------------
  2619. // Static method, called by thread, don't call anything non-threadsafe from handler!!!
  2620. //-----------------------------------------------------------------------------
  2621. void CShaderManager::QueuedLoaderCallback( void *pContext, void *pContext2, const void *pData, int nSize, LoaderError_t loaderError )
  2622. {
  2623. ShaderLookup_t* pLookup = (ShaderLookup_t *)pContext;
  2624. bool bOK = ( loaderError == LOADERERROR_NONE );
  2625. if ( bOK )
  2626. {
  2627. if ( pContext2 )
  2628. {
  2629. // presence denotes diff version
  2630. bOK = s_ShaderManager.CreateDynamicCombos_Ver4( pContext, (uint8 *)pData );
  2631. }
  2632. else
  2633. {
  2634. bOK = s_ShaderManager.CreateDynamicCombos_Ver5( pContext, (uint8 *)pData );
  2635. }
  2636. }
  2637. if ( !bOK )
  2638. {
  2639. pLookup->m_Flags |= SHADER_FAILED_LOAD;
  2640. }
  2641. }
  2642. #ifdef DYNAMIC_SHADER_COMPILE
  2643. bool CShaderManager::DoesShaderCRCMatchSourceCode( const char *pShaderName, uint32 crc32, uint32 &sourceCRC )
  2644. {
  2645. if ( mat_dynamic_shader_compile_force_reload.GetBool() )
  2646. {
  2647. return false;
  2648. }
  2649. CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  2650. bool bTryVshDirectory = false;
  2651. if ( ReadShaderSourceWithIncludes( pShaderName, buf, bTryVshDirectory ) )
  2652. {
  2653. sourceCRC = CRC32_ProcessSingleBuffer( buf.Base(), MAX( 0, buf.TellPut() - 1 ) );
  2654. if ( sourceCRC == crc32 )
  2655. {
  2656. #if defined( _GAMECONSOLE )
  2657. DevWarning( "crc match for %s\n", pShaderName );
  2658. #endif
  2659. return true;
  2660. }
  2661. }
  2662. DevWarning( "***** CRC mismatch for %s 0x%x 0x%x\n", pShaderName, sourceCRC, crc32 );
  2663. return false;
  2664. }
  2665. #endif
  2666. // Convert from a static combo/dynamic combo back into the combo values and spew.
  2667. void BitchAboutSkippedCombo( const char *pShaderName, int nStaticComboID, int nDynamicComboID )
  2668. {
  2669. char path[MAX_PATH];
  2670. V_strncpy( path, pShaderName, MAX_PATH );
  2671. V_FileBase( path, path, MAX_PATH );
  2672. if ( IsGameConsole() )
  2673. {
  2674. // Need to filebase twice to get rid of the .360.vcs or .ps3.vcs on the game consoles.
  2675. V_FileBase( path, path, MAX_PATH );
  2676. }
  2677. CUtlSymbol symbol;
  2678. symbol = s_ShaderComboInfoByName.Find( path );
  2679. if ( symbol == ( CUtlSymbol )UTL_INVAL_SYMBOL )
  2680. {
  2681. DevWarning( "Can't find combo info for skipped combo! Tell a programmer!!!\n" );
  2682. return;
  2683. }
  2684. const ShaderComboSemantics_t *pSemantics = s_ShaderComboInfoByName[symbol];
  2685. // The static combo id actually has the dynamic bits embedded in it, so we need to extract those first.
  2686. for ( int i = 0; i < pSemantics->nDynamicShaderComboArrayCount; i++ )
  2687. {
  2688. int comboSize = pSemantics->pDynamicShaderComboArray[ i ].m_nComboMax - pSemantics->pDynamicShaderComboArray[ i ].m_nComboMin + 1;
  2689. nStaticComboID /= comboSize;
  2690. }
  2691. DevWarning( "static combos: " );
  2692. for ( int i = 0; i < pSemantics->nStaticShaderComboArrayCount; i++ )
  2693. {
  2694. int comboSize = pSemantics->pStaticShaderComboArray[i].m_nComboMax - pSemantics->pStaticShaderComboArray[i].m_nComboMin + 1;
  2695. int comboVal = nStaticComboID % comboSize;
  2696. if ( SHADER_COMBO_SPEW_VERBOSE || comboVal != 0 )
  2697. {
  2698. const char *pName = pSemantics->pStaticShaderComboArray[i].m_pComboName;
  2699. DevWarning( "%s=%d ", pName, comboVal );
  2700. }
  2701. nStaticComboID /= comboSize;
  2702. }
  2703. DevWarning( "\n" );
  2704. if ( nDynamicComboID != -1 )
  2705. {
  2706. DevWarning( "dynamic combos: " );
  2707. for ( int i = 0; i < pSemantics->nDynamicShaderComboArrayCount; i++ )
  2708. {
  2709. int comboSize = pSemantics->pDynamicShaderComboArray[i].m_nComboMax - pSemantics->pDynamicShaderComboArray[i].m_nComboMin + 1;
  2710. int comboVal = nDynamicComboID % comboSize;
  2711. if ( SHADER_COMBO_SPEW_VERBOSE || comboVal != 0 )
  2712. {
  2713. const char *pName = pSemantics->pDynamicShaderComboArray[i].m_pComboName;
  2714. DevWarning( "%s=%d ", pName, comboVal );
  2715. }
  2716. nDynamicComboID /= comboSize;
  2717. }
  2718. DevWarning( "\n" );
  2719. }
  2720. }
  2721. void PrintComboDesc( const char *pShaderName, int nStaticComboID, int nDynamicComboID )
  2722. {
  2723. char path[MAX_PATH];
  2724. V_strncpy( path, pShaderName, MAX_PATH );
  2725. V_FileBase( path, path, MAX_PATH );
  2726. if ( IsX360() )
  2727. {
  2728. // Need to filebase twice to get rid of the .360.vcs or .ps3.vcs on the game consoles.
  2729. V_FileBase( path, path, MAX_PATH );
  2730. }
  2731. CUtlSymbol symbol;
  2732. symbol = s_ShaderComboInfoByName.Find( path );
  2733. if ( symbol == ( CUtlSymbol )UTL_INVAL_SYMBOL )
  2734. {
  2735. DevWarning( "Can't print combo desc for shader \"%s\"\n", pShaderName );
  2736. return;
  2737. }
  2738. const ShaderComboSemantics_t *pSemantics = s_ShaderComboInfoByName[symbol];
  2739. // The static combo id actually has the dynamic bits embedded in it, so we need to extract those first.
  2740. for ( int i = 0; i < pSemantics->nDynamicShaderComboArrayCount; i++ )
  2741. {
  2742. int comboSize = pSemantics->pDynamicShaderComboArray[ i ].m_nComboMax - pSemantics->pDynamicShaderComboArray[ i ].m_nComboMin + 1;
  2743. nStaticComboID /= comboSize;
  2744. }
  2745. Msg( "static combos: " );
  2746. for ( int i = 0; i < pSemantics->nStaticShaderComboArrayCount; i++ )
  2747. {
  2748. int comboSize = pSemantics->pStaticShaderComboArray[i].m_nComboMax - pSemantics->pStaticShaderComboArray[i].m_nComboMin + 1;
  2749. int comboVal = nStaticComboID % comboSize;
  2750. if ( SHADER_COMBO_SPEW_VERBOSE || comboVal != 0 )
  2751. {
  2752. const char *pName = pSemantics->pStaticShaderComboArray[i].m_pComboName;
  2753. Msg( "%s=%d ", pName, comboVal );
  2754. }
  2755. nStaticComboID /= comboSize;
  2756. }
  2757. Msg( "\n" );
  2758. if ( nDynamicComboID != -1 )
  2759. {
  2760. Msg( "dynamic combos: " );
  2761. for ( int i = 0; i < pSemantics->nDynamicShaderComboArrayCount; i++ )
  2762. {
  2763. int comboSize = pSemantics->pDynamicShaderComboArray[i].m_nComboMax - pSemantics->pDynamicShaderComboArray[i].m_nComboMin + 1;
  2764. int comboVal = nDynamicComboID % comboSize;
  2765. if ( SHADER_COMBO_SPEW_VERBOSE || comboVal != 0 )
  2766. {
  2767. const char *pName = pSemantics->pDynamicShaderComboArray[i].m_pComboName;
  2768. Msg( "%s=%d ", pName, comboVal );
  2769. }
  2770. nDynamicComboID /= comboSize;
  2771. }
  2772. Msg( "\n" );
  2773. }
  2774. }
  2775. //-----------------------------------------------------------------------------
  2776. // Loads all shaders
  2777. //-----------------------------------------------------------------------------
  2778. bool CShaderManager::LoadAndCreateShaders( ShaderLookup_t &lookup, bool bVertexShader, char *debugLabel )
  2779. {
  2780. const char *pName = m_ShaderSymbolTable.String( lookup.m_Name );
  2781. // find it in the cache
  2782. // a cache hit prevents costly i/o for static components, i.e. header, ref combo, etc.
  2783. ShaderFileCache_t fileCacheLookup;
  2784. fileCacheLookup.m_Name = lookup.m_Name;
  2785. fileCacheLookup.m_bVertexShader = bVertexShader;
  2786. intp fileCacheIndex = m_ShaderFileCache.Find( fileCacheLookup );
  2787. if ( fileCacheIndex == m_ShaderFileCache.InvalidIndex() )
  2788. {
  2789. // not found, create a new entry
  2790. fileCacheIndex = m_ShaderFileCache.AddToTail();
  2791. }
  2792. lookup.m_hShaderFileCache = fileCacheIndex;
  2793. // fetch from cache
  2794. ShaderFileCache_t *pFileCache = &m_ShaderFileCache[fileCacheIndex];
  2795. ShaderHeader_t *pHeader = &pFileCache->m_Header;
  2796. FileHandle_t hFile = FILESYSTEM_INVALID_HANDLE;
  2797. if ( pFileCache->IsValid() )
  2798. {
  2799. #ifdef DYNAMIC_SHADER_COMPILE
  2800. lookup.m_nVcsCrc32 = pHeader->m_nSourceCRC32;
  2801. #endif
  2802. // using cached header, just open file, no read of header needed
  2803. hFile = OpenFileAndLoadHeader( m_ShaderSymbolTable.String( pFileCache->m_Filename ), NULL );
  2804. if ( hFile == FILESYSTEM_INVALID_HANDLE )
  2805. {
  2806. // shouldn't happen
  2807. Assert( 0 );
  2808. return false;
  2809. }
  2810. }
  2811. else
  2812. {
  2813. V_memset( pHeader, 0, sizeof( ShaderHeader_t ) );
  2814. // try the vsh/psh dir first
  2815. char filename[MAX_PATH];
  2816. Q_snprintf( filename, MAX_PATH, "shaders\\%s\\%s" SHADER_FNAME_EXTENSION, bVertexShader ? "vsh" : "psh", pName );
  2817. hFile = OpenFileAndLoadHeader( filename, pHeader );
  2818. if ( hFile == FILESYSTEM_INVALID_HANDLE )
  2819. {
  2820. // next, try the fxc dir
  2821. Q_snprintf( filename, MAX_PATH, "shaders\\fxc\\%s" SHADER_FNAME_EXTENSION, pName );
  2822. hFile = OpenFileAndLoadHeader( filename, pHeader );
  2823. #ifdef DYNAMIC_SHADER_COMPILE
  2824. lookup.m_nVcsCrc32 = pHeader->m_nSourceCRC32;
  2825. // See if the CRC in the VCS file matches the source. If so, load from there rather than compiling dynamically.
  2826. uint32 sourceCRC;
  2827. if ( hFile == FILESYSTEM_INVALID_HANDLE || !DoesShaderCRCMatchSourceCode( m_ShaderSymbolTable.String( lookup.m_Name ), pHeader->m_nSourceCRC32, sourceCRC ) )
  2828. {
  2829. if ( hFile != FILESYSTEM_INVALID_HANDLE )
  2830. {
  2831. g_pFullFileSystem->Close( hFile );
  2832. hFile = FILESYSTEM_INVALID_HANDLE;
  2833. }
  2834. // Clear out the header that we loaded (if we loaded it) in case the CRCs don't match.
  2835. memset( pHeader, 0, sizeof( *pHeader ) );
  2836. // Dynamically compile if it's HLSL.
  2837. if ( LoadAndCreateShaders_Dynamic( lookup, bVertexShader ) )
  2838. {
  2839. return true;
  2840. }
  2841. else
  2842. {
  2843. return false;
  2844. }
  2845. }
  2846. #endif
  2847. if ( hFile == FILESYSTEM_INVALID_HANDLE )
  2848. {
  2849. lookup.m_Flags |= SHADER_FAILED_LOAD;
  2850. DevWarning( "Couldn't load %s shader %s\n", bVertexShader ? "vertex" : "pixel", pName );
  2851. return false;
  2852. }
  2853. }
  2854. else
  2855. {
  2856. lookup.m_Flags |= SHADER_IS_ASM;
  2857. }
  2858. lookup.m_Flags = pHeader->m_nFlags;
  2859. pFileCache->m_Name = lookup.m_Name;
  2860. pFileCache->m_Filename = m_ShaderSymbolTable.AddString( filename );
  2861. pFileCache->m_bVertexShader = bVertexShader;
  2862. if ( pFileCache->IsOldVersion() )
  2863. {
  2864. int referenceComboSize = ((ShaderHeader_t_v4 *)pHeader)->m_nDiffReferenceSize;
  2865. if ( referenceComboSize )
  2866. {
  2867. // cache the reference combo
  2868. pFileCache->m_ReferenceCombo.EnsureCapacity( referenceComboSize );
  2869. g_pFullFileSystem->Read( pFileCache->m_ReferenceCombo.Base(), referenceComboSize, hFile );
  2870. }
  2871. }
  2872. else
  2873. {
  2874. // cache the dictionary
  2875. pFileCache->m_StaticComboRecords.EnsureCount( pHeader->m_nNumStaticCombos );
  2876. g_pFullFileSystem->Read( pFileCache->m_StaticComboRecords.Base(), pHeader->m_nNumStaticCombos * sizeof( StaticComboRecord_t ), hFile );
  2877. if ( pFileCache->IsVersion6() )
  2878. {
  2879. // read static combo alias records
  2880. int nNumDups;
  2881. g_pFullFileSystem->Read( &nNumDups, sizeof( nNumDups ), hFile );
  2882. if ( nNumDups )
  2883. {
  2884. pFileCache->m_StaticComboDupRecords.EnsureCount( nNumDups );
  2885. g_pFullFileSystem->Read( pFileCache->m_StaticComboDupRecords.Base(), nNumDups * sizeof( StaticComboAliasRecord_t ), hFile );
  2886. }
  2887. }
  2888. }
  2889. }
  2890. // FIXME: should make lookup and ShaderStaticCombos_t are pool allocated.
  2891. int i;
  2892. lookup.m_ShaderStaticCombos.m_nCount = pHeader->m_nDynamicCombos;
  2893. lookup.m_ShaderStaticCombos.m_pHardwareShaders = new HardwareShader_t[pHeader->m_nDynamicCombos];
  2894. lookup.m_ShaderStaticCombos.m_nNumDynamicCombosAfterSkips = 0;
  2895. if ( IsPC() && m_bCreateShadersOnDemand )
  2896. {
  2897. lookup.m_ShaderStaticCombos.m_pCreationData = new ShaderStaticCombos_t::ShaderCreationData_t[pHeader->m_nDynamicCombos];
  2898. }
  2899. for ( i = 0; i < pHeader->m_nDynamicCombos; i++ )
  2900. {
  2901. lookup.m_ShaderStaticCombos.m_pHardwareShaders[i] = INVALID_HARDWARE_SHADER;
  2902. }
  2903. int nStartingOffset = 0;
  2904. int nEndingOffset = 0;
  2905. if ( pFileCache->IsOldVersion() )
  2906. {
  2907. int nDictionaryOffset = sizeof( ShaderHeader_t ) + ((ShaderHeader_t_v4 *)pHeader)->m_nDiffReferenceSize;
  2908. // read in shader's dynamic combos directory
  2909. lookup.m_pComboDictionary = new ShaderDictionaryEntry_t[pHeader->m_nDynamicCombos];
  2910. g_pFullFileSystem->Seek( hFile, nDictionaryOffset + lookup.m_nStaticIndex * sizeof( ShaderDictionaryEntry_t ), FILESYSTEM_SEEK_HEAD );
  2911. if( !g_pFullFileSystem->Read( lookup.m_pComboDictionary, pHeader->m_nDynamicCombos * sizeof( ShaderDictionaryEntry_t ), hFile ) )
  2912. {
  2913. g_pFullFileSystem->Close( hFile );
  2914. if( !IsCert() )
  2915. {
  2916. const char *pShaderName;
  2917. pShaderName = m_ShaderSymbolTable.String( pFileCache->m_Filename );
  2918. DevWarning( "Shader '%s' - Cannot read, skipping.\n", pShaderName );
  2919. }
  2920. return false;
  2921. }
  2922. // want single read of all this shader's dynamic combos into a target buffer
  2923. // shaders are written sequentially, determine starting offset and length
  2924. for ( i = 0; i < pHeader->m_nDynamicCombos; i++ )
  2925. {
  2926. if ( lookup.m_pComboDictionary[i].m_Offset == -1 )
  2927. {
  2928. // skipped
  2929. continue;
  2930. }
  2931. // ensure offsets are in fact sequentially ascending
  2932. Assert( lookup.m_pComboDictionary[i].m_Offset >= nStartingOffset && lookup.m_pComboDictionary[i].m_Size >= 0 );
  2933. if ( !nStartingOffset )
  2934. {
  2935. nStartingOffset = lookup.m_pComboDictionary[i].m_Offset;
  2936. }
  2937. nEndingOffset = lookup.m_pComboDictionary[i].m_Offset + lookup.m_pComboDictionary[i].m_Size;
  2938. }
  2939. if ( !nStartingOffset )
  2940. {
  2941. g_pFullFileSystem->Close( hFile );
  2942. const char *pShaderName;
  2943. pShaderName = m_ShaderSymbolTable.String( pFileCache->m_Filename );
  2944. DevWarning( "Shader '%s' - All dynamic combos skipped. This is bad!\n", pShaderName );
  2945. Assert( 0 );
  2946. return false;
  2947. }
  2948. }
  2949. else
  2950. {
  2951. int nStaticComboIdx = pFileCache->FindCombo( lookup.m_nStaticIndex / pFileCache->m_Header.m_nDynamicCombos );
  2952. if ( nStaticComboIdx == -1 )
  2953. {
  2954. g_pFullFileSystem->Close( hFile );
  2955. lookup.m_Flags |= SHADER_FAILED_LOAD;
  2956. const char *pShaderName;
  2957. pShaderName = m_ShaderSymbolTable.String( pFileCache->m_Filename );
  2958. DevWarning( "*************************************************\n" );
  2959. DevWarning( "Shader '%s' - Couldn't load combo %d of shader (dyn=%d)\n", pShaderName, lookup.m_nStaticIndex, pFileCache->m_Header.m_nDynamicCombos );
  2960. BitchAboutSkippedCombo( pShaderName, lookup.m_nStaticIndex / pFileCache->m_Header.m_nDynamicCombos, -1 );
  2961. DevWarning( "*************************************************\n" );
  2962. Assert( 0 );
  2963. return false;
  2964. }
  2965. nStartingOffset = pFileCache->m_StaticComboRecords[nStaticComboIdx].m_nFileOffset;
  2966. nEndingOffset = pFileCache->m_StaticComboRecords[nStaticComboIdx+1].m_nFileOffset;
  2967. }
  2968. // align offsets for unbuffered optimal i/o - fastest i/o possible
  2969. unsigned nOffsetAlign, nSizeAlign, nBufferAlign;
  2970. g_pFullFileSystem->GetOptimalIOConstraints( hFile, &nOffsetAlign, &nSizeAlign, &nBufferAlign );
  2971. unsigned int nAlignedOffset = AlignValue( ( nStartingOffset - nOffsetAlign ) + 1, nOffsetAlign );
  2972. unsigned int nAlignedBytesToRead = AlignValue( nEndingOffset - nAlignedOffset, nSizeAlign );
  2973. // used for adjusting provided buffer to actual data
  2974. lookup.m_nDataOffset = nStartingOffset - nAlignedOffset;
  2975. bool bOK = true;
  2976. if ( IsGameConsole() && g_pQueuedLoader->IsMapLoading() )
  2977. {
  2978. LoaderJob_t loaderJob;
  2979. loaderJob.m_pFilename = m_ShaderSymbolTable.String( pFileCache->m_Filename );
  2980. loaderJob.m_pPathID = "PLATFORM";
  2981. loaderJob.m_pCallback = QueuedLoaderCallback;
  2982. loaderJob.m_pContext = (void *)&lookup;
  2983. loaderJob.m_pContext2 = (void *)pFileCache->IsOldVersion();
  2984. loaderJob.m_Priority = LOADERPRIORITY_DURINGPRELOAD;
  2985. loaderJob.m_nBytesToRead = nAlignedBytesToRead;
  2986. loaderJob.m_nStartOffset = nAlignedOffset;
  2987. g_pQueuedLoader->AddJob( &loaderJob );
  2988. }
  2989. else
  2990. {
  2991. //printf("\n CShaderManager::LoadAndCreateShaders - reading %d bytes from file offset %d", nAlignedBytesToRead, nAlignedOffset);
  2992. // single optimal read of all dynamic combos into monolithic buffer
  2993. uint8 *pOptimalBuffer = (uint8 *)g_pFullFileSystem->AllocOptimalReadBuffer( hFile, nAlignedBytesToRead, nAlignedOffset );
  2994. g_pFullFileSystem->Seek( hFile, nAlignedOffset, FILESYSTEM_SEEK_HEAD );
  2995. if( g_pFullFileSystem->Read( pOptimalBuffer, nAlignedBytesToRead, hFile ) )
  2996. {
  2997. if ( pFileCache->IsOldVersion() )
  2998. {
  2999. bOK = CreateDynamicCombos_Ver4( &lookup, pOptimalBuffer );
  3000. }
  3001. else
  3002. {
  3003. bOK = CreateDynamicCombos_Ver5( &lookup, pOptimalBuffer, debugLabel );
  3004. }
  3005. }
  3006. g_pFullFileSystem->FreeOptimalReadBuffer( pOptimalBuffer );
  3007. }
  3008. g_pFullFileSystem->Close( hFile );
  3009. if ( !bOK )
  3010. {
  3011. lookup.m_Flags |= SHADER_FAILED_LOAD;
  3012. }
  3013. return bOK;
  3014. }
  3015. //----------------------------------------------------------------------------------old code
  3016. #if 0
  3017. // Set this convar internally to build or add to the shader cache file
  3018. // We really only expect this to work on POSIX
  3019. ConVar mat_cacheshaders( "mat_cacheshaders", "0", FCVAR_DEVELOPMENTONLY );
  3020. #define SHADER_CACHE_FILE "shader_cache.cfg"
  3021. #define PROGRAM_CACHE_FILE "program_cache.cfg"
  3022. static void WriteToShaderCache( const char *pShaderName, const int nIndex )
  3023. {
  3024. #ifndef DX_TO_GL_ABSTRACTION
  3025. return;
  3026. #endif
  3027. KeyValues *pShaderCache = new KeyValues( "shadercache" );
  3028. // we don't load anything, it starts empty.. pShaderCache->LoadFromFile( g_pFullFileSystem, SHADER_CACHE_FILE, "MOD" );
  3029. if ( !pShaderCache )
  3030. {
  3031. DevWarning( "Could not write to shader cache file!\n" );
  3032. return;
  3033. }
  3034. // Subkey for specific shader
  3035. KeyValues *pShaderKey = pShaderCache->FindKey( pShaderName, true );
  3036. Assert( pShaderKey );
  3037. bool bFound = false;
  3038. int nKeys = 0;
  3039. char szIndex[8];
  3040. FOR_EACH_VALUE( pShaderKey, pValues )
  3041. {
  3042. if ( pValues->GetInt() == nIndex )
  3043. {
  3044. bFound = true;
  3045. }
  3046. nKeys++;
  3047. }
  3048. if ( !bFound )
  3049. {
  3050. V_snprintf( szIndex, 8, "%d", nKeys );
  3051. pShaderKey->SetInt( szIndex, nIndex );
  3052. }
  3053. pShaderCache->SaveToFile( g_pFullFileSystem, SHADER_CACHE_FILE, "MOD" );
  3054. pShaderCache->deleteThis();
  3055. }
  3056. void CShaderManager::WarmShaderCache()
  3057. {
  3058. #ifndef DX_TO_GL_ABSTRACTION
  3059. return;
  3060. #endif
  3061. // Don't access the cache if we're building it!
  3062. if ( mat_cacheshaders.GetBool() )
  3063. return;
  3064. // Don't warm the cache if we're just going to monkey with the shaders anyway
  3065. #ifdef DYNAMIC_SHADER_COMPILE
  3066. return;
  3067. #endif
  3068. double st = Sys_FloatTime();
  3069. //
  3070. // First we warm SHADERS ===============================================
  3071. //
  3072. KeyValues *pShaderCache = new KeyValues( "shadercache" );
  3073. pShaderCache->LoadFromFile( g_pFullFileSystem, SHADER_CACHE_FILE, "MOD" );
  3074. if ( !pShaderCache )
  3075. {
  3076. DevWarning( "Could not find shader cache file!\n" );
  3077. return;
  3078. }
  3079. // Run through each shader in the cache
  3080. FOR_EACH_SUBKEY( pShaderCache, pShaderKey )
  3081. {
  3082. const char *pShaderName = pShaderKey->GetName();
  3083. bool bVertexShader = Q_stristr( pShaderName, "_vs20" ) || Q_stristr( pShaderName, "_vs30" );
  3084. FOR_EACH_VALUE( pShaderKey, pValue )
  3085. {
  3086. char temp[1024];
  3087. int staticIndex = pValue->GetInt();
  3088. if ( bVertexShader )
  3089. {
  3090. V_snprintf( temp, sizeof(temp), "vs-file %s vs-index %d", pShaderName, staticIndex );
  3091. CreateVertexShader( pShaderName, staticIndex, temp );
  3092. }
  3093. else
  3094. {
  3095. V_snprintf( temp, sizeof(temp), "ps-file %s ps-index %d", pShaderName, staticIndex );
  3096. CreatePixelShader( pShaderName, staticIndex, temp );
  3097. }
  3098. }
  3099. }
  3100. pShaderCache->deleteThis();
  3101. //
  3102. // Next, we warm PROGRAMS (which are pairs of shaders) =================
  3103. //
  3104. KeyValues *pProgramCache = new KeyValues( "programcache" );
  3105. pProgramCache->LoadFromFile( g_pFullFileSystem, PROGRAM_CACHE_FILE, "MOD" );
  3106. if ( !pProgramCache )
  3107. {
  3108. DevWarning( "Could not find program cache file!\n" );
  3109. return;
  3110. }
  3111. // Run through each program in the cache
  3112. FOR_EACH_SUBKEY( pProgramCache, pProgramKey )
  3113. {
  3114. KeyValues *pValue = pProgramKey->GetFirstValue();
  3115. const char *pVertexShaderName = pValue->GetString();
  3116. pValue = pValue->GetNextValue();
  3117. const char *pPixelShaderName = pValue->GetString();
  3118. pValue = pValue->GetNextValue();
  3119. int nVertexShaderStaticIndex = pValue->GetInt();
  3120. pValue = pValue->GetNextValue();
  3121. int nPixelShaderStaticIndex = pValue->GetInt();
  3122. pValue = pValue->GetNextValue();
  3123. int nVertexShaderDynamicIndex = pValue->GetInt();
  3124. pValue = pValue->GetNextValue();
  3125. int nPixelShaderDynamicIndex = pValue->GetInt();
  3126. ShaderLookup_t vshLookup;
  3127. vshLookup.m_Name = m_ShaderSymbolTable.AddString( pVertexShaderName ); // TODO: use String() here and catch this odd case
  3128. vshLookup.m_nStaticIndex = nVertexShaderStaticIndex;
  3129. VertexShader_t vertexShader = m_VertexShaderDict.Find( vshLookup );
  3130. ShaderLookup_t pshLookup;
  3131. pshLookup.m_Name = m_ShaderSymbolTable.AddString( pPixelShaderName );
  3132. pshLookup.m_nStaticIndex = nPixelShaderStaticIndex;
  3133. PixelShader_t pixelShader = m_PixelShaderDict.Find( pshLookup );
  3134. // If we found both shaders, do the link!
  3135. if ( ( vertexShader != m_VertexShaderDict.InvalidIndex() ) && ( pixelShader != m_PixelShaderDict.InvalidIndex() ) )
  3136. {
  3137. #ifdef DX_TO_GL_ABSTRACTION
  3138. //HardwareShader_t hardwareVertexShader = vshLookup.m_ShaderStaticCombos.m_pHardwareShaders[nVertexShaderDynamicIndex];
  3139. //HardwareShader_t hardwarePixelShader = pshLookup.m_ShaderStaticCombos.m_pHardwareShaders[nPixelShaderDynamicIndex];
  3140. HardwareShader_t hardwareVertexShader = m_VertexShaderDict[vertexShader].m_ShaderStaticCombos.m_pHardwareShaders[nVertexShaderDynamicIndex];
  3141. HardwareShader_t hardwarePixelShader = m_PixelShaderDict[pixelShader].m_ShaderStaticCombos.m_pHardwareShaders[nPixelShaderDynamicIndex];
  3142. if ( ( hardwareVertexShader != INVALID_HARDWARE_SHADER ) && ( hardwarePixelShader != INVALID_HARDWARE_SHADER ) )
  3143. {
  3144. if ( S_OK != Dx9Device()->LinkShaderPair( (IDirect3DVertexShader9 *)hardwareVertexShader, (IDirect3DPixelShader9 *)hardwarePixelShader ) )
  3145. {
  3146. DevWarning( "Could not link OpenGL shaders: %s (%d, %d) : %s (%d, %d)\n", pVertexShaderName, nVertexShaderStaticIndex, nVertexShaderDynamicIndex, pPixelShaderName, nPixelShaderStaticIndex, nPixelShaderDynamicIndex );
  3147. }
  3148. }
  3149. #endif
  3150. }
  3151. else
  3152. {
  3153. DevWarning( "Invalid shader linkage: %s (%d, %d) : %s (%d, %d)\n", pVertexShaderName, nVertexShaderStaticIndex, nVertexShaderDynamicIndex, pPixelShaderName, nPixelShaderStaticIndex, nPixelShaderDynamicIndex );
  3154. }
  3155. }
  3156. pProgramCache->deleteThis();
  3157. float elapsed = ( float )( Sys_FloatTime() - st ) * 1000.0;
  3158. DevMsg( "WarmShaderCache took %.3f msec\n", elapsed );
  3159. }
  3160. #endif
  3161. //----------------------------------------------------------------------------------old code
  3162. //-----------------------------------------------------------------------------
  3163. // Purpose: compare two KeyValues by name
  3164. //-----------------------------------------------------------------------------
  3165. typedef KeyValues* PKEYVALUES;
  3166. int __cdecl KeyValueNameCompare( const PKEYVALUES *pLeft, const PKEYVALUES *pRight )
  3167. {
  3168. // Compare vertex shader name
  3169. const char *pLeftString = (*pLeft)->GetString( "vs" );
  3170. const char *pRightString = (*pRight)->GetString( "vs" );
  3171. int nVSCompare = Q_stricmp( pLeftString, pRightString );
  3172. if ( nVSCompare > 0 )
  3173. return 1;
  3174. else if ( nVSCompare < 0 )
  3175. return -1;
  3176. // Compare pixel shader name
  3177. pLeftString = (*pLeft)->GetString( "ps" );
  3178. pRightString = (*pRight)->GetString( "ps" );
  3179. int nPSCompare = Q_stricmp( pLeftString, pRightString );
  3180. if ( nPSCompare > 0 )
  3181. return 1;
  3182. else if ( nPSCompare < 0 )
  3183. return -1;
  3184. // Compare vs static index
  3185. int nLeft = (*pLeft)->GetInt( "vs_static" );
  3186. int nRight = (*pRight)->GetInt( "vs_static" );
  3187. if ( nLeft > nRight )
  3188. return 1;
  3189. else if ( nRight > nLeft )
  3190. return -1;
  3191. // Compare ps static index
  3192. nLeft = (*pLeft)->GetInt( "ps_static" );
  3193. nRight = (*pRight)->GetInt( "ps_static" );
  3194. if ( nLeft > nRight )
  3195. return 1;
  3196. else if ( nRight > nLeft )
  3197. return -1;
  3198. // Compare vs dynamic index
  3199. nLeft = (*pLeft)->GetInt( "vs_dynamic" );
  3200. nRight = (*pRight)->GetInt( "vs_dynamic" );
  3201. if ( nLeft > nRight )
  3202. return 1;
  3203. else if ( nRight > nLeft )
  3204. return -1;
  3205. // Compare ps dynamic index
  3206. nLeft = (*pLeft)->GetInt( "ps_dynamic" );
  3207. nRight = (*pRight)->GetInt( "ps_dynamic" );
  3208. if ( nLeft > nRight )
  3209. return 1;
  3210. else if ( nRight > nLeft )
  3211. return -1;
  3212. return 0; // exactly equal...this should never happen
  3213. }
  3214. void CShaderManager::SaveShaderCache( char *cacheName )
  3215. {
  3216. #ifdef DX_TO_GL_ABSTRACTION // must ifdef, it uses calls which don't exist in the real DX9 interface
  3217. KeyValues *pProgramCache = new KeyValues( "glshadercache" );
  3218. if ( !pProgramCache )
  3219. {
  3220. DevWarning( "Could not write to program cache file!\n" );
  3221. return;
  3222. }
  3223. int i=0;
  3224. GLMShaderPairInfo info;
  3225. do
  3226. {
  3227. Dx9Device()->QueryShaderPair( i, &info );
  3228. if ( info.m_status == 1 )
  3229. {
  3230. // found one
  3231. // extract values of interest which represent a pair of shaders
  3232. if ( info.m_vsName[0] && info.m_psName[0] && (info.m_vsDynamicIndex > -1) && (info.m_psDynamicIndex > -1) )
  3233. {
  3234. // make up a key - this thing is really a list of tuples, so need not be keyed by anything particular
  3235. KeyValues *pProgramKey = pProgramCache->CreateNewKey();
  3236. Assert( pProgramKey );
  3237. pProgramKey->SetString ( "vs", info.m_vsName );
  3238. pProgramKey->SetString ( "ps", info.m_psName );
  3239. pProgramKey->SetInt ( "vs_static", info.m_vsStaticIndex );
  3240. pProgramKey->SetInt ( "ps_static", info.m_psStaticIndex );
  3241. pProgramKey->SetInt ( "vs_dynamic", info.m_vsDynamicIndex );
  3242. pProgramKey->SetInt ( "ps_dynamic", info.m_psDynamicIndex );
  3243. }
  3244. }
  3245. i++;
  3246. } while( info.m_status >= 0 );
  3247. // Let's sort these so that the shader cache files are more diff-able
  3248. CUtlVector<KeyValues *> allSubKeys;
  3249. FOR_EACH_SUBKEY( pProgramCache, pvSubKey )
  3250. {
  3251. allSubKeys.AddToTail( pvSubKey );
  3252. }
  3253. KeyValues *pProgramCacheToDisk = new KeyValues( "glshadercache" );
  3254. allSubKeys.Sort( KeyValueNameCompare );
  3255. FOR_EACH_VEC( allSubKeys, i )
  3256. {
  3257. KeyValues *pNewChild = allSubKeys[i]->MakeCopy();
  3258. char pNewChildName[8];
  3259. V_snprintf( pNewChildName, sizeof( pNewChildName ), "%d", i );
  3260. pNewChild->SetName( pNewChildName );
  3261. pProgramCacheToDisk->AddSubKey( pNewChild );
  3262. }
  3263. pProgramCacheToDisk->SaveToFile( g_pFullFileSystem, cacheName, "MOD" );
  3264. pProgramCacheToDisk->deleteThis();
  3265. pProgramCache->deleteThis();
  3266. // done! whew
  3267. #endif
  3268. }
  3269. bool CShaderManager::LoadShaderCache( char *cacheName )
  3270. {
  3271. #ifdef DX_TO_GL_ABSTRACTION
  3272. KeyValues *pProgramCache = new KeyValues( "glshadercache" );
  3273. bool found = pProgramCache->LoadFromFile( g_pFullFileSystem, cacheName, "MOD" );
  3274. if ( !found )
  3275. {
  3276. DevWarning( "Could not load program cache file %s\n", cacheName );
  3277. return false;
  3278. }
  3279. // walk the table..
  3280. // To take advantage of OpenGL implementations building GLSL shaders in parallel, we have 3 stages:
  3281. // * Issue compilation commands (vertex shader and pixel shader) (Defer querying compilation result)
  3282. // * Issue link commands (for a shader pair) (Defer querying link result)
  3283. // * Check compilation/link result
  3284. CUtlVector<CUtlKeyValuePair<HardwareShader_t, HardwareShader_t> > shaderPairList;
  3285. FOR_EACH_SUBKEY( pProgramCache, pProgramKey )
  3286. {
  3287. // extract values decribing the specific active pair
  3288. // then see if either stage needs a compilation done
  3289. // then proceed to link
  3290. KeyValues *pValue = pProgramKey->GetFirstValue();
  3291. if (!pValue)
  3292. continue;
  3293. const char *pVertexShaderName = pValue->GetString();
  3294. pValue = pValue->GetNextValue();
  3295. if (!pValue)
  3296. continue;
  3297. const char *pPixelShaderName = pValue->GetString();
  3298. pValue = pValue->GetNextValue();
  3299. if (!pValue)
  3300. continue;
  3301. int nVertexShaderStaticIndex = pValue->GetInt();
  3302. pValue = pValue->GetNextValue();
  3303. if (!pValue)
  3304. continue;
  3305. int nPixelShaderStaticIndex = pValue->GetInt();
  3306. pValue = pValue->GetNextValue();
  3307. if (!pValue)
  3308. continue;
  3309. int nVertexShaderDynamicIndex = pValue->GetInt();
  3310. pValue = pValue->GetNextValue();
  3311. if (!pValue)
  3312. continue;
  3313. int nPixelShaderDynamicIndex = pValue->GetInt();
  3314. ShaderLookup_t vshLookup;
  3315. vshLookup.m_Name = m_ShaderSymbolTable.AddString( pVertexShaderName ); // TODO: use String() here and catch this odd case
  3316. vshLookup.m_nStaticIndex = nVertexShaderStaticIndex;
  3317. VertexShader_t vertexShader = m_VertexShaderDict.Find( vshLookup );
  3318. // if the VS was not found - now is the time to build it
  3319. if( vertexShader == m_VertexShaderDict.InvalidIndex())
  3320. {
  3321. char temp[1024];
  3322. V_snprintf( temp, sizeof(temp), "vs-file %s vs-index %d", pVertexShaderName, nVertexShaderStaticIndex );
  3323. CreateVertexShader( pVertexShaderName, nVertexShaderStaticIndex, temp );
  3324. // this one should not fail
  3325. vertexShader = m_VertexShaderDict.Find( vshLookup );
  3326. Assert( vertexShader != m_VertexShaderDict.InvalidIndex());
  3327. }
  3328. ShaderLookup_t pshLookup;
  3329. pshLookup.m_Name = m_ShaderSymbolTable.AddString( pPixelShaderName );
  3330. pshLookup.m_nStaticIndex = nPixelShaderStaticIndex;
  3331. PixelShader_t pixelShader = m_PixelShaderDict.Find( pshLookup );
  3332. if( pixelShader == m_PixelShaderDict.InvalidIndex())
  3333. {
  3334. char temp[1024];
  3335. V_snprintf( temp, sizeof(temp), "ps-file %s ps-index %d", pPixelShaderName, nPixelShaderStaticIndex );
  3336. CreatePixelShader( pPixelShaderName, nPixelShaderStaticIndex, temp );
  3337. // this one should not fail
  3338. pixelShader = m_PixelShaderDict.Find( pshLookup );
  3339. Assert( pixelShader != m_PixelShaderDict.InvalidIndex());
  3340. }
  3341. // If we found both shaders, do the link!
  3342. if ( ( vertexShader != m_VertexShaderDict.InvalidIndex() ) && ( pixelShader != m_PixelShaderDict.InvalidIndex() ) )
  3343. {
  3344. // double check that the hardware shader arrays are actually instantiated.. bail on the attempt if not (odd...)
  3345. if (m_VertexShaderDict[vertexShader].m_ShaderStaticCombos.m_pHardwareShaders && m_PixelShaderDict[pixelShader].m_ShaderStaticCombos.m_pHardwareShaders)
  3346. {
  3347. // and sanity check the indices..
  3348. if ( ( nVertexShaderDynamicIndex >= 0 ) &&
  3349. ( nPixelShaderDynamicIndex >= 0 ) &&
  3350. ( nVertexShaderDynamicIndex < m_VertexShaderDict[vertexShader].m_ShaderStaticCombos.m_nCount ) &&
  3351. ( nPixelShaderDynamicIndex < m_PixelShaderDict[pixelShader].m_ShaderStaticCombos.m_nCount ) )
  3352. {
  3353. HardwareShader_t hardwareVertexShader = m_VertexShaderDict[vertexShader].m_ShaderStaticCombos.m_pHardwareShaders[nVertexShaderDynamicIndex];
  3354. HardwareShader_t hardwarePixelShader = m_PixelShaderDict[pixelShader].m_ShaderStaticCombos.m_pHardwareShaders[nPixelShaderDynamicIndex];
  3355. if ( ( hardwareVertexShader != INVALID_HARDWARE_SHADER ) && ( hardwarePixelShader != INVALID_HARDWARE_SHADER ) )
  3356. {
  3357. // Keep track of vertex and pixel shaders we need to link
  3358. shaderPairList.AddToTail( CUtlKeyValuePair<HardwareShader_t, HardwareShader_t>( hardwareVertexShader, hardwarePixelShader ) );
  3359. if (S_OK != Dx9Device()->LinkShaderPair( (IDirect3DVertexShader9 *)hardwareVertexShader, (IDirect3DPixelShader9 *)hardwarePixelShader ))
  3360. {
  3361. DevWarning( "Could not link OpenGL shaders\n" );
  3362. }
  3363. }
  3364. }
  3365. else
  3366. {
  3367. DevWarning( "nVertexShaderDynamicIndex or nPixelShaderDynamicIndex invalid\n" );
  3368. }
  3369. }
  3370. else
  3371. {
  3372. DevWarning( "m_pHardwareShaders was null\n" );
  3373. }
  3374. }
  3375. else
  3376. {
  3377. DevWarning( "Invalid shader linkage: %s (%d, %d) : %s (%d, %d)\n", pVertexShaderName, nVertexShaderStaticIndex, nVertexShaderDynamicIndex, pPixelShaderName, nPixelShaderStaticIndex, nPixelShaderDynamicIndex );
  3378. }
  3379. }
  3380. // Check compilation/link status
  3381. FOR_EACH_VEC( shaderPairList, i )
  3382. {
  3383. HardwareShader_t hardwareVertexShader = shaderPairList[i].m_key;
  3384. HardwareShader_t hardwarePixelShader = shaderPairList[i].m_value;
  3385. Dx9Device()->ValidateShaderPair( (IDirect3DVertexShader9 *)hardwareVertexShader, (IDirect3DPixelShader9 *)hardwarePixelShader );
  3386. }
  3387. pProgramCache->deleteThis();
  3388. return true;
  3389. #else
  3390. return false; // have to return a value on Windows build to appease compiler
  3391. #endif
  3392. }
  3393. //-----------------------------------------------------------------------------
  3394. // Creates and destroys vertex shaders
  3395. //-----------------------------------------------------------------------------
  3396. VertexShader_t CShaderManager::CreateVertexShader( const char *pFileName, int nStaticVshIndex, char *debugLabel )
  3397. {
  3398. MEM_ALLOC_CREDIT();
  3399. if ( !pFileName )
  3400. {
  3401. return INVALID_SHADER;
  3402. }
  3403. VertexShader_t shader;
  3404. ShaderLookup_t lookup;
  3405. lookup.m_Name = m_ShaderSymbolTable.AddString( pFileName );
  3406. lookup.m_nStaticIndex = nStaticVshIndex;
  3407. shader = m_VertexShaderDict.Find( lookup );
  3408. if ( shader == m_VertexShaderDict.InvalidIndex() )
  3409. {
  3410. //printf("\nCShaderManager::CreateVertexShader( filename = %s, staticVshIndex = %d - not in cache", pFileName, nStaticVshIndex );
  3411. shader = m_VertexShaderDict.AddToTail( lookup );
  3412. if ( !LoadAndCreateShaders( m_VertexShaderDict[shader], true, debugLabel ) )
  3413. {
  3414. return INVALID_SHADER;
  3415. }
  3416. }
  3417. m_VertexShaderDict[shader].IncRefCount();
  3418. return shader;
  3419. }
  3420. //-----------------------------------------------------------------------------
  3421. // Create pixel shader
  3422. //-----------------------------------------------------------------------------
  3423. PixelShader_t CShaderManager::CreatePixelShader( const char *pFileName, int nStaticPshIndex, char *debugLabel )
  3424. {
  3425. MEM_ALLOC_CREDIT();
  3426. if ( !pFileName )
  3427. {
  3428. return INVALID_SHADER;
  3429. }
  3430. PixelShader_t shader;
  3431. ShaderLookup_t lookup;
  3432. lookup.m_Name = m_ShaderSymbolTable.AddString( pFileName );
  3433. lookup.m_nStaticIndex = nStaticPshIndex;
  3434. shader = m_PixelShaderDict.Find( lookup );
  3435. if ( shader == m_PixelShaderDict.InvalidIndex() )
  3436. {
  3437. shader = m_PixelShaderDict.AddToTail( lookup );
  3438. if ( !LoadAndCreateShaders( m_PixelShaderDict[shader], false, debugLabel ) )
  3439. {
  3440. return INVALID_SHADER;
  3441. }
  3442. }
  3443. m_PixelShaderDict[shader].IncRefCount();
  3444. return shader;
  3445. }
  3446. //-----------------------------------------------------------------------------
  3447. // Clear the refCounts to zero
  3448. //-----------------------------------------------------------------------------
  3449. void CShaderManager::ClearVertexAndPixelShaderRefCounts()
  3450. {
  3451. for ( VertexShader_t vshIndex = m_VertexShaderDict.Head();
  3452. vshIndex != m_VertexShaderDict.InvalidIndex();
  3453. vshIndex = m_VertexShaderDict.Next( vshIndex ) )
  3454. {
  3455. m_VertexShaderDict[vshIndex].m_nRefCount = 0;
  3456. }
  3457. for ( PixelShader_t pshIndex = m_PixelShaderDict.Head();
  3458. pshIndex != m_PixelShaderDict.InvalidIndex();
  3459. pshIndex = m_PixelShaderDict.Next( pshIndex ) )
  3460. {
  3461. m_PixelShaderDict[pshIndex].m_nRefCount = 0;
  3462. }
  3463. }
  3464. //-----------------------------------------------------------------------------
  3465. // Destroy all shaders that have no reference
  3466. //-----------------------------------------------------------------------------
  3467. void CShaderManager::PurgeUnusedVertexAndPixelShaders()
  3468. {
  3469. #ifdef DX_TO_GL_ABSTRACTION
  3470. if (mat_autosave_glshaders.GetInt())
  3471. {
  3472. #if defined( OSX )
  3473. SaveShaderCache("glshaders_OSX.cfg");
  3474. #else
  3475. SaveShaderCache("glshaders.cfg");
  3476. #endif
  3477. }
  3478. return; // don't purge shaders, it's too costly to put them back
  3479. #endif
  3480. // iterate vertex shaders
  3481. for ( VertexShader_t vshIndex = m_VertexShaderDict.Head(); vshIndex != m_VertexShaderDict.InvalidIndex(); )
  3482. {
  3483. Assert( m_VertexShaderDict[vshIndex].m_nRefCount >= 0 );
  3484. // Get the next one before we potentially delete the current one.
  3485. VertexShader_t next = m_VertexShaderDict.Next( vshIndex );
  3486. if ( m_VertexShaderDict[vshIndex].m_nRefCount <= 0 )
  3487. {
  3488. DestroyVertexShader( vshIndex );
  3489. }
  3490. vshIndex = next;
  3491. }
  3492. // iterate pixel shaders
  3493. for ( PixelShader_t pshIndex = m_PixelShaderDict.Head(); pshIndex != m_PixelShaderDict.InvalidIndex(); )
  3494. {
  3495. Assert( m_PixelShaderDict[pshIndex].m_nRefCount >= 0 );
  3496. // Get the next one before we potentially delete the current one.
  3497. PixelShader_t next = m_PixelShaderDict.Next( pshIndex );
  3498. if ( m_PixelShaderDict[pshIndex].m_nRefCount <= 0 )
  3499. {
  3500. DestroyPixelShader( pshIndex );
  3501. }
  3502. pshIndex = next;
  3503. }
  3504. }
  3505. void* CShaderManager::GetCurrentVertexShader()
  3506. {
  3507. return (void*)m_HardwareVertexShader;
  3508. }
  3509. void* CShaderManager::GetCurrentPixelShader()
  3510. {
  3511. return (void*)m_HardwarePixelShader;
  3512. }
  3513. //-----------------------------------------------------------------------------
  3514. // The low-level dx call to set the vertex shader state
  3515. //-----------------------------------------------------------------------------
  3516. void CShaderManager::SetVertexShaderState_Internal( HardwareShader_t shader, DataCacheHandle_t hCachedShader )
  3517. {
  3518. if ( m_HardwareVertexShader != shader )
  3519. {
  3520. RECORD_COMMAND( DX8_SET_VERTEX_SHADER, 1 );
  3521. RECORD_INT( ( int )shader ); // hack hack hack
  3522. VPROF_INCREMENT_GROUP_COUNTER( "vertex shader change", COUNTER_GROUP_DEFAULT, 1 );
  3523. Dx9Device()->SetVertexShader( (IDirect3DVertexShader9*)shader );
  3524. m_HardwareVertexShader = shader;
  3525. }
  3526. }
  3527. void CShaderManager::BindVertexShader( VertexShaderHandle_t hVertexShader )
  3528. {
  3529. HardwareShader_t hHardwareShader = m_RawVertexShaderDict[ (VertexShaderIndex_t)hVertexShader] ;
  3530. SetVertexShaderState( hHardwareShader );
  3531. }
  3532. //-----------------------------------------------------------------------------
  3533. // Sets a particular vertex shader as the current shader
  3534. //-----------------------------------------------------------------------------
  3535. void CShaderManager::SetVertexShader( VertexShader_t shader )
  3536. {
  3537. // Determine which vertex shader to use...
  3538. if ( shader == INVALID_SHADER )
  3539. {
  3540. SetVertexShaderState( 0 );
  3541. return;
  3542. }
  3543. int vshIndex = m_nVertexShaderIndex;
  3544. Assert( vshIndex >= 0 );
  3545. if( vshIndex < 0 )
  3546. {
  3547. vshIndex = 0;
  3548. }
  3549. ShaderLookup_t &vshLookup = m_VertexShaderDict[shader];
  3550. // DevWarning( "vsh: %s static: %d dynamic: %d\n", m_ShaderSymbolTable.String( vshLookup.m_Name ),
  3551. // vshLookup.m_nStaticIndex, m_nVertexShaderIndex );
  3552. #ifdef DYNAMIC_SHADER_COMPILE
  3553. // *** IMPORTANT ***
  3554. // If enabling DYNAMIC_SHADER_COMPILE causes a crash here in a Release PC build, make sure you add the compiler switch /FC to the .vpc file.
  3555. // The crash occurs because __FILE__ macros return different values in Release vs Debug unless /FC is enabled, and so the shader path cannot be found without it.
  3556. static void* pNull = 0;
  3557. HardwareShader_t &dxshader = m_VertexShaderDict[shader].m_ShaderStaticCombos.m_pHardwareShaders ?
  3558. m_VertexShaderDict[shader].m_ShaderStaticCombos.m_pHardwareShaders[vshIndex] : pNull;
  3559. if ( dxshader == INVALID_HARDWARE_SHADER )
  3560. {
  3561. // compile it since we haven't already!
  3562. dxshader = CompileShader( m_ShaderSymbolTable.String( vshLookup.m_Name ), vshLookup.m_nStaticIndex, vshIndex, true );
  3563. Assert( dxshader != INVALID_HARDWARE_SHADER );
  3564. if( IsX360() )
  3565. {
  3566. //360 does not respond well at all to bad shaders or Error() calls. So we're staying here until we get something that compiles
  3567. while( dxshader == INVALID_HARDWARE_SHADER )
  3568. {
  3569. DevWarning( "A dynamically compiled vertex shader has failed to build. Pausing for 5 seconds and attempting rebuild.\n" );
  3570. #ifdef _WIN32
  3571. Sleep( 5000 );
  3572. #elif POSIX
  3573. usleep( 5000 );
  3574. #endif
  3575. dxshader = CompileShader( m_ShaderSymbolTable.String( vshLookup.m_Name ), vshLookup.m_nStaticIndex, vshIndex, true );
  3576. }
  3577. }
  3578. }
  3579. #else
  3580. if ( vshLookup.m_Flags & SHADER_FAILED_LOAD )
  3581. {
  3582. Assert( 0 );
  3583. return;
  3584. }
  3585. #ifdef _DEBUG
  3586. vshDebugIndex = (vshDebugIndex + 1) % MAX_SHADER_HISTORY;
  3587. Q_strncpy( vshDebugName[vshDebugIndex], m_ShaderSymbolTable.String( vshLookup.m_Name ), sizeof( vshDebugName[0] ) );
  3588. #endif
  3589. HardwareShader_t dxshader = vshLookup.m_ShaderStaticCombos.m_pHardwareShaders[vshIndex];
  3590. #endif
  3591. if ( IsPC() && ( dxshader == INVALID_HARDWARE_SHADER ) && m_bCreateShadersOnDemand )
  3592. {
  3593. #ifdef DYNAMIC_SHADER_COMPILE
  3594. ShaderStaticCombos_t::ShaderCreationData_t *pCreationData = &m_VertexShaderDict[shader].m_ShaderStaticCombos.m_pCreationData[vshIndex];
  3595. #else
  3596. ShaderStaticCombos_t::ShaderCreationData_t *pCreationData = &vshLookup.m_ShaderStaticCombos.m_pCreationData[vshIndex];
  3597. #endif
  3598. dxshader = CreateD3DVertexShader( ( DWORD * )pCreationData->ByteCode.Base(), pCreationData->ByteCode.Count(), m_ShaderSymbolTable.String( vshLookup.m_Name ) );
  3599. #ifdef DYNAMIC_SHADER_COMPILE
  3600. // copy the compiled shader handle back to wherever it's supposed to be stored
  3601. m_VertexShaderDict[shader].m_ShaderStaticCombos.m_pHardwareShaders[vshIndex] = dxshader;
  3602. #else
  3603. vshLookup.m_ShaderStaticCombos.m_pHardwareShaders[vshIndex] = dxshader;
  3604. #endif
  3605. }
  3606. Assert( dxshader );
  3607. #ifndef DYNAMIC_SHADER_COMPILE
  3608. if ( !dxshader )
  3609. {
  3610. static bool s_bFirst = true;
  3611. if ( s_bFirst )
  3612. {
  3613. s_bFirst = false;
  3614. DevWarning( "*************************************************\n" );
  3615. DevWarning( "!!!!!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" );
  3616. DevWarning( "Shader: %s static: %d dynamic: %d\n", m_ShaderSymbolTable.String( vshLookup.m_Name ), vshLookup.m_nStaticIndex, m_nVertexShaderIndex );
  3617. BitchAboutSkippedCombo( m_ShaderSymbolTable.String( vshLookup.m_Name ), vshLookup.m_nStaticIndex, m_nVertexShaderIndex );
  3618. DevWarning( "*************************************************\n" );
  3619. Assert( 0 );
  3620. }
  3621. }
  3622. #endif
  3623. SetVertexShaderState( dxshader );
  3624. }
  3625. //-----------------------------------------------------------------------------
  3626. // The low-level dx call to set the pixel shader state
  3627. //-----------------------------------------------------------------------------
  3628. void CShaderManager::SetPixelShaderState_Internal( HardwareShader_t shader, DataCacheHandle_t hCachedShader )
  3629. {
  3630. if ( m_HardwarePixelShader != shader )
  3631. {
  3632. VPROF_INCREMENT_GROUP_COUNTER( "pixel shader change", COUNTER_GROUP_DEFAULT, 1 );
  3633. Dx9Device()->SetPixelShader( (IDirect3DPixelShader*)shader );
  3634. m_HardwarePixelShader = shader;
  3635. }
  3636. }
  3637. void CShaderManager::BindPixelShader( PixelShaderHandle_t hPixelShader )
  3638. {
  3639. HardwareShader_t hHardwareShader = m_RawPixelShaderDict[ (PixelShaderIndex_t)hPixelShader ];
  3640. SetPixelShaderState( hHardwareShader );
  3641. }
  3642. #if defined ( DYNAMIC_SHADER_COMPILE ) && defined ( DEBUG )
  3643. ConVar mat_flushshaders_async( "mat_flushshaders_async", "0" );
  3644. #endif
  3645. //-----------------------------------------------------------------------------
  3646. // Sets a particular pixel shader as the current shader
  3647. //-----------------------------------------------------------------------------
  3648. void CShaderManager::SetPixelShader( PixelShader_t shader )
  3649. {
  3650. #if defined ( DYNAMIC_SHADER_COMPILE ) && defined ( DEBUG )
  3651. if ( mat_flushshaders_async.GetBool() )
  3652. {
  3653. FlushShaders();
  3654. mat_flushshaders_async.SetValue( false );
  3655. }
  3656. #endif
  3657. if ( shader == INVALID_SHADER )
  3658. {
  3659. SetPixelShaderState( 0 );
  3660. return;
  3661. }
  3662. int pshIndex = m_nPixelShaderIndex;
  3663. Assert( pshIndex >= 0 );
  3664. ShaderLookup_t &pshLookup = m_PixelShaderDict[shader];
  3665. if ( pshIndex > pshLookup.m_ShaderStaticCombos.m_nCount )
  3666. {
  3667. SetPixelShaderState( 0 );
  3668. DevWarning( "***** Invalid pixel shader index (out of range) for %s (%d of %d).\n", m_ShaderSymbolTable.String( pshLookup.m_Name ), pshIndex, pshLookup.m_ShaderStaticCombos.m_nCount );
  3669. Assert( 0 );
  3670. return;
  3671. }
  3672. // DevWarning( "psh: %s static: %d dynamic: %d\n", m_ShaderSymbolTable.String( lookup.m_Name ),
  3673. // lookup.m_nStaticIndex, m_nPixelShaderIndex );
  3674. #ifdef DYNAMIC_SHADER_COMPILE
  3675. static void* pNull;
  3676. HardwareShader_t &dxshader = m_PixelShaderDict[shader].m_ShaderStaticCombos.m_pHardwareShaders ?
  3677. m_PixelShaderDict[shader].m_ShaderStaticCombos.m_pHardwareShaders[pshIndex] : pNull;
  3678. if ( dxshader == INVALID_HARDWARE_SHADER )
  3679. {
  3680. // compile it since we haven't already!
  3681. dxshader = CompileShader( m_ShaderSymbolTable.String( pshLookup.m_Name ), pshLookup.m_nStaticIndex, pshIndex, false );
  3682. // Assert( dxshader != INVALID_HARDWARE_SHADER );
  3683. if( IsX360() )
  3684. {
  3685. //360 does not respond well at all to bad shaders or Error() calls. So we're staying here until we get something that compiles
  3686. while( dxshader == INVALID_HARDWARE_SHADER )
  3687. {
  3688. DevWarning( "A dynamically compiled pixel shader has failed to build. Pausing for 5 seconds and attempting rebuild.\n" );
  3689. #ifdef _WIN32
  3690. Sleep( 5000 );
  3691. #elif POSIX
  3692. usleep( 5000 );
  3693. #endif
  3694. dxshader = CompileShader( m_ShaderSymbolTable.String( pshLookup.m_Name ), pshLookup.m_nStaticIndex, pshIndex, false );
  3695. }
  3696. }
  3697. }
  3698. #else
  3699. if ( pshLookup.m_Flags & SHADER_FAILED_LOAD )
  3700. {
  3701. Assert( 0 );
  3702. DevWarning( "***** Trying to set a pixel shader (%s) that failed loading!\n", m_ShaderSymbolTable.String( pshLookup.m_Name ) );
  3703. return;
  3704. }
  3705. #ifdef _DEBUG
  3706. pshDebugIndex = (pshDebugIndex + 1) % MAX_SHADER_HISTORY;
  3707. Q_strncpy( pshDebugName[pshDebugIndex], m_ShaderSymbolTable.String( pshLookup.m_Name ), sizeof( pshDebugName[0] ) );
  3708. #endif
  3709. HardwareShader_t dxshader = pshLookup.m_ShaderStaticCombos.m_pHardwareShaders[pshIndex];
  3710. #endif
  3711. if ( IsPC() && ( dxshader == INVALID_HARDWARE_SHADER ) && m_bCreateShadersOnDemand )
  3712. {
  3713. #ifdef DYNAMIC_SHADER_COMPILE
  3714. ShaderStaticCombos_t::ShaderCreationData_t *pCreationData = &m_PixelShaderDict[shader].m_ShaderStaticCombos.m_pCreationData[pshIndex];
  3715. #else
  3716. ShaderStaticCombos_t::ShaderCreationData_t *pCreationData = &pshLookup.m_ShaderStaticCombos.m_pCreationData[pshIndex];
  3717. #endif
  3718. const char *pShaderName = m_ShaderSymbolTable.String( pshLookup.m_Name );
  3719. dxshader = CreateD3DPixelShader( ( DWORD * )pCreationData->ByteCode.Base(), pCreationData->iCentroidMask, pCreationData->ByteCode.Count(), pShaderName );
  3720. #ifdef DYNAMIC_SHADER_COMPILE
  3721. // copy the compiled shader handle back to wherever it's supposed to be stored
  3722. m_PixelShaderDict[shader].m_ShaderStaticCombos.m_pHardwareShaders[pshIndex] = dxshader;
  3723. #else
  3724. pshLookup.m_ShaderStaticCombos.m_pHardwareShaders[pshIndex] = dxshader;
  3725. #endif
  3726. }
  3727. AssertMsg( dxshader != INVALID_HARDWARE_SHADER, "Failed to set pixel shader." );
  3728. if ( dxshader == INVALID_HARDWARE_SHADER )
  3729. {
  3730. static bool s_bFirst = true;
  3731. if ( s_bFirst )
  3732. {
  3733. s_bFirst = false;
  3734. DevWarning( "*************************************************\n" );
  3735. DevWarning( "!!!!!Using invalid pixel 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" );
  3736. DevWarning( "Shader: %s static: %d dynamic: %d\n", m_ShaderSymbolTable.String( pshLookup.m_Name ), pshLookup.m_nStaticIndex, m_nPixelShaderIndex );
  3737. BitchAboutSkippedCombo( m_ShaderSymbolTable.String( pshLookup.m_Name ), pshLookup.m_nStaticIndex, m_nPixelShaderIndex );
  3738. DevWarning( "*************************************************\n" );
  3739. Assert( 0 );
  3740. }
  3741. }
  3742. SetPixelShaderState( dxshader );
  3743. }
  3744. //-----------------------------------------------------------------------------
  3745. // Resets the shader state
  3746. //-----------------------------------------------------------------------------
  3747. void CShaderManager::ResetShaderState()
  3748. {
  3749. // This will force the calls to SetVertexShader + SetPixelShader to actually set the state
  3750. m_HardwareVertexShader = (HardwareShader_t)-1;
  3751. m_HardwarePixelShader = (HardwareShader_t)-1;
  3752. SetVertexShader( INVALID_SHADER );
  3753. SetPixelShader( INVALID_SHADER );
  3754. }
  3755. //-----------------------------------------------------------------------------
  3756. // Destroy a particular vertex shader
  3757. //-----------------------------------------------------------------------------
  3758. void CShaderManager::DestroyVertexShader( VertexShader_t shader )
  3759. {
  3760. ShaderStaticCombos_t &combos = m_VertexShaderDict[shader].m_ShaderStaticCombos;
  3761. int i;
  3762. for ( i = 0; i < combos.m_nCount; i++ )
  3763. {
  3764. if ( combos.m_pHardwareShaders[i] != INVALID_HARDWARE_SHADER )
  3765. {
  3766. IDirect3DVertexShader9* pShader = ( IDirect3DVertexShader9 * )combos.m_pHardwareShaders[i];
  3767. UnregisterVS( pShader );
  3768. #ifdef DBGFLAG_ASSERT
  3769. int nRetVal =
  3770. #endif
  3771. pShader->Release();
  3772. Assert( nRetVal == 0 );
  3773. }
  3774. }
  3775. delete [] combos.m_pHardwareShaders;
  3776. combos.m_pHardwareShaders = NULL;
  3777. if ( combos.m_pCreationData != NULL )
  3778. {
  3779. delete [] combos.m_pCreationData;
  3780. combos.m_pCreationData = NULL;
  3781. }
  3782. m_VertexShaderDict.Remove( shader );
  3783. }
  3784. //-----------------------------------------------------------------------------
  3785. // Destroy a particular pixel shader
  3786. //-----------------------------------------------------------------------------
  3787. void CShaderManager::DestroyPixelShader( PixelShader_t pixelShader )
  3788. {
  3789. ShaderStaticCombos_t &combos = m_PixelShaderDict[pixelShader].m_ShaderStaticCombos;
  3790. int i;
  3791. for ( i = 0; i < combos.m_nCount; i++ )
  3792. {
  3793. if ( combos.m_pHardwareShaders[i] != INVALID_HARDWARE_SHADER )
  3794. {
  3795. IDirect3DPixelShader* pShader = ( IDirect3DPixelShader * )combos.m_pHardwareShaders[i];
  3796. UnregisterPS( pShader );
  3797. #ifdef DBGFLAG_ASSERT
  3798. int nRetVal =
  3799. #endif
  3800. pShader->Release();
  3801. Assert( nRetVal == 0 );
  3802. }
  3803. }
  3804. delete [] combos.m_pHardwareShaders;
  3805. combos.m_pHardwareShaders = NULL;
  3806. if ( combos.m_pCreationData != NULL )
  3807. {
  3808. delete [] combos.m_pCreationData;
  3809. combos.m_pCreationData = NULL;
  3810. }
  3811. m_PixelShaderDict.Remove( pixelShader );
  3812. }
  3813. HardwareShader_t CShaderManager::GetVertexShader( VertexShader_t vs, int dynIdx )
  3814. {
  3815. ShaderLookup_t &vshLookup = m_VertexShaderDict[vs];
  3816. HardwareShader_t dxshader = vshLookup.m_ShaderStaticCombos.m_pHardwareShaders[dynIdx];
  3817. return dxshader;
  3818. }
  3819. HardwareShader_t CShaderManager::GetPixelShader( PixelShader_t ps, int dynIdx )
  3820. {
  3821. ShaderLookup_t &pshLookup = m_PixelShaderDict[ps];
  3822. HardwareShader_t dxshader = pshLookup.m_ShaderStaticCombos.m_pHardwareShaders[dynIdx];
  3823. return dxshader;
  3824. }
  3825. //-----------------------------------------------------------------------------
  3826. // Destroys all shaders
  3827. //-----------------------------------------------------------------------------
  3828. void CShaderManager::DestroyAllShaders( void )
  3829. {
  3830. #ifdef DX_TO_GL_ABSTRACTION
  3831. return;
  3832. #endif
  3833. for ( VertexShader_t vshIndex = m_VertexShaderDict.Head();
  3834. vshIndex != m_VertexShaderDict.InvalidIndex(); )
  3835. {
  3836. Assert( m_VertexShaderDict[vshIndex].m_nRefCount >= 0 );
  3837. VertexShader_t next = m_VertexShaderDict.Next( vshIndex );
  3838. DestroyVertexShader( vshIndex );
  3839. vshIndex = next;
  3840. }
  3841. for ( PixelShader_t pshIndex = m_PixelShaderDict.Head();
  3842. pshIndex != m_PixelShaderDict.InvalidIndex(); )
  3843. {
  3844. Assert( m_PixelShaderDict[pshIndex].m_nRefCount >= 0 );
  3845. PixelShader_t next = m_PixelShaderDict.Next( pshIndex );
  3846. DestroyPixelShader( pshIndex );
  3847. pshIndex = next;
  3848. }
  3849. // invalidate the file cache
  3850. m_ShaderFileCache.Purge();
  3851. }
  3852. //-----------------------------------------------------------------------------
  3853. // print all vertex and pixel shaders along with refcounts to the console
  3854. //-----------------------------------------------------------------------------
  3855. void CShaderManager::SpewVertexAndPixelShaders( void )
  3856. {
  3857. // only spew a populated shader file cache
  3858. Msg( "\nShader File Cache:\n" );
  3859. for ( intp cacheIndex = m_ShaderFileCache.Head();
  3860. cacheIndex != m_ShaderFileCache.InvalidIndex();
  3861. cacheIndex = m_ShaderFileCache.Next( cacheIndex ) )
  3862. {
  3863. ShaderFileCache_t *pCache;
  3864. pCache = &m_ShaderFileCache[cacheIndex];
  3865. Msg( "Total Combos:%9d Static:%9d Dynamic:%7d SeekTable:%7d Ver:%d '%s'\n",
  3866. pCache->m_Header.m_nTotalCombos,
  3867. pCache->m_Header.m_nDynamicCombos ? pCache->m_Header.m_nTotalCombos/pCache->m_Header.m_nDynamicCombos : 0,
  3868. pCache->m_Header.m_nDynamicCombos,
  3869. pCache->IsOldVersion() ? 0 : pCache->m_Header.m_nNumStaticCombos,
  3870. pCache->m_Header.m_nVersion,
  3871. m_ShaderSymbolTable.String( pCache->m_Filename ) );
  3872. }
  3873. Msg( "\n" );
  3874. // spew vertex shader dictionary
  3875. int totalVertexShaders = 0;
  3876. int totalVertexShaderSets = 0;
  3877. const char *pName;
  3878. for ( VertexShader_t vshIndex = m_VertexShaderDict.Head();
  3879. vshIndex != m_VertexShaderDict.InvalidIndex();
  3880. vshIndex = m_VertexShaderDict.Next( vshIndex ) )
  3881. {
  3882. const ShaderLookup_t &lookup = m_VertexShaderDict[vshIndex];
  3883. pName = m_ShaderSymbolTable.String( lookup.m_Name );
  3884. Msg( "-- vsh 0x%8.8x: static combo:%9d dynamic combos:%6d refcount:%4d \"%s\"\n", vshIndex,
  3885. ( int )lookup.m_nStaticIndex, ( int )lookup.m_ShaderStaticCombos.m_nNumDynamicCombosAfterSkips,
  3886. lookup.m_nRefCount, pName );
  3887. Msg( " " );
  3888. PrintComboDesc( pName, ( int )lookup.m_nStaticIndex, -1 );
  3889. totalVertexShaders += lookup.m_ShaderStaticCombos.m_nNumDynamicCombosAfterSkips;
  3890. totalVertexShaderSets++;
  3891. }
  3892. // spew pixel shader dictionary
  3893. int totalPixelShaders = 0;
  3894. int totalPixelShaderSets = 0;
  3895. for ( PixelShader_t pshIndex = m_PixelShaderDict.Head();
  3896. pshIndex != m_PixelShaderDict.InvalidIndex();
  3897. pshIndex = m_PixelShaderDict.Next( pshIndex ) )
  3898. {
  3899. const ShaderLookup_t &lookup = m_PixelShaderDict[pshIndex];
  3900. pName = m_ShaderSymbolTable.String( lookup.m_Name );
  3901. Msg( "-- psh 0x%8.8x: static combo:%9d dynamic combos:%6d refcount:%4d \"%s\"\n", pshIndex,
  3902. ( int )lookup.m_nStaticIndex, ( int )lookup.m_ShaderStaticCombos.m_nNumDynamicCombosAfterSkips,
  3903. lookup.m_nRefCount, pName );
  3904. Msg( " " );
  3905. PrintComboDesc( pName, ( int )lookup.m_nStaticIndex, -1 );
  3906. totalPixelShaders += lookup.m_ShaderStaticCombos.m_nNumDynamicCombosAfterSkips;
  3907. totalPixelShaderSets++;
  3908. }
  3909. Msg( "Total unique vertex shaders: %d\n", totalVertexShaders );
  3910. Msg( "Total vertex shader sets: %d\n", totalVertexShaderSets );
  3911. Msg( "Total unique pixel shaders: %d\n", totalPixelShaders );
  3912. Msg( "Total pixel shader sets: %d\n", totalPixelShaderSets );
  3913. }
  3914. CON_COMMAND( mat_spewvertexandpixelshaders, "Print all vertex and pixel shaders currently loaded to the console" )
  3915. {
  3916. ( ( CShaderManager * )ShaderManager() )->SpewVertexAndPixelShaders();
  3917. }
  3918. const char *CShaderManager::GetActiveVertexShaderName()
  3919. {
  3920. #if !defined( _DEBUG )
  3921. return "";
  3922. #else
  3923. if ( !m_HardwareVertexShader )
  3924. {
  3925. return "NULL";
  3926. }
  3927. return vshDebugName[vshDebugIndex];
  3928. #endif
  3929. }
  3930. const char *CShaderManager::GetActivePixelShaderName()
  3931. {
  3932. #if !defined( _DEBUG )
  3933. return "";
  3934. #else
  3935. if ( !m_HardwarePixelShader )
  3936. {
  3937. return "NULL";
  3938. }
  3939. return pshDebugName[pshDebugIndex];
  3940. #endif
  3941. }
  3942. void CShaderManager::FlushShaders( void )
  3943. {
  3944. #ifdef DYNAMIC_SHADER_COMPILE
  3945. for( VertexShader_t shader = m_VertexShaderDict.Head();
  3946. shader != m_VertexShaderDict.InvalidIndex();
  3947. shader = m_VertexShaderDict.Next( shader ) )
  3948. {
  3949. int i;
  3950. ShaderStaticCombos_t &combos = m_VertexShaderDict[shader].m_ShaderStaticCombos;
  3951. if( m_VertexShaderDict[shader].m_Flags & SHADER_IS_ASM )
  3952. {
  3953. // don't nuke non-HLSL shaders since we don't dynamically compile them.
  3954. continue;
  3955. }
  3956. uint32 sourceCRC;
  3957. if ( DoesShaderCRCMatchSourceCode( m_ShaderSymbolTable.String( m_VertexShaderDict[shader].m_Name ), m_VertexShaderDict[shader].m_nVcsCrc32, sourceCRC ) )
  3958. {
  3959. continue;
  3960. }
  3961. m_VertexShaderDict[shader].m_nVcsCrc32 = sourceCRC;
  3962. for( i = 0; i < combos.m_nCount; i++ )
  3963. {
  3964. if( combos.m_pHardwareShaders[i] != INVALID_HARDWARE_SHADER )
  3965. {
  3966. DevWarning( "Releasing vertex shader %s: ", m_ShaderSymbolTable.String( m_VertexShaderDict[shader].m_Name ) );
  3967. PrintComboDesc( m_ShaderSymbolTable.String( m_VertexShaderDict[shader].m_Name ), m_VertexShaderDict[shader].m_nStaticIndex, -1 );
  3968. DevWarning( "\n" );
  3969. #ifdef _DEBUG
  3970. int nRetVal=
  3971. #endif
  3972. ( ( IDirect3DVertexShader9 * )combos.m_pHardwareShaders[i] )->Release();
  3973. Assert( nRetVal == 0 );
  3974. }
  3975. combos.m_pHardwareShaders[i] = INVALID_HARDWARE_SHADER;
  3976. }
  3977. }
  3978. for( PixelShader_t shader = m_PixelShaderDict.Head();
  3979. shader != m_PixelShaderDict.InvalidIndex();
  3980. shader = m_PixelShaderDict.Next( shader ) )
  3981. {
  3982. int i;
  3983. ShaderStaticCombos_t &combos = m_PixelShaderDict[shader].m_ShaderStaticCombos;
  3984. if( m_PixelShaderDict[shader].m_Flags & SHADER_IS_ASM )
  3985. {
  3986. // don't nuke non-HLSL shaders since we don't dynamically compile them.
  3987. continue;
  3988. }
  3989. uint32 sourceCRC;
  3990. if ( DoesShaderCRCMatchSourceCode( m_ShaderSymbolTable.String( m_PixelShaderDict[shader].m_Name ), m_PixelShaderDict[shader].m_nVcsCrc32, sourceCRC ) )
  3991. {
  3992. continue;
  3993. }
  3994. m_PixelShaderDict[shader].m_nVcsCrc32 = sourceCRC;
  3995. for( i = 0; i < combos.m_nCount; i++ )
  3996. {
  3997. if( combos.m_pHardwareShaders[i] != INVALID_HARDWARE_SHADER )
  3998. {
  3999. DevWarning( "Releasing pixel shader %s: ", m_ShaderSymbolTable.String( m_PixelShaderDict[shader].m_Name ) );
  4000. PrintComboDesc( m_ShaderSymbolTable.String( m_PixelShaderDict[shader].m_Name ), m_PixelShaderDict[shader].m_nStaticIndex, -1 );
  4001. DevWarning( "\n" );
  4002. #ifdef _DEBUG
  4003. int nRetVal =
  4004. #endif
  4005. ( ( IDirect3DPixelShader * )combos.m_pHardwareShaders[i] )->Release();
  4006. Assert( nRetVal == 0 );
  4007. }
  4008. combos.m_pHardwareShaders[i] = INVALID_HARDWARE_SHADER;
  4009. }
  4010. }
  4011. // invalidate the file cache
  4012. m_ShaderFileCache.Purge();
  4013. #endif
  4014. }
  4015. #ifdef DYNAMIC_SHADER_COMPILE
  4016. static void MatFlushShaders( void )
  4017. {
  4018. SyncShaderCache();
  4019. ( ( CShaderManager * )ShaderManager() )->FlushShaders();
  4020. }
  4021. #endif
  4022. #ifdef DYNAMIC_SHADER_COMPILE
  4023. CON_COMMAND( mat_flushshaders, "flush all hardware shaders when using DYNAMIC_SHADER_COMPILE" )
  4024. {
  4025. MatFlushShaders();
  4026. }
  4027. #endif
  4028. CON_COMMAND( mat_shadercount, "display count of all shaders and reset that count" )
  4029. {
  4030. DevWarning( "Num Pixel Shaders = %d Vertex Shaders=%d\n", s_NumPixelShadersCreated, s_NumVertexShadersCreated );
  4031. s_NumVertexShadersCreated = 0;
  4032. s_NumPixelShadersCreated = 0;
  4033. }
  4034. void DestroyAllVertexAndPixelShaders( void )
  4035. {
  4036. ( ( CShaderManager * )ShaderManager() )->DestroyAllShaders();
  4037. }
  4038. void CShaderManager::AddShaderComboInformation( const ShaderComboSemantics_t *pSemantics )
  4039. {
  4040. if ( !s_ShaderComboInfoByName.Defined( pSemantics->pShaderName ) )
  4041. {
  4042. s_ShaderComboInfoByName[pSemantics->pShaderName] = pSemantics;
  4043. }
  4044. }
  4045. #if defined( DX_TO_GL_ABSTRACTION )
  4046. void CShaderManager::DoStartupShaderPreloading()
  4047. {
  4048. if (mat_autoload_glshaders.GetInt())
  4049. {
  4050. #if defined( OSX )
  4051. // try base file
  4052. if ( !LoadShaderCache( "glbaseshaders_OSX.cfg" ) ) // factory cache
  4053. {
  4054. DevWarning( "Could not find base GL shader cache file (OSX)\n" );
  4055. }
  4056. if ( !LoadShaderCache( "glshaders_OSX.cfg" ) ) // user mutable cache
  4057. {
  4058. DevWarning( "Could not find user GL shader cache file (OSX)\n" );
  4059. }
  4060. #else
  4061. // try base file
  4062. if ( !LoadShaderCache( "glbaseshaders.cfg" ) ) // factory cache
  4063. {
  4064. DevWarning( "Could not find base GL shader cache file\n" );
  4065. }
  4066. if ( !LoadShaderCache( "glshaders.cfg" ) ) // user mutable cache
  4067. {
  4068. DevWarning( "Could not find user GL shader cache file\n" );
  4069. }
  4070. #endif
  4071. }
  4072. }
  4073. #endif