//////////////////////////////////////////////////////////////////////////////
//
// Asura_PS3_ScratchRenderMemory.cpp
//
// Copyright (c) 2008 Rebellion. All rights reserved.
//
//////////////////////////////////////////////////////////////////////////////

// I N C L U D E S ///////////////////////////////////////////////////////////

#include "Core/Asura.h"

// This file's header.
#include "Rendering/Asura_PS3_ScratchRenderMemory.h"

// Engine independent.
#include "Core/Memory/Asura_Mem_ResetOnlyAllocator.h"
#include "Rendering/Asura_PS3_VideoMemoryManager.h"

// G L O B A L S /////////////////////////////////////////////////////////////

static char* g_apcMainVideoMemBfrs[2];
static Asura_Mem_ResetOnlyAllocator g_xMainVideoMemAllocator;

static u_int g_uCurrentBfr;

#ifdef ASURA_PS3_ALLOW_STATS
u_int Asura_PS3_ScratchRenderMemory::s_auCurMemoryUsage[Asura_PS3_ScratchRenderMemory::MEMTYPE_COUNT];
u_int Asura_PS3_ScratchRenderMemory::s_auMaxMemoryUsage[Asura_PS3_ScratchRenderMemory::MEMTYPE_COUNT];
#endif

// P R O T O T Y P E S   A N D   I N L I N E   F U N C T I O N S /////////////

static void SwitchBuffers( void );

// C L A S S   I M P L E M E N T A T I O N S /////////////////////////////////

void Asura_PS3_ScratchRenderMemory::Initialise( void )
{
    for( u_int u = 0; u < 2; ++u )
    {
        g_apcMainVideoMemBfrs[u] = static_cast<char*>( ASURA_PS3_VIDEOMEMORY_ALLOCMAIN(ASURA_PS3_MAIN_VIDEO_SCRATCH_MEMORY_SIZE, 128) );
    }

#ifdef ASURA_PS3_ALLOW_STATS
    for( u_int u = 0; u < MEMTYPE_COUNT; ++u )
    {
        s_auCurMemoryUsage[u] = 0;
        s_auMaxMemoryUsage[u] = 0;
    }
#endif

    g_uCurrentBfr = 1; // So that in the first frame we actually start with buffer 0.
    
	g_xMainVideoMemAllocator.Initialise( g_apcMainVideoMemBfrs[g_uCurrentBfr], ASURA_PS3_MAIN_VIDEO_SCRATCH_MEMORY_SIZE, false );
}


void Asura_PS3_ScratchRenderMemory::Reset( void )
{
}


void Asura_PS3_ScratchRenderMemory::Shutdown( void )
{
    Reset();

    for( u_int u = 0; u < 2; ++u )
    {
        Asura_PS3_VideoMemoryManager::FreeMain( g_apcMainVideoMemBfrs[u] );
        g_apcMainVideoMemBfrs[u] = NULL;
    }
}


void* Asura_PS3_ScratchRenderMemory::AllocMainVideoMemory( u_int uNumBytes, u_int uAlignment )
{
    if( uNumBytes > g_xMainVideoMemAllocator.GetNumFreeBytes() )
    {
        Asura_Assert( false, "Ran out of scratch main video memory! Need to increase ASURA_PS3_MAIN_VIDEO_SCRATCH_MEMORY_SIZE" );

        // Emergency measures. This is very far from bulletproof but with
        // large buffers will give us a decent chance of avoiding any
        // problems.
        SwitchBuffers();
    }

#ifdef ASURA_PS3_ALLOW_STATS
    s_auCurMemoryUsage[MEMTYPE_MAIN_VIDEO] = g_xMainVideoMemAllocator.GetNumUsedBytes();
#endif

    return g_xMainVideoMemAllocator.Allocate( uNumBytes, uAlignment );
}


void Asura_PS3_ScratchRenderMemory::BeginFrame( void )
{
#ifdef ASURA_PS3_ALLOW_STATS
    for( u_int u = 0; u < MEMTYPE_COUNT; ++u )
    {
        s_auMaxMemoryUsage[u] = Asura_Maths::Max( s_auMaxMemoryUsage[u], s_auCurMemoryUsage[u] );
        s_auCurMemoryUsage[u] = 0;
    }
#endif

    SwitchBuffers();
}


void Asura_PS3_ScratchRenderMemory::EndFrame( void )
{
}

// F U N C T I O N   I M P L E M E N T A T I O N S ///////////////////////////

static void SwitchBuffers( void )
{
    g_uCurrentBfr ^= 1;

    g_xMainVideoMemAllocator.Initialise( g_apcMainVideoMemBfrs[g_uCurrentBfr], ASURA_PS3_MAIN_VIDEO_SCRATCH_MEMORY_SIZE, false );
}
