Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

775 lines
21 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. // vmpi_bareshell.cpp : Defines the entry point for the console application.
  9. //
  10. #include <windows.h>
  11. #include <conio.h>
  12. #include <process.h>
  13. #include "vmpi.h"
  14. #include "filesystem.h"
  15. #include "vmpi_filesystem.h"
  16. #include "vmpi_distribute_work.h"
  17. #include "vmpi_tools_shared.h"
  18. #include "cmdlib.h"
  19. #include "tier1/utlvector.h"
  20. #include "tier1/utlbuffer.h"
  21. #include "tier1/utllinkedlist.h"
  22. #include "tier1/utlstringmap.h"
  23. #include "tier0/icommandline.h"
  24. #include "tier1/strtools.h"
  25. #include "threads.h"
  26. #include "tier0/dbg.h"
  27. #include "interface.h"
  28. #include "ilaunchabledll.h"
  29. #include <direct.h>
  30. #include "io.h"
  31. #include <sys/types.h>
  32. #include <sys/stat.h>
  33. #define STARTWORK_PACKETID 5
  34. #define WORKUNIT_PACKETID 6
  35. #define ERRMSG_PACKETID 7
  36. #define TEXTUREHADERROR_PACKETID 8
  37. #define MACHINE_NAME 9
  38. #define TEXTURES_PER_WORKUNIT 1
  39. #ifdef _DEBUG
  40. //#define DEBUGFP
  41. #endif
  42. const char *g_pGameDir = NULL;
  43. const char *g_pTextureOutputDir = NULL;
  44. char g_WorkerTempPath[MAX_PATH];
  45. char g_ExeDir[MAX_PATH];
  46. CUtlVector<char *> g_CompileCommands;
  47. int g_nTexturesPerWorkUnit = 0;
  48. #ifdef DEBUGFP
  49. FILE *g_WorkerDebugFp = NULL;
  50. #endif
  51. bool g_bGotStartWorkPacket = false;
  52. double g_flStartTime;
  53. bool g_bVerbose = false;
  54. struct TextureInfo_t
  55. {
  56. };
  57. void Texture_ParseTextureInfoFromCompileCommands( int nCompileCommandID, TextureInfo_t &shaderInfo );
  58. void Worker_GetSourceFiles( int iWorkUnit );
  59. void Worker_GetLocalCopyOfTextureSource( const char *pVtfName );
  60. // g_ByteCode["shadername"][shadercombo][bytecodeoffset]
  61. //typedef CUtlVector<CUtlBuffer> VectorOfBuffers_t;
  62. //CUtlStringMap<TextureInfo_t> g_TextureToTextureInfo;
  63. typedef CUtlVector<char> CharVector_t;
  64. struct SourceTargetPair_t
  65. {
  66. char *pSrcName;
  67. char *pTargetName;
  68. };
  69. CUtlVector<SourceTargetPair_t> g_SourceTargetPairs;
  70. CUtlStringMap<bool> g_Master_TextureHadError;
  71. CDispatchReg g_DistributeWorkReg( WORKUNIT_PACKETID, DistributeWorkDispatch );
  72. unsigned long VMPI_Stats_GetJobWorkerID( void )
  73. {
  74. return 0;
  75. }
  76. bool StartWorkDispatch( MessageBuffer *pBuf, int iSource, int iPacketID )
  77. {
  78. g_bGotStartWorkPacket = true;
  79. return true;
  80. }
  81. CDispatchReg g_StartWorkReg( STARTWORK_PACKETID, StartWorkDispatch );
  82. bool ErrMsgDispatch( MessageBuffer *pBuf, int iSource, int iPacketID )
  83. {
  84. static CUtlStringMap<bool> errorMessages;
  85. if( !errorMessages.Defined( pBuf->data + 1 ) )
  86. {
  87. errorMessages[pBuf->data + 1] = true;
  88. fprintf( stderr, "ERROR: %s\n", pBuf->data + 1 );
  89. }
  90. return true;
  91. }
  92. CDispatchReg g_ErrMsgReg( ERRMSG_PACKETID, ErrMsgDispatch );
  93. bool TextureHadErrorDispatch( MessageBuffer *pBuf, int iSource, int iPacketID )
  94. {
  95. g_Master_TextureHadError[pBuf->data+1] = true;
  96. return true;
  97. }
  98. CDispatchReg g_TextureHadErrorReg( TEXTUREHADERROR_PACKETID, TextureHadErrorDispatch );
  99. void DebugOut( const char *pMsg, ... )
  100. {
  101. char msg[2048];
  102. va_list marker;
  103. va_start( marker, pMsg );
  104. _vsnprintf( msg, sizeof( msg ), pMsg, marker );
  105. va_end( marker );
  106. if (g_bVerbose)
  107. {
  108. Msg( "%s", msg );
  109. }
  110. #ifdef DEBUGFP
  111. fprintf( g_WorkerDebugFp, "%s", msg );
  112. fflush( g_WorkerDebugFp );
  113. #endif
  114. }
  115. // Worker should implement this so it will quit nicely when the master disconnects.
  116. void MyDisconnectHandler( int procID, const char *pReason )
  117. {
  118. // If we're a worker, then it's a fatal error if we lose the connection to the master.
  119. if ( !g_bMPIMaster )
  120. {
  121. Msg( "Master disconnected.\n ");
  122. DebugOut( "Master disconnected.\n" );
  123. TerminateProcess( GetCurrentProcess(), 1 );
  124. }
  125. }
  126. // pBuf is ready to read the results written to the buffer in ProcessWorkUnitFn.
  127. // work is done. .master gets it back this way.
  128. // compiled code in pBuf
  129. void Master_ReceiveWorkUnitFn( uint64 iWorkUnit, MessageBuffer *pBuf, int iWorker )
  130. {
  131. DebugOut( "Master_ReceiveWorkUnitFn\n" );
  132. int textureStart = iWorkUnit * g_nTexturesPerWorkUnit;
  133. int textureEnd = textureStart + g_nTexturesPerWorkUnit;
  134. textureEnd = min( g_CompileCommands.Count(), textureEnd );
  135. int i;
  136. for( i = textureStart; i < textureEnd; i++ )
  137. {
  138. int len;
  139. pBuf->read( &len, sizeof( len ) );
  140. if( len == 0 )
  141. {
  142. continue;
  143. }
  144. CUtlBuffer fileData;
  145. fileData.EnsureCapacity( len );
  146. pBuf->read( fileData.Base(), len );
  147. Warning( "%s\n", g_CompileCommands[i] );
  148. FILE *fp;
  149. fp = fopen( g_CompileCommands[i], "wb" );
  150. if ( !fp )
  151. Error( "Can't open %s for writing.\n", g_CompileCommands[i] );
  152. fwrite( fileData.Base(), 1, len, fp );
  153. fclose( fp );
  154. }
  155. }
  156. // same as "system", but doesn't pop up a window
  157. void MySystem( char *pCommand )
  158. {
  159. FILE *batFp = fopen( "temp.bat", "w" );
  160. fprintf( batFp, "%s\n", pCommand );
  161. fclose( batFp );
  162. STARTUPINFO si;
  163. PROCESS_INFORMATION pi;
  164. ZeroMemory( &si, sizeof(si) );
  165. si.cb = sizeof(si);
  166. ZeroMemory( &pi, sizeof(pi) );
  167. // Start the child process.
  168. if( !CreateProcess( NULL, // No module name (use command line).
  169. "temp.bat", // Command line.
  170. NULL, // Process handle not inheritable.
  171. NULL, // Thread handle not inheritable.
  172. FALSE, // Set handle inheritance to FALSE.
  173. IDLE_PRIORITY_CLASS | CREATE_NO_WINDOW, // No creation flags.
  174. NULL, // Use parent's environment block.
  175. g_WorkerTempPath, // Use parent's starting directory.
  176. &si, // Pointer to STARTUPINFO structure.
  177. &pi ) // Pointer to PROCESS_INFORMATION structure.
  178. )
  179. {
  180. Error( "CreateProcess failed." );
  181. Assert( 0 );
  182. }
  183. // Wait until child process exits.
  184. WaitForSingleObject( pi.hProcess, INFINITE );
  185. // Close process and thread handles.
  186. CloseHandle( pi.hProcess );
  187. CloseHandle( pi.hThread );
  188. }
  189. void VTFNameToTGAName( const char *pSrcName, char *pDstName )
  190. {
  191. pDstName[0] = '\0';
  192. const char *pMaterials = Q_stristr( pSrcName, "materials" );
  193. Assert( pMaterials );
  194. if( pMaterials )
  195. {
  196. Q_strncpy( pDstName, pSrcName, pMaterials - pSrcName + 1 );
  197. }
  198. Q_strcat( pDstName, "materialsrc", MAX_PATH );
  199. Q_strcat( pDstName, pMaterials + strlen( "materials" ), MAX_PATH );
  200. Q_StripExtension( pDstName, pDstName, strlen( pDstName ) );
  201. Q_strcat( pDstName, ".tga", MAX_PATH );
  202. }
  203. // You must append data to pBuf with the work unit results.
  204. void Worker_ProcessWorkUnitFn( int iThread, uint64 iWorkUnit, MessageBuffer *pBuf )
  205. {
  206. DebugOut( "Worker_ProcessWorkUnitFn textures/workunit=%d\n", g_nTexturesPerWorkUnit );
  207. Worker_GetSourceFiles( iWorkUnit );
  208. int textureStart = iWorkUnit * g_nTexturesPerWorkUnit;
  209. int textureEnd = textureStart + g_nTexturesPerWorkUnit;
  210. textureEnd = min( g_CompileCommands.Count(), textureEnd );
  211. int i;
  212. for( i = textureStart; i < textureEnd; i++ )
  213. {
  214. DebugOut( "texture to compile: \"%s\"\n", g_CompileCommands[i] );
  215. char cmdline[1024];
  216. char tganame[1024];
  217. VTFNameToTGAName( g_CompileCommands[i], tganame );
  218. sprintf( cmdline, "vtex -allowdebug -vproject \"%s%s\" -mkdir -nopause \"%s%s\"", g_WorkerTempPath, g_pGameDir + 3, g_WorkerTempPath, tganame + 3 ); // hack hack
  219. DebugOut( cmdline );
  220. DebugOut( "\n" );
  221. // MySystem( cmdline );
  222. system( cmdline );
  223. char localVTFName[1024];
  224. sprintf( localVTFName, "%s%s", g_WorkerTempPath, g_CompileCommands[i] + 3 );
  225. DebugOut( "local: \"%s\"\n", localVTFName );
  226. FILE *fp = fopen( localVTFName, "rb" );
  227. if( fp )
  228. {
  229. // Send the compiled shader to the master
  230. fseek( fp, 0, SEEK_END );
  231. int len = ftell( fp );
  232. fseek( fp, 0, SEEK_SET );
  233. CUtlBuffer buf;
  234. buf.EnsureCapacity( len );
  235. int nBytesRead = fread( buf.Base(), 1, len, fp );
  236. fclose( fp );
  237. buf.SeekPut( CUtlBuffer::SEEK_HEAD, nBytesRead );
  238. pBuf->write( &len, sizeof( len ) );
  239. pBuf->write( buf.Base(), len );
  240. }
  241. else
  242. {
  243. // static CUtlStringMap<bool> m_FileAlreadyFailed;
  244. //
  245. // if( !m_FileAlreadyFailed.Defined( g_CompileCommands[i] ) )
  246. // {
  247. // m_FileAlreadyFailed[g_CompileCommands[i]] = true;
  248. // CUtlVector<char> fileNameBuf;
  249. // fileNameBuf.AddToTail( ( char )TEXTUREHADERROR_PACKETID );
  250. // int len = strlen( g_CompileCommands[i] );
  251. // fileNameBuf.AddMultipleToTail( len + 1, g_CompileCommands[i] );
  252. // VMPI_SendData( fileNameBuf.Base(), fileNameBuf.Count(), VMPI_MASTER_ID );
  253. // }
  254. // Write zero to signify that we didn't do anything here.
  255. int len = 0;
  256. pBuf->write( &len, sizeof( len ) );
  257. }
  258. VMPI_HandleSocketErrors();
  259. }
  260. }
  261. void MakeDirHier( const char *pPath )
  262. {
  263. char temp[1024];
  264. Q_strncpy( temp, pPath, 1024 );
  265. int i;
  266. for( i = 0; i < strlen( temp ); i++ )
  267. {
  268. if( temp[i] == '/' || temp[i] == '\\' )
  269. {
  270. temp[i] = '\0';
  271. // DebugOut( "mkdir( %s )\n", temp );
  272. mkdir( temp );
  273. temp[i] = '\\';
  274. }
  275. }
  276. // DebugOut( "mkdir( %s )\n", temp );
  277. mkdir( temp );
  278. }
  279. void Worker_ReadFilesToCopy( void )
  280. {
  281. // Create virtual files for all of the stuff that we need to compile the shader
  282. // make sure and prefix the file name so that it doesn't find it locally.
  283. char filename[1024];
  284. sprintf( filename, "%s\\filestocopy.txt", g_pGameDir );
  285. DebugOut( "using \"%s\" as filestocopy\n", filename );
  286. char buf[1024];
  287. FileHandle_t fp = g_pFileSystem->Open( filename, "r" );
  288. if( fp == FILESYSTEM_INVALID_HANDLE )
  289. {
  290. fprintf( stderr, "Can't open uniquefilestocopy.txt!\n" );
  291. exit( -1 );
  292. }
  293. while( CmdLib_FGets( buf, sizeof( buf ), fp ) )
  294. {
  295. // get rid of the newline if there is one.
  296. int len = strlen( buf );
  297. if( buf[len-1] == 0xd || buf[len-1] == 0xa )
  298. {
  299. buf[len-1] = '\0';
  300. }
  301. // DebugOut( "buf: %s\n", buf );
  302. char *pStar = Q_stristr( buf, "*" );
  303. Assert( pStar );
  304. if( !pStar )
  305. {
  306. continue;
  307. }
  308. *pStar = '\0';
  309. char *pVtfName = buf;
  310. char *pSrcName = pStar + 1;
  311. SourceTargetPair_t &pair = g_SourceTargetPairs[g_SourceTargetPairs.AddToTail()];
  312. pair.pSrcName = strdup( pSrcName );
  313. pair.pTargetName = strdup( pVtfName );
  314. }
  315. g_pFileSystem->Close( fp );
  316. }
  317. void Worker_GetSourceFiles( int iWorkUnit )
  318. {
  319. DebugOut( "Worker_GetSourceFiles( %d )\n", iWorkUnit );
  320. int textureStart = iWorkUnit * g_nTexturesPerWorkUnit;
  321. int textureEnd = textureStart + g_nTexturesPerWorkUnit;
  322. textureEnd = min( g_CompileCommands.Count(), textureEnd );
  323. int i;
  324. for( i = textureStart; i < textureEnd; i++ )
  325. {
  326. Worker_GetLocalCopyOfTextureSource( g_CompileCommands[i] );
  327. }
  328. }
  329. void Worker_GetFileFromMaster( const char *pFileName )
  330. {
  331. DebugOut( "Worker_GetFileFromMaster: \"%s\"\n", pFileName );
  332. FileHandle_t fp2 = g_pFileSystem->Open( pFileName, "rb" );
  333. bool bZeroLength = false;
  334. if( fp2 == FILESYSTEM_INVALID_HANDLE )
  335. {
  336. bZeroLength = true;
  337. Warning( "zero length file: \"%s\"\n", pFileName );
  338. // make a zero length file hack hack hack
  339. // continue;
  340. }
  341. CUtlVector<char> fileBuf;
  342. int fileLen = 0;
  343. if( !bZeroLength )
  344. {
  345. // printf( "getting local copy of file: \"%s\"\n", pFileName );
  346. fileLen = g_pFileSystem->Size( fp2 );
  347. fileBuf.SetCount( fileLen );
  348. g_pFileSystem->Read( fileBuf.Base(), fileLen, fp2 );
  349. g_pFileSystem->Close( fp2 );
  350. }
  351. // create the dir that the file needs to go into.
  352. char path[1024];
  353. char filename[1024];
  354. sprintf( path, "%s%s", g_WorkerTempPath, pFileName + 3 ); // dear lord . .skip the u:\ BUG BUG BUG
  355. // printf( "creating \"%s\"\n", path );
  356. Q_StripFilename( path );
  357. MakeDirHier( path );
  358. sprintf( filename, "%s%s", g_WorkerTempPath, pFileName + 3 ); // dear lord . .skip the u:\ BUG BUG BUG
  359. // printf( "creating \"%s\"\n", pFileName );
  360. FILE *fp3 = fopen( filename, "wb" );
  361. if( !fp3 )
  362. {
  363. Error( "Couldn't open \"%s\"\n", filename );
  364. }
  365. if( !bZeroLength )
  366. {
  367. fwrite( fileBuf.Base(), 1, fileLen, fp3 );
  368. }
  369. fclose( fp3 );
  370. }
  371. void Worker_GetLocalCopyOfTextureSource( const char *pVtfName )
  372. {
  373. int i;
  374. for( i = 0; i < g_SourceTargetPairs.Count(); i++ )
  375. {
  376. // DebugOut( "comparing: \"%s\" \"%s\"\n", pVtfName, g_SourceTargetPairs[i].pTargetName );
  377. if( Q_stricmp( pVtfName, g_SourceTargetPairs[i].pTargetName ) == 0 )
  378. {
  379. // DebugOut( "MATCH!\n" );
  380. Worker_GetFileFromMaster( g_SourceTargetPairs[i].pSrcName );
  381. }
  382. }
  383. }
  384. void Worker_GetLocalCopyOfBinary( const char *pFilename )
  385. {
  386. CUtlBuffer fileBuf;
  387. char tmpFilename[MAX_PATH];
  388. sprintf( tmpFilename, "%s\\%s", g_ExeDir, pFilename );
  389. printf( "trying to open: %s\n", tmpFilename );
  390. FILE *fp = fopen( tmpFilename, "rb" );
  391. if( !fp )
  392. {
  393. Assert( 0 );
  394. fprintf( stderr, "Can't open %s!\n", pFilename );
  395. exit( -1 );
  396. }
  397. fseek( fp, 0, SEEK_END );
  398. int fileLen = ftell( fp );
  399. fseek( fp, 0, SEEK_SET );
  400. fileBuf.EnsureCapacity( fileLen );
  401. int nBytesRead = fread( fileBuf.Base(), 1, fileLen, fp );
  402. fclose( fp );
  403. fileBuf.SeekPut( CUtlBuffer::SEEK_HEAD, nBytesRead );
  404. char newFilename[MAX_PATH];
  405. sprintf( newFilename, "%s%s", g_WorkerTempPath, pFilename );
  406. DebugOut( "this is fucked \"%s\"\n", newFilename );
  407. FILE *fp2 = fopen( newFilename, "wb" );
  408. if( !fp2 )
  409. {
  410. Assert( 0 );
  411. fprintf( stderr, "Can't open %s!\n", newFilename );
  412. exit( -1 );
  413. }
  414. fwrite( fileBuf.Base(), 1, fileLen, fp2 );
  415. fclose( fp2 );
  416. }
  417. void Worker_GetLocalCopyOfBinaries( void )
  418. {
  419. Worker_GetLocalCopyOfBinary( "vtex.exe" );
  420. Worker_GetLocalCopyOfBinary( "vtex_dll.dll" );
  421. Worker_GetLocalCopyOfBinary( "vstdlib.dll" );
  422. Worker_GetLocalCopyOfBinary( "tier0.dll" );
  423. }
  424. void Shared_ParseListOfCompileCommands( void )
  425. {
  426. char buf[1024];
  427. char fileListFileName[1024];
  428. sprintf( fileListFileName, "%s\\texturelist.txt", g_pGameDir );
  429. FileHandle_t fp = g_pFileSystem->Open( fileListFileName, "r" );
  430. if( fp == FILESYSTEM_INVALID_HANDLE )
  431. {
  432. DebugOut( "Can't open %s!\n", fileListFileName );
  433. fprintf( stderr, "Can't open %s!\n", fileListFileName );
  434. exit( -1 );
  435. }
  436. while( CmdLib_FGets( buf, 1023, fp ) )
  437. {
  438. char *pNewString = new char[ strlen( buf ) + 1 ];
  439. strcpy( pNewString, buf );
  440. pNewString[strlen( pNewString ) - 2] = '\0'; // This is some hacky shit right here.
  441. int newID = g_CompileCommands.AddToTail();
  442. g_CompileCommands[newID] = pNewString;
  443. }
  444. g_pFileSystem->Close( fp );
  445. // printf( "%d compiles\n", g_CompileCommands.Count() );
  446. DebugOut( "%d compiles\n", g_CompileCommands.Count() );
  447. }
  448. void SetupPaths( int argc, char **argv )
  449. {
  450. GetTempPath( sizeof( g_WorkerTempPath ), g_WorkerTempPath );
  451. strcat( g_WorkerTempPath, "texturecompiletemp\\" );
  452. char tmp[MAX_PATH];
  453. sprintf( tmp, "rd /s /q \"%s\"", g_WorkerTempPath );
  454. system( tmp );
  455. _mkdir( g_WorkerTempPath );
  456. // printf( "g_WorkerTempPath: \"%s\"\n", g_WorkerTempPath );
  457. CommandLine()->CreateCmdLine( argc, argv );
  458. g_pGameDir = CommandLine()->ParmValue( "-gamedir", "" );
  459. strcpy( g_ExeDir, argv[0] );
  460. Q_StripFilename( g_ExeDir );
  461. Q_FixSlashes( g_ExeDir );
  462. // printf( "exedir: \"%s\"\n", g_ExeDir );
  463. g_pTextureOutputDir = CommandLine()->ParmValue( "-textureoutputdir", "" );
  464. // printf( "shaderoutputdir: \"%s\"\n", g_pShaderOutputDir );
  465. g_bVerbose = CommandLine()->FindParm("-verbose") != 0;
  466. }
  467. void SetupDebugFile( void )
  468. {
  469. #ifdef DEBUGFP
  470. const char *pComputerName = getenv( "COMPUTERNAME" );
  471. char filename[MAX_PATH];
  472. sprintf( filename, "\\\\fileserver\\user\\gary\\debug\\%s.txt", pComputerName );
  473. g_WorkerDebugFp = fopen( filename, "w" );
  474. Assert( g_WorkerDebugFp );
  475. DebugOut( "opened debug file\n" );
  476. #endif
  477. }
  478. void WriteTexture( const char *pTextureName )
  479. {
  480. #if 0
  481. CUtlVector<CUtlBuffer> &byteCodeArray = g_ByteCode[pShaderName];
  482. const ShaderInfo_t &shaderInfo = g_ShaderToShaderInfo[pShaderName];
  483. // printf( "%s : %d combos centroid mask: 0x%x numDynamicCombos: %d flags: 0x%x\n",
  484. // pShaderName, shaderInfo.m_nTotalShaderCombos,
  485. // shaderInfo.m_CentroidMask, shaderInfo.m_nDynamicCombos, shaderInfo.m_Flags );
  486. CUtlBuffer header;
  487. CUtlBuffer body;
  488. header.PutInt( SHADER_VCS_VERSION_NUMBER ); // version
  489. header.PutInt( shaderInfo.m_nTotalShaderCombos );
  490. header.PutInt( shaderInfo.m_nDynamicCombos );
  491. header.PutUnsignedInt( shaderInfo.m_Flags );
  492. header.PutUnsignedInt( shaderInfo.m_CentroidMask );
  493. int headerSize = sizeof( int ) * 5;
  494. int directorySize = sizeof( int ) * 2 * shaderInfo.m_nTotalShaderCombos;
  495. int bodyOffset = headerSize + directorySize;
  496. int nCombo;
  497. for( nCombo = 0; nCombo < shaderInfo.m_nTotalShaderCombos; nCombo++ )
  498. {
  499. CUtlBuffer &byteCode = byteCodeArray[nCombo];
  500. if( byteCode.TellPut() == 0 )
  501. {
  502. // This is a skipped combo.
  503. header.PutInt( -1 );
  504. header.PutInt( 0 );
  505. }
  506. else
  507. {
  508. header.PutInt( body.TellPut() + bodyOffset );
  509. header.PutInt( byteCode.TellPut() );
  510. body.Put( byteCode.Base(), byteCode.TellPut() );
  511. }
  512. }
  513. char filename[MAX_PATH];
  514. char filename2[MAX_PATH];
  515. // strcpy( filename2, g_pShaderOutputDir );
  516. strcpy( filename2, g_pShaderPath );
  517. strcat( filename2, "\\shaders\\fxc" );
  518. struct _stat buf;
  519. if( _stat( filename2, &buf ) == -1 )
  520. {
  521. printf( "mkdir %s\n", filename2 );
  522. // doh. . need to make the directory that the vcs file is going to go into.
  523. _mkdir( filename2 );
  524. }
  525. strcat( filename2, "\\" );
  526. strcpy( filename, pShaderName );
  527. char *dot = strstr( filename, "." );
  528. if( dot )
  529. {
  530. *dot = '\0';
  531. }
  532. strcat( filename, ".vcs" );
  533. strcat( filename2, filename );
  534. if( _stat( filename2, &buf ) != -1 )
  535. {
  536. // The file exists, let's see if it's writable.
  537. if( !( buf.st_mode & _S_IWRITE ) )
  538. {
  539. // It isn't writable. . we'd better change it's permissions (or check it out possibly).
  540. printf( "Warning: making %s writable!\n", filename2 );
  541. _chmod( filename2, _S_IREAD | _S_IWRITE );
  542. }
  543. }
  544. FILE *fp = fopen( filename2, "wb" );
  545. if( !fp )
  546. {
  547. printf( "Can't open %s\n", filename2 );
  548. return;
  549. }
  550. printf( "writing %s\n", filename );
  551. fwrite( header.Base(), 1, headerSize + directorySize, fp );
  552. fwrite( body.Base(), 1, body.TellPut(), fp );
  553. fclose( fp );
  554. #endif
  555. }
  556. void TouchFile( const char *path )
  557. {
  558. Warning( "TouchFile: %s\n", path );
  559. char dir[MAX_PATH];
  560. Q_strcpy( dir, path );
  561. Q_StripFilename( dir );
  562. MakeDirHier( dir );
  563. FILE *fp = fopen( path, "wb" );
  564. fclose( fp );
  565. }
  566. int TextureCompile_Main( int argc, char* argv[] )
  567. {
  568. InstallSpewFunction();
  569. g_bSuppressPrintfOutput = false;
  570. g_flStartTime = Plat_FloatTime();
  571. SetupDebugFile();
  572. numthreads = 1; // holy shit batman!
  573. SetupPaths( argc, argv );
  574. // Master, start accepting connections.
  575. // Worker, make a connection.
  576. DebugOut( "Before VMPI_Init\n" );
  577. g_bSuppressPrintfOutput = true;
  578. VMPIRunMode mode = VMPI_RUN_NETWORKED;
  579. if ( !VMPI_Init( argc, argv, "dependency_info_texturecompile.txt", MyDisconnectHandler, mode ) )
  580. {
  581. g_bSuppressPrintfOutput = false;
  582. DebugOut( "MPI_Init failed.\n" );
  583. Error( "MPI_Init failed." );
  584. }
  585. g_bSuppressPrintfOutput = false;
  586. DebugOut( "After VMPI_Init\n" );
  587. int maxFileSystemMemoryUsageBytes = 50000000;
  588. CmdLib_InitFileSystem( ".", maxFileSystemMemoryUsageBytes );
  589. DebugOut( "After VMPI_FileSystem_Init\n" );
  590. Shared_ParseListOfCompileCommands();
  591. DebugOut( "After Shared_ParseListOfCompileCommands\n" );
  592. // 4-ish work units per machine
  593. g_nTexturesPerWorkUnit = TEXTURES_PER_WORKUNIT;
  594. int nWorkUnits = g_CompileCommands.Count() / g_nTexturesPerWorkUnit + 1;
  595. // printf( "nWorkUnits: %d\n", nWorkUnits );
  596. // printf( "g_nShadersPerWorkUnit: %d\n", g_nShadersPerWorkUnit );
  597. DebugOut( "Before conditional\n" );
  598. if ( g_bMPIMaster )
  599. {
  600. // Send all of the workers the complete list of work to do.
  601. DebugOut( "Before STARTWORK_PACKETID\n" );
  602. char packetID = STARTWORK_PACKETID;
  603. VMPI_SendData( &packetID, sizeof( packetID ), VMPI_PERSISTENT );
  604. // nWorkUnits is how many work units. . .1000 is good.
  605. // The work unit number impies which combo to do.
  606. DebugOut( "Before DistributeWork\n" );
  607. DistributeWork( nWorkUnits, WORKUNIT_PACKETID, NULL, Master_ReceiveWorkUnitFn );
  608. }
  609. else
  610. {
  611. // wait until we get a packet from the master to start doing stuff.
  612. MessageBuffer buf;
  613. DebugOut( "Before VMPI_DispatchUntil\n" );
  614. while ( !g_bGotStartWorkPacket )
  615. {
  616. VMPI_DispatchNextMessage();
  617. }
  618. DebugOut( "after VMPI_DispatchUntil\n" );
  619. Worker_ReadFilesToCopy();
  620. // Worker_GetSourceFiles();
  621. // DebugOut( "Before Worker_GetLocalCopyOfShaders\n" );
  622. // Worker_GetLocalCopyOfTextureSource();
  623. // DebugOut( "Before Worker_GetLocalCopyOfBinaries\n" );
  624. DebugOut( "Before _chdir\n" );
  625. _chdir( g_WorkerTempPath );
  626. // DIE DIE KILL KILL AHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  627. char path[MAX_PATH];
  628. sprintf( path, "%s%s\\bin\\server.dll", g_WorkerTempPath, g_pGameDir + 3 ); // hack hack
  629. TouchFile( path );
  630. sprintf( path, "%s%s\\bin\\client.dll", g_WorkerTempPath, g_pGameDir + 3 );// hack hack
  631. TouchFile( path );
  632. Worker_GetLocalCopyOfBinaries();
  633. // nWorkUnits is how many work units. . .1000 is good.
  634. // The work unit number impies which combo to do.
  635. DebugOut( "Before DistributeWork\n" );
  636. DistributeWork( nWorkUnits, WORKUNIT_PACKETID, Worker_ProcessWorkUnitFn, NULL );
  637. }
  638. DebugOut( "Before VMPI_Finalize\n" );
  639. g_bSuppressPrintfOutput = true;
  640. VMPI_FileSystem_Term();
  641. VMPI_Finalize();
  642. g_bSuppressPrintfOutput = false;
  643. if( g_bMPIMaster )
  644. {
  645. /*
  646. printf( "\n" );
  647. int nStrings = g_ByteCode.GetNumStrings();
  648. int i;
  649. for( i = 0; i < nStrings; i++ )
  650. {
  651. if( g_Master_TextureHadError.Defined( g_ByteCode.String( i ) ) )
  652. {
  653. printf( "FAILED: \"%s\"\n", g_ByteCode.String( i ) );
  654. }
  655. else
  656. {
  657. // printf( "\"%s\" succeeded!\n", g_ByteCode.String( i ) );
  658. WriteTexture( g_ByteCode.String( i ) );
  659. }
  660. }
  661. double end = Plat_FloatTime();
  662. char str[512];
  663. GetHourMinuteSecondsString( (int)( end - g_flStartTime ), str, sizeof( str ) );
  664. Msg( "%s elapsed\n", str );
  665. */
  666. }
  667. return 0;
  668. }
  669. class CTextureCompileDLL : public ILaunchableDLL
  670. {
  671. int main( int argc, char **argv );
  672. };
  673. int CTextureCompileDLL::main( int argc, char **argv )
  674. {
  675. return TextureCompile_Main( argc, argv );
  676. }
  677. EXPOSE_SINGLE_INTERFACE( CTextureCompileDLL, ILaunchableDLL, LAUNCHABLE_DLL_INTERFACE_VERSION );