Skip to content

Commit c787113

Browse files
committed
Addendum to 49e5265: Fix crashes introduced, and other pre-existing issues that surfaced, including mem leaks.
Memory fragmentation-related crashes due to texture replacing/allocation spam in loop are also reduced or gone (This wasn't out of mem.. it could happen even with 800MB usage), which is huge for MTA.
1 parent f20610e commit c787113

File tree

9 files changed

+355
-154
lines changed

9 files changed

+355
-154
lines changed

Client/core/DXHook/CDirect3DEvents9.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1204,8 +1204,19 @@ void CDirect3DEvents9::CloseActiveShader(bool bDeviceOperational)
12041204
if (!pShaderItem)
12051205
return;
12061206

1207+
if (!SharedUtil::IsReadablePointer(pShaderItem, sizeof(void*)))
1208+
return;
1209+
12071210
SResolvedShaderState shaderState;
12081211
bool bHasShaderState = TryResolveShaderState(pShaderItem, shaderState);
1212+
1213+
if (bHasShaderState)
1214+
{
1215+
if (shaderState.pInstance && !SharedUtil::IsReadablePointer(shaderState.pInstance, sizeof(void*)))
1216+
bHasShaderState = false;
1217+
if (bHasShaderState && shaderState.pEffectWrap && !SharedUtil::IsReadablePointer(shaderState.pEffectWrap, sizeof(void*)))
1218+
bHasShaderState = false;
1219+
}
12091220

12101221
ID3DXEffect* pD3DEffect = bHasShaderState ? shaderState.pEffect : nullptr;
12111222
IDirect3DDevice9* pDevice = g_pGraphics ? g_pGraphics->GetDevice() : nullptr;

Client/game_sa/CRenderWareSA.ShaderMatching.cpp

Lines changed: 71 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -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
//////////////////////////////////////////////////////////////////
210219
void 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
//

Client/game_sa/CRenderWareSA.ShaderMatching.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ class CMatchChannelManager
266266
void RemoveClientEntityRefs(CClientEntityBase* pClientEntity);
267267
void RemoveShaderRefs(CSHADERDUMMY* pShaderData);
268268
void GetShaderReplacementStats(SShaderReplacementStats& outStats);
269+
void CleanupInvalidatedShaderCache(); // Cleanup deferred invalidated entries
269270

270271
protected:
271272
void CalcShaderForTexAndEntity(SShaderInfoLayers& outShaderLayers, STexNameInfo* pTexNameInfo, CClientEntityBase* pClientEntity, int iEntityType,

0 commit comments

Comments
 (0)