|
|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
|
|
//
|
|
|
|
// Purpose:
|
|
|
|
//
|
|
|
|
// ZONE MEMORY ALLOCATION
|
|
|
|
//
|
|
|
|
// There is never any space between memblocks, and there will never be two
|
|
|
|
// contiguous free memblocks.
|
|
|
|
//
|
|
|
|
// The rover can be left pointing at a non-empty block
|
|
|
|
//
|
|
|
|
// The zone calls are pretty much only used for small strings and structures,
|
|
|
|
// all big things are allocated on the hunk.
|
|
|
|
//=============================================================================//
|
|
|
|
|
|
|
|
#include "basetypes.h"
|
|
|
|
#include "zone.h"
|
|
|
|
#include "host.h"
|
|
|
|
#include "tier1/strtools.h"
|
|
|
|
#include "tier0/icommandline.h"
|
|
|
|
#include "memstack.h"
|
|
|
|
#include "datacache/idatacache.h"
|
|
|
|
#include "sys_dll.h"
|
|
|
|
#include "tier0/memalloc.h"
|
|
|
|
|
|
|
|
#define MINIMUM_WIN_MEMORY 0x03000000 // FIXME: copy from sys_dll.cpp, find a common header at some point
|
|
|
|
|
|
|
|
#ifdef _X360
|
|
|
|
#define HUNK_USE_16MB_PAGE
|
|
|
|
#endif
|
|
|
|
|
|
|
|
CMemoryStack g_HunkMemoryStack;
|
|
|
|
#ifdef HUNK_USE_16MB_PAGE
|
|
|
|
CMemoryStack g_HunkOverflow;
|
|
|
|
static bool g_bWarnedOverflow;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int GetTargetCacheSize()
|
|
|
|
{
|
|
|
|
int nMemLimit = host_parms.memsize - Hunk_Size();
|
|
|
|
if ( nMemLimit < 0x100000 )
|
|
|
|
{
|
|
|
|
nMemLimit = 0x100000;
|
|
|
|
}
|
|
|
|
return nMemLimit;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
===================
|
|
|
|
Hunk_AllocName
|
|
|
|
===================
|
|
|
|
*/
|
|
|
|
void *Hunk_AllocName (int size, const char *name, bool bClear)
|
|
|
|
{
|
|
|
|
MEM_ALLOC_CREDIT();
|
|
|
|
void * p = g_HunkMemoryStack.Alloc( size, bClear );
|
|
|
|
if ( p )
|
|
|
|
return p;
|
|
|
|
#ifdef HUNK_USE_16MB_PAGE
|
|
|
|
if ( !g_bWarnedOverflow )
|
|
|
|
{
|
|
|
|
g_bWarnedOverflow = true;
|
|
|
|
DevMsg( "Note: Hunk base page exhausted\n" );
|
|
|
|
}
|
|
|
|
|
|
|
|
p = g_HunkOverflow.Alloc( size, bClear );
|
|
|
|
if ( p )
|
|
|
|
return p;
|
|
|
|
#endif
|
|
|
|
Error( "Engine hunk overflow!\n" );
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
===================
|
|
|
|
Hunk_Alloc
|
|
|
|
===================
|
|
|
|
*/
|
|
|
|
void *Hunk_Alloc(int size, bool bClear )
|
|
|
|
{
|
|
|
|
MEM_ALLOC_CREDIT();
|
|
|
|
return Hunk_AllocName( size, NULL, bClear );
|
|
|
|
}
|
|
|
|
|
|
|
|
int Hunk_LowMark(void)
|
|
|
|
{
|
|
|
|
return (int)( g_HunkMemoryStack.GetCurrentAllocPoint() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Hunk_FreeToLowMark(int mark)
|
|
|
|
{
|
|
|
|
Assert( mark < g_HunkMemoryStack.GetSize() );
|
|
|
|
#ifdef HUNK_USE_16MB_PAGE
|
|
|
|
g_HunkOverflow.FreeAll();
|
|
|
|
g_bWarnedOverflow = false;
|
|
|
|
#endif
|
|
|
|
g_HunkMemoryStack.FreeToAllocPoint( mark );
|
|
|
|
}
|
|
|
|
|
|
|
|
int Hunk_MallocSize()
|
|
|
|
{
|
|
|
|
#ifdef HUNK_USE_16MB_PAGE
|
|
|
|
return g_HunkMemoryStack.GetSize() + g_HunkOverflow.GetSize();
|
|
|
|
#else
|
|
|
|
return g_HunkMemoryStack.GetSize();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
int Hunk_Size()
|
|
|
|
{
|
|
|
|
#ifdef HUNK_USE_16MB_PAGE
|
|
|
|
return g_HunkMemoryStack.GetUsed() + g_HunkOverflow.GetUsed();
|
|
|
|
#else
|
|
|
|
return g_HunkMemoryStack.GetUsed();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void Hunk_Print()
|
|
|
|
{
|
|
|
|
#ifdef HUNK_USE_16MB_PAGE
|
|
|
|
Msg( "Total used memory: %d (%d/%d)\n", Hunk_Size(), g_HunkMemoryStack.GetUsed(), g_HunkOverflow.GetUsed() );
|
|
|
|
Msg( "Total committed memory: %d (%d/%d)\n", Hunk_MallocSize(), g_HunkMemoryStack.GetSize(), g_HunkOverflow.GetSize() );
|
|
|
|
#else
|
|
|
|
Msg( "Total used memory: %d\n", Hunk_Size() );
|
|
|
|
Msg( "Total committed memory: %d\n", Hunk_MallocSize() );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose:
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void Memory_Init( void )
|
|
|
|
{
|
|
|
|
MEM_ALLOC_CREDIT();
|
|
|
|
|
|
|
|
#ifdef PLATFORM_64BITS
|
|
|
|
// Seems to need to be larger to not get exhausted on
|
|
|
|
// 64-bit. Perhaps because of larger pointer sizes.
|
|
|
|
int nMaxBytes = 128*1024*1024;
|
|
|
|
#else
|
|
|
|
int nMaxBytes = 48*1024*1024;
|
|
|
|
#endif
|
|
|
|
const int nMinCommitBytes = 0x8000;
|
|
|
|
#ifndef HUNK_USE_16MB_PAGE
|
|
|
|
const int nInitialCommit = 0x280000;
|
|
|
|
while ( !g_HunkMemoryStack.Init( nMaxBytes, nMinCommitBytes, nInitialCommit ) )
|
|
|
|
{
|
|
|
|
Warning( "Unable to allocate %d MB of memory, trying %d MB instead\n", nMaxBytes, nMaxBytes/2 );
|
|
|
|
nMaxBytes /= 2;
|
|
|
|
if ( nMaxBytes < MINIMUM_WIN_MEMORY )
|
|
|
|
{
|
|
|
|
Error( "Failed to allocate minimum memory requirement for game (%d MB)\n", MINIMUM_WIN_MEMORY/(1024*1024));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if ( !g_HunkMemoryStack.InitPhysical( 16*1024*1024 ) || !g_HunkOverflow.Init( nMaxBytes - 16*1024*1024, nMinCommitBytes ) )
|
|
|
|
{
|
|
|
|
Error( "Failed to allocate minimum memory requirement for game (%d MB)\n", nMaxBytes );
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
g_pDataCache->SetSize( GetTargetCacheSize() );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose:
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void Memory_Shutdown( void )
|
|
|
|
{
|
|
|
|
g_HunkMemoryStack.FreeAll();
|
|
|
|
|
|
|
|
// This disconnects the engine data cache
|
|
|
|
g_pDataCache->SetSize( 0 );
|
|
|
|
}
|