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.

278 lines
7.3 KiB

  1. //====== Copyright � 1996-2006, Valve Corporation, All rights reserved. =======//
  2. //
  3. // Purpose: D3DX command implementation.
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "shadercompile.h"
  9. #include "d3dxfxc.h"
  10. #include "cmdsink.h"
  11. // Required to compile using D3DX* routines in the same process
  12. #include <d3dx9shader.h>
  13. #include "dx_proxy/dx_proxy.h"
  14. #include <tier0/icommandline.h>
  15. #include <tier1/strtools.h>
  16. #define D3DXSHADER_MICROCODE_BACKEND_OLD_DEPRECATED ( 1 << 25 )
  17. namespace InterceptFxc
  18. {
  19. // The command that is intercepted by this namespace routines
  20. enum ExecutableEnum
  21. {
  22. EXEC_FXC,
  23. EXEC_SCE_CGC,
  24. EXEC_COUNT
  25. };
  26. static const char * g_pExecutables[EXEC_COUNT] =
  27. {
  28. "fxc.exe",
  29. "sce-cgc.exe"
  30. };
  31. namespace Private
  32. {
  33. //
  34. // Response implementation
  35. //
  36. class CResponse : public CmdSink::IResponse
  37. {
  38. public:
  39. explicit CResponse( LPD3DXBUFFER pShader, LPD3DXBUFFER pListing, HRESULT hr );
  40. ~CResponse( void );
  41. public:
  42. virtual bool Succeeded( void ) { return m_pShader && (m_hr == D3D_OK); }
  43. virtual size_t GetResultBufferLen( void ) { return ( Succeeded() ? m_pShader->GetBufferSize() : 0 ); }
  44. virtual const void * GetResultBuffer( void ) { return ( Succeeded() ? m_pShader->GetBufferPointer() : NULL ); }
  45. virtual const char * GetListing( void ) { return (const char *) ( m_pListing ? m_pListing->GetBufferPointer() : NULL ); }
  46. protected:
  47. LPD3DXBUFFER m_pShader;
  48. LPD3DXBUFFER m_pListing;
  49. HRESULT m_hr;
  50. };
  51. CResponse::CResponse( LPD3DXBUFFER pShader, LPD3DXBUFFER pListing, HRESULT hr ) :
  52. m_pShader(pShader),
  53. m_pListing(pListing),
  54. m_hr(hr)
  55. {
  56. NULL;
  57. }
  58. CResponse::~CResponse( void )
  59. {
  60. if ( m_pShader )
  61. m_pShader->Release();
  62. if ( m_pListing )
  63. m_pListing->Release();
  64. }
  65. //
  66. // Perform a fast shader file compilation.
  67. // TODO: avoid writing "shader.o" and "output.txt" files to avoid extra filesystem access.
  68. //
  69. // @param pszFilename the filename to compile (e.g. "debugdrawenvmapmask_vs20.fxc")
  70. // @param pMacros null-terminated array of macro-defines
  71. // @param pszModel shader model for compilation
  72. //
  73. void FastShaderCompile( ExecutableEnum nExecutable, const char *pszFilename, const D3DXMACRO *pMacros, const char *pszModel, CmdSink::IResponse **ppResponse )
  74. {
  75. LPD3DXBUFFER pShader = NULL; // NOTE: Must release the COM interface later
  76. LPD3DXBUFFER pErrorMessages = NULL; // NOTE: Must release COM interface later
  77. HRESULT hresult = S_OK;
  78. static DxProxyModule s_dxModule;
  79. hresult = s_dxModule.D3DXCompileShaderFromFile( pszFilename, pMacros, NULL /* LPD3DXINCLUDE */,
  80. "main", pszModel, 0, &pShader, &pErrorMessages,
  81. NULL /* LPD3DXCONSTANTTABLE *ppConstantTable */ );
  82. if ( ppResponse )
  83. {
  84. *ppResponse = new CResponse( pShader, pErrorMessages, hresult );
  85. }
  86. else
  87. {
  88. if ( pShader )
  89. {
  90. pShader->Release();
  91. }
  92. if ( pErrorMessages )
  93. {
  94. pErrorMessages->Release();
  95. }
  96. }
  97. }
  98. }; // namespace Private
  99. // return the next option (starting with -D or /D), or NULL
  100. inline char * FindOptionD( char * pCommand )
  101. {
  102. char * p = pCommand;
  103. while( V_isspace(*p) )
  104. ++p;
  105. while( *p )
  106. {
  107. if( ( *p == '/' || *p == '-' ) && p[1] == 'D' )
  108. {
  109. return p + 2;
  110. }
  111. ++p;
  112. }
  113. return NULL;
  114. }
  115. //
  116. // Completely mimic the behaviour of "fxc.exe" in the specific cases related
  117. // to shader compilations.
  118. //
  119. // @param pCommand the command in form
  120. // "fxc.exe /DSHADERCOMBO=1 /DTOTALSHADERCOMBOS=4 /DCENTROIDMASK=0 /DNUMDYNAMICCOMBOS=4 /DFLAGS=0x0 /DNUM_BONES=1 /Dmain=main /Emain /Tvs_2_0 /DSHADER_MODEL_VS_2_0=1 /D_X360=1 /nologo /Foshader.o debugdrawenvmapmask_vs20.fxc>output.txt 2>&1"
  121. //
  122. void ExecuteCommand( ExecutableEnum nExecutable, const char *pCommand, CmdSink::IResponse **ppResponse )
  123. {
  124. // A duplicate portion of memory for modifications
  125. void *bufEditableCommand = alloca( strlen( pCommand ) + 1 );
  126. char *pEditableCommand = strcpy( (char *) bufEditableCommand, pCommand );
  127. // Macros to be defined for D3DX
  128. CUtlVector<D3DXMACRO> macros;
  129. // Shader model (determined when parsing "/D" flags)
  130. const char *pszShaderModel = NULL;
  131. // Iterate over the command line and find all "/D...=..." settings
  132. for ( char *pszFlag = pEditableCommand;
  133. ( pszFlag = FindOptionD( pszFlag ) ) != NULL;
  134. /* advance inside */ )
  135. {
  136. // Name is immediately after "/D" or "-D", which is taken care of by FindOptionD
  137. char *pszFlagName = pszFlag ;
  138. // Value will be determined later
  139. char *pszValue = "";
  140. if ( char *pchEq = strchr( pszFlag, '=' ) )
  141. {
  142. // Value is after '=' sign
  143. *pchEq = 0;
  144. pszValue = pchEq + 1;
  145. pszFlag = pszValue;
  146. }
  147. if ( char *pchSpace = strchr( pszFlag, ' ' ) )
  148. {
  149. // Space is designating the end of the flag
  150. *pchSpace = 0;
  151. pszFlag = pchSpace + 1;
  152. }
  153. else
  154. {
  155. // Reached end of command line
  156. pszFlag = "";
  157. }
  158. // Shader model extraction; see src\devtools\bin\fxc_prep.pl for details how this is generated;
  159. // for PS3, it'll be sce_vp_rsx or sce_fp_rsx
  160. if ( !strncmp(pszFlagName, "SHADER_MODEL_", 13) )
  161. {
  162. pszShaderModel = pszFlagName + 13;
  163. }
  164. // Add the macro definition to the macros array
  165. int iMacroIdx = macros.AddToTail();
  166. D3DXMACRO &m = macros[iMacroIdx];
  167. // Fill the macro data
  168. m.Name = pszFlagName;
  169. m.Definition = pszValue;
  170. }
  171. // Add a NULL-terminator
  172. {
  173. D3DXMACRO nullTerminatorMacro = { NULL, NULL };
  174. macros.AddToTail( nullTerminatorMacro );
  175. }
  176. // Convert shader model to lowercase
  177. char chShaderModel[20] = {0};
  178. if(pszShaderModel)
  179. {
  180. Q_strncpy( chShaderModel, pszShaderModel, sizeof(chShaderModel) - 1 );
  181. }
  182. Q_strlower( chShaderModel );
  183. // Determine the file name (at the end of the command line before redirection)
  184. char const *pszFilename = "";
  185. if ( const char *pchCmdRedirect = strstr( pCommand, ">output.txt " ) )
  186. {
  187. size_t uCmdEndOffset = ( pchCmdRedirect - pCommand );
  188. pEditableCommand[uCmdEndOffset] = 0;
  189. pszFilename = &pEditableCommand[uCmdEndOffset];
  190. while ( pszFilename > pEditableCommand &&
  191. pszFilename[-1] &&
  192. ' ' != pszFilename[-1] )
  193. {
  194. -- pszFilename;
  195. }
  196. }
  197. // Compile the stuff
  198. Private::FastShaderCompile( nExecutable, pszFilename, macros.Base(), chShaderModel, ppResponse );
  199. }
  200. bool TryExecuteCommand( const char *pCommand, CmdSink::IResponse **ppResponse )
  201. {
  202. {
  203. static bool s_bNoIntercept = ( CommandLine()->FindParm("-nointercept") != 0 );
  204. if ( !s_bNoIntercept )
  205. {
  206. const char * pExecutable = pCommand;
  207. while( *pExecutable && V_isspace(*pExecutable) )
  208. ++pExecutable;
  209. const char *pExecutableEnd = pExecutable;
  210. while( *pExecutableEnd && !V_isspace(*pExecutableEnd) )
  211. ++pExecutableEnd;
  212. for( int i = 0;i < EXEC_COUNT; ++i )
  213. {
  214. if( pExecutable == strstr( pExecutable, g_pExecutables[i] ) )
  215. {
  216. // Trap "???.exe" so that we did not spawn extra process
  217. //Msg( "[shadercompile] Intercepting call to %s\n", g_pExecutables[i] );
  218. const char *pParameters = pExecutableEnd;
  219. while( *pParameters && V_isspace(*pParameters) )
  220. ++pParameters ;
  221. InterceptFxc::ExecuteCommand( ( ExecutableEnum )i, pParameters, ppResponse );
  222. return true;
  223. }
  224. }
  225. }
  226. }
  227. return false;
  228. }
  229. }; // namespace InterceptFxc