summaryrefslogtreecommitdiff
path: root/utils/shadercompile/d3dxfxc.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /utils/shadercompile/d3dxfxc.cpp
downloadarchived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.tar.xz
archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.zip
Diffstat (limited to 'utils/shadercompile/d3dxfxc.cpp')
-rw-r--r--utils/shadercompile/d3dxfxc.cpp259
1 files changed, 259 insertions, 0 deletions
diff --git a/utils/shadercompile/d3dxfxc.cpp b/utils/shadercompile/d3dxfxc.cpp
new file mode 100644
index 0000000..98327e9
--- /dev/null
+++ b/utils/shadercompile/d3dxfxc.cpp
@@ -0,0 +1,259 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: D3DX command implementation.
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#include "shadercompile.h"
+
+#include "d3dxfxc.h"
+#include "cmdsink.h"
+
+// Required to compile using D3DX* routines in the same process
+#include <d3dx9shader.h>
+#include "dx_proxy/dx_proxy.h"
+
+#include <tier0/icommandline.h>
+#include <tier1/strtools.h>
+
+#define D3DXSHADER_MICROCODE_BACKEND_OLD_DEPRECATED ( 1 << 25 )
+
+namespace InterceptFxc
+{
+
+ // The command that is intercepted by this namespace routines
+ static const char *s_pszCommand = "fxc.exe ";
+ static size_t s_uCommandLen = strlen( s_pszCommand );
+
+ namespace Private
+ {
+ //
+ // Response implementation
+ //
+ class CResponse : public CmdSink::IResponse
+ {
+ public:
+ explicit CResponse( LPD3DXBUFFER pShader, LPD3DXBUFFER pListing, HRESULT hr );
+ ~CResponse( void );
+
+ public:
+ virtual bool Succeeded( void ) { return m_pShader && (m_hr == D3D_OK); }
+ virtual size_t GetResultBufferLen( void ) { return ( Succeeded() ? m_pShader->GetBufferSize() : 0 ); }
+ virtual const void * GetResultBuffer( void ) { return ( Succeeded() ? m_pShader->GetBufferPointer() : NULL ); }
+ virtual const char * GetListing( void ) { return (const char *) ( m_pListing ? m_pListing->GetBufferPointer() : NULL ); }
+
+ protected:
+ LPD3DXBUFFER m_pShader;
+ LPD3DXBUFFER m_pListing;
+ HRESULT m_hr;
+ };
+
+ CResponse::CResponse( LPD3DXBUFFER pShader, LPD3DXBUFFER pListing, HRESULT hr ) :
+ m_pShader(pShader),
+ m_pListing(pListing),
+ m_hr(hr)
+ {
+ NULL;
+ }
+
+ CResponse::~CResponse( void )
+ {
+ if ( m_pShader )
+ m_pShader->Release();
+
+ if ( m_pListing )
+ m_pListing->Release();
+ }
+
+ //
+ // Perform a fast shader file compilation.
+ // TODO: avoid writing "shader.o" and "output.txt" files to avoid extra filesystem access.
+ //
+ // @param pszFilename the filename to compile (e.g. "debugdrawenvmapmask_vs20.fxc")
+ // @param pMacros null-terminated array of macro-defines
+ // @param pszModel shader model for compilation
+ //
+ void FastShaderCompile( const char *pszFilename, const D3DXMACRO *pMacros, const char *pszModel, CmdSink::IResponse **ppResponse )
+ {
+ LPD3DXBUFFER pShader = NULL; // NOTE: Must release the COM interface later
+ LPD3DXBUFFER pErrorMessages = NULL; // NOTE: Must release COM interface later
+
+ // DxProxyModule
+ static DxProxyModule s_dxModule;
+
+ // X360TEMP: This needs to be moved to an external semantic (or fixed)
+ bool bIsX360 = false;
+ for ( int i=0; ;i++ )
+ {
+ if ( !pMacros[i].Name )
+ {
+ break;
+ }
+ if ( V_stristr( pMacros[i].Name, "_X360" ) && atoi( pMacros[i].Definition ) )
+ {
+ bIsX360 = true;
+ break;
+ }
+ }
+
+ HRESULT hr = s_dxModule.D3DXCompileShaderFromFile( pszFilename, pMacros, NULL /* LPD3DXINCLUDE */,
+ "main", pszModel, 0, &pShader, &pErrorMessages,
+ NULL /* LPD3DXCONSTANTTABLE *ppConstantTable */ );
+
+ if ( ppResponse )
+ {
+ *ppResponse = new CResponse( pShader, pErrorMessages, hr );
+ }
+ else
+ {
+ if ( pShader )
+ {
+ pShader->Release();
+ }
+
+ if ( pErrorMessages )
+ {
+ pErrorMessages->Release();
+ }
+ }
+ }
+
+ }; // namespace Private
+
+ //
+ // Completely mimic the behaviour of "fxc.exe" in the specific cases related
+ // to shader compilations.
+ //
+ // @param pCommand the command in form
+ // "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"
+ //
+ void ExecuteCommand( const char *pCommand, CmdSink::IResponse **ppResponse )
+ {
+ // Expect that the command passed is exactly "fxc.exe"
+ Assert( !strncmp( pCommand, s_pszCommand, s_uCommandLen ) );
+ pCommand += s_uCommandLen;
+
+ // A duplicate portion of memory for modifications
+ void *bufEditableCommand = alloca( strlen( pCommand ) + 1 );
+ char *pEditableCommand = strcpy( (char *) bufEditableCommand, pCommand );
+
+ // Macros to be defined for D3DX
+ CUtlVector<D3DXMACRO> macros;
+
+ // Shader model (determined when parsing "/D" flags)
+ const char *pszShaderModel = NULL;
+
+ // Iterate over the command line and find all "/D...=..." settings
+ for ( char *pszFlag = pEditableCommand;
+ ( pszFlag = strstr( pszFlag, "/D" ) ) != NULL;
+ /* advance inside */ )
+ {
+ // Make sure this is a command-line flag (basic check for preceding space)
+ if ( pszFlag > pEditableCommand &&
+ pszFlag[-1] &&
+ ' ' != pszFlag[-1] )
+ {
+ ++ pszFlag;
+ continue;
+ }
+
+ // Name is immediately after "/D"
+ char *pszFlagName = pszFlag + 2; // 2 = length of "/D"
+ // Value will be determined later
+ char *pszValue = "";
+
+ if ( char *pchEq = strchr( pszFlag, '=' ) )
+ {
+ // Value is after '=' sign
+ *pchEq = 0;
+ pszValue = pchEq + 1;
+ pszFlag = pszValue;
+ }
+
+ if ( char *pchSpace = strchr( pszFlag, ' ' ) )
+ {
+ // Space is designating the end of the flag
+ *pchSpace = 0;
+ pszFlag = pchSpace + 1;
+ }
+ else
+ {
+ // Reached end of command line
+ pszFlag = "";
+ }
+
+ // Shader model extraction
+ if ( !strncmp(pszFlagName, "SHADER_MODEL_", 13) )
+ {
+ pszShaderModel = pszFlagName + 13;
+ }
+
+ // Add the macro definition to the macros array
+ int iMacroIdx = macros.AddToTail();
+ D3DXMACRO &m = macros[iMacroIdx];
+
+ // Fill the macro data
+ m.Name = pszFlagName;
+ m.Definition = pszValue;
+ }
+
+ // Add a NULL-terminator
+ {
+ D3DXMACRO nullTerminatorMacro = { NULL, NULL };
+ macros.AddToTail( nullTerminatorMacro );
+ }
+
+ // Convert shader model to lowercase
+ char chShaderModel[20] = {0};
+ if(pszShaderModel)
+ {
+ Q_strncpy( chShaderModel, pszShaderModel, sizeof(chShaderModel) - 1 );
+ }
+ Q_strlower( chShaderModel );
+
+ // Determine the file name (at the end of the command line before redirection)
+ char const *pszFilename = "";
+ if ( const char *pchCmdRedirect = strstr( pCommand, ">output.txt " ) )
+ {
+ size_t uCmdEndOffset = ( pchCmdRedirect - pCommand );
+
+ pEditableCommand[uCmdEndOffset] = 0;
+ pszFilename = &pEditableCommand[uCmdEndOffset];
+
+ while ( pszFilename > pEditableCommand &&
+ pszFilename[-1] &&
+ ' ' != pszFilename[-1] )
+ {
+ -- pszFilename;
+ }
+ }
+
+ // Compile the stuff
+ Private::FastShaderCompile( pszFilename, macros.Base(), chShaderModel, ppResponse );
+ }
+
+ bool TryExecuteCommand( const char *pCommand, CmdSink::IResponse **ppResponse )
+ {
+ {
+ static bool s_bNoIntercept = ( CommandLine()->FindParm("-nointercept") != 0 );
+ static int s_dummy = ( Msg( s_bNoIntercept ?
+ "[shadercompile] Using old slow technique - runs 'fxc.exe'.\n" :
+ "[shadercompile] Using new faster Vitaliy's implementation.\n" ), 1 );
+ if ( !s_bNoIntercept && !strncmp(pCommand, InterceptFxc::s_pszCommand, InterceptFxc::s_uCommandLen) )
+ {
+ // Trap "fxc.exe" so that we did not spawn extra process every time
+ InterceptFxc::ExecuteCommand( pCommand, ppResponse );
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+}; // namespace InterceptFxc
+
+
+
+