Skip to content

Commit

Permalink
Temporary textures cleanup (#3978)
Browse files Browse the repository at this point in the history
Fix issue #3977
  • Loading branch information
tederis authored Jan 28, 2025
1 parent 583e675 commit f91e1de
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 7 deletions.
1 change: 1 addition & 0 deletions Client/mods/deathmatch/logic/CClientManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ void CClientManager::DoPulse(bool bDoStandardPulses, bool bDoVehicleManagerPulse
m_pColManager->DoPulse();
m_pGUIManager->DoPulse();
m_pWeaponManager->DoPulse();
m_pRenderElementManager->DoPulse();
}
else
{
Expand Down
56 changes: 50 additions & 6 deletions Client/mods/deathmatch/logic/CClientRenderElementManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
#include "StdInc.h"
#include "CClientVectorGraphic.h"

constexpr std::int64_t TEMPORARY_TEXTURES_CLEANUP_PERIOD = 5000ll;
constexpr std::int64_t TEMPORARY_TEXTURES_CLEANUP_THRESHOLD = 10000ll;
constexpr std::size_t TEMPORARY_TEXTURES_DELETE_THRESHOLD = 10u;

////////////////////////////////////////////////////////////////
//
// CClientRenderElementManager::CClientRenderElementManager
Expand Down Expand Up @@ -283,20 +287,24 @@ CClientVectorGraphic* CClientRenderElementManager::CreateVectorGraphic(uint widt
CClientTexture* CClientRenderElementManager::FindAutoTexture(const SString& strFullFilePath, const SString& strUniqueName)
{
// Check if we've already done this file
CClientTexture** ppTextureElement = MapFind(m_AutoTextureMap, strUniqueName);
SAutoTexture* ppTextureElement = MapFind(m_AutoTextureMap, strUniqueName);
if (!ppTextureElement)
{
// Try to create
CClientTexture* pNewTextureElement = CreateTexture(strFullFilePath);
if (!pNewTextureElement)
return NULL;
return nullptr;

pNewTextureElement->MakeSystemEntity();

// Add to automap if created
MapSet(m_AutoTextureMap, strUniqueName, pNewTextureElement);
MapSet(m_AutoTextureMap, strUniqueName, SAutoTexture{pNewTextureElement});
ppTextureElement = MapFind(m_AutoTextureMap, strUniqueName);
}

return *ppTextureElement;
ppTextureElement->lastUse = CTickCount::Now();

return ppTextureElement->texture;
}

////////////////////////////////////////////////////////////////
Expand All @@ -318,9 +326,9 @@ void CClientRenderElementManager::Remove(CClientRenderElement* pElement)
// Remove from auto texture map
if (pElement->IsA(CClientTexture::GetClassId()))
{
for (std::map<SString, CClientTexture*>::iterator iter = m_AutoTextureMap.begin(); iter != m_AutoTextureMap.end(); ++iter)
for (auto iter = m_AutoTextureMap.begin(); iter != m_AutoTextureMap.end(); ++iter)
{
if (iter->second == pElement)
if (iter->second.texture == pElement)
{
m_AutoTextureMap.erase(iter);
break;
Expand Down Expand Up @@ -350,3 +358,39 @@ void CClientRenderElementManager::Remove(CClientRenderElement* pElement)
CRenderItem* pRenderItem = pElement->GetRenderItem();
SAFE_RELEASE(pRenderItem);
}

void CClientRenderElementManager::DoPulse()
{
if (m_texturePulseTimer.Get() < TEMPORARY_TEXTURES_CLEANUP_PERIOD)
return;

m_texturePulseTimer.Reset();

const CTickCount now = CTickCount::Now();

std::vector<CClientTexture*> deleteCandidates;
deleteCandidates.reserve(TEMPORARY_TEXTURES_DELETE_THRESHOLD);

for (const auto& [texName, texInfo] : m_AutoTextureMap)
{
const std::int64_t timeElapsedMs = (now - texInfo.lastUse).ToLongLong();
if (timeElapsedMs < TEMPORARY_TEXTURES_CLEANUP_THRESHOLD)
continue;

CTextureItem* textureItem = texInfo.texture->GetTextureItem();
if (textureItem && textureItem->m_iRefCount > 1)
continue;

// CElementDeleter::Delete causes changes in m_AutoTextureMap
// and we cannot delete a texture while iterating over it
deleteCandidates.push_back(texInfo.texture);

// The deletion procedure can be expensive
// and we're interested in capping on the number of deleted texture at once
if (deleteCandidates.size() == TEMPORARY_TEXTURES_DELETE_THRESHOLD)
break;
}

for (CClientTexture* texture : deleteCandidates)
g_pClientGame->GetElementDeleter()->Delete(texture);
}
11 changes: 10 additions & 1 deletion Client/mods/deathmatch/logic/CClientRenderElementManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ class CClientRenderElementManager
CClientTexture* FindAutoTexture(const SString& strFullFilePath, const SString& strUniqueName);
void Remove(CClientRenderElement* pElement);

void DoPulse();

uint GetDxFontCount() { return m_uiStatsDxFontCount; }
uint GetGuiFontCount() { return m_uiStatsGuiFontCount; }
uint GetTextureCount() { return m_uiStatsTextureCount; }
Expand All @@ -49,9 +51,16 @@ class CClientRenderElementManager
uint GetVectorGraphicCount() { return m_uiStatsVectorGraphicCount; }

protected:
struct SAutoTexture
{
CClientTexture* texture{};
CTickCount lastUse;
};

CElapsedTime m_texturePulseTimer;
CClientManager* m_pClientManager;
CRenderItemManagerInterface* m_pRenderItemManager;
std::map<SString, CClientTexture*> m_AutoTextureMap;
std::map<SString, SAutoTexture> m_AutoTextureMap;
std::map<CRenderItem*, CClientRenderElement*> m_ItemElementMap;
uint m_uiStatsGuiFontCount;
uint m_uiStatsDxFontCount;
Expand Down

0 comments on commit f91e1de

Please sign in to comment.