2084 lines
62 KiB
C++
2084 lines
62 KiB
C++
//==============================================================================
|
|
// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
|
|
//
|
|
// File: memory.cpp
|
|
//
|
|
// Description:
|
|
//
|
|
// History: 3/20/2002 + Created -- Darwin Chau
|
|
//
|
|
//==============================================================================
|
|
|
|
//========================================
|
|
// System Includes
|
|
//========================================
|
|
#ifdef RAD_PS2
|
|
#include <malloc.h>
|
|
#endif
|
|
|
|
// Foundation Tech
|
|
#include <radmath/util.hpp>
|
|
#include <radmemory.hpp>
|
|
#include <radmemorymonitor.hpp>
|
|
#include <radthread.hpp>
|
|
#include <raddebug.hpp>
|
|
#include <radtextdisplay.hpp>
|
|
#include <radsound_hal.hpp>
|
|
#include <p3d/utility.hpp>
|
|
|
|
#include <string.h>
|
|
|
|
//========================================
|
|
// Project Includes
|
|
//========================================
|
|
#include <main/game.h>
|
|
#include <memory/createheap.h>
|
|
#include <memory/srrmemory.h>
|
|
#include <memory/memoryutilities.h>
|
|
|
|
#include <cheats/cheatinputsystem.h>
|
|
|
|
#include <mission/gameplaymanager.h>
|
|
|
|
#ifdef RAD_PS2
|
|
#include <pddi/pddiext.hpp>
|
|
#include <main/ps2platform.h>
|
|
#define INIT_MEM() Memory::InitializeMemoryUtilities();PS2Platform::InitializeMemory();
|
|
#endif // RAD_PS2
|
|
|
|
#ifdef RAD_XBOX
|
|
#include <main/xboxplatform.h>
|
|
#define INIT_MEM() Memory::InitializeMemoryUtilities();XboxPlatform::InitializeMemory();radMemoryInitialize();
|
|
void MemoryHackCallback() { INIT_MEM() };
|
|
#endif // RAD_XBOX
|
|
|
|
#ifdef RAD_GAMECUBE
|
|
#include <main/gcplatform.h>
|
|
#include <dolphin.h>
|
|
#define INIT_MEM() Memory::InitializeMemoryUtilities();GCPlatform::InitializeMemory();
|
|
extern IRadMemoryHeap *vmmHeap;
|
|
void MemoryHackCallback() { INIT_MEM() };
|
|
#endif // RAD_GAMECUBE
|
|
|
|
#ifdef RAD_PS2
|
|
void MemoryHackCallback() { INIT_MEM() };
|
|
#endif
|
|
|
|
#ifdef RAD_WIN32
|
|
#include <main/win32platform.h>
|
|
#define INIT_MEM() Memory::InitializeMemoryUtilities();Win32Platform::InitializeMemory();
|
|
#define SHUTDOWN_MEM() Win32Platform::ShutdownMemory();
|
|
#endif // RAD_WIN32
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Global Data, Local Data, Local Classes
|
|
//
|
|
//******************************************************************************
|
|
bool g_LockedPersistentHeap = false;
|
|
bool g_HeapManagerCreated = false;
|
|
//
|
|
// Has the memory system been intialized via FTech?
|
|
//
|
|
bool gMemorySystemInitialized = false;
|
|
|
|
//
|
|
// Temporarily disable allocation routing (to avoid infinite loops)
|
|
//
|
|
bool g_NoHeapRoute = false;
|
|
|
|
const char* HeapNames[] =
|
|
{
|
|
"Default Heap",
|
|
"Temp Heap",
|
|
"GameCube Virtual Memory Heap",
|
|
"Persistent Heap",
|
|
"Level Heap",
|
|
"Movie Heap",
|
|
"Frontend Heap",
|
|
"Zone and Rail Heap",
|
|
"Level Other Heap",
|
|
"HUD Heap",
|
|
"Mission Heap",
|
|
"Audio Heap",
|
|
"Debug Heap",
|
|
"Special Heap",
|
|
"Music Heap",
|
|
"Audio Persistent",
|
|
"Small Alloc Heap",
|
|
#ifdef RAD_XBOX
|
|
"Xbox Sound Heap",
|
|
#endif
|
|
#ifdef USE_CHAR_GAG_HEAP
|
|
"Character and Gag Heap",
|
|
#endif
|
|
"Anywhere in Level",
|
|
"Anywhere in FE",
|
|
"Either Other or Zone",
|
|
"Allocator Search"
|
|
};
|
|
|
|
|
|
#ifndef RAD_RELEASE
|
|
//
|
|
// For overriding all allocation routing and sending everything to the special heap
|
|
//
|
|
bool HeapManager::s_bSpecialRoute = false;
|
|
#endif
|
|
|
|
inline void* AllocateThis( GameMemoryAllocator allocator, size_t size )
|
|
{
|
|
void* pMemory = NULL;
|
|
#ifdef CORRAL_SMALL_ALLOCS
|
|
if( size < 201 )
|
|
{
|
|
if( allocator != GMA_AUDIO_PERSISTENT && allocator != GMA_PERSISTENT && allocator != GMA_TEMP)
|
|
{
|
|
pMemory = radMemoryAlloc( GMA_SMALL_ALLOC, size );
|
|
}
|
|
else
|
|
{
|
|
pMemory = radMemoryAlloc( allocator, size );
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
if ( allocator >= GMA_ANYWHERE_IN_LEVEL && allocator != ALLOCATOR_SEARCH )
|
|
{
|
|
pMemory = FindFreeMemory( allocator, size );
|
|
}
|
|
else
|
|
{
|
|
//pMemory = radMemoryAlloc( ::radMemoryGetCurrentAllocator (), size );
|
|
pMemory = radMemoryAlloc( allocator, size );
|
|
}
|
|
}
|
|
|
|
return pMemory;
|
|
}
|
|
|
|
//==============================================================================
|
|
// new
|
|
//==============================================================================
|
|
//
|
|
// Description: regular new
|
|
//
|
|
// Parameters: size - size of memory we're allocating
|
|
//
|
|
// Return:
|
|
//
|
|
//==============================================================================
|
|
void* operator new( size_t size )
|
|
#ifdef RAD_PS2
|
|
#ifndef RAD_MW
|
|
throw( std::bad_alloc )
|
|
#endif
|
|
#endif
|
|
{
|
|
if( gMemorySystemInitialized == false )
|
|
{
|
|
INIT_MEM();
|
|
}
|
|
|
|
void* pMemory;
|
|
|
|
if (g_NoHeapRoute)
|
|
{
|
|
pMemory = radMemoryAlloc( 0, size );
|
|
}
|
|
else
|
|
{
|
|
GameMemoryAllocator curr = HeapMgr()->GetCurrentHeap();
|
|
pMemory = AllocateThis( curr, size );
|
|
|
|
#ifdef MEMORYTRACKER_ENABLED
|
|
::radMemoryMonitorIdentifyAllocation (pMemory, HeapMgr()->GetCurrentGroupID ());
|
|
#endif
|
|
}
|
|
|
|
|
|
//MEMTRACK_ALLOC( pMemory, size, 0 );
|
|
|
|
return( pMemory );
|
|
}
|
|
|
|
|
|
//==============================================================================
|
|
// delete
|
|
//==============================================================================
|
|
//
|
|
// Description: regular delete
|
|
//
|
|
// Parameters: pMemory - pointer to the memory we're deleting
|
|
//
|
|
// Return:
|
|
//
|
|
//==============================================================================
|
|
void operator delete( void* pMemory )
|
|
#ifdef RAD_PS2
|
|
#ifndef RAD_MW
|
|
throw()
|
|
#endif
|
|
#endif
|
|
{
|
|
radMemoryFree( pMemory );
|
|
}
|
|
|
|
|
|
//==============================================================================
|
|
//
|
|
//==============================================================================
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Return:
|
|
//
|
|
//==============================================================================
|
|
void* operator new[]( size_t size )
|
|
#ifdef RAD_PS2
|
|
#ifndef RAD_MW
|
|
throw( std::bad_alloc )
|
|
#endif
|
|
#endif
|
|
{
|
|
if( gMemorySystemInitialized == false )
|
|
{
|
|
INIT_MEM();
|
|
}
|
|
|
|
void* pMemory;
|
|
|
|
if (g_NoHeapRoute)
|
|
{
|
|
pMemory = radMemoryAlloc( 0, size );
|
|
}
|
|
else
|
|
{
|
|
GameMemoryAllocator curr = HeapMgr()->GetCurrentHeap();
|
|
pMemory = AllocateThis( curr, size );
|
|
|
|
#ifdef MEMORYTRACKER_ENABLED
|
|
::radMemoryMonitorIdentifyAllocation (pMemory, HeapMgr()->GetCurrentGroupID ());
|
|
#endif
|
|
}
|
|
|
|
//MEMTRACK_ALLOC( pMemory, size, ALLOC_ARRAY );
|
|
|
|
return( pMemory );
|
|
}
|
|
|
|
|
|
//==============================================================================
|
|
//
|
|
//==============================================================================
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Return:
|
|
//
|
|
//==============================================================================
|
|
void operator delete[]( void* pMemory )
|
|
#ifdef RAD_PS2
|
|
#ifndef RAD_MW
|
|
throw()
|
|
#endif
|
|
#endif
|
|
{
|
|
radMemoryFree( pMemory );
|
|
}
|
|
|
|
|
|
//==============================================================================
|
|
//
|
|
//==============================================================================
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Return:
|
|
//
|
|
//==============================================================================
|
|
void* operator new( size_t size, GameMemoryAllocator allocator )
|
|
{
|
|
if( gMemorySystemInitialized == false )
|
|
{
|
|
INIT_MEM();
|
|
}
|
|
|
|
#ifndef RAD_RELEASE
|
|
if (HeapManager::s_bSpecialRoute)
|
|
{
|
|
allocator = GMA_SPECIAL;
|
|
}
|
|
#endif
|
|
|
|
void* pMemory = AllocateThis( allocator, size );
|
|
|
|
if (!g_NoHeapRoute)
|
|
{
|
|
#ifdef MEMORYTRACKER_ENABLED
|
|
::radMemoryMonitorIdentifyAllocation (pMemory, HeapMgr()->GetCurrentGroupID ());
|
|
#endif
|
|
}
|
|
|
|
//MEMTRACK_ALLOC( pMemory, size, 0 );
|
|
|
|
return( pMemory );
|
|
}
|
|
|
|
|
|
//==============================================================================
|
|
//
|
|
//==============================================================================
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Return:
|
|
//
|
|
//==============================================================================
|
|
void operator delete( void* pMemory, GameMemoryAllocator allocator )
|
|
{
|
|
radMemoryFree( pMemory );
|
|
}
|
|
|
|
|
|
//==============================================================================
|
|
//
|
|
//==============================================================================
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Return:
|
|
//
|
|
//==============================================================================
|
|
void* operator new[]( size_t size, GameMemoryAllocator allocator )
|
|
{
|
|
if( gMemorySystemInitialized == false )
|
|
{
|
|
INIT_MEM();
|
|
}
|
|
|
|
#ifndef RAD_RELEASE
|
|
if (HeapManager::s_bSpecialRoute)
|
|
{
|
|
allocator = GMA_SPECIAL;
|
|
}
|
|
#endif
|
|
|
|
void* pMemory = AllocateThis( allocator, size );
|
|
|
|
if (!g_NoHeapRoute)
|
|
{
|
|
#ifdef MEMORYTRACKER_ENABLED
|
|
::radMemoryMonitorIdentifyAllocation (pMemory, HeapMgr()->GetCurrentGroupID ());
|
|
#endif
|
|
}
|
|
|
|
//MEMTRACK_ALLOC( pMemory, size, ALLOC_ARRAY );
|
|
|
|
return( pMemory );
|
|
}
|
|
|
|
|
|
//==============================================================================
|
|
//
|
|
//==============================================================================
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Return:
|
|
//
|
|
//==============================================================================
|
|
void operator delete[]( void* pMemory, GameMemoryAllocator allocator )
|
|
{
|
|
radMemoryFree( pMemory );
|
|
}
|
|
|
|
static GameMemoryAllocator AVAILABLE_FOR_RENT_IN_LEVEL[] =
|
|
{
|
|
GMA_TEMP,
|
|
GMA_LEVEL_ZONE, // 7 6 6
|
|
GMA_LEVEL_OTHER, // 8 7 7
|
|
GMA_LEVEL_MISSION, // 10 9 9
|
|
GMA_LEVEL_HUD // 9 8 8
|
|
};
|
|
static GameMemoryAllocator AVAILABLE_FOR_RENT_IN_FE[] =
|
|
{
|
|
GMA_LEVEL_MOVIE, // 5 4 4
|
|
GMA_LEVEL_FE, // 6 5 5
|
|
GMA_LEVEL_AUDIO // 11 10 10
|
|
};
|
|
static GameMemoryAllocator AVAILABLE_IN_OTHER_OR_ZONE[] =
|
|
{
|
|
GMA_LEVEL_OTHER, // 8 7 7
|
|
GMA_LEVEL_ZONE // 7 6 6
|
|
};
|
|
|
|
|
|
void* FindFreeMemory( GameMemoryAllocator allocator, size_t size )
|
|
{
|
|
GameMemoryAllocator* list = NULL;
|
|
unsigned int numAvailable = 0;
|
|
|
|
if ( allocator == GMA_ANYWHERE_IN_LEVEL )
|
|
{
|
|
list = AVAILABLE_FOR_RENT_IN_LEVEL;
|
|
numAvailable = sizeof ( AVAILABLE_FOR_RENT_IN_LEVEL ) / sizeof( GameMemoryAllocator );
|
|
}
|
|
else if ( allocator == GMA_ANYWHERE_IN_FE )
|
|
{
|
|
list = AVAILABLE_FOR_RENT_IN_FE;
|
|
numAvailable = sizeof ( AVAILABLE_FOR_RENT_IN_FE ) / sizeof( GameMemoryAllocator );
|
|
}
|
|
else if ( allocator == GMA_EITHER_OTHER_OR_ZONE )
|
|
{
|
|
list = AVAILABLE_IN_OTHER_OR_ZONE;
|
|
numAvailable = sizeof ( AVAILABLE_IN_OTHER_OR_ZONE ) / sizeof( GameMemoryAllocator );
|
|
}
|
|
else
|
|
{
|
|
rAssert( false );
|
|
}
|
|
|
|
if ( list != NULL )
|
|
{
|
|
::radMemorySetUsableAllocators( (radMemoryAllocator*)list, numAvailable );
|
|
void* memory = radMemoryAlloc( ALLOCATOR_SEARCH, size );
|
|
|
|
return memory;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void SetupAllocatorSearch( GameMemoryAllocator allocator )
|
|
{
|
|
rAssert( allocator >= GMA_ANYWHERE_IN_LEVEL );
|
|
|
|
GameMemoryAllocator* list = NULL;
|
|
unsigned int numAvailable = 0;
|
|
|
|
if ( allocator == GMA_ANYWHERE_IN_LEVEL )
|
|
{
|
|
list = AVAILABLE_FOR_RENT_IN_LEVEL;
|
|
numAvailable = sizeof ( AVAILABLE_FOR_RENT_IN_LEVEL ) / sizeof( GameMemoryAllocator );
|
|
}
|
|
else if ( allocator == GMA_ANYWHERE_IN_FE )
|
|
{
|
|
list = AVAILABLE_FOR_RENT_IN_FE;
|
|
numAvailable = sizeof ( AVAILABLE_FOR_RENT_IN_FE ) / sizeof( GameMemoryAllocator );
|
|
}
|
|
else if ( allocator == GMA_EITHER_OTHER_OR_ZONE )
|
|
{
|
|
list = AVAILABLE_IN_OTHER_OR_ZONE;
|
|
numAvailable = sizeof ( AVAILABLE_IN_OTHER_OR_ZONE ) / sizeof( GameMemoryAllocator );
|
|
}
|
|
else
|
|
{
|
|
rAssert( false );
|
|
}
|
|
|
|
if ( list != NULL )
|
|
{
|
|
radMemorySetUsableAllocators( (radMemoryAllocator*)list, numAvailable );
|
|
}
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Public Member Functions
|
|
//
|
|
//******************************************************************************
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Private Member Functions
|
|
//
|
|
//******************************************************************************
|
|
|
|
//
|
|
// Use FTT's radTextDisplay functionality to slap an out-of-memory
|
|
// message onto the screen before we die
|
|
//
|
|
void PrintOutOfMemoryMessage( void* userData, radMemoryAllocator heap, const unsigned int size )
|
|
{
|
|
#ifndef FINAL
|
|
//
|
|
// Print out memory information to the TTY first
|
|
//
|
|
Memory::PrintMemoryStatsToTty();
|
|
|
|
//Disable this while we're here...
|
|
::radMemorySetOutOfMemoryCallback( NULL, NULL );
|
|
|
|
#ifdef RAD_GAMECUBE
|
|
::radMemoryMonitorSuspend();
|
|
#endif
|
|
|
|
IRadTextDisplay* textDisplay;
|
|
GameMemoryAllocator heapEnum = static_cast<GameMemoryAllocator>(heap);
|
|
|
|
#ifdef RAD_PS2
|
|
//
|
|
// Need to shut down the MFIFO for this to work properly
|
|
//
|
|
((pddiExtPS2Control*)p3d::pddi->GetExtension(PDDI_EXT_PS2_CONTROL))->MFIFOEnable( false );
|
|
rReleasePrintf("MFIFO Disabled.\n");
|
|
#endif
|
|
|
|
//
|
|
// Ironically, the text display object needs to be allocated on a heap,
|
|
// one of which is out of memory. Hopefully we're not out on more
|
|
// than one.
|
|
//
|
|
if( heapEnum == GMA_DEFAULT )
|
|
{
|
|
::radTextDisplayGet( &textDisplay, GMA_TEMP );
|
|
}
|
|
else
|
|
{
|
|
::radTextDisplayGet( &textDisplay, GMA_DEFAULT );
|
|
}
|
|
|
|
IRadMemoryAllocator* heapPtr = GetAllocator( static_cast< GameMemoryAllocator >( heap ) );
|
|
unsigned int totalFree = 0;
|
|
unsigned int largestBlock = 0;
|
|
unsigned int numberOfObjects = 0;
|
|
unsigned int highWaterMark = 0;
|
|
unsigned int lastAllocation = 0;
|
|
if( heapPtr != NULL )
|
|
{
|
|
lastAllocation = size;
|
|
heapPtr->GetStatus( &totalFree, &largestBlock, &numberOfObjects, &highWaterMark );
|
|
largestBlock = Memory::GetLargestFreeBlock( heapPtr );
|
|
}
|
|
char freeMemoryString[256] = "";
|
|
char largestBlockString[256] = "";
|
|
char lastAllocationStr[256] = "";
|
|
sprintf( freeMemoryString, "Free: %d", totalFree );
|
|
sprintf( largestBlockString, "LargestBlock: %d", largestBlock );
|
|
sprintf( lastAllocationStr, "LastAlloc: %d", lastAllocation );
|
|
|
|
int yPos = 10;
|
|
if ( textDisplay )
|
|
{
|
|
//GetHeapMgr()->DumpHeapStats(true)
|
|
textDisplay->SetBackgroundColor( 0 );
|
|
textDisplay->SetTextColor( 0xffffffff );
|
|
textDisplay->Clear();
|
|
textDisplay->TextOutAt( "OUT OF MEMORY", 20, yPos );
|
|
textDisplay->TextOutAt( HeapNames[heapEnum], 20, yPos += 1 );
|
|
textDisplay->TextOutAt( freeMemoryString, 20, yPos += 1 );
|
|
textDisplay->TextOutAt( largestBlockString, 20, yPos += 1 );
|
|
textDisplay->TextOutAt( lastAllocationStr, 20, yPos += 1 );
|
|
|
|
if ( CommandLineOptions::Get( CLO_DEMO_TEST ) ||
|
|
GetCheatInputSystem()->IsCheatEnabled( CHEAT_ID_DEMO_TEST ) )
|
|
{
|
|
char buffy[32];
|
|
sprintf( buffy, "Demo Count: %d", GetGame()->GetDemoCount() );
|
|
textDisplay->TextOutAt( buffy, 20, yPos += 2 );
|
|
|
|
unsigned int time = GetGame()->GetTime();
|
|
unsigned int hours = time / 3600000;
|
|
unsigned int deltaTime = time % 3600000;
|
|
|
|
unsigned int minutes = deltaTime / 60000;
|
|
deltaTime = deltaTime % 60000;
|
|
|
|
unsigned int seconds = deltaTime / 1000;
|
|
deltaTime = deltaTime % 1000;
|
|
sprintf( buffy, "Time: %d:%d:%d.%d", hours, minutes, seconds, deltaTime );
|
|
textDisplay->TextOutAt( buffy, 20, yPos += 2 );
|
|
|
|
if ( GetGameplayManager() )
|
|
{
|
|
sprintf( buffy, "Level %d", GetGameplayManager()->GetCurrentLevelIndex() );
|
|
textDisplay->TextOutAt( buffy, 20, yPos += 2 );
|
|
}
|
|
}
|
|
|
|
textDisplay->SwapBuffers();
|
|
textDisplay->Release();
|
|
}
|
|
|
|
rReleaseBreak();
|
|
|
|
#ifndef RAD_GAMECUBE
|
|
::radMemoryMonitorSuspend();
|
|
#endif
|
|
|
|
//Re-enable now that we're through
|
|
::radMemorySetOutOfMemoryCallback( PrintOutOfMemoryMessage, NULL );
|
|
#endif
|
|
}
|
|
|
|
static int pushNumberStack[ 48 ];
|
|
static int currentStackPointer = 0;
|
|
|
|
HeapStack::HeapStack (GameMemoryAllocator defaultAllocator)
|
|
{
|
|
int i;
|
|
for( i = 0; i < 48; ++i )
|
|
{
|
|
pushNumberStack[ i ] = -1;
|
|
}
|
|
|
|
m_Size = STACKSIZE;
|
|
m_CurPos = 0;
|
|
m_Stack = new(GMA_PERSISTENT) GameMemoryAllocator[m_Size];
|
|
|
|
// Seed this with the default heap
|
|
//
|
|
m_Stack[m_CurPos] = defaultAllocator;
|
|
}
|
|
|
|
|
|
HeapStack::~HeapStack ()
|
|
{
|
|
delete[] m_Stack;
|
|
}
|
|
|
|
void HeapStack::Push (GameMemoryAllocator alloc)
|
|
{
|
|
static int pushNumber = 0;
|
|
rAssert( currentStackPointer < 48 );
|
|
pushNumberStack[ currentStackPointer ] = pushNumber;
|
|
++currentStackPointer;
|
|
++pushNumber;
|
|
m_CurPos++;
|
|
rAssertMsg (m_CurPos < m_Size, "Heap Stack Overflow! Increase size of the Heap Stack. [jdy]");
|
|
m_Stack[m_CurPos] = alloc;
|
|
}
|
|
|
|
void HeapStack::Pop ()
|
|
{
|
|
--currentStackPointer;
|
|
pushNumberStack[ currentStackPointer ] = -1;
|
|
GameMemoryAllocator current = m_Stack[ m_CurPos ];
|
|
m_CurPos--;
|
|
rAssertMsg (m_CurPos >= 0, "Heap Stack Underflow! Calls to Push and Pop on heap stack are mismatched. [jdy]");
|
|
}
|
|
|
|
void HeapStack::Pop( GameMemoryAllocator alloc )
|
|
{
|
|
--currentStackPointer;
|
|
pushNumberStack[ currentStackPointer ] = -1;
|
|
rAssertMsg( m_Stack[ m_CurPos ] == alloc, "HeapStack - Detected mismatch in push/pop calls - fix, or tell Ian Gipson immediately" );
|
|
m_CurPos--;
|
|
rAssertMsg (m_CurPos >= 0, "Heap Stack Underflow! Calls to Push and Pop on heap stack are mismatched. [jdy]");
|
|
}
|
|
|
|
|
|
void HeapStack::SetTop (GameMemoryAllocator alloc)
|
|
{
|
|
m_Stack[m_CurPos] = alloc;
|
|
}
|
|
|
|
|
|
GameMemoryAllocator HeapStack::Top () const
|
|
{
|
|
return m_Stack[m_CurPos];
|
|
}
|
|
|
|
|
|
HeapActivityTracker::HeapActivityTracker ()
|
|
{
|
|
for (int i = 0; i < NUM_GAME_MEMORY_ALLOCATORS; i++)
|
|
{
|
|
m_AllocsEnabled[i] = true;
|
|
m_FreesEnabled[i] = true;
|
|
}
|
|
}
|
|
|
|
|
|
void HeapActivityTracker::MemoryAllocated (radMemoryAllocator allocator, void* address, unsigned int size)
|
|
{
|
|
if (CommandLineOptions::Get( CLO_NO_HEAPS ))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// If you assert here, you are trying to allocate on a heap that does not allow it
|
|
//
|
|
rTuneAssert (m_AllocsEnabled[allocator]);
|
|
|
|
/*
|
|
if (HeapManager::s_pIRadMemoryHeapTemp)
|
|
{
|
|
unsigned int size;
|
|
size = HeapManager::s_pIRadMemoryHeapTemp->GetSize();
|
|
unsigned int totalFree, largestBlock, numObjects, highWater;
|
|
HeapManager::s_pIRadMemoryHeapTemp->GetStatus( &totalFree, &largestBlock, &numObjects, &highWater );
|
|
if (totalFree < size)
|
|
{
|
|
unsigned int used = size - totalFree;
|
|
if (used > 200 * 1024)
|
|
{
|
|
rTunePrintf ("Temp Used: %d\n", used);
|
|
::radMemoryMonitorSuspend ();
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
void HeapActivityTracker::MemoryFreed (radMemoryAllocator allocator, void* address)
|
|
{
|
|
if (CommandLineOptions::Get( CLO_NO_HEAPS ))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// If you assert here, you are trying to free on a heap that does not allow it
|
|
//
|
|
rTuneAssert (m_FreesEnabled[allocator]);
|
|
}
|
|
|
|
HeapActivityTracker g_HeapActivityTracker;
|
|
|
|
|
|
|
|
IRadThreadLocalStorage* HeapManager::s_Instance = 0;
|
|
|
|
#ifdef DEBUGINFO_ENABLED
|
|
HeapManager* HeapManager::s_Instances[MAX_INST];
|
|
int HeapManager::s_NumInstances = 0;
|
|
#endif
|
|
|
|
HeapManager* HeapManager::GetInstance ()
|
|
{
|
|
g_NoHeapRoute = true;
|
|
|
|
// First check to see if the thread local storage object has been created
|
|
//
|
|
if (!s_Instance)
|
|
{
|
|
::radThreadCreateLocalStorage (&s_Instance, GMA_PERSISTENT);
|
|
s_Instance->SetValue (0); // Is there a better way to initialize these values? Perhaps radThread should do this.
|
|
}
|
|
|
|
// Now s_Instance is non-null.
|
|
// Check to see if we have a HeapManager created for this thread yet.
|
|
// If not, create it.
|
|
//
|
|
void* p = s_Instance->GetValue ();
|
|
if (!p)
|
|
{
|
|
GameMemoryAllocator currentHeap = static_cast<GameMemoryAllocator>(::radMemoryGetCurrentAllocator ());
|
|
p = static_cast<void*>(new(GMA_PERSISTENT) HeapManager (currentHeap)); // Create a heap manager. Init the heap stack with the current heap.
|
|
s_Instance->SetValue (p);
|
|
::radMemorySetAllocatorCallback (static_cast<IRadMemorySetAllocatorCallback*>(p));
|
|
|
|
#ifdef DEBUGINFO_ENABLED
|
|
s_Instances[s_NumInstances] = static_cast<HeapManager*>(p);
|
|
s_NumInstances++;
|
|
#endif
|
|
}
|
|
|
|
g_NoHeapRoute = false;
|
|
g_HeapManagerCreated = true;
|
|
return static_cast<HeapManager*>(p);
|
|
}
|
|
|
|
bool HeapManager::IsCreated()
|
|
{
|
|
if( !g_HeapManagerCreated )
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
void* p = s_Instance->GetValue();
|
|
if( p == NULL )
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void HeapManager::DestroyInstance()
|
|
{
|
|
if( s_Instance != NULL )
|
|
{
|
|
void* p = s_Instance->GetValue();
|
|
if( p != NULL )
|
|
{
|
|
::radMemorySetAllocatorCallback( NULL );
|
|
|
|
HeapManager* hm = static_cast<HeapManager*>( p );
|
|
delete( GMA_PERSISTENT, hm );
|
|
|
|
s_Instance->SetValue( NULL );
|
|
}
|
|
|
|
s_Instance->Release();
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
void HeapManager::DumpHeapStacks ()
|
|
{
|
|
for (int i = 0; i < s_NumInstances; i++)
|
|
{
|
|
HeapManager* pHeapMgr = s_Instances[i];
|
|
char s[64];
|
|
if (pHeapMgr == HeapMgr())
|
|
{
|
|
strcpy (s, "Main Thread Heap Stack");
|
|
}
|
|
else
|
|
{
|
|
sprintf (s, "Heap Stack %p", pHeapMgr);
|
|
}
|
|
DEBUGINFO_PUSH_SECTION (s);
|
|
|
|
pHeapMgr->m_HeapStack.Dump ();
|
|
|
|
DEBUGINFO_POP_SECTION ();
|
|
}
|
|
}
|
|
|
|
|
|
void HeapStack::Dump ()
|
|
{
|
|
for (int i = m_CurPos-1; i >= 0; i--)
|
|
{
|
|
char s[64];
|
|
sprintf (s, "%2d: %s", i, HeapNames[m_Stack[i]]);
|
|
DEBUGINFO_ADDSCREENTEXT (s);
|
|
}
|
|
}
|
|
*/
|
|
|
|
#ifdef RAD_GAMECUBE
|
|
IRadMemoryHeap* s_pIRadMemoryHeapVMM = 0;
|
|
#endif
|
|
|
|
HeapManager::HeapManager (GameMemoryAllocator defaultAllocator) :
|
|
m_HeapStack (defaultAllocator)
|
|
#ifndef FINAL
|
|
,mLowestFPS(2000), mHighestTris(0), mFPSLWTris(0), mHWTriFPS(0)
|
|
#endif
|
|
{
|
|
|
|
}
|
|
|
|
|
|
HeapManager::~HeapManager ()
|
|
{
|
|
// Shut down all the heaps.
|
|
for( int i = 0; i < NUM_GAME_MEMORY_ALLOCATORS; i++ )
|
|
{
|
|
DestroyHeapA( static_cast<GameMemoryAllocator>( i ) );
|
|
}
|
|
}
|
|
|
|
|
|
void HeapManager::DestroyHeap (IRadMemoryHeap*& heap, bool justTest)
|
|
{
|
|
if (heap)
|
|
{
|
|
// Check for heap not empty.
|
|
// If it's not empty this is a Bad Thing. We will be leaving dangling pointers to all the contained memory.
|
|
// This either means we have a leak and they will never get deleted or they will get deleted eventually but
|
|
// the heap will no longer exist.
|
|
//
|
|
// If you assert here, DO NOT IGNORE IT. If you need help diagnosing the cause of the assertion, see Joel.
|
|
//
|
|
unsigned int numAllocs;
|
|
heap->GetStatus (0, 0, &numAllocs, 0);
|
|
if (numAllocs > 0)
|
|
{
|
|
#ifndef FINAL
|
|
#ifndef RAD_RELEASE
|
|
char s[64];
|
|
sprintf (s, "%s is being destroyed but is not empty!", HeapNames[GetHeapID (heap)]);
|
|
if ( CommandLineOptions::Get( CLO_MEMORY_MONITOR ) )
|
|
{
|
|
rTunePrintf( s );
|
|
::radMemoryMonitorSuspend ();
|
|
}
|
|
else
|
|
{
|
|
// rAssertMsg (0, s);
|
|
}
|
|
#endif
|
|
#endif // RAD_RELEASE
|
|
}
|
|
|
|
if ( !justTest )
|
|
{
|
|
// Destroy the heap
|
|
//
|
|
::radMemoryUnregisterAllocator (GetHeapID (heap));
|
|
heap->Release ();
|
|
heap = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
GameMemoryAllocator HeapManager::GetHeapID (const IRadMemoryHeap* heap)
|
|
{
|
|
/*
|
|
if (s_pIRadMemoryHeapDefault && (heap == s_pIRadMemoryHeapDefault))
|
|
{
|
|
return GMA_DEFAULT;
|
|
}
|
|
if (s_pIRadMemoryHeapLevelMovie && (heap == s_pIRadMemoryHeapLevelMovie))
|
|
{
|
|
return GMA_LEVEL_MOVIE;
|
|
}
|
|
if (s_pIRadMemoryHeapDebug && (heap == s_pIRadMemoryHeapDebug))
|
|
{
|
|
return GMA_DEBUG;
|
|
}
|
|
#ifdef RAD_GAMECUBE
|
|
if (s_pIRadMemoryHeapVMM && (heap == s_pIRadMemoryHeapVMM))
|
|
{
|
|
#ifdef NO_ARAM
|
|
return GMA_LEVEL_OTHER;
|
|
#else
|
|
return GMA_GC_VMM;
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
rAssert (false);
|
|
*/
|
|
return GMA_DEFAULT;
|
|
}
|
|
|
|
|
|
float HeapManager::GetFudgeFactor ()
|
|
{
|
|
float FUDGE;
|
|
|
|
#ifndef RAD_RELEASE
|
|
if( CommandLineOptions::Get( CLO_FIREWIRE ) )
|
|
{
|
|
FUDGE = 1.0f;
|
|
}
|
|
else
|
|
{
|
|
#if defined( RAD_GAMECUBE ) && defined( RAD_TUNE )
|
|
FUDGE = 1.0f;
|
|
#else
|
|
#ifdef RAD_MW
|
|
FUDGE = 1.5f;
|
|
#else
|
|
FUDGE = 2.0f;
|
|
#endif
|
|
#endif
|
|
}
|
|
#else
|
|
if( CommandLineOptions::Get( CLO_LARGEHEAPS ) )
|
|
{
|
|
FUDGE = 1.5f;
|
|
}
|
|
else
|
|
{
|
|
FUDGE = 1.0f;
|
|
}
|
|
#endif
|
|
|
|
return FUDGE;
|
|
}
|
|
|
|
|
|
void HeapManager::PushHeap (GameMemoryAllocator alloc)
|
|
{
|
|
#ifndef RAD_RELEASE
|
|
static bool init = false;
|
|
if (!init)
|
|
{
|
|
init = true;
|
|
//::radMemorySetActivityCallback (&g_HeapActivityTracker);
|
|
}
|
|
#endif
|
|
|
|
m_HeapStack.Push (alloc);
|
|
}
|
|
|
|
void HeapManager::PopHeap( GameMemoryAllocator alloc )
|
|
{
|
|
m_HeapStack.Pop( alloc );
|
|
}
|
|
|
|
GameMemoryAllocator HeapManager::GetCurrentHeap () const
|
|
{
|
|
#ifndef RAD_RELEASE
|
|
if (s_bSpecialRoute)
|
|
{
|
|
return GMA_SPECIAL;
|
|
}
|
|
#endif
|
|
|
|
return m_HeapStack.Top ();
|
|
}
|
|
|
|
|
|
#ifdef MEMORYTRACKER_ENABLED
|
|
|
|
void HeapManager::PushGroup( const char* name )
|
|
{
|
|
rAssert( strcmp( name, "ScroobyBootup" ) != 0 );
|
|
HeapMgr()->PushHeap (GMA_DEBUG);
|
|
|
|
MemoryIDString str;
|
|
strncpy (str.id, name, MAXSTRING);
|
|
|
|
m_GroupIDStack.push (str);
|
|
|
|
HeapMgr()->PopHeap ( GMA_DEBUG );
|
|
}
|
|
|
|
|
|
void HeapManager::PopGroup ( const char* name )
|
|
{
|
|
HeapMgr()->PushHeap( GMA_DEBUG );
|
|
|
|
rAssert( !m_GroupIDStack.empty () );
|
|
MemoryIDString str = m_GroupIDStack.top();
|
|
int equal = strncmp( name, str.id, MAXSTRING );
|
|
rAssert( equal == 0 );
|
|
m_GroupIDStack.pop();
|
|
|
|
HeapMgr()->PopHeap( GMA_DEBUG );
|
|
}
|
|
|
|
|
|
const char* HeapManager::GetCurrentGroupID () const
|
|
{
|
|
if (m_GroupIDStack.empty ())
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return m_GroupIDStack.top ().id;
|
|
}
|
|
}
|
|
|
|
|
|
void HeapManager::PushFlag (const char* name)
|
|
{
|
|
HeapMgr()->PushHeap (GMA_DEBUG);
|
|
|
|
MemoryIDString str;
|
|
strncpy (str.id, name, MAXSTRING);
|
|
|
|
m_FlagStack.push (str);
|
|
|
|
::radMemoryMonitorIssueFlag (name);
|
|
|
|
HeapMgr()->PopHeap (GMA_DEBUG);
|
|
}
|
|
|
|
|
|
void HeapManager::PopFlag (const char* name)
|
|
{
|
|
HeapMgr()->PushHeap (GMA_DEBUG);
|
|
|
|
assert (!m_FlagStack.empty ());
|
|
MemoryIDString str = m_GroupIDStack.top();
|
|
int equal = strncmp( name, str.id, MAXSTRING );
|
|
//rAssert( equal == 0 );
|
|
m_FlagStack.pop ();
|
|
|
|
if (m_FlagStack.empty ())
|
|
{
|
|
::radMemoryMonitorIssueFlag ("");
|
|
}
|
|
else
|
|
{
|
|
::radMemoryMonitorIssueFlag (m_FlagStack.top ().id);
|
|
}
|
|
|
|
HeapMgr()->PopHeap (GMA_DEBUG);
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
radMemoryAllocator HeapManager::GetCurrentAllocator ()
|
|
{
|
|
return GetCurrentHeap ();
|
|
}
|
|
|
|
|
|
radMemoryAllocator HeapManager::SetCurrentAllocator ( radMemoryAllocator allocator )
|
|
{
|
|
radMemoryAllocator old = GetCurrentHeap ();
|
|
m_HeapStack.SetTop ((GameMemoryAllocator)allocator);
|
|
return old;
|
|
}
|
|
|
|
|
|
void HeapManager::DumpHeapStats ( bool text )
|
|
{
|
|
//#ifndef FINAL
|
|
//#ifndef RAD_GAMECUBE
|
|
struct HeapInfo
|
|
{
|
|
GameMemoryAllocator gma;
|
|
const char* name;
|
|
IRadMemoryHeap** heap;
|
|
unsigned int highwater;
|
|
};
|
|
|
|
#ifdef RAD_GAMECUBE
|
|
if ( vmmHeap && !s_pIRadMemoryHeapVMM )
|
|
{
|
|
//The virtual memory heap.
|
|
rReleaseString ("Creating Heap: VMM\n");
|
|
s_pIRadMemoryHeapVMM = vmmHeap;
|
|
s_pIRadMemoryHeapVMM->AddRef();
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
|
|
HeapInfo info[] =
|
|
{
|
|
{ GMA_DEFAULT, "Default", &s_pIRadMemoryHeapDefault, 0 },
|
|
{ GMA_TEMP, "Temp", &s_pIRadMemoryHeapTemp, 0 },
|
|
{ GMA_PERSISTENT, "Persist", &s_pIRadMemoryHeapPersistent, 0 },
|
|
{ GMA_MUSIC, "Music", &s_pIRadMemoryHeapMusic, 0 },
|
|
{ GMA_AUDIO_PERSISTENT, "Audio Persistent", &s_pIRadMemoryHeapAudioPersistent, 0 },
|
|
{ GMA_LEVEL, "Level", &s_pIRadMemoryHeapLevel, 0 },
|
|
{ GMA_LEVEL_MOVIE, "- Movie", &s_pIRadMemoryHeapLevelMovie, 0 },
|
|
{ GMA_LEVEL_FE, "- FE", &s_pIRadMemoryHeapLevelFE, 0 },
|
|
|
|
{ GMA_LEVEL_ZONE, "- Zone", &s_pIRadMemoryHeapLevelZone, 0 },
|
|
// { GMA_LEVEL_OTHER, "- Other", &s_pIRadMemoryHeapLevelOther, 0 },
|
|
{ GMA_LEVEL_HUD, "- HUD", &s_pIRadMemoryHeapLevelHUD, 0 },
|
|
// { GMA_LEVEL_MISSION, "- Mission", &s_pIRadMemoryHeapLevelMission, 0 },
|
|
|
|
{ GMA_LEVEL_AUDIO, "- Audio", &s_pIRadMemoryHeapLevelAudio, 0 },
|
|
|
|
{ GMA_GC_VMM, "VMM", &s_pIRadMemoryHeapVMM, 0 }
|
|
};
|
|
*/
|
|
|
|
HeapInfo info[] =
|
|
{
|
|
{ GMA_DEFAULT, "Default", GetHeapReference( GMA_DEFAULT ), 0 },
|
|
{ GMA_TEMP, "Temp", GetHeapReference( GMA_TEMP ), 0 },
|
|
{ GMA_PERSISTENT, "Persist", GetHeapReference( GMA_PERSISTENT ), 0 },
|
|
{ GMA_MUSIC, "Music", GetHeapReference( GMA_MUSIC ), 0 },
|
|
{ GMA_AUDIO_PERSISTENT, "Audio Persistent", GetHeapReference( GMA_AUDIO_PERSISTENT ), 0 },
|
|
{ GMA_LEVEL_ZONE, "Zones", GetHeapReference( GMA_LEVEL_ZONE ), 0 },
|
|
{ GMA_SMALL_ALLOC, "Small Alloc", GetHeapReference( GMA_SMALL_ALLOC ), 0 },
|
|
#ifdef USE_CHAR_GAG_HEAP
|
|
{ GMA_CHARS_AND_GAGS, "Chars and Gags", GetHeapReference( GMA_CHARS_AND_GAGS ), 0 },
|
|
#endif
|
|
// { GMA_LEVEL_MISSION, "Mission", &s_pIRadMemoryHeapLevelMission, 0 },
|
|
{ GMA_LEVEL_AUDIO, "Audio", GetHeapReference( GMA_LEVEL_AUDIO ),0 },
|
|
{ GMA_LEVEL_FE, "F/E", GetHeapReference( GMA_LEVEL_FE ), 0 },
|
|
{ GMA_LEVEL_HUD, "HUD", GetHeapReference( GMA_LEVEL_HUD ), 0 }
|
|
// { GMA_LEVEL_OTHER, "Other", &s_pIRadMemoryHeapLevelOther, 0 }
|
|
#ifdef RAD_GAMECUBE
|
|
,{ GMA_GC_VMM, "VMM", &s_pIRadMemoryHeapVMM, 0 }
|
|
#endif
|
|
};
|
|
|
|
if ( text )
|
|
{
|
|
size_t used = Memory::GetTotalMemoryUsed();
|
|
size_t available = Memory::GetTotalMemoryFree();
|
|
size_t unavailable = Memory::GetTotalMemoryUnavailable();
|
|
size_t lowWater = Memory::GetTotalMemoryFreeLowWaterMark();
|
|
size_t freeInAllHeaps = GetTotalMemoryFreeInAllHeaps();
|
|
//size_t allocatable = Memory::GetFreeMemoryProfile();
|
|
size_t allocatable = 0;
|
|
size_t largestBlock = Memory::GetLargestFreeBlock();
|
|
char buffer[ 256 ];
|
|
sprintf( buffer, "Used: %d\n", used );
|
|
rReleaseString( buffer );
|
|
sprintf( buffer, "Free: %d Free in Malloc: %d\n", freeInAllHeaps, available );
|
|
rReleaseString( buffer );
|
|
sprintf( buffer, "Unavailable: %d\n", unavailable );
|
|
rReleaseString( buffer );
|
|
sprintf( buffer, "LargestFragment: %d\n", largestBlock );
|
|
rReleaseString( buffer );
|
|
sprintf( buffer, "Allocatable: %d\n", allocatable );
|
|
rReleaseString( buffer );
|
|
sprintf( buffer, "LowWater: %d\n", lowWater );
|
|
rReleaseString( buffer );
|
|
|
|
|
|
int i;
|
|
int line = 0;
|
|
for( i = 0; i < static_cast<int>(sizeof(info) / sizeof(info[0])); ++i )
|
|
{
|
|
|
|
IRadMemoryHeap* heap = *(info[i].heap);
|
|
if(i==4)
|
|
{
|
|
// rReleasePrintf("\nheap %s size: %d", info[i].name, heap->GetSize() );
|
|
}
|
|
if (heap)
|
|
{
|
|
unsigned int size;
|
|
size = heap->GetSize();
|
|
|
|
unsigned int totalFree, largestBlock, numObjects, highWater;
|
|
heap->GetStatus( &totalFree, &largestBlock, &numObjects, &highWater );
|
|
unsigned int used = size - totalFree;
|
|
|
|
float percentUsed = static_cast<float>( used ) / static_cast<float>( size ) * 100.0f;
|
|
float highWaterPercentUsed = static_cast<float>( highWater ) / static_cast<float>( size ) * 100.0f;
|
|
float usedMB = (float)used / MB;
|
|
float sizeMB = (float)size / MB;
|
|
float hwMB = (float)highWater / MB;
|
|
|
|
char buffy[256];
|
|
sprintf( buffy, "%8s %d/%d [%2.1f%%] HW: %2.2f [%2.1f%%] %d\n", info[i].name, used, size, percentUsed, hwMB, highWaterPercentUsed, numObjects );
|
|
rReleaseString( buffy );
|
|
++line;
|
|
}
|
|
}
|
|
}
|
|
|
|
const pddiColour BLACK( 0, 0, 0 );
|
|
const pddiColour ORANGE(255,127,0);
|
|
const pddiColour WHITE(255,255,255);
|
|
const pddiColour WHITE_50(255,255,255,128);
|
|
const int LEFT = 30;
|
|
const int TOP = 200;
|
|
|
|
if( CommandLineOptions::Get( CLO_HEAP_STATS ) )
|
|
{
|
|
//
|
|
// What does Malloc have left
|
|
//
|
|
|
|
static pddiShader* shader = p3d::device->NewShader( "simple" );
|
|
shader->SetInt(PDDI_SP_SHADEMODE, PDDI_SHADE_FLAT);
|
|
shader->SetInt(PDDI_SP_BLENDMODE, PDDI_BLEND_ALPHA);
|
|
|
|
pddiProjectionMode proj = p3d::pddi->GetProjectionMode();
|
|
p3d::pddi->SetProjectionMode(PDDI_PROJECTION_DEVICE);
|
|
p3d::pddi->PushIdentityMatrix(PDDI_MATRIX_MODELVIEW);
|
|
pddiPrimStream* stream;
|
|
stream = p3d::pddi->BeginPrims(shader, PDDI_PRIM_TRISTRIP, PDDI_V_C, 4 );
|
|
float z = 1.001f;
|
|
float xMin = 0.0f;
|
|
float xMax = 500.0f;
|
|
float yMin = 0.0f + TOP;
|
|
float yMax = 250.0f + TOP;
|
|
stream->Colour(WHITE_50);
|
|
stream->Coord( 0.0f, yMin, z );
|
|
stream->Colour(WHITE_50);
|
|
stream->Coord( xMax, yMin, z );
|
|
stream->Colour(WHITE_50);
|
|
stream->Coord( 0.0f, yMax, z );
|
|
stream->Colour(WHITE_50);
|
|
stream->Coord( xMax, yMax, z );
|
|
p3d::pddi->EndPrims(stream);
|
|
p3d::pddi->PopMatrix(PDDI_MATRIX_MODELVIEW);
|
|
p3d::pddi->SetProjectionMode(proj);
|
|
|
|
size_t used = Memory::GetTotalMemoryUsed();
|
|
size_t available = Memory::GetTotalMemoryFree();
|
|
size_t unavailable = Memory::GetTotalMemoryUnavailable();
|
|
size_t lowWater = Memory::GetTotalMemoryFreeLowWaterMark();
|
|
size_t freeInAllHeaps = GetTotalMemoryFreeInAllHeaps();
|
|
//size_t allocatable = Memory::GetFreeMemoryProfile();
|
|
size_t allocatable = 0;
|
|
size_t largestBlock = Memory::GetLargestFreeBlock();
|
|
char buffer[ 256 ];
|
|
int printLine = TOP - 10;
|
|
sprintf( buffer, "Used: %d", used );
|
|
p3d::pddi->DrawString( buffer, LEFT, printLine += 15 , BLACK );
|
|
sprintf( buffer, "Free: %d Free in Malloc: %d", freeInAllHeaps, available );
|
|
p3d::pddi->DrawString( buffer, LEFT, printLine += 15 , BLACK );
|
|
sprintf( buffer, "Unavailable: %d", unavailable );
|
|
p3d::pddi->DrawString( buffer, LEFT, printLine += 15 , BLACK );
|
|
sprintf( buffer, "LargestFragment: %d", largestBlock );
|
|
p3d::pddi->DrawString( buffer, LEFT, printLine += 15 , BLACK );
|
|
sprintf( buffer, "Allocatable: %d", allocatable );
|
|
p3d::pddi->DrawString( buffer, LEFT, printLine += 15 , BLACK );
|
|
sprintf( buffer, "LowWater: %d", lowWater );
|
|
p3d::pddi->DrawString( buffer, LEFT, printLine += 15 , BLACK );
|
|
|
|
|
|
int i;
|
|
int line = 0;
|
|
for( i = 0; i < static_cast<int>(sizeof(info) / sizeof(info[0])); ++i )
|
|
{
|
|
|
|
IRadMemoryHeap* heap = *(info[i].heap);
|
|
if (heap)
|
|
{
|
|
unsigned int size;
|
|
size = heap->GetSize();
|
|
|
|
unsigned int totalFree, largestBlock, numObjects, highWater;
|
|
heap->GetStatus( &totalFree, &largestBlock, &numObjects, &highWater );
|
|
unsigned int used = size - totalFree;
|
|
|
|
float percentUsed = static_cast<float>( used ) / static_cast<float>( size ) * 100.0f;
|
|
float highWaterPercentUsed = static_cast<float>( highWater ) / static_cast<float>( size ) * 100.0f;
|
|
float usedMB = (float)used / MB;
|
|
float sizeMB = (float)size / MB;
|
|
float hwMB = (float)highWater / MB;
|
|
|
|
char buffy[256];
|
|
sprintf( buffy, "%8s %d/%d [%2.1f%%] HW: %2.2f [%2.1f%%] %d", info[i].name, used, size, percentUsed, hwMB, highWaterPercentUsed, numObjects );
|
|
p3d::pddi->DrawString( buffy,
|
|
LEFT ,
|
|
100 + TOP + (line*20),
|
|
BLACK );
|
|
++line;
|
|
}
|
|
}
|
|
}
|
|
|
|
//#endif // !RAD_GAMECUBE
|
|
|
|
//#endif // !FINAL
|
|
}
|
|
|
|
void HeapManager::ResetArtStats()
|
|
{
|
|
#ifndef FINAL
|
|
mLowestFPS = 2000;
|
|
mHighestTris = 0;
|
|
mFPSLWTris = 0;
|
|
mHWTriFPS = 0;
|
|
#endif
|
|
}
|
|
|
|
void HeapManager::DumpArtStats ()
|
|
{
|
|
#ifndef FINAL
|
|
|
|
struct HeapInfo
|
|
{
|
|
GameMemoryAllocator gma;
|
|
const char* name;
|
|
IRadMemoryHeap** heap;
|
|
unsigned int highwater;
|
|
};
|
|
|
|
static HeapInfo info[] =
|
|
{
|
|
{ GMA_LEVEL_ZONE, "Zones", GetHeapReference( GMA_LEVEL_ZONE ), 0 },
|
|
// { GMA_LEVEL_MISSION, "Mission", &s_pIRadMemoryHeapLevelMission, 0 },
|
|
// { GMA_LEVEL_OTHER, "Other", &s_pIRadMemoryHeapLevelOther, 0 }
|
|
};
|
|
|
|
if( CommandLineOptions::Get( CLO_ART_STATS ) )
|
|
{
|
|
const int LEFT = 35;
|
|
const int TOP = 285;
|
|
const pddiColour BLACK(0,0,0);
|
|
const pddiColour WHITE(128,128,128);
|
|
|
|
int i;
|
|
int count = static_cast<int>(sizeof(info) / sizeof(info[0]));
|
|
for( i = 0; i < count; ++i )
|
|
{
|
|
IRadMemoryHeap* heap = *(info[i].heap);
|
|
if (heap)
|
|
{
|
|
unsigned int size;
|
|
size = heap->GetSize();
|
|
|
|
unsigned int totalFree, largestBlock, numObjects, highWater;
|
|
heap->GetStatus( &totalFree, &largestBlock, &numObjects, &highWater );
|
|
|
|
unsigned int used = size - totalFree;
|
|
float percentUsed = static_cast<float>( used ) / static_cast<float>( size ) * 100.0f;
|
|
float highWaterPercentUsed = static_cast<float>( highWater ) / static_cast<float>( size ) * 100.0f;
|
|
float usedMB = (float)used / MB;
|
|
float sizeMB = (float)size / MB;
|
|
float hwMB = (float)info[i].highwater / MB;
|
|
|
|
char buffy[256];
|
|
sprintf( buffy, "%8s %2.2f/%2.2f [%2.1f%%] HW: %2.2f [%2.1f%%]", info[i].name, usedMB, sizeMB, percentUsed, hwMB, highWaterPercentUsed );
|
|
|
|
p3d::pddi->DrawString( buffy,
|
|
LEFT ,
|
|
TOP + (i*20),
|
|
WHITE );
|
|
}
|
|
}
|
|
|
|
char buff1[256];
|
|
char buff2[256];
|
|
char buff3[256];
|
|
char buff4[256];
|
|
float memtextures = 0;
|
|
float memmeshes = 0;
|
|
int fps=0,tris;
|
|
|
|
int frameTime = p3d::pddi->GetIntStat(PDDI_STAT_FRAME_TIME);
|
|
if( frameTime == 0 )
|
|
{
|
|
frameTime = 1;
|
|
}
|
|
fps = 1000 / ( frameTime );
|
|
#ifdef RAD_RELEASE
|
|
tris = 300000;
|
|
#else
|
|
tris = p3d::pddi->GetIntStat(PDDI_STAT_BUFFERED_PRIM) + p3d::pddi->GetIntStat(PDDI_STAT_BUFFERED_INDEXED_PRIM);
|
|
#endif
|
|
|
|
if(tris>20000 && fps>12)
|
|
{
|
|
if(fps<mLowestFPS)
|
|
{
|
|
mLowestFPS = fps;
|
|
mFPSLWTris = tris;
|
|
}
|
|
}
|
|
if(tris>mHighestTris)
|
|
{
|
|
mHighestTris = tris;
|
|
mHWTriFPS = fps;
|
|
}
|
|
|
|
memtextures = p3d::pddi->GetFloatStat(PDDI_STAT_TEXTURE_ALLOC_8BIT);
|
|
memtextures = memtextures /1024;
|
|
memmeshes = p3d::pddi->GetFloatStat(PDDI_STAT_BUFFERED_ALLOC);
|
|
memmeshes = memmeshes/1024 ;
|
|
|
|
sprintf(buff1,"FPS: %d \n", fps);
|
|
sprintf(buff2,"# Textures 8bit: %d ,MemUsage %2.2f MB \n",p3d::pddi->GetIntStat(PDDI_STAT_TEXTURE_COUNT_8BIT),memtextures );
|
|
sprintf(buff3,"# Meshes: %d , MemUsage %2.2f MB \n",p3d::pddi->GetIntStat(PDDI_STAT_BUFFERED_COUNT),memmeshes);
|
|
sprintf(buff4,"Tri's: %d Tri(HW): %d, FPS at TriHW: %d\n FPS(LW):%d, Tri's at FPS LW: %d\n",tris,mHighestTris,mHWTriFPS,
|
|
mLowestFPS,mFPSLWTris);
|
|
|
|
p3d::pddi->DrawString(buff1,LEFT,TOP+(count*20)+ 0,WHITE);
|
|
p3d::pddi->DrawString(buff2,LEFT,TOP+(count*20)+20,WHITE);
|
|
p3d::pddi->DrawString(buff3,LEFT,TOP+(count*20)+40,WHITE);
|
|
p3d::pddi->DrawString(buff4,LEFT,TOP+(count*20)+60,WHITE);
|
|
p3d::pddi->EnableStatsOverlay(0); //disable the regular p3d debug stats.
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
//Memory Layout.
|
|
//--HS_DEFAULT
|
|
//--HS_TEMP
|
|
//--HS_MUSIC
|
|
//--HS_AUDIO_PERSISTENT
|
|
//--HS_PERSISTENT
|
|
//--HS_LEVEL
|
|
// ||
|
|
// | --HS_LEVEL_MOVIE -|
|
|
// | --HS_LEVEL_AUDIO_FE | - Front end sub heaps.
|
|
// | --HS_LEVEL_FE -|
|
|
// |
|
|
// --HS_LEVEL_ZONE -|
|
|
// --HS_LEVEL_OTHER |
|
|
// --HS_LEVEL_HUD | - In-game sub heaps.
|
|
// --HS_LEVEL_MISSION |
|
|
// --HS_LEVEL_AUDIO_INGAME -|
|
|
|
|
//==================================
|
|
//These only exist in debug and tune
|
|
|
|
//--HS_DEBUG
|
|
//--HS_DEBUG_FIREWIRE
|
|
//--HS_SPECIAL
|
|
|
|
// These constants are the heap sizes for each platform
|
|
//
|
|
#if defined (RAD_PS2)
|
|
#ifdef RAD_RELEASE
|
|
const float HS_DEFAULT = 0.12f; // For only very core FTech stuff (DO NOT change this)
|
|
#else // If you run out of room in GMA_DEFAULT,
|
|
// you have an unrouted allocation
|
|
const float HS_DEFAULT = 0.13f; // For that plus debug comm stuff, etc (DO NOT change this)
|
|
#endif
|
|
|
|
#ifdef CORRAL_SMALL_ALLOCS
|
|
const float HS_TEMP = 0.350000f;
|
|
#else
|
|
const float HS_TEMP = 0.550000f;
|
|
#endif
|
|
|
|
#ifdef PAL
|
|
// an additional 4-5K is needed for PAL builds, due to other languages
|
|
// in the text bible using up slightly more memory
|
|
//
|
|
const float HS_PERSISTENT = 1.905f;
|
|
#else
|
|
const float HS_PERSISTENT = 1.900f;
|
|
#endif
|
|
|
|
const float HS_MUSIC = 0.2f;
|
|
const float HS_AUDIO_PERSISTENT = 0.62f;//0.693000f;
|
|
|
|
//FE Only
|
|
const float HS_LEVEL_MOVIE = 1.94f;
|
|
const float HS_LEVEL_AUDIO_FE = 0.05f;
|
|
const float HS_LEVEL_FE = 14.0f;
|
|
//In-game Only
|
|
//const float HS_LEVEL_ZONE = 11.25f;
|
|
const float HS_LEVEL_ZONE = 11.50f;
|
|
//const float HS_LEVEL_OTHER = 6.48f;
|
|
#ifdef CORRAL_SMALL_ALLOCS
|
|
const float HS_LEVEL_HUD = 1.6700f;
|
|
#else
|
|
const float HS_LEVEL_HUD = 2.51f;;
|
|
#endif
|
|
|
|
const float HS_LEVEL_AUDIO_INGAME = 0.05f;
|
|
|
|
// level heap is the sum of other heaps
|
|
const float HS_LEVEL = 0.01 + rmt::Max( ( HS_LEVEL_ZONE + HS_LEVEL_HUD + HS_LEVEL_AUDIO_INGAME ), ( HS_LEVEL_FE + HS_LEVEL_AUDIO_FE + HS_LEVEL_MOVIE ) );
|
|
|
|
//Mnigame Only
|
|
const float HS_MINIGAME_ZONE = 3.0f;
|
|
const float HS_MINIGAME_OTHER = 7.7f;
|
|
const float HS_MINIGAME_HUD = 2.3f;
|
|
const float HS_MINIGAME_MISSION = 2.0f;
|
|
const float HS_MINIGAME_AUDIO = 0.5f;
|
|
|
|
#ifndef RAD_RELEASE
|
|
const float HS_DEBUG = 5.0f;
|
|
const float HS_DEBUG_FIREWIRE = 0.4f;
|
|
const float HS_SPECIAL = 10.0f;
|
|
#endif
|
|
|
|
#elif defined (RAD_GAMECUBE)
|
|
//NOTE: The VMM is using 1 MEG - See VMM_MAIN_RAM in gcplatform.h
|
|
//NOTE2: GameCube libraries now allocate from GMA_AUDIO_PERSISTENT rather than OSAlloc,
|
|
//NOTE3: There is also a static heap defined in radCore/radmemory memorymanager.cpp of
|
|
// STATIC_HEAP_SIZE ( 1024 * 1024 * 2 ) + ( 600 * 1024 ) = 2.6 Megs This is replacing the
|
|
// regular persistent heap.
|
|
//NOTE4: There is also an amount of emergency memory in radmemory (memorymanager) in the initializePlatform
|
|
// for printfs and such. It is 32 * 1024 bytes = 32K
|
|
const float HS_DEFAULT = 0.08f; //0.13f // For only very core FTech stuff
|
|
const float HS_TEMP = 0.3f; //0.37f;
|
|
|
|
const float HS_PERSISTENT = 2.56f; //Need extra 8K for PAL
|
|
const float HS_MUSIC = 0.2f;
|
|
const float HS_AUDIO_PERSISTENT = 0.65f;
|
|
const float HS_LEVEL = 12.95f; // a little extra sub-heap creation overhead
|
|
//FE Only
|
|
const float HS_LEVEL_MOVIE = 3.1f;
|
|
const float HS_LEVEL_AUDIO_FE = 0.1f;
|
|
const float HS_LEVEL_FE = 9.75f;
|
|
//In-game Only
|
|
const float HS_LEVEL_ZONE = 6.48f;
|
|
const float HS_LEVEL_OTHER = 3.20f;
|
|
const float HS_LEVEL_HUD = 2.50f;
|
|
//const float HS_LEVEL_MISSION = 0.0f;
|
|
const float HS_LEVEL_AUDIO_INGAME = 0.04f;
|
|
//Mnigame Only
|
|
const float HS_MINIGAME_ZONE = 3.0f;
|
|
const float HS_MINIGAME_OTHER = 7.5f;
|
|
const float HS_MINIGAME_HUD = 1.7f;
|
|
const float HS_MINIGAME_MISSION = 2.0f;
|
|
const float HS_MINIGAME_AUDIO = 0.5f;
|
|
|
|
#ifndef RAD_RELEASE
|
|
const float HS_DEBUG = 2.0f;
|
|
const float HS_DEBUG_FIREWIRE = 99999.99f;
|
|
const float HS_SPECIAL = 0.0f;
|
|
#endif
|
|
|
|
#elif defined (RAD_XBOX)
|
|
#ifdef RAD_RELEASE
|
|
const float HS_DEFAULT = 0.1f; // For only very core FTech stuff
|
|
#else
|
|
const float HS_DEFAULT = 0.4f; // For that plus debug comm stuff, etc
|
|
#endif
|
|
const float HS_TEMP = 1.0f;
|
|
const float HS_PERSISTENT = 1.65f;
|
|
const float HS_MUSIC = 0.2f;
|
|
const float HS_AUDIO_PERSISTENT = 0.7f;
|
|
const float HS_LEVEL = 20.01f; // 0.01 for sub-heap creation overhead
|
|
//FE Only
|
|
const float HS_LEVEL_MOVIE = 3.94f; // TC: added extra 2.0 MB until memory leak
|
|
// in radMovie Bink player is fixed
|
|
const float HS_LEVEL_AUDIO_FE = 0.05f;
|
|
const float HS_LEVEL_FE = 5.0f;
|
|
//In-game Only
|
|
const float HS_LEVEL_ZONE = 8.0f;
|
|
//const float HS_LEVEL_OTHER = 5.0f;
|
|
const float HS_LEVEL_HUD = 2.5f;
|
|
//const float HS_LEVEL_MISSION = 2.8f;
|
|
const float HS_LEVEL_AUDIO_INGAME = 0.05f;
|
|
//Mnigame Only
|
|
const float HS_MINIGAME_ZONE = 3.0f;
|
|
const float HS_MINIGAME_OTHER = 8.0f;
|
|
const float HS_MINIGAME_HUD = 1.55f;
|
|
const float HS_MINIGAME_MISSION = 2.0f;
|
|
const float HS_MINIGAME_AUDIO = 0.5f;
|
|
|
|
#ifndef RAD_RELEASE
|
|
const float HS_DEBUG = 5.0f;
|
|
const float HS_DEBUG_FIREWIRE = 0.4f;
|
|
const float HS_SPECIAL = 10.0f;
|
|
#endif
|
|
|
|
#elif defined (RAD_WIN32) // these have not been optimized yet.
|
|
#ifdef RAD_RELEASE
|
|
const float HS_DEFAULT = 0.1f; // For only very core FTech stuff
|
|
#else
|
|
const float HS_DEFAULT = 0.4f; // For that plus debug comm stuff, etc
|
|
#endif
|
|
const float HS_TEMP = 1.0f;
|
|
const float HS_PERSISTENT = 1.65f;
|
|
const float HS_MUSIC = 0.2f;
|
|
const float HS_AUDIO_PERSISTENT = 2.7f;
|
|
const float HS_LEVEL = 20.01f; // 0.01 for sub-heap creation overhead
|
|
//FE Only
|
|
const float HS_LEVEL_MOVIE = 3.94f; // TC: added extra 2.0 MB until memory leak
|
|
// in radMovie Bink player is fixed
|
|
const float HS_LEVEL_AUDIO_FE = 0.05f;
|
|
const float HS_LEVEL_FE = 5.0f;
|
|
//In-game Only
|
|
const float HS_LEVEL_ZONE = 8.0f;
|
|
//const float HS_LEVEL_OTHER = 5.0f;
|
|
const float HS_LEVEL_HUD = 2.5f;
|
|
//const float HS_LEVEL_MISSION = 2.8f;
|
|
const float HS_LEVEL_AUDIO_INGAME = 0.05f;
|
|
//Mnigame Only
|
|
const float HS_MINIGAME_ZONE = 3.0f;
|
|
const float HS_MINIGAME_OTHER = 8.0f;
|
|
const float HS_MINIGAME_HUD = 1.55f;
|
|
const float HS_MINIGAME_MISSION = 2.0f;
|
|
const float HS_MINIGAME_AUDIO = 0.5f;
|
|
|
|
#ifndef RAD_RELEASE
|
|
const float HS_DEBUG = 5.0f;
|
|
const float HS_DEBUG_FIREWIRE = 0.4f;
|
|
const float HS_SPECIAL = 10.0f;
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
#define ALL_DL_HEAPS
|
|
|
|
void HeapManager::PrepareHeapsStartup ()
|
|
{
|
|
//
|
|
// Setup our memory heaps.
|
|
//
|
|
const float FUDGE = GetFudgeFactor ();
|
|
|
|
// The temporary heap.
|
|
// This heap is for temporary allocations that happen during loading, to prevent fragmentation.
|
|
//
|
|
CreateHeap( GMA_TEMP, static_cast<unsigned int>(HS_TEMP * MB * FUDGE) );
|
|
|
|
// The persistent heap.
|
|
// This heap holds everything that is allocated at the beginning of the game and never gets freed.
|
|
//
|
|
float persistent_size = HS_PERSISTENT;
|
|
#ifdef RAD_PS2
|
|
#ifndef RAD_RELEASE
|
|
// On the PS2, in non-release, radSound allocates about 0.1 MB more for radRemoteScript
|
|
//
|
|
persistent_size += 0.1f;
|
|
#endif
|
|
|
|
// On the PS2, the host drive mount costs about 254K more than the CD drive mount
|
|
//
|
|
if (!CommandLineOptions::Get( CLO_CD_FILES_ONLY ))
|
|
{
|
|
persistent_size += 0.25f;
|
|
}
|
|
#endif
|
|
|
|
CreateHeap( GMA_PERSISTENT, static_cast<unsigned int>(persistent_size * MB * FUDGE) );
|
|
|
|
//#ifndef RAD_GAMECUBE
|
|
//
|
|
// The audio persistent heap.
|
|
// This heap holds allocations that audio makes that are done once
|
|
// and persist throughout the game. They aren't necessarily done
|
|
// at start up, hence its own heap
|
|
//
|
|
#if defined( RAD_GAMECUBE ) || defined( RAD_PS2 )
|
|
CreateHeap( GMA_AUDIO_PERSISTENT, static_cast< int >( HS_AUDIO_PERSISTENT * FUDGE * MB ) );
|
|
IRadMemoryAllocator* audioHeap = GetAllocator( GMA_AUDIO_PERSISTENT );
|
|
radMemoryRegisterAllocator( GMA_MUSIC, RADMEMORY_ALLOC_DEFAULT, audioHeap );
|
|
#endif
|
|
#ifdef CORRAL_SMALL_ALLOCS
|
|
CreateHeap( GMA_SMALL_ALLOC, (int)(((float)4*(1024*1024))*FUDGE+(200*1024)));//-170608) );
|
|
extern bool gbSmallAllocCreated;
|
|
gbSmallAllocCreated = true;
|
|
#endif
|
|
//#else
|
|
// radMemoryRegisterAllocator( GMA_AUDIO_PERSISTENT, RADMEMORY_ALLOC_VMM, vmmHeap );
|
|
// radMemoryRegisterAllocator( GMA_MUSIC, RADMEMORY_ALLOC_VMM, vmmHeap );
|
|
//#endif
|
|
|
|
#ifdef RAD_GAMECUBE
|
|
// The default heap.
|
|
// This heap holds everything we are otherwise unable to route to a heap.
|
|
// This includes objects initialized before the heaps are created.
|
|
//
|
|
unsigned int size = Memory::GetTotalMemoryFree() - 3 * 1024;
|
|
CreateHeap( GMA_DEFAULT, size );
|
|
IRadMemoryAllocator* defaultHeap = GetAllocator( GMA_DEFAULT );
|
|
//radMemoryRegisterAllocator( GMA_TEMP, RADMEMORY_ALLOC_DEFAULT, defaultHeap );
|
|
radMemoryRegisterAllocator( GMA_LEVEL_MOVIE, RADMEMORY_ALLOC_DEFAULT, defaultHeap );
|
|
radMemoryRegisterAllocator( GMA_LEVEL_FE, RADMEMORY_ALLOC_DEFAULT, defaultHeap );
|
|
radMemoryRegisterAllocator( GMA_LEVEL_ZONE, RADMEMORY_ALLOC_DEFAULT, defaultHeap );
|
|
radMemoryRegisterAllocator( GMA_LEVEL_OTHER, RADMEMORY_ALLOC_DEFAULT, defaultHeap );
|
|
// radMemoryRegisterAllocator( GMA_LEVEL_HUD, RADMEMORY_ALLOC_DEFAULT, defaultHeap );
|
|
radMemoryRegisterAllocator( GMA_LEVEL_MISSION, RADMEMORY_ALLOC_DEFAULT, defaultHeap );
|
|
radMemoryRegisterAllocator( GMA_LEVEL_AUDIO, RADMEMORY_ALLOC_DEFAULT, defaultHeap );
|
|
radMemoryRegisterAllocator( GMA_DEBUG, RADMEMORY_ALLOC_DEFAULT, defaultHeap );
|
|
radMemoryRegisterAllocator( GMA_SPECIAL, RADMEMORY_ALLOC_DEFAULT, defaultHeap );
|
|
// radMemoryRegisterAllocator( GMA_MUSIC, RADMEMORY_ALLOC_DEFAULT, defaultHeap );
|
|
// radMemoryRegisterAllocator( GMA_AUDIO_PERSISTENT, RADMEMORY_ALLOC_DEFAULT, defaultHeap );
|
|
#endif
|
|
|
|
#if defined(RAD_PS2) && defined(ALL_DL_HEAPS)
|
|
unsigned int fudgeFactor;
|
|
|
|
if( CommandLineOptions::Get( CLO_MEMORY_MONITOR ) )
|
|
{
|
|
fudgeFactor = 64 * 1024;
|
|
}
|
|
else
|
|
{
|
|
#ifdef RAD_TUNE
|
|
fudgeFactor = 64 * 1024;
|
|
#else
|
|
fudgeFactor = 16 * 1024;
|
|
#endif
|
|
}
|
|
|
|
//unsigned int size = Memory::GetTotalMemoryFree() - fudgeFactor;// - 256 * 1024; //mfifo
|
|
unsigned int size = Memory::GetLargestFreeBlock() - fudgeFactor;// - 256 * 1024; //mfifo
|
|
#ifdef RAD_MW
|
|
size -= (512 * 1024);
|
|
#endif
|
|
//size -= (512*1024);
|
|
CreateHeap( GMA_DEFAULT, size );
|
|
IRadMemoryAllocator* defaultHeap = GetAllocator( GMA_DEFAULT );
|
|
//radMemoryRegisterAllocator( GMA_TEMP, RADMEMORY_ALLOC_DEFAULT, defaultHeap );
|
|
radMemoryRegisterAllocator( GMA_LEVEL_MOVIE, RADMEMORY_ALLOC_DEFAULT, defaultHeap );
|
|
radMemoryRegisterAllocator( GMA_LEVEL_FE, RADMEMORY_ALLOC_DEFAULT, defaultHeap );
|
|
radMemoryRegisterAllocator( GMA_LEVEL_ZONE, RADMEMORY_ALLOC_DEFAULT, defaultHeap );
|
|
radMemoryRegisterAllocator( GMA_LEVEL_OTHER, RADMEMORY_ALLOC_DEFAULT, defaultHeap );
|
|
//radMemoryRegisterAllocator( GMA_LEVEL_HUD, RADMEMORY_ALLOC_DEFAULT, defaultHeap );
|
|
radMemoryRegisterAllocator( GMA_LEVEL_MISSION, RADMEMORY_ALLOC_DEFAULT, defaultHeap );
|
|
radMemoryRegisterAllocator( GMA_LEVEL_AUDIO, RADMEMORY_ALLOC_DEFAULT, defaultHeap );
|
|
radMemoryRegisterAllocator( GMA_DEBUG, RADMEMORY_ALLOC_DEFAULT, defaultHeap );
|
|
radMemoryRegisterAllocator( GMA_SPECIAL, RADMEMORY_ALLOC_DEFAULT, defaultHeap );
|
|
// radMemoryRegisterAllocator( GMA_MUSIC, RADMEMORY_ALLOC_DEFAULT, defaultHeap );
|
|
// radMemoryRegisterAllocator( GMA_AUDIO_PERSISTENT, RADMEMORY_ALLOC_DEFAULT, defaultHeap );
|
|
|
|
#endif
|
|
|
|
if (CommandLineOptions::Get( CLO_NO_HEAPS ))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// The music heap.
|
|
// This heap holds allocations related to radMusic. It's a bit of a tweener,
|
|
// since it can allocate/deallocate unpredictably, and can occasionally
|
|
// persist temporarily over the FE/game crossover. It doesn't seem to fit
|
|
// anywhere else, hence its own heap.
|
|
//
|
|
// CreateHeap( GMA_MUSIC, static_cast< unsigned int >( HS_MUSIC * FUDGE ) );
|
|
|
|
//
|
|
// The audio persistent heap.
|
|
// This heap holds allocations that audio makes that are done once
|
|
// and persist throughout the game. They aren't necessarily done
|
|
// at start up, hence its own heap
|
|
//
|
|
rReleasePrintf( "Creating Heap: AUDIO PERSISTENT (%f)\n", HS_AUDIO_PERSISTENT * FUDGE );
|
|
//s_pIRadMemoryHeapAudioPersistent = radMemoryCreateDougLeaHeap( static_cast<unsigned int>( HS_AUDIO_PERSISTENT * MB * FUDGE ), RADMEMORY_ALLOC_DEFAULT, "Audio Persistent" );
|
|
//s_pIRadMemoryHeapAudioPersistent->AddRef();
|
|
//radMemoryRegisterAllocator( GMA_AUDIO_PERSISTENT, RADMEMORY_ALLOC_DEFAULT, s_pIRadMemoryHeapAudioPersistent );
|
|
|
|
// The level heap.
|
|
// This is the main heap for holding game data. This includes the front end and all in-game assets.
|
|
// This is the largest heap.
|
|
//
|
|
//rReleasePrintf ("Creating Heap: LEVEL (%f)\n", HS_LEVEL * FUDGE);
|
|
//s_pIRadMemoryHeapLevel = radMemoryCreateTrackingHeap( static_cast<unsigned int>(HS_LEVEL * MB * FUDGE), RADMEMORY_ALLOC_DEFAULT, "Level" );
|
|
//s_pIRadMemoryHeapLevel->AddRef();
|
|
//radMemoryRegisterAllocator( GMA_LEVEL, RADMEMORY_ALLOC_DEFAULT, s_pIRadMemoryHeapLevel );
|
|
|
|
#ifndef RAD_RELEASE
|
|
// The debug heap.
|
|
// This heap is for holding all debugging related materials, such as the host communication channel, the watcher, the profiler, etc.
|
|
// It is not created in release mode.
|
|
//
|
|
float debugSize;
|
|
if( CommandLineOptions::Get( CLO_FIREWIRE ) )
|
|
{
|
|
debugSize = HS_DEBUG_FIREWIRE;
|
|
}
|
|
else
|
|
{
|
|
debugSize = HS_DEBUG;
|
|
}
|
|
|
|
CreateHeap( GMA_DEBUG, static_cast<unsigned int>(debugSize * MB) );
|
|
|
|
if ( !CommandLineOptions::Get( CLO_FIREWIRE ) )
|
|
{
|
|
// The special heap.
|
|
// This heap is created in debug and tune only and is used for routing a group of allocations to a specific place.
|
|
//
|
|
CreateHeap( GMA_SPECIAL, static_cast<unsigned int>(HS_SPECIAL * MB) );
|
|
}
|
|
#endif
|
|
|
|
// The default heap.
|
|
// This heap holds everything we are otherwise unable to route to a heap.
|
|
// This includes objects initialized before the heaps are created.
|
|
//
|
|
//rReleasePrintf ("Creating Heap: DEFAULT (%f)\n", HS_DEFAULT);
|
|
//s_pIRadMemoryHeapDefault = radMemoryCreateDougLeaHeap( static_cast<unsigned int>(HS_DEFAULT * MB), RADMEMORY_ALLOC_DEFAULT, "Default" );
|
|
//s_pIRadMemoryHeapDefault->AddRef();
|
|
//radMemoryRegisterAllocator( GMA_DEFAULT, RADMEMORY_ALLOC_DEFAULT, s_pIRadMemoryHeapDefault );
|
|
|
|
/*
|
|
#ifdef RAD_GAMECUBE
|
|
if ( vmmHeap )
|
|
{
|
|
//The virtual memory heap.
|
|
rReleaseString ("Creating Heap: VMM\n");
|
|
s_pIRadMemoryHeapVMM = vmmHeap;
|
|
s_pIRadMemoryHeapVMM->AddRef();
|
|
}
|
|
|
|
// The default heap.
|
|
// This heap holds everything we are otherwise unable to route to a heap.
|
|
// This includes objects initialized before the heaps are created.
|
|
//
|
|
unsigned int size = Memory::GetTotalMemoryFree();
|
|
rReleasePrintf ("Creating Heap: DEFAULT (%f)\n", HS_DEFAULT);
|
|
s_pIRadMemoryHeapDefault = radMemoryCreateDougLeaHeap( static_cast<unsigned int>(size), RADMEMORY_ALLOC_DEFAULT, "Default" );
|
|
s_pIRadMemoryHeapDefault->AddRef();
|
|
radMemoryRegisterAllocator( GMA_DEFAULT, RADMEMORY_ALLOC_DEFAULT, s_pIRadMemoryHeapDefault );
|
|
|
|
#endif
|
|
*/
|
|
}
|
|
//=============================================================================
|
|
// HeapManager::PrepareHeapsFeCleanup
|
|
//=============================================================================
|
|
void HeapManager::PrepareHeapsFeCleanup()
|
|
{
|
|
DestroyHeapA( GMA_LEVEL_HUD );
|
|
|
|
if (CommandLineOptions::Get( CLO_NO_HEAPS ))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Free in game heaps
|
|
//
|
|
DestroyHeapA( GMA_LEVEL_ZONE );
|
|
DestroyHeapA( GMA_LEVEL_OTHER );
|
|
DestroyHeapA( GMA_LEVEL_MISSION );
|
|
DestroyHeapA( GMA_LEVEL_AUDIO );
|
|
#ifdef USE_CHAR_GAG_HEAP
|
|
DestroyHeapA( GMA_CHARS_AND_GAGS );
|
|
#endif
|
|
}
|
|
|
|
//=============================================================================
|
|
// HeapManager::PrepareHeapsFeSetup
|
|
//=============================================================================
|
|
void HeapManager::PrepareHeapsFeSetup()
|
|
{
|
|
if (CommandLineOptions::Get( CLO_NO_HEAPS ))
|
|
{
|
|
return;
|
|
}
|
|
const float FUDGE = GetFudgeFactor ();
|
|
CreateHeap( GMA_LEVEL_FE, static_cast<unsigned int>(HS_LEVEL_FE * FUDGE * MB) );
|
|
CreateHeap( GMA_LEVEL_MOVIE, static_cast<unsigned int>(HS_LEVEL_MOVIE * MB) );
|
|
CreateHeap( GMA_LEVEL_AUDIO, static_cast<unsigned int>(HS_LEVEL_AUDIO_FE * MB) );
|
|
}
|
|
|
|
|
|
void HeapManager::PrepareHeapsInGame ()
|
|
{
|
|
const float FUDGE = GetFudgeFactor ();
|
|
DestroyHeapA( GMA_LEVEL_MOVIE );
|
|
|
|
DestroyHeapA( GMA_LEVEL_HUD );
|
|
CreateHeap( GMA_LEVEL_HUD, static_cast<unsigned int>(HS_LEVEL_HUD * FUDGE * MB) );
|
|
|
|
#ifdef USE_CHAR_GAG_HEAP
|
|
CreateHeap( GMA_CHARS_AND_GAGS, static_cast<unsigned int>(1.3f * MB) );
|
|
#endif
|
|
|
|
if (CommandLineOptions::Get( CLO_NO_HEAPS ))
|
|
{
|
|
return;
|
|
}
|
|
|
|
DestroyHeapA( GMA_LEVEL_AUDIO );
|
|
DestroyHeapA( GMA_LEVEL_FE );
|
|
DestroyHeapA( GMA_LEVEL_ZONE );
|
|
|
|
// Create in game heaps
|
|
//
|
|
CreateHeap( GMA_LEVEL_ZONE, static_cast<unsigned int>(HS_LEVEL_ZONE * FUDGE * MB) );
|
|
CreateHeap( GMA_LEVEL_AUDIO, static_cast<unsigned int>(HS_LEVEL_AUDIO_INGAME * FUDGE * MB) );
|
|
}
|
|
|
|
void HeapManager::PrepareHeapsSuperSprint ()
|
|
{
|
|
const float FUDGE = GetFudgeFactor ();
|
|
|
|
DestroyHeapA( GMA_LEVEL_HUD );
|
|
CreateHeap( GMA_LEVEL_HUD, static_cast<unsigned int>(HS_MINIGAME_HUD * FUDGE * MB) );
|
|
|
|
if (CommandLineOptions::Get( CLO_NO_HEAPS ))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Free front end heaps
|
|
//
|
|
DestroyHeapA( GMA_LEVEL_FE );
|
|
DestroyHeapA( GMA_LEVEL_MOVIE );
|
|
DestroyHeapA( GMA_LEVEL_AUDIO );
|
|
|
|
// Free in game heaps (this has to happen for the mission select case, i.e. jumping level to level)
|
|
//
|
|
DestroyHeapA( GMA_LEVEL_ZONE );
|
|
// DestroyHeap (s_pIRadMemoryHeapLevelOther);
|
|
DestroyHeapA( GMA_LEVEL_HUD );
|
|
// DestroyHeap (s_pIRadMemoryHeapLevelMission);
|
|
|
|
// Create in game heaps
|
|
//
|
|
CreateHeap( GMA_LEVEL_ZONE, static_cast<unsigned int>(HS_MINIGAME_ZONE * FUDGE * MB) );
|
|
|
|
// rReleaseString ("Creating Heap: OTHER\n");
|
|
// s_pIRadMemoryHeapLevelOther = radMemoryCreateDougLeaHeap ( static_cast<unsigned int>(HS_MINIGAME_OTHER * FUDGE * MB), GMA_LEVEL, "Other" );
|
|
// s_pIRadMemoryHeapLevelOther->AddRef ();
|
|
// radMemoryRegisterAllocator (GMA_LEVEL_OTHER, GMA_LEVEL, s_pIRadMemoryHeapLevelOther);
|
|
|
|
CreateHeap( GMA_LEVEL_HUD, static_cast<unsigned int>(HS_MINIGAME_HUD * FUDGE * MB) );
|
|
|
|
// rReleaseString ("Creating Heap: MISSION\n");
|
|
// s_pIRadMemoryHeapLevelMission = radMemoryCreateDougLeaHeap ( static_cast<unsigned int>(HS_MINIGAME_MISSION * FUDGE * MB), GMA_LEVEL, "Mission" );
|
|
// s_pIRadMemoryHeapLevelMission->AddRef ();
|
|
// radMemoryRegisterAllocator (GMA_LEVEL_MISSION, GMA_LEVEL, s_pIRadMemoryHeapLevelMission);
|
|
|
|
CreateHeap( GMA_LEVEL_AUDIO, static_cast<unsigned int>(HS_MINIGAME_AUDIO * FUDGE * MB) );
|
|
|
|
#ifdef USE_CHAR_GAG_HEAP
|
|
CreateHeap( GMA_CHARS_AND_GAGS, static_cast<unsigned int>(1.0f * MB) );
|
|
#endif
|
|
}
|
|
|
|
|
|
int HeapManager::GetLoadedUsageFE ()
|
|
{
|
|
return GetHeapUsage( GetAllocator( GMA_LEVEL_FE ) ) +
|
|
GetHeapUsage ( GetAllocator( GMA_LEVEL_MOVIE ) ) +
|
|
GetHeapUsage ( GetAllocator( GMA_LEVEL_AUDIO ) ) +
|
|
GetSoundMemoryHeapUsage();
|
|
}
|
|
|
|
|
|
int HeapManager::GetLoadedUsageInGame ()
|
|
{
|
|
return GetHeapUsage ( GetAllocator( GMA_LEVEL_ZONE ) ) +
|
|
// GetHeapUsage (s_pIRadMemoryHeapLevelOther) +
|
|
GetHeapUsage ( GetAllocator( GMA_LEVEL_HUD ) ) +
|
|
// GetHeapUsage (s_pIRadMemoryHeapLevelMission) +
|
|
GetHeapUsage ( GetAllocator( GMA_LEVEL_AUDIO ) ) +
|
|
GetSoundMemoryHeapUsage();
|
|
}
|
|
|
|
|
|
int HeapManager::GetLoadedUsageSuperSprint ()
|
|
{
|
|
// Right now this should be the same as In Game loading
|
|
//
|
|
return GetLoadedUsageInGame ();
|
|
}
|
|
|
|
int HeapManager::GetLoadedUsage( enum GameMemoryAllocator allocator )
|
|
{
|
|
return GetHeapUsage ( GetAllocator( allocator ) );
|
|
}
|
|
|
|
int HeapManager::GetHeapUsage (IRadMemoryAllocator* allocator)
|
|
{
|
|
if( allocator != NULL )
|
|
{
|
|
unsigned int size, totalFree, largestBlock, numObjects, highWater;
|
|
size = allocator->GetSize();
|
|
allocator->GetStatus( &totalFree, &largestBlock, &numObjects, &highWater );
|
|
return size - totalFree;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int HeapManager::GetSoundMemoryHeapUsage()
|
|
{
|
|
int soundMemoryUsage = 0;
|
|
|
|
#ifdef RAD_PS2
|
|
unsigned int size;
|
|
unsigned int totalFree;
|
|
unsigned int largestBlock;
|
|
unsigned int numObjects;
|
|
IRadSoundHalMemoryRegion* soundMemory = ::radSoundHalSystemGet()->GetRootMemoryRegion();
|
|
rAssert( soundMemory != NULL );
|
|
|
|
size = soundMemory->GetSize();
|
|
soundMemory->GetStats( &totalFree, &numObjects, &largestBlock, true );
|
|
|
|
soundMemoryUsage = size - totalFree;
|
|
#endif
|
|
|
|
return( soundMemoryUsage );
|
|
}
|
|
|
|
HeapManager* HeapMgr ()
|
|
{
|
|
return HeapManager::GetInstance ();
|
|
}
|
|
|
|
void LockPersistentHeap()
|
|
{
|
|
g_LockedPersistentHeap = true;
|
|
}
|