//----------------------------------------------------------------------------- // Computes lighting for the static props. // Must be after all other surface lighting has been computed for the indirect sampling. //----------------------------------------------------------------------------- void CVradStaticPropMgr::ComputeLighting( int iThread ) { // illuminate them all int count = m_StaticProps.Count(); if ( !count ) { // nothing to do return; } StartPacifier( "Computing static prop lighting : " ); // ensure any traces against us are ignored because we have no inherit lighting contribution m_bIgnoreStaticPropTrace = true; for (int i = 0; i < count; ++i) { UpdatePacifier( (float)i / (float)count ); ComputeLighting( m_StaticProps[i], iThread, i ); } // restore default m_bIgnoreStaticPropTrace = false; // save data to bsp SerializeLighting(); EndPacifier( true ); }
//----------------------------------------------------------------------------- // Computes lighting for the detail props //----------------------------------------------------------------------------- void ComputeDetailPropLighting( int iThread ) { // illuminate them all DetailObjectLump_t* pProps; int count = UnserializeDetailProps( pProps ); if (!count) return; // unserialize the lump that we aren't computing. if( g_bHDR ) { UnserializeDetailPropLighting( GAMELUMP_DETAIL_PROP_LIGHTING, GAMELUMP_DETAIL_PROP_LIGHTING_VERSION, s_DetailPropLightStyleLumpLDR ); } else { UnserializeDetailPropLighting( GAMELUMP_DETAIL_PROP_LIGHTING_HDR, GAMELUMP_DETAIL_PROP_LIGHTING_HDR_VERSION, s_DetailPropLightStyleLumpHDR ); } StartPacifier("Computing detail prop lighting : "); for (int i = 0; i < count; ++i) { UpdatePacifier( (float)i / (float)count ); ComputeLighting( pProps[i], iThread ); } // Write detail prop lightstyle lump... WriteDetailLightingLumps(); EndPacifier( true ); }
/* ============= RunThreadsOn ============= */ void RunThreadsOn( int workcnt, qboolean showpacifier, RunThreadsFn fn, void *pUserData ) { int start, end; start = Plat_FloatTime(); dispatch = 0; workcount = workcnt; StartPacifier(""); pacifier = showpacifier; #ifdef _PROFILE threaded = false; (*func)( 0 ); return; #endif RunThreads_Start( fn, pUserData ); RunThreads_End(); end = Plat_FloatTime(); if (pacifier) { EndPacifier(false); printf (" (%i)\n", end-start); } }
void ComputePerLeafAmbientLighting() { // Figure out which lights should go in the per-leaf ambient cubes. int nInAmbientCube = 0; int nSurfaceLights = 0; for ( int i=0; i < *pNumworldlights; i++ ) { dworldlight_t *wl = &dworldlights[i]; if ( IsLeafAmbientSurfaceLight( wl ) ) wl->flags |= DWL_FLAGS_INAMBIENTCUBE; else wl->flags &= ~DWL_FLAGS_INAMBIENTCUBE; if ( wl->type == emit_surface ) ++nSurfaceLights; if ( wl->flags & DWL_FLAGS_INAMBIENTCUBE ) ++nInAmbientCube; } Msg( "%d of %d (%d%% of) surface lights went in leaf ambient cubes.\n", nInAmbientCube, nSurfaceLights, nSurfaceLights ? ((nInAmbientCube*100) / nSurfaceLights) : 0 ); g_pLeafAmbientLighting->SetCount( numleafs ); StartPacifier( "ComputePerLeafAmbientLighting: " ); for ( int leafID = 0; leafID < numleafs; leafID++ ) { dleaf_t *pLeaf = &dleafs[leafID]; Vector cube[6]; Vector center = ( Vector( pLeaf->mins[0], pLeaf->mins[1], pLeaf->mins[2] ) + Vector( pLeaf->maxs[0], pLeaf->maxs[1], pLeaf->maxs[2] ) ) * 0.5f; #if MAKE_LIGHT_BELOW_WATER_MATCH_LIGHT_ABOVE_WATER if (pLeaf->contents & CONTENTS_WATER) { center.z=pLeaf->maxs[2]+1; int above_leaf=PointLeafnum( center); dleaf_t *pLeaf = &dleafs[above_leaf]; center = ( Vector( pLeaf->mins[0], pLeaf->mins[1], pLeaf->mins[2] ) + Vector( pLeaf->maxs[0], pLeaf->maxs[1], pLeaf->maxs[2] ) ) * 0.5f; } #endif ComputeAmbientFromSphericalSamples( center, cube ); for ( int i = 0; i < 6; i++ ) { VectorToColorRGBExp32( cube[i], (*g_pLeafAmbientLighting)[leafID].m_Color[i] ); } UpdatePacifier( (float)leafID / numleafs ); } EndPacifier( true ); }
void RunMPIBuildVisLeafs() { g_CPUTime.Init(); Msg( "%-20s ", "BuildVisLeafs :" ); if ( g_bMPIMaster ) { StartPacifier(""); } memset( g_VMPIVisLeafsData, 0, sizeof( g_VMPIVisLeafsData ) ); if ( !g_bMPIMaster || VMPI_GetActiveWorkUnitDistributor() == k_eWorkUnitDistributor_SDK ) { // Allocate space for the transfers for each thread. for ( int i=0; i < numthreads; i++ ) { g_VMPIVisLeafsData[i].m_pBuildVisLeafsTransfers = BuildVisLeafs_Start(); } } // // Slaves ask for work via GetMPIBuildVisLeafWork() // Results are returned in BuildVisRow() // VMPI_SetCurrentStage( "RunMPIBuildVisLeafs" ); double elapsed = DistributeWork( dvis->numclusters, VMPI_DISTRIBUTEWORK_PACKETID, MPI_ProcessVisLeafs, MPI_ReceiveVisLeafsResults ); // Free the transfers from each thread. for ( int i=0; i < numthreads; i++ ) { if ( g_VMPIVisLeafsData[i].m_pBuildVisLeafsTransfers ) BuildVisLeafs_End( g_VMPIVisLeafsData[i].m_pBuildVisLeafsTransfers ); } if ( g_bMPIMaster ) { EndPacifier(false); Msg( " (%d)\n", (int)elapsed ); } else { if ( g_iVMPIVerboseLevel >= 1 ) Msg( "%.1f%% CPU utilization during PortalFlow\n", (g_CPUTime.GetSeconds() * 100.0f / elapsed) / numthreads ); } }
void RunMPIBuildFacelights() { g_CPUTime.Init(); Msg( "%-20s ", "BuildFaceLights:" ); if ( g_bMPIMaster ) { StartPacifier(""); } VMPI_SetCurrentStage( "RunMPIBuildFaceLights" ); double elapsed = DistributeWork( numfaces, VMPI_DISTRIBUTEWORK_PACKETID, MPI_ProcessFaces, MPI_ReceiveFaceResults ); if ( g_bMPIMaster ) { EndPacifier(false); Msg( " (%d)\n", (int)elapsed ); } if ( g_bMPIMaster ) { // // BuildPatchLights is normally called from BuildFacelights(), // but in MPI mode we have the master do the calculation // We might be able to speed this up by doing while the master // is idling in the above loop. Wouldn't want to slow down the // handing out of work - maybe another thread? // for ( int i=0; i < numfaces; ++i ) { BuildPatchLights(i); } } else { if ( g_iVMPIVerboseLevel >= 1 ) Msg( "\n\n%.1f%% CPU utilization during BuildFaceLights\n\n", ( g_CPUTime.GetSeconds() * 100 / elapsed ) ); } }
//----------------------------------------- // // Run PortalFlow across all available processing nodes // void RunMPIPortalFlow() { Msg( "%-20s ", "MPIPortalFlow:" ); if ( g_bMPIMaster ) StartPacifier(""); // Workers wait until we get the MC socket address. g_PortalMCThreadUniqueID = StatsDB_GetUniqueJobID(); if ( g_bMPIMaster ) { CCycleCount cnt; cnt.Sample(); CUniformRandomStream randomStream; randomStream.SetSeed( cnt.GetMicroseconds() ); g_PortalMCAddr.port = randomStream.RandomInt( 22000, 25000 ); // Pulled out of something else. g_PortalMCAddr.ip[0] = (unsigned char)RandomInt( 225, 238 ); g_PortalMCAddr.ip[1] = (unsigned char)RandomInt( 0, 255 ); g_PortalMCAddr.ip[2] = (unsigned char)RandomInt( 0, 255 ); g_PortalMCAddr.ip[3] = (unsigned char)RandomInt( 3, 255 ); g_pPortalMCSocket = CreateIPSocket(); int i=0; for ( i; i < 5; i++ ) { if ( g_pPortalMCSocket->BindToAny( randomStream.RandomInt( 20000, 30000 ) ) ) break; } if ( i == 5 ) { Error( "RunMPIPortalFlow: can't open a socket to multicast on." ); } char cPacketID[2] = { VMPI_VVIS_PACKET_ID, VMPI_SUBPACKETID_MC_ADDR }; VMPI_Send2Chunks( cPacketID, sizeof( cPacketID ), &g_PortalMCAddr, sizeof( g_PortalMCAddr ), VMPI_PERSISTENT ); } else { VMPI_SetCurrentStage( "wait for MC address" ); while ( !g_bGotMCAddr ) { VMPI_DispatchNextMessage(); } // Open our multicast receive socket. g_pPortalMCSocket = CreateMulticastListenSocket( g_PortalMCAddr ); if ( !g_pPortalMCSocket ) { char err[512]; IP_GetLastErrorString( err, sizeof( err ) ); Error( "RunMPIPortalFlow: CreateMulticastListenSocket failed. (%s).", err ); } // Make a thread to listen for the data on the multicast socket. DWORD dwDummy = 0; g_MCThreadExitEvent.Init( false, false ); // Make sure we kill the MC thread if the app exits ungracefully. CmdLib_AtCleanup( MCThreadCleanupFn ); g_hMCThread = CreateThread( NULL, 0, PortalMCThreadFn, NULL, 0, &dwDummy ); if ( !g_hMCThread ) { Error( "RunMPIPortalFlow: CreateThread failed for multicast receive thread." ); } } VMPI_SetCurrentStage( "RunMPIBasePortalFlow" ); g_pDistributeWorkCallbacks = &g_VisDistributeWorkCallbacks; g_CPUTime.Init(); double elapsed = DistributeWork( g_numportals * 2, // # work units VMPI_DISTRIBUTEWORK_PACKETID, // packet ID ProcessPortalFlow, // Worker function to process work units ReceivePortalFlow // Master function to receive work results ); g_pDistributeWorkCallbacks = NULL; CheckExitedEarly(); // Stop the multicast stuff. VMPI_DeletePortalMCSocket(); if( !g_bMPIMaster ) { if ( g_iVMPIVerboseLevel >= 1 ) { Msg( "Received %d (out of %d) portals from multicast.\n", g_nMulticastPortalsReceived, g_numportals * 2 ); Msg( "%.1f%% CPU utilization during PortalFlow\n", (g_CPUTime.GetSeconds() * 100.0f / elapsed) / numthreads ); } Msg( "VVIS worker finished. Over and out.\n" ); VMPI_SetCurrentStage( "worker done" ); CmdLib_Exit( 0 ); } if ( g_bMPIMaster ) { EndPacifier( false ); Msg( " (%d)\n", (int)elapsed ); } }
//----------------------------------------- // // Run BasePortalVis across all available processing nodes // Then collect and redistribute the results. // void RunMPIBasePortalVis() { int i; Msg( "\n\nportalbytes: %d\nNum Work Units: %d\nTotal data size: %d\n", portalbytes, g_numportals*2, portalbytes*g_numportals*2 ); Msg("%-20s ", "BasePortalVis:"); if ( g_bMPIMaster ) StartPacifier(""); VMPI_SetCurrentStage( "RunMPIBasePortalVis" ); // Note: we're aiming for about 1500 portals in a map, so about 3000 work units. g_CPUTime.Init(); double elapsed = DistributeWork( g_numportals * 2, // # work units VMPI_DISTRIBUTEWORK_PACKETID, // packet ID ProcessBasePortalVis, // Worker function to process work units ReceiveBasePortalVis // Master function to receive work results ); if ( g_bMPIMaster ) { EndPacifier( false ); Msg( " (%d)\n", (int)elapsed ); } // // Distribute the results to all the workers. // if ( g_bMPIMaster ) { if ( !fastvis ) { VMPI_SetCurrentStage( "SendPortalResults" ); // Store all the portal results in a temp file and multicast that to the workers. CUtlVector<char> allPortalData; allPortalData.SetSize( g_numportals * 2 * portalbytes * 2 ); char *pOut = allPortalData.Base(); for ( i=0; i < g_numportals * 2; i++) { portal_t *p = &portals[i]; memcpy( pOut, p->portalfront, portalbytes ); pOut += portalbytes; memcpy( pOut, p->portalflood, portalbytes ); pOut += portalbytes; } const char *pVirtualFilename = "--portal-results--"; VMPI_FileSystem_CreateVirtualFile( pVirtualFilename, allPortalData.Base(), allPortalData.Count() ); char cPacketID[2] = { VMPI_VVIS_PACKET_ID, VMPI_BASEPORTALVIS_RESULTS }; VMPI_Send2Chunks( cPacketID, sizeof( cPacketID ), pVirtualFilename, strlen( pVirtualFilename ) + 1, VMPI_PERSISTENT ); } } else { VMPI_SetCurrentStage( "RecvPortalResults" ); // Wait until we've received the filename from the master. while ( g_BasePortalVisResultsFilename.Count() == 0 ) { VMPI_DispatchNextMessage(); } // Open FileHandle_t fp = g_pFileSystem->Open( g_BasePortalVisResultsFilename.Base(), "rb", VMPI_VIRTUAL_FILES_PATH_ID ); if ( !fp ) Error( "Can't open '%s' to read portal info.", g_BasePortalVisResultsFilename.Base() ); for ( i=0; i < g_numportals * 2; i++) { portal_t *p = &portals[i]; p->portalfront = (byte*)malloc (portalbytes); g_pFileSystem->Read( p->portalfront, portalbytes, fp ); p->portalflood = (byte*)malloc (portalbytes); g_pFileSystem->Read( p->portalflood, portalbytes, fp ); p->portalvis = (byte*)malloc (portalbytes); memset (p->portalvis, 0, portalbytes); p->nummightsee = CountBits (p->portalflood, g_numportals*2); } g_pFileSystem->Close( fp ); } if ( !g_bMPIMaster ) { if ( g_iVMPIVerboseLevel >= 1 ) Msg( "\n%% worker CPU utilization during BasePortalVis: %.1f\n", (g_CPUTime.GetSeconds() * 100.0f / elapsed) / numthreads ); } }
//----------------------------------------------------------------------------- // Places Detail Objects in the level //----------------------------------------------------------------------------- void EmitDetailModels() { StartPacifier("Placing detail props : "); // Place stuff on each face dface_t* pFace = dfaces; for (int j = 0; j < numfaces; ++j) { UpdatePacifier( (float)j / (float)numfaces ); // Get at the material associated with this face texinfo_t* pTexInfo = &texinfo[pFace[j].texinfo]; dtexdata_t* pTexData = GetTexData( pTexInfo->texdata ); // Try to get at the material bool found; MaterialSystemMaterial_t handle = FindOriginalMaterial( TexDataStringTable_GetString( pTexData->nameStringTableID ), &found, false ); if (!found) continue; // See if its got any detail objects on it const char* pDetailType = GetMaterialVar( handle, "%detailtype" ); if (!pDetailType) continue; // Get the detail type... DetailObject_t search; search.m_Name = pDetailType; int objectType = s_DetailObjectDict.Find(search); if (objectType < 0) { Warning("Material %s uses unknown detail object type %s!\n", TexDataStringTable_GetString( pTexData->nameStringTableID ), pDetailType); continue; } // Emit objects on a particular face DetailObject_t& detail = s_DetailObjectDict[objectType]; if (pFace[j].dispinfo < 0) { EmitDetailObjectsOnFace( &pFace[j], detail ); } else { // Get a CCoreDispInfo. All we need is the triangles and lightmap texture coordinates. mapdispinfo_t *pMapDisp = &mapdispinfo[pFace[j].dispinfo]; CCoreDispInfo coreDispInfo; DispMapToCoreDispInfo( pMapDisp, &coreDispInfo, &pFace[j] ); EmitDetailObjectsOnDisplacementFace( &pFace[j], detail, coreDispInfo ); } } // Emit specifically specified detail props Vector origin; QAngle angles; Vector2D pos[2]; Vector2D tex[2]; for (int i = 0; i < num_entities; ++i) { char* pEntity = ValueForKey(&entities[i], "classname"); if (!strcmp(pEntity, "detail_prop") || !strcmp(pEntity, "prop_detail")) { GetVectorForKey( &entities[i], "origin", origin ); GetAnglesForKey( &entities[i], "angles", angles ); char* pModelName = ValueForKey( &entities[i], "model" ); int nOrientation = IntForKey( &entities[i], "detailOrientation" ); AddDetailToLump( pModelName, origin, angles, nOrientation ); // strip this ent from the .bsp file entities[i].epairs = 0; continue; } if (!strcmp(pEntity, "prop_detail_sprite")) { GetVectorForKey( &entities[i], "origin", origin ); GetAnglesForKey( &entities[i], "angles", angles ); int nOrientation = IntForKey( &entities[i], "detailOrientation" ); GetVector2DForKey( &entities[i], "position_ul", pos[0] ); GetVector2DForKey( &entities[i], "position_lr", pos[1] ); GetVector2DForKey( &entities[i], "tex_ul", tex[0] ); GetVector2DForKey( &entities[i], "tex_size", tex[1] ); float flTextureSize = FloatForKey( &entities[i], "tex_total_size" ); tex[1].x += tex[0].x - 0.5f; tex[1].y += tex[0].y - 0.5f; tex[0].x += 0.5f; tex[0].y += 0.5f; tex[0] /= flTextureSize; tex[1] /= flTextureSize; AddDetailSpriteToLump( origin, angles, nOrientation, pos, tex, 1.0f ); // strip this ent from the .bsp file entities[i].epairs = 0; continue; } } EndPacifier( true ); }
void EmitDispLMAlphaAndNeighbors() { int i; Msg( "Finding displacement neighbors...\n" ); // Do lightmap alpha. g_DispLightmapAlpha.RemoveAll(); // Build the CCoreDispInfos. CUtlVector<dface_t*> faces; // Create the core dispinfos and init them for use as CDispUtilsHelpers. g_CoreDispInfos.SetSize( nummapdispinfo ); for ( i=0; i < nummapdispinfo; i++ ) { g_CoreDispInfos[i].SetDispUtilsHelperInfo( g_CoreDispInfos.Base(), nummapdispinfo ); } faces.SetSize( nummapdispinfo ); for( i = 0; i < numfaces; i++ ) { dface_t *pFace = &dfaces[i]; if( pFace->dispinfo == -1 ) continue; mapdispinfo_t *pMapDisp = &mapdispinfo[pFace->dispinfo]; // Set the displacement's face index. ddispinfo_t *pDisp = &g_dispinfo[pFace->dispinfo]; pDisp->m_iMapFace = i; // Get a CCoreDispInfo. All we need is the triangles and lightmap texture coordinates. CCoreDispInfo *pCoreDispInfo = &g_CoreDispInfos[pFace->dispinfo]; DispMapToCoreDispInfo( pMapDisp, pCoreDispInfo, pFace ); faces[pFace->dispinfo] = pFace; } // Generate and export neighbor data. ExportNeighborData( g_CoreDispInfos.Base(), g_dispinfo.Base(), nummapdispinfo ); // Generate and export the active vert lists. ExportAllowedVertLists( g_CoreDispInfos.Base(), g_dispinfo.Base(), nummapdispinfo ); Msg( "Finding lightmap sample positions...\n" ); for ( i=0; i < nummapdispinfo; i++ ) { dface_t *pFace = faces[i]; ddispinfo_t *pDisp = &g_dispinfo[pFace->dispinfo]; CCoreDispInfo *pCoreDispInfo = &g_CoreDispInfos[i]; pDisp->m_iLightmapSamplePositionStart = g_DispLightmapSamplePositions.Count(); CalculateLightmapSamplePositions( pCoreDispInfo, pFace, g_DispLightmapSamplePositions ); } StartPacifier( "Displacement Alpha : "); // Build lightmap alphas. int dispCount = 0; // How many we've processed. for( i = 0; i < nummapdispinfo; i++ ) { dface_t *pFace = faces[i]; Assert( pFace->dispinfo == i ); mapdispinfo_t *pMapDisp = &mapdispinfo[pFace->dispinfo]; ddispinfo_t *pDisp = &g_dispinfo[pFace->dispinfo]; CCoreDispInfo *pCoreDispInfo = &g_CoreDispInfos[i]; // Allocate space for the alpha values. pDisp->m_iLightmapAlphaStart = g_DispLightmapAlpha.Count(); int nLuxelsToAdd = (pFace->m_LightmapTextureSizeInLuxels[0]+1) * (pFace->m_LightmapTextureSizeInLuxels[1]+1); g_DispLightmapAlpha.AddMultipleToTail( nLuxelsToAdd ); DispUpdateLightmapAlpha( g_CoreDispInfos.Base(), i, (float)dispCount / g_dispinfo.Count(), (float)(dispCount+1) / g_dispinfo.Count(), pDisp, pFace->m_LightmapTextureSizeInLuxels[0], pFace->m_LightmapTextureSizeInLuxels[1] ); ++dispCount; } EndPacifier(); }
void EmitDispLMAlphaAndNeighbors() { int i; Msg( "Finding displacement neighbors...\n" ); // Build the CCoreDispInfos. CUtlVector<dface_t*> faces; // Create the core dispinfos and init them for use as CDispUtilsHelpers. for ( int iDisp = 0; iDisp < nummapdispinfo; ++iDisp ) { CCoreDispInfo *pDisp = new CCoreDispInfo; if ( !pDisp ) { g_CoreDispInfos.Purge(); return; } int nIndex = g_CoreDispInfos.AddToTail(); pDisp->SetListIndex( nIndex ); g_CoreDispInfos[nIndex] = pDisp; } for ( i=0; i < nummapdispinfo; i++ ) { g_CoreDispInfos[i]->SetDispUtilsHelperInfo( g_CoreDispInfos.Base(), nummapdispinfo ); } faces.SetSize( nummapdispinfo ); for( i = 0; i < numfaces; i++ ) { dface_t *pFace = &dfaces[i]; if( pFace->dispinfo == -1 ) continue; mapdispinfo_t *pMapDisp = &mapdispinfo[pFace->dispinfo]; // Set the displacement's face index. ddispinfo_t *pDisp = &g_dispinfo[pFace->dispinfo]; pDisp->m_iMapFace = i; // Get a CCoreDispInfo. All we need is the triangles and lightmap texture coordinates. CCoreDispInfo *pCoreDispInfo = g_CoreDispInfos[pFace->dispinfo]; DispMapToCoreDispInfo( pMapDisp, pCoreDispInfo, pFace ); faces[pFace->dispinfo] = pFace; } // Generate and export neighbor data. ExportNeighborData( g_CoreDispInfos.Base(), g_dispinfo.Base(), nummapdispinfo ); // Generate and export the active vert lists. ExportAllowedVertLists( g_CoreDispInfos.Base(), g_dispinfo.Base(), nummapdispinfo ); // Now that we know which vertices are actually going to be around, snap the ones that won't // be around onto the slightly-reduced mesh. This is so the engine's ray test code and // overlay code works right. SnapRemainingVertsToSurface( g_CoreDispInfos.Base(), g_dispinfo.Base(), nummapdispinfo ); Msg( "Finding lightmap sample positions...\n" ); for ( i=0; i < nummapdispinfo; i++ ) { dface_t *pFace = faces[i]; ddispinfo_t *pDisp = &g_dispinfo[pFace->dispinfo]; CCoreDispInfo *pCoreDispInfo = g_CoreDispInfos[i]; pDisp->m_iLightmapSamplePositionStart = g_DispLightmapSamplePositions.Count(); CalculateLightmapSamplePositions( pCoreDispInfo, pFace, g_DispLightmapSamplePositions ); } StartPacifier( "Displacement Alpha : "); // Build lightmap alphas. int dispCount = 0; // How many we've processed. for( i = 0; i < nummapdispinfo; i++ ) { dface_t *pFace = faces[i]; Assert( pFace->dispinfo == i ); mapdispinfo_t *pMapDisp = &mapdispinfo[pFace->dispinfo]; ddispinfo_t *pDisp = &g_dispinfo[pFace->dispinfo]; CCoreDispInfo *pCoreDispInfo = g_CoreDispInfos[i]; // Allocate space for the alpha values. pDisp->m_iLightmapAlphaStart = 0; // not used anymore ++dispCount; } EndPacifier(); }