Skip to content

Commit f91e1de

Browse files
authored
Temporary textures cleanup (#3978)
Fix issue #3977
1 parent 583e675 commit f91e1de

File tree

3 files changed

+61
-7
lines changed

3 files changed

+61
-7
lines changed

Client/mods/deathmatch/logic/CClientManager.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ void CClientManager::DoPulse(bool bDoStandardPulses, bool bDoVehicleManagerPulse
218218
m_pColManager->DoPulse();
219219
m_pGUIManager->DoPulse();
220220
m_pWeaponManager->DoPulse();
221+
m_pRenderElementManager->DoPulse();
221222
}
222223
else
223224
{

Client/mods/deathmatch/logic/CClientRenderElementManager.cpp

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
#include "StdInc.h"
1212
#include "CClientVectorGraphic.h"
1313

14+
constexpr std::int64_t TEMPORARY_TEXTURES_CLEANUP_PERIOD = 5000ll;
15+
constexpr std::int64_t TEMPORARY_TEXTURES_CLEANUP_THRESHOLD = 10000ll;
16+
constexpr std::size_t TEMPORARY_TEXTURES_DELETE_THRESHOLD = 10u;
17+
1418
////////////////////////////////////////////////////////////////
1519
//
1620
// CClientRenderElementManager::CClientRenderElementManager
@@ -283,20 +287,24 @@ CClientVectorGraphic* CClientRenderElementManager::CreateVectorGraphic(uint widt
283287
CClientTexture* CClientRenderElementManager::FindAutoTexture(const SString& strFullFilePath, const SString& strUniqueName)
284288
{
285289
// Check if we've already done this file
286-
CClientTexture** ppTextureElement = MapFind(m_AutoTextureMap, strUniqueName);
290+
SAutoTexture* ppTextureElement = MapFind(m_AutoTextureMap, strUniqueName);
287291
if (!ppTextureElement)
288292
{
289293
// Try to create
290294
CClientTexture* pNewTextureElement = CreateTexture(strFullFilePath);
291295
if (!pNewTextureElement)
292-
return NULL;
296+
return nullptr;
297+
298+
pNewTextureElement->MakeSystemEntity();
293299

294300
// Add to automap if created
295-
MapSet(m_AutoTextureMap, strUniqueName, pNewTextureElement);
301+
MapSet(m_AutoTextureMap, strUniqueName, SAutoTexture{pNewTextureElement});
296302
ppTextureElement = MapFind(m_AutoTextureMap, strUniqueName);
297303
}
298304

299-
return *ppTextureElement;
305+
ppTextureElement->lastUse = CTickCount::Now();
306+
307+
return ppTextureElement->texture;
300308
}
301309

302310
////////////////////////////////////////////////////////////////
@@ -318,9 +326,9 @@ void CClientRenderElementManager::Remove(CClientRenderElement* pElement)
318326
// Remove from auto texture map
319327
if (pElement->IsA(CClientTexture::GetClassId()))
320328
{
321-
for (std::map<SString, CClientTexture*>::iterator iter = m_AutoTextureMap.begin(); iter != m_AutoTextureMap.end(); ++iter)
329+
for (auto iter = m_AutoTextureMap.begin(); iter != m_AutoTextureMap.end(); ++iter)
322330
{
323-
if (iter->second == pElement)
331+
if (iter->second.texture == pElement)
324332
{
325333
m_AutoTextureMap.erase(iter);
326334
break;
@@ -350,3 +358,39 @@ void CClientRenderElementManager::Remove(CClientRenderElement* pElement)
350358
CRenderItem* pRenderItem = pElement->GetRenderItem();
351359
SAFE_RELEASE(pRenderItem);
352360
}
361+
362+
void CClientRenderElementManager::DoPulse()
363+
{
364+
if (m_texturePulseTimer.Get() < TEMPORARY_TEXTURES_CLEANUP_PERIOD)
365+
return;
366+
367+
m_texturePulseTimer.Reset();
368+
369+
const CTickCount now = CTickCount::Now();
370+
371+
std::vector<CClientTexture*> deleteCandidates;
372+
deleteCandidates.reserve(TEMPORARY_TEXTURES_DELETE_THRESHOLD);
373+
374+
for (const auto& [texName, texInfo] : m_AutoTextureMap)
375+
{
376+
const std::int64_t timeElapsedMs = (now - texInfo.lastUse).ToLongLong();
377+
if (timeElapsedMs < TEMPORARY_TEXTURES_CLEANUP_THRESHOLD)
378+
continue;
379+
380+
CTextureItem* textureItem = texInfo.texture->GetTextureItem();
381+
if (textureItem && textureItem->m_iRefCount > 1)
382+
continue;
383+
384+
// CElementDeleter::Delete causes changes in m_AutoTextureMap
385+
// and we cannot delete a texture while iterating over it
386+
deleteCandidates.push_back(texInfo.texture);
387+
388+
// The deletion procedure can be expensive
389+
// and we're interested in capping on the number of deleted texture at once
390+
if (deleteCandidates.size() == TEMPORARY_TEXTURES_DELETE_THRESHOLD)
391+
break;
392+
}
393+
394+
for (CClientTexture* texture : deleteCandidates)
395+
g_pClientGame->GetElementDeleter()->Delete(texture);
396+
}

Client/mods/deathmatch/logic/CClientRenderElementManager.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ class CClientRenderElementManager
3939
CClientTexture* FindAutoTexture(const SString& strFullFilePath, const SString& strUniqueName);
4040
void Remove(CClientRenderElement* pElement);
4141

42+
void DoPulse();
43+
4244
uint GetDxFontCount() { return m_uiStatsDxFontCount; }
4345
uint GetGuiFontCount() { return m_uiStatsGuiFontCount; }
4446
uint GetTextureCount() { return m_uiStatsTextureCount; }
@@ -49,9 +51,16 @@ class CClientRenderElementManager
4951
uint GetVectorGraphicCount() { return m_uiStatsVectorGraphicCount; }
5052

5153
protected:
54+
struct SAutoTexture
55+
{
56+
CClientTexture* texture{};
57+
CTickCount lastUse;
58+
};
59+
60+
CElapsedTime m_texturePulseTimer;
5261
CClientManager* m_pClientManager;
5362
CRenderItemManagerInterface* m_pRenderItemManager;
54-
std::map<SString, CClientTexture*> m_AutoTextureMap;
63+
std::map<SString, SAutoTexture> m_AutoTextureMap;
5564
std::map<CRenderItem*, CClientRenderElement*> m_ItemElementMap;
5665
uint m_uiStatsGuiFontCount;
5766
uint m_uiStatsDxFontCount;

0 commit comments

Comments
 (0)