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.

498 lines
13 KiB

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