@@ -111,7 +111,7 @@ void CMatchChannelManager::RemoveTexture(STexInfo* pTexInfo)
111111    //  Remove association
112112    dassert (MapContains (pTexNameInfo->usedByTexInfoList , pTexInfo));
113113    MapRemove (pTexNameInfo->usedByTexInfoList , pTexInfo);
114-     pTexInfo->pAssociatedTexNameInfo  = NULL ;
114+     pTexInfo->pAssociatedTexNameInfo  = nullptr ;
115115}
116116
117117// ////////////////////////////////////////////////////////////////
@@ -125,24 +125,24 @@ void CMatchChannelManager::FinalizeLayers(SShaderInfoLayers& shaderLayers)
125125{
126126    //  Sort layers by priority
127127    std::sort (shaderLayers.layerList .begin (), shaderLayers.layerList .end ());
128-     uint  uiNumLayers = shaderLayers.layerList . size ( );
128+     const   auto   uiNumLayers = std::size ( shaderLayers.layerList );
129129
130130    //  Set output
131131    shaderLayers.output  = SShaderItemLayers ();
132132    shaderLayers.output .layerList .resize (uiNumLayers);
133133
134134    //  Copy base
135-     SShaderInfo* pShaderInfo = shaderLayers.pBase .pShaderInfo ;
136-     if  (pShaderInfo)
135+     if  (const  SShaderInfo* pBaseShaderInfo = shaderLayers.pBase .pShaderInfo )
137136    {
138-         shaderLayers.output .pBase  = pShaderInfo ->pShaderData ;
139-         shaderLayers.output .bUsesVertexShader  = pShaderInfo ->bUsesVertexShader ;
137+         shaderLayers.output .pBase  = pBaseShaderInfo ->pShaderData ;
138+         shaderLayers.output .bUsesVertexShader  = pBaseShaderInfo ->bUsesVertexShader ;
140139    }
141140
142141    //  Copy layers
143-     for  (uint  i = 0 ; i < uiNumLayers; i++ )
142+     for  (std:: size_t  i = 0 ; i < uiNumLayers; ++i )
144143    {
145-         SShaderInfo* pShaderInfo = shaderLayers.layerList [i].pShaderInfo ;
144+         const  SShaderInfo* pShaderInfo = shaderLayers.layerList [i].pShaderInfo ;
145+         dassert (pShaderInfo);            //  Layers should always have valid shader info
146146        shaderLayers.output .layerList [i] = pShaderInfo->pShaderData ;
147147        shaderLayers.output .bUsesVertexShader  |= pShaderInfo->bUsesVertexShader ;
148148    }
@@ -166,29 +166,38 @@ STexShaderReplacement* CMatchChannelManager::UpdateTexShaderReplacement(STexName
166166        pTexShaderReplacement = MapFind (pTexNameInfo->texEntityShaderMap , pClientEntity);
167167    }
168168
169-     if  (!pTexShaderReplacement->bSet )
169+     if  (!pTexShaderReplacement->bSet  || !pTexShaderReplacement-> bValid )
170170    {
171-         //  If not done yet for this entity, needs to be done
172-         dassert (!pTexShaderReplacement->shaderLayers .pBase .pShaderInfo  && pTexShaderReplacement->shaderLayers .layerList .empty ());
171+         //  If not calculated yet or invalidated, (re)build it
172+         if  (!pTexShaderReplacement->bValid )
173+         {
174+             //  Clear invalidated data before rebuilding
175+             pTexShaderReplacement->shaderLayers  = SShaderInfoLayers ();
176+         }
177+         else 
178+         {
179+             //  Fresh entry - should be empty
180+             dassert (!pTexShaderReplacement->shaderLayers .pBase .pShaderInfo  && pTexShaderReplacement->shaderLayers .layerList .empty ());
181+         }
173182        CalcShaderForTexAndEntity (pTexShaderReplacement->shaderLayers , pTexNameInfo, pClientEntity, iEntityType, false );
174183        pTexShaderReplacement->bSet  = true ;
184+         pTexShaderReplacement->bValid  = true ;
175185
176186        //  texNoEntityShader need to be done also, so we can see what needs to be inherited from it
187+         if  (STexShaderReplacement& texNoEntityShader = pTexNameInfo->GetTexNoEntityShader (iEntityType); true )
177188        {
178-             STexShaderReplacement& texNoEntityShader = pTexNameInfo->GetTexNoEntityShader (iEntityType);
179189            UpdateTexShaderReplacementNoEntity (pTexNameInfo, texNoEntityShader, iEntityType);
180190
181191            //  Handle base inheritance
182-             if  (pTexShaderReplacement->shaderLayers .pBase .pShaderInfo  == NULL )
192+             if  (pTexShaderReplacement->shaderLayers .pBase .pShaderInfo  == nullptr )
183193            {
184194                if  (texNoEntityShader.shaderLayers .pBase .bMixEntityAndNonEntity )
185195                    pTexShaderReplacement->shaderLayers .pBase  = texNoEntityShader.shaderLayers .pBase ;
186196            }
187197
188198            //  Handle layer inheritance
189-             for  (uint i =  0 ; i <  texNoEntityShader.shaderLayers .layerList . size (); i++ )
199+             for  (const   auto & info :  texNoEntityShader.shaderLayers .layerList )
190200            {
191-                 const  SShaderInfoInstance& info = texNoEntityShader.shaderLayers .layerList [i];
192201                if  (info.bMixEntityAndNonEntity )
193202                    pTexShaderReplacement->shaderLayers .layerList .push_back (info);
194203            }
@@ -209,12 +218,22 @@ STexShaderReplacement* CMatchChannelManager::UpdateTexShaderReplacement(STexName
209218// ////////////////////////////////////////////////////////////////
210219void  CMatchChannelManager::UpdateTexShaderReplacementNoEntity (STexNameInfo* pTexNameInfo, STexShaderReplacement& texNoEntityShader, int  iEntityType)
211220{
212-     if  (!texNoEntityShader.bSet )
221+     if  (!texNoEntityShader.bSet  || !texNoEntityShader. bValid )
213222    {
214-         //  If not done yet, needs to be done
215-         dassert (!texNoEntityShader.shaderLayers .pBase .pShaderInfo  && texNoEntityShader.shaderLayers .layerList .empty ());
216-         CalcShaderForTexAndEntity (texNoEntityShader.shaderLayers , pTexNameInfo, NULL , iEntityType, false );
223+         //  If not calculated yet or invalidated, (re)build it
224+         if  (!texNoEntityShader.bValid )
225+         {
226+             //  Clear invalidated data before rebuilding
227+             texNoEntityShader.shaderLayers  = SShaderInfoLayers ();
228+         }
229+         else 
230+         {
231+             //  Fresh entry - should be empty
232+             dassert (!texNoEntityShader.shaderLayers .pBase .pShaderInfo  && texNoEntityShader.shaderLayers .layerList .empty ());
233+         }
234+         CalcShaderForTexAndEntity (texNoEntityShader.shaderLayers , pTexNameInfo, nullptr , iEntityType, false );
217235        texNoEntityShader.bSet  = true ;
236+         texNoEntityShader.bValid  = true ;
218237
219238        FinalizeLayers (texNoEntityShader.shaderLayers );
220239    }
@@ -237,14 +256,15 @@ SShaderInfoLayers* CMatchChannelManager::GetShaderForTexAndEntity(STexInfo* pTex
237256    //  Ignore unknown client entities
238257    if  (pClientEntity)
239258        if  (!MapContains (m_KnownClientEntities, pClientEntity))
240-             pClientEntity = NULL ;
259+             pClientEntity = nullptr ;
241260
242261    if  (pClientEntity)
243262    {
244263        //  Get entity info for this replace
245264        STexShaderReplacement* pTexShaderReplacement = MapFind (pTexNameInfo->texEntityShaderMap , pClientEntity);
246265
247-         if  (!pTexShaderReplacement || !pTexShaderReplacement->bSet )
266+         //  Rebuild only if: doesn't exist, not yet calculated, or explicitly invalidated
267+         if  (!pTexShaderReplacement || !pTexShaderReplacement->bSet  || !pTexShaderReplacement->bValid )
248268        {
249269            pTexShaderReplacement = UpdateTexShaderReplacement (pTexNameInfo, pClientEntity, iEntityType);
250270        }
@@ -259,16 +279,15 @@ SShaderInfoLayers* CMatchChannelManager::GetShaderForTexAndEntity(STexInfo* pTex
259279
260280            //  Handle base inheritance
261281            STexShaderReplacement& texNoEntityShader = pTexNameInfo->GetTexNoEntityShader (iEntityType);
262-             if  (shaderLayersCheck1.pBase .pShaderInfo  == NULL )
282+             if  (shaderLayersCheck1.pBase .pShaderInfo  == nullptr )
263283            {
264284                if  (texNoEntityShader.shaderLayers .pBase .bMixEntityAndNonEntity )
265285                    shaderLayersCheck1.pBase  = texNoEntityShader.shaderLayers .pBase ;
266286            }
267287
268288            //  Handle layer inheritance
269-             for  (uint i =  0 ; i <  texNoEntityShader.shaderLayers .layerList . size (); i++ )
289+             for  (const   auto & info :  texNoEntityShader.shaderLayers .layerList )
270290            {
271-                 const  SShaderInfoInstance& info = texNoEntityShader.shaderLayers .layerList [i];
272291                if  (info.bMixEntityAndNonEntity )
273292                    shaderLayersCheck1.layerList .push_back (info);
274293            }
@@ -285,7 +304,7 @@ SShaderInfoLayers* CMatchChannelManager::GetShaderForTexAndEntity(STexInfo* pTex
285304    {
286305        STexShaderReplacement& texNoEntityShader = pTexNameInfo->GetTexNoEntityShader (iEntityType);
287306
288-         if  (!texNoEntityShader.bSet )
307+         if  (!texNoEntityShader.bSet  || !texNoEntityShader. bValid )
289308        {
290309            UpdateTexShaderReplacementNoEntity (pTexNameInfo, texNoEntityShader, iEntityType);
291310        }
@@ -296,7 +315,7 @@ SShaderInfoLayers* CMatchChannelManager::GetShaderForTexAndEntity(STexInfo* pTex
296315            //  Check cached shader is correct
297316            pTexNameInfo->iDebugCounter2  = rand () % 100 ;
298317            SShaderInfoLayers shaderLayersCheck2;
299-             CalcShaderForTexAndEntity (shaderLayersCheck2, pTexNameInfo, NULL , iEntityType, true );
318+             CalcShaderForTexAndEntity (shaderLayersCheck2, pTexNameInfo, nullptr , iEntityType, true );
300319            FinalizeLayers (shaderLayersCheck2);
301320            assert (texNoEntityShader.shaderLayers  == shaderLayersCheck2);
302321        }
@@ -368,11 +387,10 @@ void CMatchChannelManager::RemoveClientEntityRefs(CClientEntityBase* pClientEnti
368387    }
369388
370389    //  Flag affected textures to re-calc shader results
371-     for  (CFastHashSet< CMatchChannel*>::iterator iter =  affectedChannels. begin (); iter != affectedChannels. end (); ++iter )
390+     for  (CMatchChannel* pChannel :  affectedChannels)
372391    {
373-         CMatchChannel* pChannel = *iter;
374-         for  (CFastHashSet<STexNameInfo*>::iterator iter = pChannel->m_MatchedTextureList .begin (); iter != pChannel->m_MatchedTextureList .end (); ++iter)
375-             (*iter)->ResetReplacementResults ();
392+         for  (STexNameInfo* pTexNameInfo : pChannel->m_MatchedTextureList )
393+             pTexNameInfo->ResetReplacementResults ();
376394
377395        //  Also delete channel if is not refed anymore
378396        if  (pChannel->GetShaderAndEntityCount () == 0 )
@@ -381,9 +399,9 @@ void CMatchChannelManager::RemoveClientEntityRefs(CClientEntityBase* pClientEnti
381399    }
382400
383401    //  Need to remove client entity entries that were used even though they had no matches
384-     for  (CFastHashMap<SString, STexNameInfo*>::const_iterator iter = m_AllTextureList. begin (); iter !=  m_AllTextureList. end (); ++iter )
402+     for  (const   auto & [name, pTexNameInfo] :  m_AllTextureList)
385403    {
386-         MapRemove (iter-> second ->texEntityShaderMap , pClientEntity);
404+         MapRemove (pTexNameInfo ->texEntityShaderMap , pClientEntity);
387405    }
388406
389407#ifdef  SHADER_DEBUG_CHECKS
@@ -599,27 +617,24 @@ void CMatchChannelManager::ProcessRematchTexturesQueue()
599617    m_RematchQueue.clear ();
600618
601619    //  For each queued channel
602-     for  (CFastHashSet< CMatchChannel*>::iterator iter =  rematchQueue. begin (); iter != rematchQueue. end (); ++iter )
620+     for  (CMatchChannel* pChannel :  rematchQueue)
603621    {
604-         CMatchChannel* pChannel = *iter;
605622        pChannel->m_bResetReplacements  = true ;
606623
607624        OutputDebug (SString ("     [ProcessRematchTexturesQueue] - Channel:%s" GetDebugTag (pChannel)));
608625
609626        //  Remove existing matches
610627        CFastHashSet<STexNameInfo*> matchedTextureList = pChannel->m_MatchedTextureList ;
611-         for  (CFastHashSet< STexNameInfo*>::iterator iter =  matchedTextureList. begin (); iter != matchedTextureList. end (); ++iter )
628+         for  (STexNameInfo* pTexNameInfo :  matchedTextureList)
612629        {
613-             STexNameInfo* pTexNameInfo = *iter;
614630            pChannel->RemoveTexture (pTexNameInfo);
615631            MapRemove (pTexNameInfo->matchChannelList , pChannel);
616632            pTexNameInfo->ResetReplacementResults ();            //  Do this here as it won't get picked up in RecalcEverything now
617633        }
618634
619635        //  Rematch against texture list
620-         for  (CFastHashMap<SString, STexNameInfo*>::iterator iter =  m_AllTextureList. begin (); iter != m_AllTextureList. end (); ++iter )
636+         for  (auto & [name, pTexNameInfo] :  m_AllTextureList)
621637        {
622-             STexNameInfo* pTexNameInfo = iter->second ;
623638            if  (pChannel->m_MatchChain .IsAdditiveMatch (pTexNameInfo->strTextureName ))
624639            {
625640                pChannel->AddTexture (pTexNameInfo);
@@ -912,6 +927,24 @@ void CMatchChannelManager::GetShaderReplacementStats(SShaderReplacementStats& ou
912927    }
913928}
914929
930+ // //////////////////////////////////////////////////////////////
931+ // 
932+ //  CMatchChannelManager::CleanupInvalidatedShaderCache
933+ // 
934+ //  Remove shader cache entries that were marked invalid (deferred cleanup)
935+ //  This prevents memory growth from invalidated-but-not-yet-deleted entries
936+ // 
937+ // //////////////////////////////////////////////////////////////
938+ void  CMatchChannelManager::CleanupInvalidatedShaderCache ()
939+ {
940+     for  (CFastHashMap<SString, STexNameInfo*>::iterator iter = m_AllTextureList.begin (); iter != m_AllTextureList.end (); ++iter)
941+     {
942+         STexNameInfo* pTexNameInfo = iter->second ;
943+         if  (pTexNameInfo)
944+             pTexNameInfo->CleanupInvalidatedEntries ();
945+     }
946+ }
947+ 
915948// 
916949// 
917950// 
0 commit comments