@@ -34,7 +34,7 @@ class VMatrix; // forward decl
3434static ConVar cl_drawleaf (" cl_drawleaf" , " -1" , FCVAR_CHEAT );
3535static ConVar r_PortalTestEnts ( " r_PortalTestEnts" , " 1" , FCVAR_CHEAT, " Clip entities against portal frustums." );
3636static ConVar r_portalsopenall ( " r_portalsopenall" , " 0" , FCVAR_CHEAT, " Open all portals" );
37- static ConVar cl_threaded_client_leaf_system ( " cl_threaded_client_leaf_system" , " 0 " );
37+ static ConVar cl_threaded_client_leaf_system ( " cl_threaded_client_leaf_system" , " 1 " );
3838
3939
4040DEFINE_FIXEDSIZE_ALLOCATOR ( CClientRenderablesList, 1 , CUtlMemoryPool::GROW_SLOW );
@@ -133,7 +133,6 @@ class CClientLeafSystem : public IClientLeafSystem, public ISpatialLeafEnumerato
133133 // Find all shadow casters in a set of leaves
134134 virtual void EnumerateShadowsInLeaves ( int leafCount, LeafIndex_t* pLeaves, IClientLeafShadowEnum* pEnum );
135135 virtual void DisableLeafReinsertion (bool bDisable);
136-
137136 virtual void ComputeAllBounds (void );
138137
139138 // methods of ISpatialLeafEnumerator
@@ -198,9 +197,12 @@ class CClientLeafSystem : public IClientLeafSystem, public ISpatialLeafEnumerato
198197
199198 void SortEntities ( const Vector &vecRenderOrigin, const Vector &vecRenderForward, CClientRenderablesList::CEntry *pEntities, int nEntities );
200199
200+ virtual void ComputeBounds (RenderableInfo_t*& info);
201+
201202 // remove renderables from leaves
202203 void InsertIntoTree (ClientRenderHandle_t& handle, const Vector& absMins, const Vector& absMaxs);
203- void RemoveFromTree ( ClientRenderHandle_t handle );
204+ void InsertIntoTree (ClientRenderHandle_t& handle);
205+ void RemoveFromTree ( ClientRenderHandle_t& handle );
204206
205207 // Returns if it's a view model render group
206208 inline bool IsViewModelRenderGroup ( RenderGroup_t group ) const ;
@@ -229,7 +231,7 @@ class CClientLeafSystem : public IClientLeafSystem, public ISpatialLeafEnumerato
229231
230232 void ProcessDirtyRenderable (ClientRenderHandle_t& handle);
231233
232- void CalcRenderableWorldSpaceAABB_Bloated (const RenderableInfo_t& info, Vector& absMin, Vector& absMax);
234+ void CalcRenderableWorldSpaceAABB_Bloated (RenderableInfo_t& info, Vector& absMin, Vector& absMax);
233235
234236 // Methods associated with the various bi-directional sets
235237 static unsigned int & FirstRenderableInLeaf ( int leaf )
@@ -339,8 +341,6 @@ class CClientLeafSystem : public IClientLeafSystem, public ISpatialLeafEnumerato
339341 bool m_bDisableLeafReinsertion;
340342
341343 // A little enumerator to help us when adding shadows to renderables
342- // TODO: fix client leaf system infinitely adding shadows
343- // std::atomic<int> m_ShadowEnum{ 0 };
344344 int m_ShadowEnum;
345345
346346 CTSList<EnumResultList_t> m_DeferredInserts;
@@ -464,29 +464,26 @@ void CClientLeafSystem::DisableLeafReinsertion(bool bDisable)
464464void CClientLeafSystem::ComputeAllBounds (void )
465465{
466466 MDLCACHE_CRITICAL_SECTION ();
467+ static CUtlVector<RenderableInfo_t*> renderablesToUpdate;
468+ bool bThreaded = ( cl_threaded_client_leaf_system.GetBool () && cl_threaded_client_leaf_system.GetInt () < 3 && g_pThreadPool->NumThreads () );
467469 for (int i = m_Renderables.Head (); i != m_Renderables.InvalidIndex (); i = m_Renderables.Next (i))
468470 {
469- RenderableInfo_t* pInfo = &m_Renderables[i];
470-
471- if (pInfo->m_Flags & RENDER_FLAGS_DISABLE_RENDERING)
472- continue ;
471+ RenderableInfo_t* info = &m_Renderables[i];
473472
474- if ((pInfo-> m_Flags & RENDER_FLAGS_BOUNDS_VALID) == 0 )
473+ if (bThreaded )
475474 {
476- CalcRenderableWorldSpaceAABB (pInfo->m_pRenderable , pInfo->m_vecAbsMins , pInfo->m_vecAbsMaxs );
477- pInfo->m_Flags |= RENDER_FLAGS_BOUNDS_VALID;
475+ renderablesToUpdate.AddToTail (info);
478476 }
479- #ifdef _DEBUG
480477 else
481478 {
482- // If these assertions trigger, it means there's some state that GetRenderBounds
483- // depends on which, on change, doesn't call ClientLeafSystem::RenderableChanged().
484- Vector vecTestMins, vecTestMaxs;
485- CalcRenderableWorldSpaceAABB (pInfo->m_pRenderable , vecTestMins, vecTestMaxs);
486- Assert (VectorsAreEqual (vecTestMins, pInfo->m_vecAbsMins , 1e-3 ));
487- Assert (VectorsAreEqual (vecTestMaxs, pInfo->m_vecAbsMaxs , 1e-3 ));
479+ ComputeBounds (info);
488480 }
489- #endif
481+ }
482+
483+ if ( bThreaded )
484+ {
485+ ParallelProcess ( " CClientLeafSystem::ComputeAllBounds" , renderablesToUpdate.Base (), renderablesToUpdate.Count (), this , &CClientLeafSystem::ComputeBounds );
486+ renderablesToUpdate.RemoveAll ();
490487 }
491488}
492489
@@ -573,8 +570,7 @@ void CClientLeafSystem::PreRender()
573570
574571 int nDirty = m_DirtyRenderables.Count ();
575572
576- // bool bThreaded = ( nDirty > 5 && cl_threaded_client_leaf_system.GetBool() && g_pThreadPool->NumThreads() );
577- bool bThreaded = false ;
573+ bool bThreaded = ( nDirty > 5 && cl_threaded_client_leaf_system.GetBool () && cl_threaded_client_leaf_system.GetInt () < 3 && g_pThreadPool->NumThreads () );
578574
579575 if ( !bThreaded )
580576 {
@@ -586,17 +582,46 @@ void CClientLeafSystem::PreRender()
586582 }
587583 else
588584 {
589- // InsertIntoTree can result in new renderables being added, so copy:
590- ClientRenderHandle_t *pDirtyRenderables = (ClientRenderHandle_t *)alloca ( sizeof (ClientRenderHandle_t) * nDirty );
591- memcpy ( pDirtyRenderables, m_DirtyRenderables.Base (), sizeof (ClientRenderHandle_t) * nDirty );
592- ParallelProcess ( " CClientLeafSystem::PreRender" , pDirtyRenderables, nDirty, this , &CClientLeafSystem::ProcessDirtyRenderable, &CClientLeafSystem::FrameLock, &CClientLeafSystem::FrameUnlock );
585+ for ( i = nDirty; --i >= 0 ; )
586+ {
587+ ClientRenderHandle_t handle = m_DirtyRenderables[i];
588+ RenderableInfo_t& info = m_Renderables[handle];
589+
590+ Assert (m_Renderables[handle].m_Flags & RENDER_FLAGS_HASCHANGED);
591+ Vector absMins, absMaxs;
592+ CalcRenderableWorldSpaceAABB_Bloated (info, absMins, absMaxs);
593+ if (absMins != info.m_vecBloatedAbsMins || absMaxs != info.m_vecBloatedAbsMaxs )
594+ {
595+ // Update position in leaf system
596+ RemoveFromTree (handle);
597+ info.m_vecBloatedAbsMins = absMins;
598+ info.m_vecBloatedAbsMaxs = absMaxs;
599+ }
600+ else
601+ {
602+ // We don't need to update it
603+ info.m_Flags &= ~RENDER_FLAGS_HASCHANGED;
604+ m_DirtyRenderables.Remove (i);
605+ }
606+ }
607+
608+ nDirty = m_DirtyRenderables.Count ();
609+
610+ if (nDirty)
611+ {
612+ // InsertIntoTree can result in new renderables being added, so copy:
613+ ClientRenderHandle_t *pDirtyRenderables = (ClientRenderHandle_t *)alloca ( sizeof (ClientRenderHandle_t) * nDirty );
614+ memcpy ( pDirtyRenderables, m_DirtyRenderables.Base (), sizeof (ClientRenderHandle_t) * nDirty );
615+ ParallelProcess ( " CClientLeafSystem::PreRender" , pDirtyRenderables, nDirty, this , &CClientLeafSystem::InsertIntoTree );
616+ }
593617 }
594618
595619 if ( m_DeferredInserts.Count () )
596620 {
597621 EnumResultList_t enumResultList;
598622 while ( m_DeferredInserts.PopItem ( &enumResultList ) )
599623 {
624+ m_ShadowEnum++;
600625 const bool bReceiveShadows = ShouldRenderableReceiveShadow (enumResultList.handle , SHADOW_FLAGS_PROJECTED_TEXTURE_TYPE_MASK);
601626 while ( enumResultList.pHead )
602627 {
@@ -612,8 +637,6 @@ void CClientLeafSystem::PreRender()
612637 // "Re-entrancy found in CClientLeafSystem::RenderableChanged\n"
613638 // We'll have to reenable this code and remove the line that
614639 // removes the RENDER_FLAGS_HASCHANGED in the loop above.
615- // UNDONE(mastercoms): doesn't seem like there are re-entrancy problems
616- /*
617640 for ( i = nDirty; --i >= 0 ; )
618641 {
619642 // Cache off the area it's sitting in.
@@ -622,7 +645,6 @@ void CClientLeafSystem::PreRender()
622645
623646 renderable.m_Flags &= ~RENDER_FLAGS_HASCHANGED;
624647 }
625- */
626648
627649 m_DirtyRenderables.RemoveMultiple ( 0 , nDirty );
628650 }
@@ -1066,7 +1088,7 @@ void CClientLeafSystem::ProcessDirtyRenderable(ClientRenderHandle_t& handle)
10661088 Assert (m_Renderables[handle].m_Flags & RENDER_FLAGS_HASCHANGED);
10671089
10681090 // See note at the end of PreRender
1069- info.m_Flags &= ~RENDER_FLAGS_HASCHANGED;
1091+ // info.m_Flags &= ~RENDER_FLAGS_HASCHANGED;
10701092
10711093 Vector absMins, absMaxs;
10721094 CalcRenderableWorldSpaceAABB_Bloated (info, absMins, absMaxs);
@@ -1085,10 +1107,19 @@ void CClientLeafSystem::ProcessDirtyRenderable(ClientRenderHandle_t& handle)
10851107#define BBOX_GRANULARITY 32 .0f
10861108#define MIN_SHRINK_VOLUME ( 32 .0f * 32 .0f * 32 .0f )
10871109
1088- void CClientLeafSystem::CalcRenderableWorldSpaceAABB_Bloated (const RenderableInfo_t& info, Vector& absMin,
1110+ void CClientLeafSystem::CalcRenderableWorldSpaceAABB_Bloated (RenderableInfo_t& info, Vector& absMin,
10891111 Vector& absMax)
10901112{
1091- CalcRenderableWorldSpaceAABB (info.m_pRenderable , absMin, absMax);
1113+ if ((info.m_Flags & RENDER_FLAGS_BOUNDS_VALID) == 0 )
1114+ {
1115+ CalcRenderableWorldSpaceAABB (info.m_pRenderable , absMin, absMax);
1116+ info.m_Flags |= RENDER_FLAGS_BOUNDS_VALID;
1117+ }
1118+ else
1119+ {
1120+ absMin = info.m_vecAbsMins ;
1121+ absMax = info.m_vecAbsMaxs ;
1122+ }
10921123
10931124 // Bloat bounds to avoid reinsertion into tree
10941125 absMin.x = floor (absMin.x / BBOX_GRANULARITY) * BBOX_GRANULARITY;
@@ -1275,7 +1306,7 @@ void CClientLeafSystem::AddRenderableToLeaves( ClientRenderHandle_t handle, int
12751306{
12761307 for (int j = 0 ; j < nLeafCount; ++j)
12771308 {
1278- AddRenderableToLeaf (pLeaves[j], handle, bReceiveShadows);
1309+ AddRenderableToLeaf (pLeaves[j], handle, bReceiveShadows);
12791310 }
12801311 m_Renderables[handle].m_Area = engine->GetLeavesArea (pLeaves, nLeafCount);
12811312}
@@ -1317,17 +1348,28 @@ void CClientLeafSystem::InsertIntoTree( ClientRenderHandle_t &handle, const Vect
13171348 info.m_vecBloatedAbsMins = absMins;
13181349 info.m_vecBloatedAbsMaxs = absMaxs;
13191350
1320- // When we insert into the tree, increase the shadow enumerator
1321- // to make sure each shadow is added exactly once to each renderable
1322- m_ShadowEnum++;
1351+ InsertIntoTree (handle);
1352+ }
1353+
1354+ void CClientLeafSystem::InsertIntoTree (ClientRenderHandle_t& handle)
1355+ {
1356+ RenderableInfo_t& info = m_Renderables[handle];
1357+
1358+ const bool bMainThread = ThreadInMainThread ();
1359+ if ( bMainThread )
1360+ {
1361+ // When we insert into the tree, increase the shadow enumerator
1362+ // to make sure each shadow is added exactly once to each renderable
1363+ m_ShadowEnum++;
1364+ }
13231365
13241366 EnumResultList_t list = { NULL , handle };
13251367
13261368 unsigned short leafList[1024 ];
13271369 ISpatialQuery* pQuery = engine->GetBSPTreeQuery ();
1328- int leafCount = pQuery->ListLeavesInBox (absMins, absMaxs , leafList, ARRAYSIZE (leafList));
1370+ int leafCount = pQuery->ListLeavesInBox (info. m_vecBloatedAbsMins , info. m_vecBloatedAbsMaxs , leafList, ARRAYSIZE (leafList));
13291371
1330- if (ThreadInMainThread () )
1372+ if (bMainThread )
13311373 {
13321374 AddRenderableToLeaves (handle, leafCount, leafList);
13331375 }
@@ -1348,7 +1390,7 @@ void CClientLeafSystem::InsertIntoTree( ClientRenderHandle_t &handle, const Vect
13481390// -----------------------------------------------------------------------------
13491391// Removes an element from the tree
13501392// -----------------------------------------------------------------------------
1351- void CClientLeafSystem::RemoveFromTree ( ClientRenderHandle_t handle )
1393+ void CClientLeafSystem::RemoveFromTree ( ClientRenderHandle_t& handle )
13521394{
13531395 m_RenderablesInLeaf.RemoveElement ( handle );
13541396
@@ -1513,8 +1555,7 @@ void CClientLeafSystem::ComputeTranslucentRenderLeaf( int count, const LeafIndex
15131555
15141556 // For better sorting, we're gonna choose the leaf that is closest to the camera.
15151557 // The leaf list passed in here is sorted front to back
1516- // bool bThreaded = ( cl_threaded_client_leaf_system.GetBool() && g_pThreadPool->NumThreads() );
1517- bool bThreaded = false ;
1558+ bool bThreaded = ( cl_threaded_client_leaf_system.GetInt () > 1 && g_pThreadPool->NumThreads () );
15181559 int globalFrameCount = gpGlobals->framecount ;
15191560 int i;
15201561
@@ -1925,6 +1966,29 @@ void CClientLeafSystem::SortEntities( const Vector &vecRenderOrigin, const Vecto
19251966 }
19261967}
19271968
1969+ void CClientLeafSystem::ComputeBounds (RenderableInfo_t*& pInfo)
1970+ {
1971+ if (pInfo->m_Flags & RENDER_FLAGS_DISABLE_RENDERING)
1972+ return ;
1973+
1974+ if ((pInfo->m_Flags & RENDER_FLAGS_BOUNDS_VALID) == 0 )
1975+ {
1976+ CalcRenderableWorldSpaceAABB (pInfo->m_pRenderable , pInfo->m_vecAbsMins , pInfo->m_vecAbsMaxs );
1977+ pInfo->m_Flags |= RENDER_FLAGS_BOUNDS_VALID;
1978+ }
1979+ #ifdef _DEBUG
1980+ else
1981+ {
1982+ // If these assertions trigger, it means there's some state that GetRenderBounds
1983+ // depends on which, on change, doesn't call ClientLeafSystem::RenderableChanged().
1984+ Vector vecTestMins, vecTestMaxs;
1985+ CalcRenderableWorldSpaceAABB (pInfo->m_pRenderable , vecTestMins, vecTestMaxs);
1986+ Assert (VectorsAreEqual (vecTestMins, pInfo->m_vecAbsMins , 1e-3 ));
1987+ Assert (VectorsAreEqual (vecTestMaxs, pInfo->m_vecAbsMaxs , 1e-3 ));
1988+ }
1989+ #endif
1990+ }
1991+
19281992
19291993void CClientLeafSystem::BuildRenderablesList ( const SetupRenderInfo_t &info )
19301994{
0 commit comments