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.

496 lines
13 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. //
  9. // mpivrad.cpp
  10. //
  11. #include <windows.h>
  12. #include <conio.h>
  13. #include "vrad.h"
  14. #include "physdll.h"
  15. #include "lightmap.h"
  16. #include "tier1/strtools.h"
  17. #include "radial.h"
  18. #include "utlbuffer.h"
  19. #include "pacifier.h"
  20. #include "messbuf.h"
  21. #include "bsplib.h"
  22. #include "consolewnd.h"
  23. #include "vismat.h"
  24. #include "vmpi_filesystem.h"
  25. #include "vmpi_dispatch.h"
  26. #include "utllinkedlist.h"
  27. #include "vmpi.h"
  28. #include "mpi_stats.h"
  29. #include "vmpi_distribute_work.h"
  30. #include "vmpi_tools_shared.h"
  31. CUtlVector<char> g_LightResultsFilename;
  32. extern int total_transfer;
  33. extern int max_transfer;
  34. extern void BuildVisLeafs(int);
  35. extern void BuildPatchLights( int facenum );
  36. // Handle VRAD packets.
  37. bool VRAD_DispatchFn( MessageBuffer *pBuf, int iSource, int iPacketID )
  38. {
  39. switch( pBuf->data[1] )
  40. {
  41. case VMPI_SUBPACKETID_PLIGHTDATA_RESULTS:
  42. {
  43. const char *pFilename = &pBuf->data[2];
  44. g_LightResultsFilename.CopyArray( pFilename, strlen( pFilename ) + 1 );
  45. return true;
  46. }
  47. default:
  48. return false;
  49. }
  50. }
  51. CDispatchReg g_VRADDispatchReg( VMPI_VRAD_PACKET_ID, VRAD_DispatchFn ); // register to handle the messages we want
  52. CDispatchReg g_DistributeWorkReg( VMPI_DISTRIBUTEWORK_PACKETID, DistributeWorkDispatch );
  53. void VRAD_SetupMPI( int &argc, char **&argv )
  54. {
  55. CmdLib_AtCleanup( VMPI_Stats_Term );
  56. //
  57. // Preliminary check -mpi flag
  58. //
  59. if ( !VMPI_FindArg( argc, argv, "-mpi", "" ) && !VMPI_FindArg( argc, argv, VMPI_GetParamString( mpi_Worker ), "" ) )
  60. return;
  61. // Force local mode?
  62. VMPIRunMode mode;
  63. if ( VMPI_FindArg( argc, argv, VMPI_GetParamString( mpi_Local ), "" ) )
  64. mode = VMPI_RUN_LOCAL;
  65. else
  66. mode = VMPI_RUN_NETWORKED;
  67. VMPI_Stats_InstallSpewHook();
  68. //
  69. // Extract mpi specific arguments
  70. //
  71. Msg( "Initializing VMPI...\n" );
  72. if ( !VMPI_Init(
  73. argc,
  74. argv,
  75. "dependency_info_vrad.txt",
  76. HandleMPIDisconnect,
  77. mode
  78. ) )
  79. {
  80. Error( "MPI_Init failed." );
  81. }
  82. StatsDB_InitStatsDatabase( argc, argv, "dbinfo_vrad.txt" );
  83. }
  84. //-----------------------------------------
  85. //
  86. // Run BuildFaceLights across all available processing nodes
  87. // and collect the results.
  88. //
  89. CCycleCount g_CPUTime;
  90. template<class T> void WriteValues( MessageBuffer *pmb, T const *pSrc, int nNumValues)
  91. {
  92. pmb->write(pSrc, sizeof( pSrc[0]) * nNumValues );
  93. }
  94. template<class T> int ReadValues( MessageBuffer *pmb, T *pDest, int nNumValues)
  95. {
  96. return pmb->read( pDest, sizeof( pDest[0]) * nNumValues );
  97. }
  98. //--------------------------------------------------
  99. // Serialize face data
  100. void SerializeFace( MessageBuffer * pmb, int facenum )
  101. {
  102. int i, n;
  103. dface_t * f = &g_pFaces[facenum];
  104. facelight_t * fl = &facelight[facenum];
  105. pmb->write(f, sizeof(dface_t));
  106. pmb->write(fl, sizeof(facelight_t));
  107. WriteValues( pmb, fl->sample, fl->numsamples);
  108. //
  109. // Write the light information
  110. //
  111. for (i=0; i<MAXLIGHTMAPS; ++i) {
  112. for (n=0; n<NUM_BUMP_VECTS+1; ++n) {
  113. if (fl->light[i][n])
  114. {
  115. WriteValues( pmb, fl->light[i][n], fl->numsamples);
  116. }
  117. }
  118. }
  119. if (fl->luxel)
  120. WriteValues( pmb, fl->luxel, fl->numluxels);
  121. if (fl->luxelNormals)
  122. WriteValues( pmb, fl->luxelNormals, fl->numluxels);
  123. }
  124. //--------------------------------------------------
  125. // UnSerialize face data
  126. //
  127. void UnSerializeFace( MessageBuffer * pmb, int facenum, int iSource )
  128. {
  129. int i, n;
  130. dface_t * f = &g_pFaces[facenum];
  131. facelight_t * fl = &facelight[facenum];
  132. if (pmb->read(f, sizeof(dface_t)) < 0)
  133. Error("UnSerializeFace - invalid dface_t from %s (mb len: %d, offset: %d)", VMPI_GetMachineName( iSource ), pmb->getLen(), pmb->getOffset() );
  134. if (pmb->read(fl, sizeof(facelight_t)) < 0)
  135. Error("UnSerializeFace - invalid facelight_t from %s (mb len: %d, offset: %d)", VMPI_GetMachineName( iSource ), pmb->getLen(), pmb->getOffset() );
  136. fl->sample = (sample_t *) calloc(fl->numsamples, sizeof(sample_t));
  137. if (pmb->read(fl->sample, sizeof(sample_t) * fl->numsamples) < 0)
  138. Error("UnSerializeFace - invalid sample_t from %s (mb len: %d, offset: %d, fl->numsamples: %d)", VMPI_GetMachineName( iSource ), pmb->getLen(), pmb->getOffset(), fl->numsamples );
  139. //
  140. // Read the light information
  141. //
  142. for (i=0; i<MAXLIGHTMAPS; ++i) {
  143. for (n=0; n<NUM_BUMP_VECTS+1; ++n) {
  144. if (fl->light[i][n])
  145. {
  146. fl->light[i][n] = (LightingValue_t *) calloc( fl->numsamples, sizeof(LightingValue_t ) );
  147. if ( ReadValues( pmb, fl->light[i][n], fl->numsamples) < 0)
  148. Error("UnSerializeFace - invalid fl->light from %s (mb len: %d, offset: %d)", VMPI_GetMachineName( iSource ), pmb->getLen(), pmb->getOffset() );
  149. }
  150. }
  151. }
  152. if (fl->luxel) {
  153. fl->luxel = (Vector *) calloc(fl->numluxels, sizeof(Vector));
  154. if (ReadValues( pmb, fl->luxel, fl->numluxels) < 0)
  155. Error("UnSerializeFace - invalid fl->luxel from %s (mb len: %d, offset: %d)", VMPI_GetMachineName( iSource ), pmb->getLen(), pmb->getOffset() );
  156. }
  157. if (fl->luxelNormals) {
  158. fl->luxelNormals = (Vector *) calloc(fl->numluxels, sizeof( Vector ));
  159. if ( ReadValues( pmb, fl->luxelNormals, fl->numluxels) < 0)
  160. Error("UnSerializeFace - invalid fl->luxelNormals from %s (mb len: %d, offset: %d)", VMPI_GetMachineName( iSource ), pmb->getLen(), pmb->getOffset() );
  161. }
  162. }
  163. void MPI_ReceiveFaceResults( uint64 iWorkUnit, MessageBuffer *pBuf, int iWorker )
  164. {
  165. UnSerializeFace( pBuf, iWorkUnit, iWorker );
  166. }
  167. void MPI_ProcessFaces( int iThread, uint64 iWorkUnit, MessageBuffer *pBuf )
  168. {
  169. // Do BuildFacelights on the face.
  170. CTimeAdder adder( &g_CPUTime );
  171. BuildFacelights( iThread, iWorkUnit );
  172. // Send the results.
  173. if ( pBuf )
  174. {
  175. SerializeFace( pBuf, iWorkUnit );
  176. }
  177. }
  178. void RunMPIBuildFacelights()
  179. {
  180. g_CPUTime.Init();
  181. Msg( "%-20s ", "BuildFaceLights:" );
  182. if ( g_bMPIMaster )
  183. {
  184. StartPacifier("");
  185. }
  186. VMPI_SetCurrentStage( "RunMPIBuildFaceLights" );
  187. double elapsed = DistributeWork(
  188. numfaces,
  189. VMPI_DISTRIBUTEWORK_PACKETID,
  190. MPI_ProcessFaces,
  191. MPI_ReceiveFaceResults );
  192. if ( g_bMPIMaster )
  193. {
  194. EndPacifier(false);
  195. Msg( " (%d)\n", (int)elapsed );
  196. }
  197. if ( g_bMPIMaster )
  198. {
  199. //
  200. // BuildPatchLights is normally called from BuildFacelights(),
  201. // but in MPI mode we have the master do the calculation
  202. // We might be able to speed this up by doing while the master
  203. // is idling in the above loop. Wouldn't want to slow down the
  204. // handing out of work - maybe another thread?
  205. //
  206. for ( int i=0; i < numfaces; ++i )
  207. {
  208. BuildPatchLights(i);
  209. }
  210. }
  211. else
  212. {
  213. if ( g_iVMPIVerboseLevel >= 1 )
  214. Msg( "\n\n%.1f%% CPU utilization during BuildFaceLights\n\n", ( g_CPUTime.GetSeconds() * 100 / elapsed ) );
  215. }
  216. }
  217. //-----------------------------------------
  218. //
  219. // Run BuildVisLeafs across all available processing nodes
  220. // and collect the results.
  221. //
  222. // This function is called when the master receives results back from a worker.
  223. void MPI_ReceiveVisLeafsResults( uint64 iWorkUnit, MessageBuffer *pBuf, int iWorker )
  224. {
  225. int patchesInCluster = 0;
  226. pBuf->read(&patchesInCluster, sizeof(patchesInCluster));
  227. for ( int k=0; k < patchesInCluster; ++k )
  228. {
  229. int patchnum = 0;
  230. pBuf->read(&patchnum, sizeof(patchnum));
  231. CPatch * patch = &g_Patches[patchnum];
  232. int numtransfers;
  233. pBuf->read( &numtransfers, sizeof(numtransfers) );
  234. patch->numtransfers = numtransfers;
  235. if (numtransfers)
  236. {
  237. patch->transfers = new transfer_t[numtransfers];
  238. pBuf->read(patch->transfers, numtransfers * sizeof(transfer_t));
  239. }
  240. total_transfer += numtransfers;
  241. if (max_transfer < numtransfers)
  242. max_transfer = numtransfers;
  243. }
  244. }
  245. // Temporary variables used during callbacks. If we're going to be threadsafe, these
  246. // should go in a structure and get passed around.
  247. class CVMPIVisLeafsData
  248. {
  249. public:
  250. MessageBuffer *m_pVisLeafsMB;
  251. int m_nPatchesInCluster;
  252. transfer_t *m_pBuildVisLeafsTransfers;
  253. };
  254. CVMPIVisLeafsData g_VMPIVisLeafsData[MAX_TOOL_THREADS+1];
  255. // This is called by BuildVisLeafs_Cluster every time it finishes a patch.
  256. // The results are appended to g_VisLeafsMB and sent back to the master when all clusters are done.
  257. void MPI_AddPatchData( int iThread, int patchnum, CPatch *patch )
  258. {
  259. CVMPIVisLeafsData *pData = &g_VMPIVisLeafsData[iThread];
  260. if ( pData->m_pVisLeafsMB )
  261. {
  262. // Add in results for this patch
  263. ++pData->m_nPatchesInCluster;
  264. pData->m_pVisLeafsMB->write(&patchnum, sizeof(patchnum));
  265. pData->m_pVisLeafsMB->write(&patch->numtransfers, sizeof(patch->numtransfers));
  266. pData->m_pVisLeafsMB->write( patch->transfers, patch->numtransfers * sizeof(transfer_t) );
  267. }
  268. }
  269. // This handles a work unit sent by the master. Each work unit here is a
  270. // list of clusters.
  271. void MPI_ProcessVisLeafs( int iThread, uint64 iWorkUnit, MessageBuffer *pBuf )
  272. {
  273. CTimeAdder adder( &g_CPUTime );
  274. CVMPIVisLeafsData *pData = &g_VMPIVisLeafsData[iThread];
  275. int iCluster = iWorkUnit;
  276. // Start this cluster.
  277. pData->m_nPatchesInCluster = 0;
  278. pData->m_pVisLeafsMB = pBuf;
  279. // Write a temp value in there. We overwrite it later.
  280. int iSavePos = 0;
  281. if ( pBuf )
  282. {
  283. iSavePos = pBuf->getLen();
  284. pBuf->write( &pData->m_nPatchesInCluster, sizeof(pData->m_nPatchesInCluster) );
  285. }
  286. // Collect the results in MPI_AddPatchData.
  287. BuildVisLeafs_Cluster( iThread, pData->m_pBuildVisLeafsTransfers, iCluster, MPI_AddPatchData );
  288. // Now send the results back..
  289. if ( pBuf )
  290. {
  291. pBuf->update( iSavePos, &pData->m_nPatchesInCluster, sizeof(pData->m_nPatchesInCluster) );
  292. pData->m_pVisLeafsMB = NULL;
  293. }
  294. }
  295. void RunMPIBuildVisLeafs()
  296. {
  297. g_CPUTime.Init();
  298. Msg( "%-20s ", "BuildVisLeafs :" );
  299. if ( g_bMPIMaster )
  300. {
  301. StartPacifier("");
  302. }
  303. memset( g_VMPIVisLeafsData, 0, sizeof( g_VMPIVisLeafsData ) );
  304. if ( !g_bMPIMaster || VMPI_GetActiveWorkUnitDistributor() == k_eWorkUnitDistributor_SDK )
  305. {
  306. // Allocate space for the transfers for each thread.
  307. for ( int i=0; i < numthreads; i++ )
  308. {
  309. g_VMPIVisLeafsData[i].m_pBuildVisLeafsTransfers = BuildVisLeafs_Start();
  310. }
  311. }
  312. //
  313. // Slaves ask for work via GetMPIBuildVisLeafWork()
  314. // Results are returned in BuildVisRow()
  315. //
  316. VMPI_SetCurrentStage( "RunMPIBuildVisLeafs" );
  317. double elapsed = DistributeWork(
  318. dvis->numclusters,
  319. VMPI_DISTRIBUTEWORK_PACKETID,
  320. MPI_ProcessVisLeafs,
  321. MPI_ReceiveVisLeafsResults );
  322. // Free the transfers from each thread.
  323. for ( int i=0; i < numthreads; i++ )
  324. {
  325. if ( g_VMPIVisLeafsData[i].m_pBuildVisLeafsTransfers )
  326. BuildVisLeafs_End( g_VMPIVisLeafsData[i].m_pBuildVisLeafsTransfers );
  327. }
  328. if ( g_bMPIMaster )
  329. {
  330. EndPacifier(false);
  331. Msg( " (%d)\n", (int)elapsed );
  332. }
  333. else
  334. {
  335. if ( g_iVMPIVerboseLevel >= 1 )
  336. Msg( "%.1f%% CPU utilization during PortalFlow\n", (g_CPUTime.GetSeconds() * 100.0f / elapsed) / numthreads );
  337. }
  338. }
  339. void VMPI_DistributeLightData()
  340. {
  341. if ( !g_bUseMPI )
  342. return;
  343. if ( g_bMPIMaster )
  344. {
  345. const char *pVirtualFilename = "--plightdata--";
  346. CUtlBuffer lightFaceData;
  347. // write out the light data
  348. lightFaceData.EnsureCapacity( pdlightdata->Count() + (numfaces * (MAXLIGHTMAPS+sizeof(int))) );
  349. Q_memcpy( lightFaceData.PeekPut(), pdlightdata->Base(), pdlightdata->Count() );
  350. lightFaceData.SeekPut( CUtlBuffer::SEEK_HEAD, pdlightdata->Count() );
  351. // write out the relevant face info into the stream
  352. for ( int i = 0; i < numfaces; i++ )
  353. {
  354. for ( int j = 0; j < MAXLIGHTMAPS; j++ )
  355. {
  356. lightFaceData.PutChar(g_pFaces[i].styles[j]);
  357. }
  358. lightFaceData.PutInt(g_pFaces[i].lightofs);
  359. }
  360. VMPI_FileSystem_CreateVirtualFile( pVirtualFilename, lightFaceData.Base(), lightFaceData.TellMaxPut() );
  361. char cPacketID[2] = { VMPI_VRAD_PACKET_ID, VMPI_SUBPACKETID_PLIGHTDATA_RESULTS };
  362. VMPI_Send2Chunks( cPacketID, sizeof( cPacketID ), pVirtualFilename, strlen( pVirtualFilename ) + 1, VMPI_PERSISTENT );
  363. }
  364. else
  365. {
  366. VMPI_SetCurrentStage( "VMPI_DistributeLightData" );
  367. // Wait until we've received the filename from the master.
  368. while ( g_LightResultsFilename.Count() == 0 )
  369. {
  370. VMPI_DispatchNextMessage();
  371. }
  372. // Open
  373. FileHandle_t fp = g_pFileSystem->Open( g_LightResultsFilename.Base(), "rb", VMPI_VIRTUAL_FILES_PATH_ID );
  374. if ( !fp )
  375. Error( "Can't open '%s' to read lighting info.", g_LightResultsFilename.Base() );
  376. int size = g_pFileSystem->Size( fp );
  377. int faceSize = (numfaces*(MAXLIGHTMAPS+sizeof(int)));
  378. if ( size > faceSize )
  379. {
  380. int lightSize = size - faceSize;
  381. CUtlBuffer faceData;
  382. pdlightdata->EnsureCount( lightSize );
  383. faceData.EnsureCapacity( faceSize );
  384. g_pFileSystem->Read( pdlightdata->Base(), lightSize, fp );
  385. g_pFileSystem->Read( faceData.Base(), faceSize, fp );
  386. g_pFileSystem->Close( fp );
  387. faceData.SeekPut( CUtlBuffer::SEEK_HEAD, faceSize );
  388. // write out the face data
  389. for ( int i = 0; i < numfaces; i++ )
  390. {
  391. for ( int j = 0; j < MAXLIGHTMAPS; j++ )
  392. {
  393. g_pFaces[i].styles[j] = faceData.GetChar();
  394. }
  395. g_pFaces[i].lightofs = faceData.GetInt();
  396. }
  397. }
  398. }
  399. }