@@ -243,10 +243,10 @@ namespace
243243 constexpr int TXD_POOL_HARD_LIMIT_PERCENT = 95 ;
244244
245245 // Pool pressure thresholds for stale slot reclamation
246- constexpr int TXD_POOL_PROACTIVE_CLEANUP_PERCENT = 80 ;
247- constexpr int TXD_POOL_MEDIUM_PRESSURE_PERCENT = 85 ;
246+ constexpr int TXD_POOL_PROACTIVE_CLEANUP_PERCENT = 70 ;
247+ constexpr int TXD_POOL_MEDIUM_PRESSURE_PERCENT = 80 ;
248248 constexpr int TXD_POOL_AGGRESSIVE_CLEANUP_PERCENT = 90 ;
249- constexpr uint32_t ISOLATION_STALE_TIMEOUT_MS = 30000 ;
249+ constexpr uint32_t ISOLATION_STALE_TIMEOUT_MS = 15000 ;
250250 constexpr uint32_t STALE_CLEANUP_INTERVAL_MS = 1000 ;
251251 constexpr int TXD_POOL_RESERVED_SLOTS = 64 ;
252252 constexpr int TXD_POOL_RESERVED_PERCENT = 10 ;
@@ -977,6 +977,24 @@ namespace
977977 g_IsolatedTxdLastUseTime.erase (usModelId);
978978 }
979979
980+ // Mark an isolated slot for early stale reclamation by zeroing its last-use
981+ // time. (now - 0) always exceeds any stale timeout, so the slot will be
982+ // picked up on the next TryReclaimStaleIsolatedSlots pass.
983+ // Called when all replacement tracking is removed from a TXD but the slot
984+ // could not be freed (e.g. leaked texture refs prevent destruction).
985+ static void MarkIsolatedSlotReadyForReclamation (unsigned short usTxdId)
986+ {
987+ auto itOwner = g_IsolatedModelByTxd.find (usTxdId);
988+ if (itOwner == g_IsolatedModelByTxd.end ())
989+ return ;
990+
991+ const unsigned short usModelId = itOwner->second ;
992+ if (g_IsolatedTxdByModel.count (usModelId) == 0 )
993+ return ;
994+
995+ g_IsolatedTxdLastUseTime[usModelId] = 0 ;
996+ }
997+
980998 // Reclaim isolated TXD slots unused for ISOLATION_STALE_TIMEOUT_MS under pool pressure
981999 static void TryReclaimStaleIsolatedSlots ()
9821000 {
@@ -2598,23 +2616,14 @@ namespace
25982616 g_IsolatedTxdByModel.erase (itExisting);
25992617 }
26002618
2601- // Pool pressure: try to reclaim stale slots before allocating
2602- const int iPoolSize = pTxdPoolSA->GetPoolSize ();
2603- if (iPoolSize > 0 )
2619+ // Reclaim stale and orphaned isolated slots before allocating.
2620+ // This keeps the pool clean and lets the allocation below reuse a
2621+ // freed slot instead of always usig a fresh one.
2622+ TryReclaimStaleIsolatedSlots ();
2623+ if (!g_OrphanedIsolatedTxdSlots.empty ())
26042624 {
2605- constexpr int iIsolationPoolSize = CTxdPoolSA::SA_TXD_POOL_CAPACITY;
2606- const int iUsedSlots = pTxdPoolSA->GetUsedSlotCountInRange (static_cast <std::uint32_t >(iIsolationPoolSize));
2607- if (iUsedSlots >= 0 )
2608- {
2609- const int iUsagePercent = (iUsedSlots * 100 ) / iIsolationPoolSize;
2610- if (iUsagePercent >= TXD_POOL_HARD_LIMIT_PERCENT)
2611- {
2612- TryReclaimStaleIsolatedSlots ();
2613- if (!g_OrphanedIsolatedTxdSlots.empty ())
2614- TryCleanupOrphanedIsolatedSlots (true );
2615- MarkTxdPoolCountDirty ();
2616- }
2617- }
2625+ TryCleanupOrphanedIsolatedSlots (true );
2626+ MarkTxdPoolCountDirty ();
26182627 }
26192628
26202629 // Store usParentIndex=0xFFFF when the parent TXD is not yet loaded; ProcessPendingIsolatedModels
@@ -6117,6 +6126,20 @@ void CRenderWareSA::ModelInfoTXDRemoveTextures(SReplacementTextures* pReplacemen
61176126 CleanupIsolatedTxdForModel (itOwner->second );
61186127 }
61196128
6129+ // For isolated slots whose replacements were all removed but the slot
6130+ // could not be freed (leaked texture refs or deferred state),
6131+ // mark for early stale reclamation so the next allocation or periodic
6132+ // cleanup pass reclaims the slot without waiting for the full timeout.
6133+ for (unsigned short usTxdId : processedTxdIds)
6134+ {
6135+ if (cleanedTxdIds.count (usTxdId) > 0 )
6136+ continue ;
6137+
6138+ auto * pRemainingInfo = MapFind (ms_ModelTexturesInfoMap, usTxdId);
6139+ if (pRemainingInfo && pRemainingInfo->usedByReplacements .empty ())
6140+ MarkIsolatedSlotReadyForReclamation (usTxdId);
6141+ }
6142+
61206143 // Invalidate caches for all TXDs that were modified
61216144 for (unsigned short usTxdId : processedTxdIds)
61226145 InvalidateTxdTextureMapCache (usTxdId);
0 commit comments