1
0
mirror of https://github.com/alliedmodders/hl2sdk.git synced 2024-12-23 01:59:43 +08:00
hl2sdk/tier1/datamanager.cpp

378 lines
9.2 KiB
C++

//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "basetypes.h"
#include "datamanager.h"
DECLARE_POINTER_HANDLE( memhandle_t );
CDataManagerBase::CDataManagerBase( unsigned int maxSize )
{
m_targetMemorySize = maxSize;
m_memUsed = 0;
m_lruList = m_memoryLists.CreateList();
m_lockList = m_memoryLists.CreateList();
m_freeList = m_memoryLists.CreateList();
m_listsAreFreed = 0;
}
CDataManagerBase::~CDataManagerBase()
{
Assert( m_listsAreFreed );
}
void CDataManagerBase::SetTargetSize( unsigned int targetSize )
{
m_targetMemorySize = targetSize;
}
// Frees everything! The LRU AND the LOCKED items. This is only used to forcibly free the resources,
// not to make space.
void CDataManagerBase::FreeAllLists()
{
int node;
int nextNode;
node = m_memoryLists.Head(m_lruList);
while ( node != m_memoryLists.InvalidIndex() )
{
nextNode = m_memoryLists.Next(node);
m_memoryLists.Unlink( m_lruList, node );
FreeByIndex( node );
node = nextNode;
}
node = m_memoryLists.Head(m_lockList);
while ( node != m_memoryLists.InvalidIndex() )
{
nextNode = m_memoryLists.Next(node);
m_memoryLists.Unlink( m_lockList, node );
m_memoryLists[node].lockCount = 0;
FreeByIndex( node );
node = nextNode;
}
m_listsAreFreed = true;
}
unsigned int CDataManagerBase::FlushAllUnlocked()
{
unsigned nBytesInitial = MemUsed_Inline();
int node = m_memoryLists.Head(m_lruList);
while ( node != m_memoryLists.InvalidIndex() )
{
int next = m_memoryLists.Next(node);
m_memoryLists.Unlink( m_lruList, node );
FreeByIndex( node );
node = next;
}
return ( nBytesInitial - MemUsed_Inline() );
}
unsigned int CDataManagerBase::FlushToTargetSize()
{
unsigned nBytesInitial = MemUsed_Inline();
EnsureCapacity(0);
return ( nBytesInitial - MemUsed_Inline() );
}
unsigned int CDataManagerBase::FlushAll()
{
unsigned result = MemUsed_Inline();
FreeAllLists();
m_listsAreFreed = false;
return result;
}
unsigned int CDataManagerBase::Purge( unsigned int nBytesToPurge )
{
unsigned int nOriginalTargetSize = MemTotal_Inline();
unsigned int nTempTargetSize = MemUsed_Inline() - nBytesToPurge;
if ( nTempTargetSize < 0 )
nTempTargetSize = 0;
SetTargetSize( nTempTargetSize );
unsigned result = FlushToTargetSize();
SetTargetSize( nOriginalTargetSize );
return result;
}
void CDataManagerBase::DestroyResource( memhandle_t handle )
{
unsigned short index = FromHandle( handle );
if ( !m_memoryLists.IsValidIndex(index) )
return;
Assert( m_memoryLists[index].lockCount == 0 );
if ( m_memoryLists[index].lockCount )
BreakLock( handle );
m_memoryLists.Unlink( m_lruList, index );
FreeByIndex( index );
}
void *CDataManagerBase::LockResource( memhandle_t handle )
{
return LockByIndex( FromHandle(handle) );
}
int CDataManagerBase::UnlockResource( memhandle_t handle )
{
return UnlockByIndex( FromHandle(handle) );
}
void *CDataManagerBase::GetResource_NoLockNoLRUTouch( memhandle_t handle )
{
unsigned short memoryIndex = FromHandle(handle);
if ( memoryIndex != m_memoryLists.InvalidIndex() )
{
return m_memoryLists[memoryIndex].pStore;
}
return NULL;
}
void *CDataManagerBase::GetResource_NoLock( memhandle_t handle )
{
unsigned short memoryIndex = FromHandle(handle);
if ( memoryIndex != m_memoryLists.InvalidIndex() )
{
TouchByIndex( memoryIndex );
return m_memoryLists[memoryIndex].pStore;
}
return NULL;
}
void CDataManagerBase::TouchResource( memhandle_t handle )
{
TouchByIndex( FromHandle(handle) );
}
void CDataManagerBase::MarkAsStale( memhandle_t handle )
{
MarkAsStaleByIndex( FromHandle(handle) );
}
int CDataManagerBase::BreakLock( memhandle_t handle )
{
unsigned short memoryIndex = FromHandle(handle);
if ( memoryIndex != m_memoryLists.InvalidIndex() && m_memoryLists[memoryIndex].lockCount )
{
int nBroken = m_memoryLists[memoryIndex].lockCount;
m_memoryLists[memoryIndex].lockCount = 0;
m_memoryLists.Unlink( m_lockList, memoryIndex );
m_memoryLists.LinkToTail( m_lruList, memoryIndex );
return nBroken;
}
return 0;
}
int CDataManagerBase::BreakAllLocks()
{
int nBroken = 0;
int node;
int nextNode;
node = m_memoryLists.Head(m_lockList);
while ( node != m_memoryLists.InvalidIndex() )
{
nBroken++;
nextNode = m_memoryLists.Next(node);
m_memoryLists[node].lockCount = 0;
m_memoryLists.Unlink( m_lockList, node );
m_memoryLists.LinkToTail( m_lruList, node );
node = nextNode;
}
return nBroken;
}
unsigned short CDataManagerBase::CreateHandle()
{
int memoryIndex = m_memoryLists.Head(m_freeList);
if ( memoryIndex != m_memoryLists.InvalidIndex() )
{
m_memoryLists.Unlink( m_freeList, memoryIndex );
m_memoryLists.LinkToTail( m_lruList, memoryIndex );
}
else
{
memoryIndex = m_memoryLists.AddToTail( m_lruList );
}
return memoryIndex;
}
memhandle_t CDataManagerBase::StoreResourceInHandle( unsigned short memoryIndex, void *pStore, unsigned int realSize )
{
resource_lru_element_t &mem = m_memoryLists[memoryIndex];
mem.pStore = pStore;
m_memUsed += realSize;
return ToHandle(memoryIndex);
}
void *CDataManagerBase::LockByIndex( unsigned short memoryIndex )
{
if ( memoryIndex != m_memoryLists.InvalidIndex() )
{
if ( m_memoryLists[memoryIndex].lockCount == 0 )
{
m_memoryLists.Unlink( m_lruList, memoryIndex );
m_memoryLists.LinkToTail( m_lockList, memoryIndex );
}
Assert(m_memoryLists[memoryIndex].lockCount != (unsigned short)-1);
m_memoryLists[memoryIndex].lockCount++;
return m_memoryLists[memoryIndex].pStore;
}
return NULL;
}
void CDataManagerBase::TouchByIndex( unsigned short memoryIndex )
{
if ( memoryIndex != m_memoryLists.InvalidIndex() )
{
if ( m_memoryLists[memoryIndex].lockCount == 0 )
{
m_memoryLists.Unlink( m_lruList, memoryIndex );
m_memoryLists.LinkToTail( m_lruList, memoryIndex );
}
}
}
void CDataManagerBase::MarkAsStaleByIndex( unsigned short memoryIndex )
{
if ( memoryIndex != m_memoryLists.InvalidIndex() )
{
if ( m_memoryLists[memoryIndex].lockCount == 0 )
{
m_memoryLists.Unlink( m_lruList, memoryIndex );
m_memoryLists.LinkToHead( m_lruList, memoryIndex );
}
}
}
memhandle_t CDataManagerBase::ToHandle( unsigned short index )
{
unsigned int hiword = m_memoryLists.Element(index).serial;
hiword <<= 16;
index++;
return (memhandle_t)( hiword|index );
}
unsigned int CDataManagerBase::TargetSize()
{
return MemTotal_Inline();
}
unsigned int CDataManagerBase::AvailableSize()
{
return MemAvailable_Inline();
}
unsigned int CDataManagerBase::UsedSize()
{
return MemUsed_Inline();
}
bool CDataManagerBase::FreeLRU()
{
int lruIndex = m_memoryLists.Head( m_lruList );
if ( lruIndex == m_memoryLists.InvalidIndex() )
return false;
m_memoryLists.Unlink( m_lruList, lruIndex );
FreeByIndex( lruIndex );
return true;
}
// free resources until there is enough space to hold "size"
unsigned int CDataManagerBase::EnsureCapacity( unsigned int size )
{
unsigned nBytesInitial = MemUsed_Inline();
while ( MemUsed_Inline() > MemTotal_Inline() || MemAvailable_Inline() < size )
{
if ( !FreeLRU() )
break;
}
return ( MemUsed_Inline() - nBytesInitial );
}
// unlock this resource, moving out of the locked list if ref count is zero
int CDataManagerBase::UnlockByIndex( unsigned short memoryIndex )
{
if ( memoryIndex != m_memoryLists.InvalidIndex() )
{
Assert( m_memoryLists[memoryIndex].lockCount > 0 );
if ( m_memoryLists[memoryIndex].lockCount > 0 )
{
m_memoryLists[memoryIndex].lockCount--;
if ( m_memoryLists[memoryIndex].lockCount == 0 )
{
m_memoryLists.Unlink( m_lockList, memoryIndex );
m_memoryLists.LinkToTail( m_lruList, memoryIndex );
}
}
return m_memoryLists[memoryIndex].lockCount;
}
return 0;
}
// free this resource and move the handle to the free list
void CDataManagerBase::FreeByIndex( unsigned short memoryIndex )
{
if ( memoryIndex != m_memoryLists.InvalidIndex() )
{
Assert( m_memoryLists[memoryIndex].lockCount == 0 );
resource_lru_element_t &mem = m_memoryLists[memoryIndex];
unsigned size = GetRealSize( mem.pStore );
if ( size > m_memUsed )
{
ExecuteOnce( Warning( "Data manager 'used' memory incorrect\n" ) );
size = m_memUsed;
}
m_memUsed -= size;
this->DestroyResourceStorage( mem.pStore );
mem.pStore = NULL;
mem.serial++;
m_memoryLists.LinkToTail( m_freeList, memoryIndex );
}
}
// get a list of everything in the LRU
void CDataManagerBase::GetLRUHandleList( CUtlVector< memhandle_t >& list )
{
for ( int node = m_memoryLists.Tail(m_lruList);
node != m_memoryLists.InvalidIndex();
node = m_memoryLists.Previous(node) )
{
list.AddToTail( ToHandle( node ) );
}
}
// get a list of everything locked
void CDataManagerBase::GetLockHandleList( CUtlVector< memhandle_t >& list )
{
for ( int node = m_memoryLists.Head(m_lockList);
node != m_memoryLists.InvalidIndex();
node = m_memoryLists.Next(node) )
{
list.AddToTail( ToHandle( node ) );
}
}