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
283287CClientTexture* 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+ }
0 commit comments