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.
775 lines
21 KiB
775 lines
21 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
// |
|
//=============================================================================// |
|
// vmpi_bareshell.cpp : Defines the entry point for the console application. |
|
// |
|
|
|
#include <windows.h> |
|
#include <conio.h> |
|
#include <process.h> |
|
#include "vmpi.h" |
|
#include "filesystem.h" |
|
#include "vmpi_filesystem.h" |
|
#include "vmpi_distribute_work.h" |
|
#include "vmpi_tools_shared.h" |
|
#include "cmdlib.h" |
|
#include "tier1/utlvector.h" |
|
#include "tier1/utlbuffer.h" |
|
#include "tier1/utllinkedlist.h" |
|
#include "tier1/utlstringmap.h" |
|
#include "tier0/icommandline.h" |
|
#include "tier1/strtools.h" |
|
#include "threads.h" |
|
#include "tier0/dbg.h" |
|
#include "interface.h" |
|
#include "ilaunchabledll.h" |
|
#include <direct.h> |
|
#include "io.h" |
|
#include <sys/types.h> |
|
#include <sys/stat.h> |
|
|
|
#define STARTWORK_PACKETID 5 |
|
#define WORKUNIT_PACKETID 6 |
|
#define ERRMSG_PACKETID 7 |
|
#define TEXTUREHADERROR_PACKETID 8 |
|
#define MACHINE_NAME 9 |
|
|
|
#define TEXTURES_PER_WORKUNIT 1 |
|
|
|
#ifdef _DEBUG |
|
//#define DEBUGFP |
|
#endif |
|
|
|
const char *g_pGameDir = NULL; |
|
const char *g_pTextureOutputDir = NULL; |
|
char g_WorkerTempPath[MAX_PATH]; |
|
char g_ExeDir[MAX_PATH]; |
|
CUtlVector<char *> g_CompileCommands; |
|
int g_nTexturesPerWorkUnit = 0; |
|
#ifdef DEBUGFP |
|
FILE *g_WorkerDebugFp = NULL; |
|
#endif |
|
bool g_bGotStartWorkPacket = false; |
|
double g_flStartTime; |
|
bool g_bVerbose = false; |
|
|
|
struct TextureInfo_t |
|
{ |
|
}; |
|
|
|
void Texture_ParseTextureInfoFromCompileCommands( int nCompileCommandID, TextureInfo_t &shaderInfo ); |
|
void Worker_GetSourceFiles( int iWorkUnit ); |
|
|
|
void Worker_GetLocalCopyOfTextureSource( const char *pVtfName ); |
|
|
|
// g_ByteCode["shadername"][shadercombo][bytecodeoffset] |
|
//typedef CUtlVector<CUtlBuffer> VectorOfBuffers_t; |
|
|
|
//CUtlStringMap<TextureInfo_t> g_TextureToTextureInfo; |
|
|
|
typedef CUtlVector<char> CharVector_t; |
|
|
|
struct SourceTargetPair_t |
|
{ |
|
char *pSrcName; |
|
char *pTargetName; |
|
}; |
|
|
|
CUtlVector<SourceTargetPair_t> g_SourceTargetPairs; |
|
|
|
CUtlStringMap<bool> g_Master_TextureHadError; |
|
|
|
CDispatchReg g_DistributeWorkReg( WORKUNIT_PACKETID, DistributeWorkDispatch ); |
|
|
|
unsigned long VMPI_Stats_GetJobWorkerID( void ) |
|
{ |
|
return 0; |
|
} |
|
|
|
|
|
bool StartWorkDispatch( MessageBuffer *pBuf, int iSource, int iPacketID ) |
|
{ |
|
g_bGotStartWorkPacket = true; |
|
return true; |
|
} |
|
|
|
CDispatchReg g_StartWorkReg( STARTWORK_PACKETID, StartWorkDispatch ); |
|
|
|
bool ErrMsgDispatch( MessageBuffer *pBuf, int iSource, int iPacketID ) |
|
{ |
|
static CUtlStringMap<bool> errorMessages; |
|
if( !errorMessages.Defined( pBuf->data + 1 ) ) |
|
{ |
|
errorMessages[pBuf->data + 1] = true; |
|
fprintf( stderr, "ERROR: %s\n", pBuf->data + 1 ); |
|
} |
|
return true; |
|
} |
|
|
|
CDispatchReg g_ErrMsgReg( ERRMSG_PACKETID, ErrMsgDispatch ); |
|
|
|
bool TextureHadErrorDispatch( MessageBuffer *pBuf, int iSource, int iPacketID ) |
|
{ |
|
g_Master_TextureHadError[pBuf->data+1] = true; |
|
return true; |
|
} |
|
|
|
CDispatchReg g_TextureHadErrorReg( TEXTUREHADERROR_PACKETID, TextureHadErrorDispatch ); |
|
|
|
void DebugOut( const char *pMsg, ... ) |
|
{ |
|
char msg[2048]; |
|
va_list marker; |
|
va_start( marker, pMsg ); |
|
_vsnprintf( msg, sizeof( msg ), pMsg, marker ); |
|
va_end( marker ); |
|
|
|
if (g_bVerbose) |
|
{ |
|
Msg( "%s", msg ); |
|
} |
|
|
|
#ifdef DEBUGFP |
|
fprintf( g_WorkerDebugFp, "%s", msg ); |
|
fflush( g_WorkerDebugFp ); |
|
#endif |
|
} |
|
|
|
|
|
// Worker should implement this so it will quit nicely when the master disconnects. |
|
void MyDisconnectHandler( int procID, const char *pReason ) |
|
{ |
|
// If we're a worker, then it's a fatal error if we lose the connection to the master. |
|
if ( !g_bMPIMaster ) |
|
{ |
|
Msg( "Master disconnected.\n "); |
|
DebugOut( "Master disconnected.\n" ); |
|
TerminateProcess( GetCurrentProcess(), 1 ); |
|
} |
|
} |
|
|
|
|
|
// pBuf is ready to read the results written to the buffer in ProcessWorkUnitFn. |
|
// work is done. .master gets it back this way. |
|
// compiled code in pBuf |
|
void Master_ReceiveWorkUnitFn( uint64 iWorkUnit, MessageBuffer *pBuf, int iWorker ) |
|
{ |
|
DebugOut( "Master_ReceiveWorkUnitFn\n" ); |
|
int textureStart = iWorkUnit * g_nTexturesPerWorkUnit; |
|
int textureEnd = textureStart + g_nTexturesPerWorkUnit; |
|
textureEnd = min( g_CompileCommands.Count(), textureEnd ); |
|
int i; |
|
for( i = textureStart; i < textureEnd; i++ ) |
|
{ |
|
int len; |
|
pBuf->read( &len, sizeof( len ) ); |
|
if( len == 0 ) |
|
{ |
|
continue; |
|
} |
|
CUtlBuffer fileData; |
|
fileData.EnsureCapacity( len ); |
|
pBuf->read( fileData.Base(), len ); |
|
|
|
Warning( "%s\n", g_CompileCommands[i] ); |
|
FILE *fp; |
|
fp = fopen( g_CompileCommands[i], "wb" ); |
|
if ( !fp ) |
|
Error( "Can't open %s for writing.\n", g_CompileCommands[i] ); |
|
fwrite( fileData.Base(), 1, len, fp ); |
|
fclose( fp ); |
|
} |
|
} |
|
|
|
// same as "system", but doesn't pop up a window |
|
void MySystem( char *pCommand ) |
|
{ |
|
FILE *batFp = fopen( "temp.bat", "w" ); |
|
fprintf( batFp, "%s\n", pCommand ); |
|
fclose( batFp ); |
|
|
|
STARTUPINFO si; |
|
PROCESS_INFORMATION pi; |
|
|
|
ZeroMemory( &si, sizeof(si) ); |
|
si.cb = sizeof(si); |
|
ZeroMemory( &pi, sizeof(pi) ); |
|
|
|
// Start the child process. |
|
if( !CreateProcess( NULL, // No module name (use command line). |
|
"temp.bat", // Command line. |
|
NULL, // Process handle not inheritable. |
|
NULL, // Thread handle not inheritable. |
|
FALSE, // Set handle inheritance to FALSE. |
|
IDLE_PRIORITY_CLASS | CREATE_NO_WINDOW, // No creation flags. |
|
NULL, // Use parent's environment block. |
|
g_WorkerTempPath, // Use parent's starting directory. |
|
&si, // Pointer to STARTUPINFO structure. |
|
&pi ) // Pointer to PROCESS_INFORMATION structure. |
|
) |
|
{ |
|
Error( "CreateProcess failed." ); |
|
Assert( 0 ); |
|
} |
|
|
|
// Wait until child process exits. |
|
WaitForSingleObject( pi.hProcess, INFINITE ); |
|
|
|
// Close process and thread handles. |
|
CloseHandle( pi.hProcess ); |
|
CloseHandle( pi.hThread ); |
|
} |
|
|
|
void VTFNameToTGAName( const char *pSrcName, char *pDstName ) |
|
{ |
|
pDstName[0] = '\0'; |
|
const char *pMaterials = Q_stristr( pSrcName, "materials" ); |
|
Assert( pMaterials ); |
|
if( pMaterials ) |
|
{ |
|
Q_strncpy( pDstName, pSrcName, pMaterials - pSrcName + 1 ); |
|
} |
|
Q_strcat( pDstName, "materialsrc", MAX_PATH ); |
|
Q_strcat( pDstName, pMaterials + strlen( "materials" ), MAX_PATH ); |
|
Q_StripExtension( pDstName, pDstName, strlen( pDstName ) ); |
|
Q_strcat( pDstName, ".tga", MAX_PATH ); |
|
} |
|
|
|
// You must append data to pBuf with the work unit results. |
|
void Worker_ProcessWorkUnitFn( int iThread, uint64 iWorkUnit, MessageBuffer *pBuf ) |
|
{ |
|
DebugOut( "Worker_ProcessWorkUnitFn textures/workunit=%d\n", g_nTexturesPerWorkUnit ); |
|
Worker_GetSourceFiles( iWorkUnit ); |
|
int textureStart = iWorkUnit * g_nTexturesPerWorkUnit; |
|
int textureEnd = textureStart + g_nTexturesPerWorkUnit; |
|
textureEnd = min( g_CompileCommands.Count(), textureEnd ); |
|
|
|
int i; |
|
for( i = textureStart; i < textureEnd; i++ ) |
|
{ |
|
DebugOut( "texture to compile: \"%s\"\n", g_CompileCommands[i] ); |
|
char cmdline[1024]; |
|
char tganame[1024]; |
|
VTFNameToTGAName( g_CompileCommands[i], tganame ); |
|
sprintf( cmdline, "vtex -allowdebug -vproject \"%s%s\" -mkdir -nopause \"%s%s\"", g_WorkerTempPath, g_pGameDir + 3, g_WorkerTempPath, tganame + 3 ); // hack hack |
|
DebugOut( cmdline ); |
|
DebugOut( "\n" ); |
|
// MySystem( cmdline ); |
|
system( cmdline ); |
|
|
|
char localVTFName[1024]; |
|
sprintf( localVTFName, "%s%s", g_WorkerTempPath, g_CompileCommands[i] + 3 ); |
|
DebugOut( "local: \"%s\"\n", localVTFName ); |
|
|
|
FILE *fp = fopen( localVTFName, "rb" ); |
|
if( fp ) |
|
{ |
|
// Send the compiled shader to the master |
|
fseek( fp, 0, SEEK_END ); |
|
int len = ftell( fp ); |
|
fseek( fp, 0, SEEK_SET ); |
|
CUtlBuffer buf; |
|
buf.EnsureCapacity( len ); |
|
int nBytesRead = fread( buf.Base(), 1, len, fp ); |
|
fclose( fp ); |
|
buf.SeekPut( CUtlBuffer::SEEK_HEAD, nBytesRead ); |
|
|
|
pBuf->write( &len, sizeof( len ) ); |
|
pBuf->write( buf.Base(), len ); |
|
} |
|
else |
|
{ |
|
// static CUtlStringMap<bool> m_FileAlreadyFailed; |
|
// |
|
// if( !m_FileAlreadyFailed.Defined( g_CompileCommands[i] ) ) |
|
// { |
|
// m_FileAlreadyFailed[g_CompileCommands[i]] = true; |
|
// CUtlVector<char> fileNameBuf; |
|
// fileNameBuf.AddToTail( ( char )TEXTUREHADERROR_PACKETID ); |
|
// int len = strlen( g_CompileCommands[i] ); |
|
// fileNameBuf.AddMultipleToTail( len + 1, g_CompileCommands[i] ); |
|
// VMPI_SendData( fileNameBuf.Base(), fileNameBuf.Count(), VMPI_MASTER_ID ); |
|
// } |
|
|
|
// Write zero to signify that we didn't do anything here. |
|
int len = 0; |
|
pBuf->write( &len, sizeof( len ) ); |
|
} |
|
VMPI_HandleSocketErrors(); |
|
} |
|
} |
|
|
|
void MakeDirHier( const char *pPath ) |
|
{ |
|
char temp[1024]; |
|
Q_strncpy( temp, pPath, 1024 ); |
|
int i; |
|
for( i = 0; i < strlen( temp ); i++ ) |
|
{ |
|
if( temp[i] == '/' || temp[i] == '\\' ) |
|
{ |
|
temp[i] = '\0'; |
|
// DebugOut( "mkdir( %s )\n", temp ); |
|
mkdir( temp ); |
|
temp[i] = '\\'; |
|
} |
|
} |
|
// DebugOut( "mkdir( %s )\n", temp ); |
|
mkdir( temp ); |
|
} |
|
|
|
void Worker_ReadFilesToCopy( void ) |
|
{ |
|
// Create virtual files for all of the stuff that we need to compile the shader |
|
// make sure and prefix the file name so that it doesn't find it locally. |
|
char filename[1024]; |
|
sprintf( filename, "%s\\filestocopy.txt", g_pGameDir ); |
|
DebugOut( "using \"%s\" as filestocopy\n", filename ); |
|
char buf[1024]; |
|
FileHandle_t fp = g_pFileSystem->Open( filename, "r" ); |
|
if( fp == FILESYSTEM_INVALID_HANDLE ) |
|
{ |
|
fprintf( stderr, "Can't open uniquefilestocopy.txt!\n" ); |
|
exit( -1 ); |
|
} |
|
|
|
while( CmdLib_FGets( buf, sizeof( buf ), fp ) ) |
|
{ |
|
// get rid of the newline if there is one. |
|
int len = strlen( buf ); |
|
if( buf[len-1] == 0xd || buf[len-1] == 0xa ) |
|
{ |
|
buf[len-1] = '\0'; |
|
} |
|
// DebugOut( "buf: %s\n", buf ); |
|
|
|
char *pStar = Q_stristr( buf, "*" ); |
|
Assert( pStar ); |
|
if( !pStar ) |
|
{ |
|
continue; |
|
} |
|
|
|
*pStar = '\0'; |
|
char *pVtfName = buf; |
|
char *pSrcName = pStar + 1; |
|
|
|
SourceTargetPair_t &pair = g_SourceTargetPairs[g_SourceTargetPairs.AddToTail()]; |
|
pair.pSrcName = strdup( pSrcName ); |
|
pair.pTargetName = strdup( pVtfName ); |
|
} |
|
g_pFileSystem->Close( fp ); |
|
} |
|
|
|
void Worker_GetSourceFiles( int iWorkUnit ) |
|
{ |
|
DebugOut( "Worker_GetSourceFiles( %d )\n", iWorkUnit ); |
|
int textureStart = iWorkUnit * g_nTexturesPerWorkUnit; |
|
int textureEnd = textureStart + g_nTexturesPerWorkUnit; |
|
textureEnd = min( g_CompileCommands.Count(), textureEnd ); |
|
int i; |
|
for( i = textureStart; i < textureEnd; i++ ) |
|
{ |
|
Worker_GetLocalCopyOfTextureSource( g_CompileCommands[i] ); |
|
} |
|
} |
|
|
|
void Worker_GetFileFromMaster( const char *pFileName ) |
|
{ |
|
DebugOut( "Worker_GetFileFromMaster: \"%s\"\n", pFileName ); |
|
FileHandle_t fp2 = g_pFileSystem->Open( pFileName, "rb" ); |
|
bool bZeroLength = false; |
|
if( fp2 == FILESYSTEM_INVALID_HANDLE ) |
|
{ |
|
bZeroLength = true; |
|
Warning( "zero length file: \"%s\"\n", pFileName ); |
|
// make a zero length file hack hack hack |
|
// continue; |
|
} |
|
CUtlVector<char> fileBuf; |
|
int fileLen = 0; |
|
if( !bZeroLength ) |
|
{ |
|
// printf( "getting local copy of file: \"%s\"\n", pFileName ); |
|
fileLen = g_pFileSystem->Size( fp2 ); |
|
fileBuf.SetCount( fileLen ); |
|
g_pFileSystem->Read( fileBuf.Base(), fileLen, fp2 ); |
|
g_pFileSystem->Close( fp2 ); |
|
} |
|
|
|
// create the dir that the file needs to go into. |
|
char path[1024]; |
|
char filename[1024]; |
|
sprintf( path, "%s%s", g_WorkerTempPath, pFileName + 3 ); // dear lord . .skip the u:\ BUG BUG BUG |
|
// printf( "creating \"%s\"\n", path ); |
|
Q_StripFilename( path ); |
|
MakeDirHier( path ); |
|
|
|
sprintf( filename, "%s%s", g_WorkerTempPath, pFileName + 3 ); // dear lord . .skip the u:\ BUG BUG BUG |
|
// printf( "creating \"%s\"\n", pFileName ); |
|
|
|
FILE *fp3 = fopen( filename, "wb" ); |
|
if( !fp3 ) |
|
{ |
|
Error( "Couldn't open \"%s\"\n", filename ); |
|
} |
|
if( !bZeroLength ) |
|
{ |
|
fwrite( fileBuf.Base(), 1, fileLen, fp3 ); |
|
} |
|
fclose( fp3 ); |
|
} |
|
|
|
void Worker_GetLocalCopyOfTextureSource( const char *pVtfName ) |
|
{ |
|
int i; |
|
for( i = 0; i < g_SourceTargetPairs.Count(); i++ ) |
|
{ |
|
// DebugOut( "comparing: \"%s\" \"%s\"\n", pVtfName, g_SourceTargetPairs[i].pTargetName ); |
|
if( Q_stricmp( pVtfName, g_SourceTargetPairs[i].pTargetName ) == 0 ) |
|
{ |
|
// DebugOut( "MATCH!\n" ); |
|
Worker_GetFileFromMaster( g_SourceTargetPairs[i].pSrcName ); |
|
} |
|
} |
|
} |
|
|
|
void Worker_GetLocalCopyOfBinary( const char *pFilename ) |
|
{ |
|
CUtlBuffer fileBuf; |
|
char tmpFilename[MAX_PATH]; |
|
sprintf( tmpFilename, "%s\\%s", g_ExeDir, pFilename ); |
|
printf( "trying to open: %s\n", tmpFilename ); |
|
|
|
FILE *fp = fopen( tmpFilename, "rb" ); |
|
if( !fp ) |
|
{ |
|
Assert( 0 ); |
|
fprintf( stderr, "Can't open %s!\n", pFilename ); |
|
exit( -1 ); |
|
} |
|
fseek( fp, 0, SEEK_END ); |
|
int fileLen = ftell( fp ); |
|
fseek( fp, 0, SEEK_SET ); |
|
fileBuf.EnsureCapacity( fileLen ); |
|
int nBytesRead = fread( fileBuf.Base(), 1, fileLen, fp ); |
|
fclose( fp ); |
|
fileBuf.SeekPut( CUtlBuffer::SEEK_HEAD, nBytesRead ); |
|
|
|
char newFilename[MAX_PATH]; |
|
sprintf( newFilename, "%s%s", g_WorkerTempPath, pFilename ); |
|
|
|
DebugOut( "this is fucked \"%s\"\n", newFilename ); |
|
FILE *fp2 = fopen( newFilename, "wb" ); |
|
if( !fp2 ) |
|
{ |
|
Assert( 0 ); |
|
fprintf( stderr, "Can't open %s!\n", newFilename ); |
|
exit( -1 ); |
|
} |
|
fwrite( fileBuf.Base(), 1, fileLen, fp2 ); |
|
fclose( fp2 ); |
|
} |
|
|
|
void Worker_GetLocalCopyOfBinaries( void ) |
|
{ |
|
Worker_GetLocalCopyOfBinary( "vtex.exe" ); |
|
Worker_GetLocalCopyOfBinary( "vtex_dll.dll" ); |
|
Worker_GetLocalCopyOfBinary( "vstdlib.dll" ); |
|
Worker_GetLocalCopyOfBinary( "tier0.dll" ); |
|
} |
|
|
|
void Shared_ParseListOfCompileCommands( void ) |
|
{ |
|
char buf[1024]; |
|
|
|
char fileListFileName[1024]; |
|
sprintf( fileListFileName, "%s\\texturelist.txt", g_pGameDir ); |
|
FileHandle_t fp = g_pFileSystem->Open( fileListFileName, "r" ); |
|
if( fp == FILESYSTEM_INVALID_HANDLE ) |
|
{ |
|
DebugOut( "Can't open %s!\n", fileListFileName ); |
|
fprintf( stderr, "Can't open %s!\n", fileListFileName ); |
|
exit( -1 ); |
|
} |
|
while( CmdLib_FGets( buf, 1023, fp ) ) |
|
{ |
|
char *pNewString = new char[ strlen( buf ) + 1 ]; |
|
strcpy( pNewString, buf ); |
|
pNewString[strlen( pNewString ) - 2] = '\0'; // This is some hacky shit right here. |
|
int newID = g_CompileCommands.AddToTail(); |
|
g_CompileCommands[newID] = pNewString; |
|
} |
|
g_pFileSystem->Close( fp ); |
|
|
|
// printf( "%d compiles\n", g_CompileCommands.Count() ); |
|
DebugOut( "%d compiles\n", g_CompileCommands.Count() ); |
|
} |
|
|
|
void SetupPaths( int argc, char **argv ) |
|
{ |
|
GetTempPath( sizeof( g_WorkerTempPath ), g_WorkerTempPath ); |
|
strcat( g_WorkerTempPath, "texturecompiletemp\\" ); |
|
char tmp[MAX_PATH]; |
|
sprintf( tmp, "rd /s /q \"%s\"", g_WorkerTempPath ); |
|
system( tmp ); |
|
_mkdir( g_WorkerTempPath ); |
|
// printf( "g_WorkerTempPath: \"%s\"\n", g_WorkerTempPath ); |
|
|
|
CommandLine()->CreateCmdLine( argc, argv ); |
|
g_pGameDir = CommandLine()->ParmValue( "-gamedir", "" ); |
|
strcpy( g_ExeDir, argv[0] ); |
|
Q_StripFilename( g_ExeDir ); |
|
Q_FixSlashes( g_ExeDir ); |
|
// printf( "exedir: \"%s\"\n", g_ExeDir ); |
|
|
|
g_pTextureOutputDir = CommandLine()->ParmValue( "-textureoutputdir", "" ); |
|
// printf( "shaderoutputdir: \"%s\"\n", g_pShaderOutputDir ); |
|
|
|
g_bVerbose = CommandLine()->FindParm("-verbose") != 0; |
|
} |
|
|
|
void SetupDebugFile( void ) |
|
{ |
|
#ifdef DEBUGFP |
|
const char *pComputerName = getenv( "COMPUTERNAME" ); |
|
char filename[MAX_PATH]; |
|
sprintf( filename, "\\\\fileserver\\user\\gary\\debug\\%s.txt", pComputerName ); |
|
g_WorkerDebugFp = fopen( filename, "w" ); |
|
Assert( g_WorkerDebugFp ); |
|
DebugOut( "opened debug file\n" ); |
|
#endif |
|
} |
|
|
|
void WriteTexture( const char *pTextureName ) |
|
{ |
|
#if 0 |
|
CUtlVector<CUtlBuffer> &byteCodeArray = g_ByteCode[pShaderName]; |
|
const ShaderInfo_t &shaderInfo = g_ShaderToShaderInfo[pShaderName]; |
|
// printf( "%s : %d combos centroid mask: 0x%x numDynamicCombos: %d flags: 0x%x\n", |
|
// pShaderName, shaderInfo.m_nTotalShaderCombos, |
|
// shaderInfo.m_CentroidMask, shaderInfo.m_nDynamicCombos, shaderInfo.m_Flags ); |
|
CUtlBuffer header; |
|
CUtlBuffer body; |
|
header.PutInt( SHADER_VCS_VERSION_NUMBER ); // version |
|
header.PutInt( shaderInfo.m_nTotalShaderCombos ); |
|
header.PutInt( shaderInfo.m_nDynamicCombos ); |
|
header.PutUnsignedInt( shaderInfo.m_Flags ); |
|
header.PutUnsignedInt( shaderInfo.m_CentroidMask ); |
|
|
|
int headerSize = sizeof( int ) * 5; |
|
int directorySize = sizeof( int ) * 2 * shaderInfo.m_nTotalShaderCombos; |
|
int bodyOffset = headerSize + directorySize; |
|
int nCombo; |
|
for( nCombo = 0; nCombo < shaderInfo.m_nTotalShaderCombos; nCombo++ ) |
|
{ |
|
CUtlBuffer &byteCode = byteCodeArray[nCombo]; |
|
if( byteCode.TellPut() == 0 ) |
|
{ |
|
// This is a skipped combo. |
|
header.PutInt( -1 ); |
|
header.PutInt( 0 ); |
|
} |
|
else |
|
{ |
|
header.PutInt( body.TellPut() + bodyOffset ); |
|
header.PutInt( byteCode.TellPut() ); |
|
body.Put( byteCode.Base(), byteCode.TellPut() ); |
|
} |
|
} |
|
|
|
char filename[MAX_PATH]; |
|
char filename2[MAX_PATH]; |
|
// strcpy( filename2, g_pShaderOutputDir ); |
|
strcpy( filename2, g_pShaderPath ); |
|
strcat( filename2, "\\shaders\\fxc" ); |
|
|
|
struct _stat buf; |
|
if( _stat( filename2, &buf ) == -1 ) |
|
{ |
|
printf( "mkdir %s\n", filename2 ); |
|
// doh. . need to make the directory that the vcs file is going to go into. |
|
_mkdir( filename2 ); |
|
} |
|
|
|
strcat( filename2, "\\" ); |
|
strcpy( filename, pShaderName ); |
|
char *dot = strstr( filename, "." ); |
|
if( dot ) |
|
{ |
|
*dot = '\0'; |
|
} |
|
strcat( filename, ".vcs" ); |
|
strcat( filename2, filename ); |
|
if( _stat( filename2, &buf ) != -1 ) |
|
{ |
|
// The file exists, let's see if it's writable. |
|
if( !( buf.st_mode & _S_IWRITE ) ) |
|
{ |
|
// It isn't writable. . we'd better change it's permissions (or check it out possibly). |
|
printf( "Warning: making %s writable!\n", filename2 ); |
|
_chmod( filename2, _S_IREAD | _S_IWRITE ); |
|
} |
|
} |
|
FILE *fp = fopen( filename2, "wb" ); |
|
if( !fp ) |
|
{ |
|
printf( "Can't open %s\n", filename2 ); |
|
return; |
|
} |
|
printf( "writing %s\n", filename ); |
|
fwrite( header.Base(), 1, headerSize + directorySize, fp ); |
|
fwrite( body.Base(), 1, body.TellPut(), fp ); |
|
fclose( fp ); |
|
#endif |
|
} |
|
|
|
void TouchFile( const char *path ) |
|
{ |
|
Warning( "TouchFile: %s\n", path ); |
|
char dir[MAX_PATH]; |
|
Q_strcpy( dir, path ); |
|
Q_StripFilename( dir ); |
|
MakeDirHier( dir ); |
|
FILE *fp = fopen( path, "wb" ); |
|
fclose( fp ); |
|
} |
|
|
|
int TextureCompile_Main( int argc, char* argv[] ) |
|
{ |
|
InstallSpewFunction(); |
|
g_bSuppressPrintfOutput = false; |
|
g_flStartTime = Plat_FloatTime(); |
|
|
|
SetupDebugFile(); |
|
numthreads = 1; // holy shit batman! |
|
SetupPaths( argc, argv ); |
|
|
|
// Master, start accepting connections. |
|
// Worker, make a connection. |
|
DebugOut( "Before VMPI_Init\n" ); |
|
g_bSuppressPrintfOutput = true; |
|
VMPIRunMode mode = VMPI_RUN_NETWORKED; |
|
if ( !VMPI_Init( argc, argv, "dependency_info_texturecompile.txt", MyDisconnectHandler, mode ) ) |
|
{ |
|
g_bSuppressPrintfOutput = false; |
|
DebugOut( "MPI_Init failed.\n" ); |
|
Error( "MPI_Init failed." ); |
|
} |
|
g_bSuppressPrintfOutput = false; |
|
|
|
DebugOut( "After VMPI_Init\n" ); |
|
|
|
int maxFileSystemMemoryUsageBytes = 50000000; |
|
CmdLib_InitFileSystem( ".", maxFileSystemMemoryUsageBytes ); |
|
|
|
DebugOut( "After VMPI_FileSystem_Init\n" ); |
|
Shared_ParseListOfCompileCommands(); |
|
DebugOut( "After Shared_ParseListOfCompileCommands\n" ); |
|
|
|
// 4-ish work units per machine |
|
g_nTexturesPerWorkUnit = TEXTURES_PER_WORKUNIT; |
|
int nWorkUnits = g_CompileCommands.Count() / g_nTexturesPerWorkUnit + 1; |
|
|
|
// printf( "nWorkUnits: %d\n", nWorkUnits ); |
|
// printf( "g_nShadersPerWorkUnit: %d\n", g_nShadersPerWorkUnit ); |
|
|
|
DebugOut( "Before conditional\n" ); |
|
if ( g_bMPIMaster ) |
|
{ |
|
// Send all of the workers the complete list of work to do. |
|
DebugOut( "Before STARTWORK_PACKETID\n" ); |
|
|
|
char packetID = STARTWORK_PACKETID; |
|
VMPI_SendData( &packetID, sizeof( packetID ), VMPI_PERSISTENT ); |
|
|
|
// nWorkUnits is how many work units. . .1000 is good. |
|
// The work unit number impies which combo to do. |
|
DebugOut( "Before DistributeWork\n" ); |
|
DistributeWork( nWorkUnits, WORKUNIT_PACKETID, NULL, Master_ReceiveWorkUnitFn ); |
|
} |
|
else |
|
{ |
|
// wait until we get a packet from the master to start doing stuff. |
|
MessageBuffer buf; |
|
DebugOut( "Before VMPI_DispatchUntil\n" ); |
|
while ( !g_bGotStartWorkPacket ) |
|
{ |
|
VMPI_DispatchNextMessage(); |
|
} |
|
DebugOut( "after VMPI_DispatchUntil\n" ); |
|
|
|
Worker_ReadFilesToCopy(); |
|
// Worker_GetSourceFiles(); |
|
// DebugOut( "Before Worker_GetLocalCopyOfShaders\n" ); |
|
// Worker_GetLocalCopyOfTextureSource(); |
|
// DebugOut( "Before Worker_GetLocalCopyOfBinaries\n" ); |
|
DebugOut( "Before _chdir\n" ); |
|
_chdir( g_WorkerTempPath ); |
|
|
|
// DIE DIE KILL KILL AHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|
char path[MAX_PATH]; |
|
sprintf( path, "%s%s\\bin\\server.dll", g_WorkerTempPath, g_pGameDir + 3 ); // hack hack |
|
TouchFile( path ); |
|
sprintf( path, "%s%s\\bin\\client.dll", g_WorkerTempPath, g_pGameDir + 3 );// hack hack |
|
TouchFile( path ); |
|
|
|
Worker_GetLocalCopyOfBinaries(); |
|
|
|
// nWorkUnits is how many work units. . .1000 is good. |
|
// The work unit number impies which combo to do. |
|
DebugOut( "Before DistributeWork\n" ); |
|
|
|
DistributeWork( nWorkUnits, WORKUNIT_PACKETID, Worker_ProcessWorkUnitFn, NULL ); |
|
} |
|
|
|
DebugOut( "Before VMPI_Finalize\n" ); |
|
g_bSuppressPrintfOutput = true; |
|
VMPI_FileSystem_Term(); |
|
VMPI_Finalize(); |
|
g_bSuppressPrintfOutput = false; |
|
|
|
if( g_bMPIMaster ) |
|
{ |
|
/* |
|
printf( "\n" ); |
|
int nStrings = g_ByteCode.GetNumStrings(); |
|
int i; |
|
for( i = 0; i < nStrings; i++ ) |
|
{ |
|
if( g_Master_TextureHadError.Defined( g_ByteCode.String( i ) ) ) |
|
{ |
|
printf( "FAILED: \"%s\"\n", g_ByteCode.String( i ) ); |
|
} |
|
else |
|
{ |
|
// printf( "\"%s\" succeeded!\n", g_ByteCode.String( i ) ); |
|
WriteTexture( g_ByteCode.String( i ) ); |
|
} |
|
} |
|
|
|
double end = Plat_FloatTime(); |
|
|
|
char str[512]; |
|
GetHourMinuteSecondsString( (int)( end - g_flStartTime ), str, sizeof( str ) ); |
|
Msg( "%s elapsed\n", str ); |
|
*/ |
|
} |
|
return 0; |
|
} |
|
|
|
class CTextureCompileDLL : public ILaunchableDLL |
|
{ |
|
int main( int argc, char **argv ); |
|
}; |
|
|
|
int CTextureCompileDLL::main( int argc, char **argv ) |
|
{ |
|
return TextureCompile_Main( argc, argv ); |
|
} |
|
|
|
EXPOSE_SINGLE_INTERFACE( CTextureCompileDLL, ILaunchableDLL, LAUNCHABLE_DLL_INTERFACE_VERSION );
|
|
|