//////////////////////////////////////////////////////////////////////////////
//
// Asura_PS2_GS.cpp
//
// Copyright (c) 2001-2003 Rebellion. All rights reserved.
//
//////////////////////////////////////////////////////////////////////////////

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

#include "Core/Asura.h"

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

// Standard platform-specific.
#include <libdma.h>
#include <libgraph.h>

// Engine independent.
#include "Camera/Asura_Camera.h"
#include "Core/Asura_Timers.h"
#include "Debugging/Asura_Assert.h"
#include "Debugging/Asura_Logfile.h"
#include "Debugging/Asura_ScreenShot_System.h"
#include "Rendering/Asura_Module.h"
#include "Rendering/Asura_Render.h"
#include "Rendering/Asura_Viewport.h"

// Engine platform-specific.
#include "Core/Asura_PlatformBasics.h"
#include "Core/Asura_PS2_DMA.h"
#include "Core/Asura_PS2_OS.h"
#include "Core/Asura_PS2_Timers.h"
#include "Debugging/Asura_PS2_DebugInfo.h"
#include "Profiling/Asura_PS2_Profiling.h"
#include "Rendering/Asura_PlatformRenderStates.h"
#include "Rendering/Asura_PlatformTextureManagement.h"
#include "Rendering/Asura_PS2_2D_Graphics.h"
#include "Rendering/Asura_PS2_DeferredRendering.h"
#include "Rendering/Asura_PS2_VU1.h"

// D E B U G V A R S /////////////////////////////////////////////////////////

DEBUGVAR int dbg_iDefaultScreenOffsetX = 0;
DEBUGVAR int dbg_iDefaultScreenOffsetY = 0;
DEBUGVAR int dbg_iAdditionalScreenOffsetYForPAL = 20;
DEBUGVAR int dbg_iMinScreenOffsetX = -100;
DEBUGVAR int dbg_iMinScreenOffsetY = -100;
DEBUGVAR int dbg_iMaxScreenOffsetX = 100;
DEBUGVAR int dbg_iMaxScreenOffsetY = 100;

DEBUGVAR bool dbg_bUseDitherForBackBfrToFrontBfrBlit = true;

DEBUGVAR bool dbg_bDisplayFrameBufferAlphaChannel = false;
DEBUGVAR bool dbg_bDisplayZBuffer                 = false;

DEBUGVAR bool dbg_bIncludeDebugInfoInScreenshots = false;

DEBUGVAR u_int dbg_uTimerMode = 3 | (1<<7);

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

static int g_iDisplayOffsetX = dbg_iDefaultScreenOffsetX;   // for screen centering
static int g_iDisplayOffsetY = dbg_iDefaultScreenOffsetY;

static bool   g_bMotionBlurOn = false;
static u_char g_ucMotionBlurValue = 32;

static void (*g_pfnEndFrameCB)(void)            = NULL;
static void (*g_pfnInitDblBfrCB)(sceGsDBuffDc*) = NULL;

// 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 u_short GetPSMFromBitDepth( u_int uBitDepth )
{
    switch( uBitDepth )
    {
        default:
            Asura_Assert( false, "Invalid bit depth." );
            // And fall through to a valid case.

        case 32: return SCE_GS_PSMCT32;
        case 24: return SCE_GS_PSMCT24;
		case 16: return ( Asura_PS2_GS::GetZBfrBitDepth() == 16 ? SCE_GS_PSMCT16 : SCE_GS_PSMCT16S );
    }
}

static void ResetGSRegsToKnownState( void )
{
    // Registers that we can rely on (and why):
    //
    //     Stuff setup by sceGsSetDefDrawEnv():
    //
    //         COLCLAMP   = 1
    //         DTHE       = 0 (assuming target bfr depth is >= 24 bit)
    //         PRMODECONT = 1
    //
    //     Stuff we always setup in the CreateDefaultRenderStatePacket()
    //     method of Asura_PlatformRenderStates:
    //
    //         TEXA

    // Registers we can't necessarily rely on (and are therefore set
    // below):
    //
    //     These would be done by sceGsSetDefAlphaEnv() but we don't
    //     use that:
    //
    //         FBA
    //         PABE
    //
    //     This is only relevant if doing FRAME stuff with a single buffer
    //     at 60Hz.
    //
    //         SCANMSK

    // Obviously we don't bother fiddling with any registers that we're going
    // to be continuously setting up - ALPHA, etc.

    const u_int uNLOOP = 4;
    const u_int uQWs   = 1 + uNLOOP;

    Asura_PS2_QW* const pxBase = Asura_PS2_SPR_Alloc( 0, uQWs );
    Asura_PS2_QW* pxOut = pxBase;

    // GIF tag.
    {
        Asura_PS2_GifTag* pxGifTag = reinterpret_cast<Asura_PS2_GifTag*>( pxOut );
        pxGifTag->SetExceptRegs( uNLOOP, true, false, 0, SCE_GIF_PACKED, 1 );
        pxGifTag->uAllRegs = SCE_GIF_PACKED_AD;
        ++pxOut;
    }

    // No alpha correction, in either context.
    pxOut->u64s[0] = SCE_GS_SET_FBA( 0 );
    pxOut->u64s[1] = SCE_GS_FBA_1;
    ++pxOut;
    pxOut->u64s[0] = SCE_GS_SET_FBA( 0 );
    pxOut->u64s[1] = SCE_GS_FBA_2;
    ++pxOut;

    // Don't control alpha blending based on MSB of alpha value.
    pxOut->u64s[0] = SCE_GS_SET_PABE( 0 );
    pxOut->u64s[1] = SCE_GS_PABE;
    ++pxOut;

    // No masking for rasterising rows of pixels.
    pxOut->u64s[0] = SCE_GS_SET_SCANMSK( 0 );
    pxOut->u64s[1] = SCE_GS_SCANMSK;
    ++pxOut;

    Asura_Assert( static_cast<u_int>(pxOut - pxBase) == uQWs, "" );

    // Send.
    Asura_PS2_DMA::NormalTransferFromMem( Asura_PS2_DMA::CHANNEL_GIF, pxBase, uQWs, true, true, true );

    Asura_PS2_SPR_Dealloc( pxBase );
}

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

sceGsDBuffDc Asura_PS2_GS::s_xDoubleBuffer;
u_int   Asura_PS2_GS::s_uCurDispBuffer = 0;
bool    Asura_PS2_GS::s_bAllowDisplayBufferToBeFixed = true;
bool    Asura_PS2_GS::s_bAutoScreenBufferSwap = true;

short   Asura_PS2_GS::s_sScreenWidth;
short   Asura_PS2_GS::s_sScreenHeight;

u_short Asura_PS2_GS::s_usDispBfrBitDepth = 32;
u_short Asura_PS2_GS::s_usDrawBfrBitDepth = 32;
u_short Asura_PS2_GS::s_usZBfrBitDepth    = 24;
u_short Asura_PS2_GS::s_usZBfrBasePtr;

bool    Asura_PS2_GS::s_bClearDrawBufferOnSwap = false;// true;
bool    Asura_PS2_GS::s_bClearZBufferOnSwap    = true;
u_int   Asura_PS2_GS::s_uClearColour           = 0x00000000;

bool Asura_PS2_GS::s_bFullScreenRendering = true;
Asura_PS2_GS::ViewportParams Asura_PS2_GS::s_axViewportParams[ASURA_MAX_NO_OF_CAMERAS + 1];

float Asura_PS2_GS::s_fTargetFrameRate = 0.0f;

unsigned int Asura_PS2_GS::s_uRGBAFrameMask = 0x00000000;

Asura_PS2_VideoMode Asura_PS2_GS::s_eVideoMode = ASURA_PS2_VIDEOMODE_USEDEFAULT;

u_short Asura_PS2_GS::GetDispBfrPSM( void )
{
    return GetPSMFromBitDepth( GetDispBfrBitDepth() );
}

u_short Asura_PS2_GS::GetDrawBfrPSM( void )
{
	return GetPSMFromBitDepth( GetDrawBfrBitDepth() );
}

u_short Asura_PS2_GS::TranslateZBfrBitDepthToPSM( u_short usBitDepth )
{
    switch( usBitDepth )
    {
        default:
            Asura_Assert( false, "Invalid Z buffer bit depth." );
            // And fall through to a valid case.

        case 32: return SCE_GS_PSMZ32;
        case 24: return SCE_GS_PSMZ24;
        case 16: return( GetDrawBfrBitDepth() == 16 ? SCE_GS_PSMZ16 : SCE_GS_PSMZ16S );
    }
}

/////////////////////////////////////////////////////////////////////////////////////////
// FUNCTION     Asura_PS2_GS::Initialise
// PARAMETERS   None
// RETURNS      None
// DESCRIPTION  Initialise the GS and set the desired screen mode
/////////////////////////////////////////////////////////////////////////////////////////
void Asura_PS2_GS::Initialise(void)
{
// Resets devices on the data path to GS (VIF1,Vu0,GIF)
    sceGsResetPath();

// (MP - 08.11.2001) TODO: This should be with the DMA stuff.
// Resets the DMAC
    sceDmaReset( 1 );    

    // set initial video mode
    ChangeVideoMode();
    
#ifndef ASURA_PS2_SONY_SUBMISSION
    // Setup debug console.
    Asura_PS2_DebugInfo::Initialise();
#endif

    // init T0 counter at Hsync freq
    *T1_MODE  = dbg_uTimerMode;
    *T1_COUNT = 0;
}
// End Function Asura_PS2_GS::Initialise().

void Asura_PS2_GS::ChangeVideoMode( Asura_PS2_VideoMode eVideoMode /* = ASURA_PS2_VIDEOMODE_USEDEFAULT */, 
                                    int iWidth /* = -1 */, 
                                    int iHeight /* = -1 */,
                                    int iFrontBfrBitDepth /* = -1 */,
                                    bool bFrameMode /* = false  */)
{
    // (MP - 17.10.2005) Seems to me that it would be an extraordinarily bad
    // idea for this to be done while deferred rendering is ongoing.
    Asura_PS2_DeferredRendering::WaitForDeferredRendering();

    if( ASURA_PS2_VIDEOMODE_USEDEFAULT == eVideoMode )
    {
        eVideoMode = ( ASURA_PS2_VIDEOMODE_USEDEFAULT == s_eVideoMode ? Project_GetDefaultVideoMode() : s_eVideoMode );
    }

    bool bNewVideoMode = ( eVideoMode != s_eVideoMode );
    s_eVideoMode = eVideoMode;

    u_int uDefaultScrW, uDefaultScrH, uDefaultFrontBfrBitDepth, uDefaultDrawBfrBitDepth = 32;
    Project_GetDefaultScreenParamsForVideoMode( eVideoMode, &uDefaultScrW, &uDefaultScrH, &uDefaultFrontBfrBitDepth, &uDefaultDrawBfrBitDepth );

    if( bNewVideoMode )
    {
        if (eVideoMode == ASURA_PS2_VIDEOMODE_PROGRESSIVESCAN)
		{
			sceGsResetGraph(0, SCE_GS_NOINTERLACE, SCE_GS_DTV480P, SCE_GS_FRAME);
		}
		else
		{
			sceGsResetGraph( 0, SCE_GS_INTERLACE, (VideoModeIsPal() ? SCE_GS_PAL : SCE_GS_NTSC), (bFrameMode ? SCE_GS_FRAME : SCE_GS_FIELD) );
		}

        ResetGSRegsToKnownState();
    }

    s_sScreenWidth      = ( -1 == iWidth            ? uDefaultScrW :             iWidth            );
    s_sScreenHeight     = ( -1 == iHeight           ? uDefaultScrH :             iHeight           );
    s_usDispBfrBitDepth = ( -1 == iFrontBfrBitDepth ? uDefaultFrontBfrBitDepth : iFrontBfrBitDepth );
	s_usDrawBfrBitDepth = uDefaultDrawBfrBitDepth;

    // Z buffer base ptr is dependent upon these values so this would be a
    // good time to set that, not least because it's required in
    // InitialiseDoubleBuffer().
    s_usZBfrBasePtr = ASURA_PS2_ZBFR_DEFAULT_BASE_PTR;

    InitialiseDoubleBuffer();

    Asura_Viewport::Set( s_sScreenWidth, s_sScreenHeight );

    CacheViewportParams();

    ClearVRAM();
    for( u_int u = 20; u; --u )
    {
        sceGsSyncV( 0 );
    }

#if _DEBUG
    {
        const char* szVideoFormat;
        switch( s_eVideoMode )
        {
            case ASURA_PS2_VIDEOMODE_PAL:
                szVideoFormat = "PAL";
                break;
            case ASURA_PS2_VIDEOMODE_NTSC: 
                szVideoFormat = "NTSC";
                break;
            case ASURA_PS2_VIDEOMODE_PROGRESSIVESCAN:
                szVideoFormat = "NTSC Progressive Scan";
                break;
            default:
                Asura_Assert( false, "" );
                szVideoFormat = "unknown";
                break;
        }

        const char* szFieldOrFrame = ( bFrameMode ? "FRAME" : "FIELD" );

        Asura_OutputToDebugger(( "Video mode: %ix%i %s %s\n", s_sScreenWidth, s_sScreenHeight, szVideoFormat, szFieldOrFrame ));
        Asura_OutputToDebugger(( "Bit depths: disp=%u draw=%u z=%u\n", s_usDispBfrBitDepth, s_usDrawBfrBitDepth, s_usZBfrBitDepth ));

        // Amount of space available for textures out of our 4Mb of VRAM.
        u_int uAvailableTexSpace = (4 * 1024 * 1024) - ((GetZBfrBasePtr() << 13) + (ASURA_PS2_ZBFR_NUM_WORDS << 2));
        Asura_OutputToDebugger(( "Available texture space: %u bytes (%ukB)\n", uAvailableTexSpace, uAvailableTexSpace >> 10 ));
    }
#endif
}

void Asura_PS2_GS::SetClearDrawBufferOnSwap(bool bEnable)
{
    s_bClearDrawBufferOnSwap = bEnable;

    if ( bEnable )
        s_bClearZBufferOnSwap = false;
}

void Asura_PS2_GS::SetClearZBufferOnSwap(bool bEnable)
{
    s_bClearZBufferOnSwap = bEnable;

    if ( bEnable )
        s_bClearDrawBufferOnSwap = false;
}


void Asura_PS2_GS::InitialiseDoubleBuffer( void )
{
    const u_short usDispBfrPSM = GetDispBfrPSM();
    const u_short usDrawBfrPSM = GetDrawBfrPSM();
    const u_short usZBfrPSM    = GetZBfrPSM();
    const u_short usZBfrZBP    = GetZBfrBasePtr();

    sceGsSetDefDispEnv( &s_xDoubleBuffer.disp[0], usDispBfrPSM, s_sScreenWidth, s_sScreenHeight, 0, 0 );
    sceGsSetDefDrawEnv( &s_xDoubleBuffer.draw01, usDrawBfrPSM, s_sScreenWidth, s_sScreenHeight, SCE_GS_ZGEQUAL, usZBfrPSM );
    sceGsSetDefDrawEnv2( &s_xDoubleBuffer.draw02, usDrawBfrPSM, s_sScreenWidth, s_sScreenHeight, SCE_GS_ZGEQUAL, usZBfrPSM );

    s_xDoubleBuffer.disp[0].dispfb.FBP = ASURA_PS2_FRAMEBFR_0_BASE_PTR;
    s_xDoubleBuffer.draw01.frame1.FBP = ASURA_PS2_FRAMEBFR_1_BASE_PTR;
    s_xDoubleBuffer.draw02.frame2.FBP = ASURA_PS2_FRAMEBFR_1_BASE_PTR;

    sceGsSetDefDispEnv( &s_xDoubleBuffer.disp[1], usDrawBfrPSM, s_sScreenWidth, s_sScreenHeight, 0, 0 );
    sceGsSetDefDrawEnv( &s_xDoubleBuffer.draw11, usDispBfrPSM, s_sScreenWidth, s_sScreenHeight, SCE_GS_ZGEQUAL, usZBfrPSM );
    sceGsSetDefDrawEnv2( &s_xDoubleBuffer.draw12, usDispBfrPSM, s_sScreenWidth, s_sScreenHeight, SCE_GS_ZGEQUAL, usZBfrPSM );

    s_xDoubleBuffer.disp[1].dispfb.FBP = ASURA_PS2_FRAMEBFR_1_BASE_PTR;
    s_xDoubleBuffer.draw11.frame1.FBP = ASURA_PS2_FRAMEBFR_0_BASE_PTR;
    s_xDoubleBuffer.draw12.frame2.FBP = ASURA_PS2_FRAMEBFR_0_BASE_PTR;

    (reinterpret_cast<Asura_PS2_GifTag&>(s_xDoubleBuffer.giftag0)).Set( 16, true, false, 0, SCE_GIF_PACKED, 1, SCE_GIF_PACKED_AD );
    (reinterpret_cast<Asura_PS2_GifTag&>(s_xDoubleBuffer.giftag1)).Set( 16, true, false, 0, SCE_GIF_PACKED, 1, SCE_GIF_PACKED_AD );

    s_xDoubleBuffer.draw01.zbuf1.ZBP = usZBfrZBP;
    s_xDoubleBuffer.draw02.zbuf2.ZBP = usZBfrZBP;
    s_xDoubleBuffer.draw11.zbuf1.ZBP = usZBfrZBP;
    s_xDoubleBuffer.draw12.zbuf2.ZBP = usZBfrZBP;

    if( g_pfnInitDblBfrCB )
    {
        g_pfnInitDblBfrCB( &s_xDoubleBuffer );
    }
}


void Asura_PS2_GS::SetInitialiseDoubleBufferCallback( void(*pfnCallback)(sceGsDBuffDc*) )
{
    g_pfnInitDblBfrCB = pfnCallback;
}


void Asura_PS2_GS::Shutdown( void )
{
#ifndef ASURA_PS2_SONY_SUBMISSION
    Asura_PS2_DebugInfo::Shutdown();
#endif
}


#define USE_LIBGRAPH 0
#define ENABLE_2_CIRCUIT_ANTI_ALIASING 1

int dbg_2CircuitAlphaValue = 127;   // RMS: This is here so that the effect of the 2 circuit can be demonstrated!


bool Asura_PS2_GS::s_bEnableVsync = true;

//////////////////////////////////////////////////////////////////////////////
//
// FUNCTION     Asura_PS2_GS::PutDispEnvExplicit().
// PARAMETERS   None.
// RETURNS      None.
// DESCRIPTION  Our version of sceGsPutDispEnv which uses 2-circuit AA
// AUTHOR       Mike Healey - 21.08.2002.
//
//////////////////////////////////////////////////////////////////////////////
void Asura_PS2_GS::PutDispEnvExplicit()
{
#if ENABLE_2_CIRCUIT_ANTI_ALIASING
    DPUT_GS_PMODE( SCE_GS_SET_PMODE( 1,
                                     1,
                                     0,
                                     1,
                                     0,
                                     0,
                                     dbg_2CircuitAlphaValue ) );
#else
    DPUT_GS_PMODE( SCE_GS_SET_PMODE( s_xDoubleBuffer.disp[s_uCurDispBuffer].pmode.EN1,
                                     s_xDoubleBuffer.disp[s_uCurDispBuffer].pmode.EN2,
                                     s_xDoubleBuffer.disp[s_uCurDispBuffer].pmode.CRTMD,
                                     s_xDoubleBuffer.disp[s_uCurDispBuffer].pmode.MMOD,
                                     s_xDoubleBuffer.disp[s_uCurDispBuffer].pmode.AMOD,
                                     s_xDoubleBuffer.disp[s_uCurDispBuffer].pmode.SLBG,
                                     s_xDoubleBuffer.disp[s_uCurDispBuffer].pmode.ALP ) );
#endif //ENABLE_2_CIRCUIT_ANTI_ALIASING
    

    DPUT_GS_SMODE2( SCE_GS_SET_SMODE2( s_xDoubleBuffer.disp[s_uCurDispBuffer].smode2.INT,
                                       s_xDoubleBuffer.disp[s_uCurDispBuffer].smode2.FFMD,
                                       s_xDoubleBuffer.disp[s_uCurDispBuffer].smode2.DPMS ) );

    DPUT_GS_DISPFB2( SCE_GS_SET_DISPFB( s_xDoubleBuffer.disp[s_uCurDispBuffer].dispfb.FBP,
                                        s_xDoubleBuffer.disp[s_uCurDispBuffer].dispfb.FBW,
                                        s_xDoubleBuffer.disp[s_uCurDispBuffer].dispfb.PSM,
                                        s_xDoubleBuffer.disp[s_uCurDispBuffer].dispfb.DBX,
                                        s_xDoubleBuffer.disp[s_uCurDispBuffer].dispfb.DBY ) );

    int nDX = g_iDisplayOffsetX;
    int nDY = g_iDisplayOffsetY;
    // (MH - 30.05.2003) this extra offset should be constant for PAL, doing this
    // allow the settings to correct the TV display to be shared between PAL/NTSC.
    if (VideoModeIsPal())
    {
        nDY += dbg_iAdditionalScreenOffsetYForPAL;
    }

    DPUT_GS_DISPLAY2( SCE_GS_SET_DISPLAY2( nDX /* 0 */, /* s_xDoubleBuffer.disp[s_uCurDispBuffer].display.DX, */
                                           nDY /* 0 */, /* s_xDoubleBuffer.disp[s_uCurDispBuffer].display.DY, */
                                           s_xDoubleBuffer.disp[s_uCurDispBuffer].display.MAGH,
                                           s_xDoubleBuffer.disp[s_uCurDispBuffer].display.MAGV,
                                           s_xDoubleBuffer.disp[s_uCurDispBuffer].display.DW,
                                           s_xDoubleBuffer.disp[s_uCurDispBuffer].display.DH ) );


#if ENABLE_2_CIRCUIT_ANTI_ALIASING
    DPUT_GS_DISPFB1( SCE_GS_SET_DISPFB( s_xDoubleBuffer.disp[s_uCurDispBuffer].dispfb.FBP,
                                        s_xDoubleBuffer.disp[s_uCurDispBuffer].dispfb.FBW,
                                        s_xDoubleBuffer.disp[s_uCurDispBuffer].dispfb.PSM,
                                        s_xDoubleBuffer.disp[s_uCurDispBuffer].dispfb.DBX,
                                        s_xDoubleBuffer.disp[s_uCurDispBuffer].dispfb.DBY ) );

    DPUT_GS_DISPLAY1( SCE_GS_SET_DISPLAY2( nDX, /* s_xDoubleBuffer.disp[s_uCurDispBuffer].display.DX, */
                                           nDY + 1, /* s_xDoubleBuffer.disp[s_uCurDispBuffer].display.DY, */
                                           s_xDoubleBuffer.disp[s_uCurDispBuffer].display.MAGH,
                                           s_xDoubleBuffer.disp[s_uCurDispBuffer].display.MAGV,
                                           s_xDoubleBuffer.disp[s_uCurDispBuffer].display.DW,
                                           s_xDoubleBuffer.disp[s_uCurDispBuffer].display.DH ) );
#endif //ENABLE_2_CIRCUIT_ANTI_ALIASING

    DPUT_GS_BGCOLOR( SCE_GS_SET_BGCOLOR( s_xDoubleBuffer.disp[s_uCurDispBuffer].bgcolor.R,
                                         s_xDoubleBuffer.disp[s_uCurDispBuffer].bgcolor.G,
                                         s_xDoubleBuffer.disp[s_uCurDispBuffer].bgcolor.B ) );

    asm("sync.l");
}


void Asura_PS2_GS::SwapScreenBuffers( bool bPutDrawEnv )
{
    if( !IsDisplayBufferFixed() )
    {
        s_uCurDispBuffer ^= 1;
    }

    // Not necessary if we're not flipping but do it anyway to simplify
    // dealing with changing video mode.
    PutDispEnvExplicit();

    if( bPutDrawEnv ) { sceGsPutDrawEnv( s_uCurDispBuffer ? &s_xDoubleBuffer.giftag1 : &s_xDoubleBuffer.giftag0 ); }
    
    Asura_PS2_BetterGsSyncPath( 0, 0 );
}
// End Function 'Asura_PS2_GS::SwapScreenBuffers'

#ifndef ASURA_PS2_SONY_SUBMISSION
void Asura_PS2_GS::EnableDrawToFrontBfr( bool bOn )
{
    Asura_PS2_BetterGsSyncPath( 0, 0 );

    if( bOn )
    {
        // May be coming out of some situation where the display buffer isn't
        // set to what we expect so fix that up.
        PutDispEnvExplicit();

        // And now we want the draw buffer set to be the same place.
        sceGsPutDrawEnv( s_uCurDispBuffer ? &s_xDoubleBuffer.giftag0 : &s_xDoubleBuffer.giftag1 );
    }
    else
    {
        sceGsPutDrawEnv( s_uCurDispBuffer ? &s_xDoubleBuffer.giftag1 : &s_xDoubleBuffer.giftag0 );
    }

    Asura_PS2_BetterGsSyncPath( 0, 0 );
}
#endif

u_int Asura_PS2_GS::GetCurDispBuff( void )
{
    if( IsDisplayBufferFixed() )
    {
        return s_uCurDispBuffer;
    }
    else
    {
		// note that this returns the disp buffer index for deferred rendering which is the 
		// other one as far as the non-deferred current state is concerned.
        return( 1 - s_uCurDispBuffer );
    }
}

void Asura_PS2_GS::SetFramerateTarget( float fTarget )
{
    s_fTargetFrameRate = fTarget;
}

void Asura_PS2_GS::FillDrawBuffer( u_int uABGR /*= 0*/, bool bClearZBuffer /*= true*/ )
{
    const u_int uFBP    = GetDrawBfrFBP();
    const u_int uWidth  = GetScreenWidth();
    const u_int uHeight = GetScreenHeight();

    const u_int uNLOOP    = 4 + Asura_PS2_2D_Graphics::GetNumQWsForSpriteStrips(uWidth, false) + 1;
    const u_int uQWC      = 1 + uNLOOP;
    const u_int uTotalQWs = 1 + uQWC;

    Asura_PS2_QW* const pxBase = Asura_PS2_DeferredRendering::GetVifBuffer( uTotalQWs );
    Asura_PS2_QW* pxOut = pxBase;

    // DMA tag.
    (reinterpret_cast<Asura_PS2_DmaTag*>(pxOut++))->Set( uQWC,
                                                         Asura_PS2_DmaTag::PCE_NOCHANGE,
                                                         Asura_PS2_DmaTag::ID_CNT,
                                                         0,
                                                         false,
                                                         0,
                                                         SCE_VIF1_SET_NOP(false),
                                                         SCE_VIF1_SET_DIRECT(uQWC, false) );

    // GIF tag.
    {
        const u_int uPRIM = SCE_GS_SET_PRIM( SCE_GS_PRIM_SPRITE, // PRIM
                                             0,                  // IIP
                                             false,              // TME
                                             false,              // FGE
                                             false,              // ABE
                                             false,              // AA1
                                             0,                  // FST
                                             0,                  // CTXT
                                             0 );                // FIX

        (reinterpret_cast<Asura_PS2_GifTag*>(pxOut++))->Set( uNLOOP, true, true, uPRIM, SCE_GIF_PACKED, 1, SCE_GIF_PACKED_AD );
    }

    // (PSJE - 03.03.2003) Make sure that frame writes are unmasked before we clear the screen
    pxOut->u64s[0] = SCE_GS_SET_FRAME_1( uFBP,                   // FBP   - Frame buffer base pointer as word address / 2048.
                                         uWidth >> 6,            // FBW   - Frame buffer width in units of pixels / 64.
                                         GetDrawBfrPSM(),        // PSM   - Frame buffer storage format.
                                         0 );                    // FBMSK - Frame buffer write mask - allow writing to all
    pxOut->u64s[1] = SCE_GS_FRAME_1;
    ++pxOut;

    // Enable/Disable z writes
    pxOut->u64s[0] = SCE_GS_SET_ZBUF_1( GetZBfrBasePtr(),           // ZBP   - Z buffer base pointer as word address / 2048.
                                        GetZBfrPSM(),               // PSM   - Z buffer storage format.
                                        (bClearZBuffer) ? 0 : 1 );  // ZMSK  - Z buffer write mask; 1 => Z buffer is not updated.
    pxOut->u64s[1] = SCE_GS_ZBUF_1;
    ++pxOut;

    // Setup pixel test: disable both alpha test and depth test (though we
    // disable the depth test in a roundabout way to work around a known bug.)
    pxOut->u64s[0] = SCE_GS_SET_TEST_1( false,                  // ATE   - Alpha test on iff true.
                                        0,                      // ATST  - Alpha test method. Irrelevant if ATE is false.
                                        0,                      // AREF  - Alpha reference value. Irrelevant if ATE is false.
                                        0,                      // AFAIL - Behaviour when alpha test fails. Irrelevant if ATE is false.
                                        false,                  // DATE  - Destination alpha test on iff true.
                                        0,                      // DATM  - Destination alpha test method. Irrelevant if DATE is false.
                                        true,                   // ZTE   - Depth test on iff true.
                                        SCE_GS_ZALWAYS );       // ZTST  - Depth test method. SCE_GS_ZALWAYS = all pixels pass regardless, ie. equivalent to no depth test.
    pxOut->u64s[1] = SCE_GS_TEST_1;
    ++pxOut;

    // Set RGBAQ of sprite.
    pxOut->u64s[0] = uABGR;
    pxOut->u64s[1] = SCE_GS_RGBAQ;
    ++pxOut;

    // Write strips.
    {
        const u_int uX = ASURA_PS2_SCREEN_CENTRE_X - (uWidth  >> 1);
        const u_int uY = ASURA_PS2_SCREEN_CENTRE_Y - (uHeight >> 1);
        pxOut = Asura_PS2_2D_Graphics::WriteSpriteStrips( pxOut, uX, uY, uWidth, uHeight, false );
    }

    // (PSJE - 03.03.2003) Re mask frame writes
    pxOut->u64s[0] = SCE_GS_SET_FRAME_1( uFBP,                 // FBP   - Frame buffer base pointer as word address / 2048.
                                         uWidth >> 6,          // FBW   - Frame buffer width in units of pixels / 64.
                                         GetDrawBfrPSM(),      // PSM   - Frame buffer storage format.
                                         GetRGBAFrameMask() ); // FBMSK - Frame buffer write mask - allow writing to all
    pxOut->u64s[1] = SCE_GS_FRAME_1;
    ++pxOut;

    Asura_Assert( static_cast<u_int>(pxOut - pxBase) == uTotalQWs, "" );
}

void Asura_PS2_GS::AllowFullScreenRendering( void )
{
    SetupViewport( -1 );
}

void Asura_PS2_GS::CacheViewportParams( u_int uCameras /*= UINT_MAX*/ )
{
    // Pixel offsets from frame buffer origin.
    const int iScreenOriginX = ASURA_PS2_SCREEN_CENTRE_X - (s_sScreenWidth  >> 1);
    const int iScreenOriginY = ASURA_PS2_SCREEN_CENTRE_Y - (s_sScreenHeight >> 1);

    const u_int uNumCams = Asura_Camera::GetNumberOfCameras();
    for( u_int uCam = 0; uCam < uNumCams; ++uCam )
    {
		if ((uCameras & (1 << uCam)) == 0) { continue; }

        Asura_Camera::SetCameraIndex( uCam );

        const Asura_ViewingArea* pxArea = Asura_Camera::GetViewingArea();

        int iX = Asura_Maths::FloatToInt_Near( pxArea->m_fXOffset * s_sScreenWidth  );
        int iY = Asura_Maths::FloatToInt_Near( pxArea->m_fYOffset * s_sScreenHeight );
        int iW = Asura_Maths::FloatToInt_Near( pxArea->m_fWidth   * s_sScreenWidth  );
        int iH = Asura_Maths::FloatToInt_Near( pxArea->m_fHeight  * s_sScreenHeight );

        s_axViewportParams[uCam].sOriginX = iX;
        s_axViewportParams[uCam].sOriginY = iY;
        s_axViewportParams[uCam].sWidth   = iW;
        s_axViewportParams[uCam].sHeight  = iH;

        int iHalfW = iW >> 1;
        int iHalfH = iH >> 1;

        s_axViewportParams[uCam].sPrimTransX = (ASURA_PS2_SCREEN_CENTRE_X - (iX + iHalfW)) << 4;
        s_axViewportParams[uCam].sPrimTransY = (ASURA_PS2_SCREEN_CENTRE_Y - (iY + iHalfH)) << 4;
    }

	// If we are updating all cameras, update the non-camera specific parameters
	if (uCameras == UINT_MAX)
	{
		// Fake entry for full screen rendering.
		s_axViewportParams[ASURA_MAX_NO_OF_CAMERAS].sOriginX    = 0;
		s_axViewportParams[ASURA_MAX_NO_OF_CAMERAS].sOriginY    = 0;
		s_axViewportParams[ASURA_MAX_NO_OF_CAMERAS].sWidth      = s_sScreenWidth;
		s_axViewportParams[ASURA_MAX_NO_OF_CAMERAS].sHeight     = s_sScreenHeight;
		s_axViewportParams[ASURA_MAX_NO_OF_CAMERAS].sPrimTransX = iScreenOriginX << 4;
		s_axViewportParams[ASURA_MAX_NO_OF_CAMERAS].sPrimTransY = iScreenOriginY << 4;
	}
}

//////////////////////////////////////////////////////////////////////////////
//
// FUNCTION     Asura_PS2_GS::SetupViewport().
// PARAMETERS   iCamID - Camera whose viewport should be setup. A camera ID
//                       of -1 means fullscreen.
// RETURNS      None.
// DESCRIPTION  Sets up viewport for specified camera. Blocks until transfer
//              to GS is complete.
// AUTHOR       Mike Healey.
// MODIFIED     MP - 31.05.2002 - Now setting both contexts' SCISSOR register.
//              MP - 05.06.2002 - Now implemented via the method
//                                GetViewportSetupGifCmds().
//              PSJE - 11.10.2002 - Changed to use path2 instead of path3  - for mskpath3 implementation
//
//////////////////////////////////////////////////////////////////////////////
void Asura_PS2_GS::SetupViewport( int iCamID )
{
    const u_int uNumQWs = NUM_QWS_FOR_VIEWPORT_SETUP+1;
    const u_int uNLOOP  = uNumQWs - 2;

    Asura_PS2_QW* const pxBase = Asura_PS2_DeferredRendering::GetVifBuffer(NUM_QWS_FOR_VIEWPORT_SETUP+1);
    Asura_PS2_QW* pxOut = pxBase;

    // Create a DMA tag
    pxOut->u32s[0] = PY_DMA_CNT | NUM_QWS_FOR_VIEWPORT_SETUP;
    pxOut->u32s[1] = 0;
    pxOut->u32s[2] = 0;
    pxOut->u32s[3] = SCE_VIF1_SET_DIRECT( uNumQWs-1, 0 ) ;
    pxOut++;

    // Write GIF tag.
    pxOut->u64s[0] = SCE_GIF_SET_TAG( uNLOOP,               // NLOOP 
                                      1,                // EOP  (End Of Packet)
                                      NULL,             // PRE  (PRIM field Enable)
                                      NULL,             // PRIM
                                      SCE_GIF_PACKED,   // FLG  (Data format, 0 = PACKED, 1 = REGLIST, 2 = IMAGE)
                                      1 );              // NREG (Number of registers)
    pxOut->u64s[1] = SCE_GIF_PACKED_AD;
    pxOut++;

    // Write register settings.
    pxOut = GetViewportSetupGifCmds( iCamID, CONTEXTS_1_AND_2, pxOut );

    Asura_Assert( static_cast<u_int>(pxOut - pxBase) == (uNumQWs), "" );
}
// End function Asura_PS2_GS::SetupViewport().

//////////////////////////////////////////////////////////////////////////////
//
// FUNCTION     Asura_PS2_GS::GetViewportSetupGifCmds().
// PARAMETERS   iCamID   - ID of the camera whose settings should be applied.
//                         A camera ID of -1 means fullscreen.
//              uContext - Which context(s) need the settings. A value of 1
//                         or 2 specifies just that context; any other value
//                         specifies both.
//              pxQW     - Base address of buffer to be written to.
// RETURNS      Ptr to QW after end of GIF cmds.
// DESCRIPTION  Writes GIF cmds with viewport settings for the specified
//              camera to the specified buffer. The caller needs to deal
//              with the GIF tag (and sending the data, of course.) The GIF
//              tag should specify A+D register(s) being set per iteration.
//              This function will write 2 QWs per context required.
// AUTHOR       MP - 07.05.2002.
// MODIFIED     MP - 05.06.2002 - Renamed from SetViewport_NonBlocking().
//                                Now setting XYOFFSET register too.
//                                Now (optionally) sets both contexts.
//
//////////////////////////////////////////////////////////////////////////////
Asura_PS2_QW* Asura_PS2_GS::GetViewportSetupGifCmds( int iCamID, RenderContext eContext, Asura_PS2_QW* pxOut )
{
    // (MP - 17.06.2002) NB: If the number of QWs output here changes, be
    // sure to update Asura_PS2_GS::NUM_QWS_FOR_VIEWPORT_SETUP and
    // Asura_PS2_GS::NUM_QWS_FOR_VIEWPORT_SETUP_PER_CONTEXT.

    bool bIsFullScreenRendering = ( -1 == iCamID );
    s_bFullScreenRendering = bIsFullScreenRendering;

    const ViewportParams& xViewportParams = s_axViewportParams[bIsFullScreenRendering ? ASURA_MAX_NO_OF_CAMERAS : iCamID];

    const u_long uSCISSOR = SCE_GS_SET_SCISSOR( xViewportParams.sOriginX,
                                                xViewportParams.sOriginX + xViewportParams.sWidth - 1,
                                                xViewportParams.sOriginY,
                                                xViewportParams.sOriginY + xViewportParams.sHeight - 1 );

    const u_long uXYOFFSET = SCE_GS_SET_XYOFFSET( xViewportParams.sPrimTransX, xViewportParams.sPrimTransY );

    for( u_int u = 0; u < 2; ++u )
    {
        // Skip if they only want the other context.
        if( static_cast<u_int>(eContext) == (u ^ 1) ) { continue; }

        pxOut->u64s[0] = uSCISSOR;
        pxOut->u64s[1] = SCE_GS_SCISSOR_1 + u;
        ++pxOut;
        pxOut->u64s[0] = uXYOFFSET;
        pxOut->u64s[1] = SCE_GS_XYOFFSET_1 + u;
        ++pxOut;
    }

    return pxOut;
}


void Asura_PS2_GS::BeginFrame(void)
{
    CacheViewportParams();
}


void Asura_PS2_GS::EndFrame(void)
{
#ifndef ASURA_PS2_SONY_SUBMISSION
    if( dbg_bDisplayFrameBufferAlphaChannel ) { ShowAlphaChannel(); }
    if( dbg_bDisplayZBuffer                 ) { ShowZBuffer();      }
#endif

    if( g_pfnEndFrameCB )
    {
        g_pfnEndFrameCB();
    }

    ASURA_PS2_PROFILE__ADD_EE_END( ASURA_PS2_PROFILE__TOTAL_FRAME_MARKER )

    // Wait for the previous frame to finish drawing
    Asura_PS2_DeferredRendering::WaitForDeferredRendering();

#ifndef ASURA_PS2_SONY_SUBMISSION
    if( dbg_bIncludeDebugInfoInScreenshots || (!Asura_ScreenShot_System::IsScreenShotPending()) )
    {
        Asura_PS2_DebugInfo::Render();
    }
#endif

	Asura_ScreenShot_System::DrawBufferIsReady();

    Asura_PS2_ProfilingSystem::Update();

    if( s_bEnableVsync )
    {
        sceGsSyncV( 0 );
    }

    DoMotionBlurOrBackToFrontBlit( false );

    if( s_bAutoScreenBufferSwap )
    {
        SwapScreenBuffers( true );
    }

    ASURA_PS2_PROFILE__ADD_VIF_END( ASURA_PS2_PROFILE__TOTAL_FRAME_MARKER )

    // Send the last frames draw list off to be drawn
    Asura_PS2_DeferredRendering::SendDeferredRenderingBlock();
    
    ASURA_PS2_PROFILE__ADD_VIF_START( ASURA_PS2_PROFILE__TOTAL_FRAME_MARKER )
    ASURA_PS2_PROFILE__ADD_EE_START( ASURA_PS2_PROFILE__TOTAL_FRAME_MARKER )

    // Clear the ZBuffer or Frame buffer (or both :oO)
    Asura_Assert( !(s_bClearDrawBufferOnSwap && s_bClearZBufferOnSwap), "ClearZBuffer and ClearFrameBuffer enabled... choose one or the other" );
    if(Asura_Render::GetEnableScreenClear() && (s_bClearDrawBufferOnSwap || Asura_Render::GetWireframe()) )
    {
        FillDrawBuffer( s_uClearColour, true );
    }
    else if (s_bClearZBufferOnSwap)
    {
        ClearZBuffer();
    }
}


void Asura_PS2_GS::SetEndFrameCallback( void(*pfnCallback)(void) )
{
    g_pfnEndFrameCB = pfnCallback;
}


void Asura_PS2_GS::SetMotionBlur(bool on_off)
{
    g_bMotionBlurOn = on_off;
}


void Asura_PS2_GS::SetMotionBlurValue( u_char ucValue )
{
    g_ucMotionBlurValue = ucValue;
}


void Asura_PS2_GS::DoMotionBlurOrBackToFrontBlit( bool bBlitOnly )
{
    // (MP - 08.10.2003)
    //
    // Four cases:
    //
    //     (i) std double buffering, alpha blend off
    //             - nothing to do here
    //
    //    (ii) std double buffering, alpha blend on
    //             - blend front buffer into back buffer
    //
    //   (iii) 32 back / 16 front, alpha blend off
    //             - blit back buffer into front buffer, using dithering
    //
    //    (iv) 32 back / 16 front, alpha blend on
    //             - blend back buffer over front buffer, using dithering
    //
    // We treat (iii) is simply a special case of (iv). Cases (ii)-(iv) all
    // consist of a full screen blit, just with varying src/dst and blend
    // settings, and a couple of extra register settings for (iii) and (iv).
    //
    // Note that the src is *always* the draw buffer. Two cases:
    //
    //     (i) std double buffering
    //             - disp/draw is swapped as we have a one frame latency
    //               from deferred rendering
    //             - however, we're doing this outside the usual deferred
    //               rendering chains and so we need to undo this swap
    //
    //    (ii) 32 back / 16 front
    //             - dst has to be disp bfr hence src has to be draw bfr
    //             - but we then need to invert the alpha blend
    //                

    if( !IsDisplayBufferFixed() && (bBlitOnly || !g_bMotionBlurOn) ) { return; }

    u_long uAlphaFIX;

    // Determine required FIX value for alpha blend.
    {
        uAlphaFIX = g_ucMotionBlurValue;

        if( bBlitOnly || !g_bMotionBlurOn )
        {
            uAlphaFIX = 0;
        }

        if( IsDisplayBufferFixed() )
        {
            // Same as regular flipping case except dst and src are reversed.
            // Just invert alpha value.
            uAlphaFIX = 128 - uAlphaFIX;
        }
    }

    const u_int uWidth  = GetScreenWidth();
    const u_int uHeight = GetScreenHeight();

    u_int uNLOOP = NUM_QWS_FOR_VIEWPORT_SETUP_PER_CONTEXT + 2 + Asura_PS2_2D_Graphics::GetNumQWsForSpriteStrips(uWidth, true);
    if( IsDisplayBufferFixed() )
    {
        uNLOOP += 5;
    }

    const u_int uQWC = Asura_PlatformRenderStates::NUM_RENDERSTATE_PACKET_QWS + 1 + uNLOOP;

    Asura_PS2_QW* const pxBase = Asura_PS2_SPR_Alloc( 0, uQWC );
    Asura_PS2_QW* pxOut = pxBase;

    Asura_PlatformRenderStates::CreateDefaultRenderStatePacket( Asura_PlatformRenderStates::CONTEXT_1, pxOut, false, true );
    Asura_PlatformRenderStates::SetAlphaBlend( SCE_GS_ALPHA_CS, SCE_GS_ALPHA_CD, SCE_GS_ALPHA_FIX, SCE_GS_ALPHA_CD, uAlphaFIX );
    Asura_PlatformRenderStates::SetPixelTest( false, false );
    Asura_PlatformRenderStates::SetTextureClamp( true );
    Asura_PlatformRenderStates::ForgetMyBuffer( pxOut );
    pxOut += Asura_PlatformRenderStates::NUM_RENDERSTATE_PACKET_QWS;

    (reinterpret_cast<Asura_PS2_GifTag*>(pxOut++))->Set( uNLOOP,              // NLOOP                    
                                                         true,                // EOP
                                                         true,                // PRE
                                                         SCE_GS_SET_PRIM( SCE_GS_PRIM_SPRITE, // PRIM
                                                                          0,                  // IIP
                                                                          true,               // TME
                                                                          false,              // FGE
                                                                          true,               // ABE
                                                                          false,              // AA1
                                                                          1,                  // FST
                                                                          0,                  // CTXT
                                                                          0 ),                // FIX
                                                         SCE_GIF_PACKED,      // FLG
                                                         1,                   // NREG
                                                         SCE_GIF_PACKED_AD ); // REG0

    if( IsDisplayBufferFixed() )
    {
        // Need to draw this in the front buffer then...
        pxOut->u64s[0] = reinterpret_cast<u_long&>( s_xDoubleBuffer.draw11.frame1 );
        pxOut->u64s[1] = SCE_GS_FRAME_1;
        ++pxOut;
        // ... with dithering on.
        pxOut->u64s[0] = SCE_GS_SET_DTHE( dbg_bUseDitherForBackBfrToFrontBfrBlit );
        pxOut->u64s[1] = SCE_GS_DTHE;
        ++pxOut;
        pxOut->u64s[0] = 0x0716524334256170; // Value stolen from PS2 Shell code.
        pxOut->u64s[1] = SCE_GS_DIMX;
        ++pxOut;
    }
    
    pxOut = GetViewportSetupGifCmds( -1, CONTEXT_1, pxOut );

    pxOut->u64s[0] = SCE_GS_SET_TEX0( GetDrawBfrFBP() << 5, // TBP0
                                      uWidth >> 6,          // TBW
                                      GetDrawBfrPSM(),      // PSM
                                      10, 10,               // TW, TH - using UVs so just set to maximum.
                                      SCE_GS_DECAL, 1,      // TFX, TCC
                                      0, 0, 0, 0, 0 );      // CLUT stuff - irrelevant.
    pxOut->u64s[1] = SCE_GS_TEX0_1;
    ++pxOut;

    // Note: 1:1 copy so no filtering required.
    pxOut->u64s[0] = SCE_GS_SET_TEX1( 1, 0,                           // LOD, MXL
                                      SCE_GS_NEAREST, SCE_GS_NEAREST, // MMAG, MMIN
                                      0,                              // MTBA
                                      0, 0 );                         // L, K
    pxOut->u64s[1] = SCE_GS_TEX1_1;
    ++pxOut;

    // Write strips.
    {
        const u_int uX = ASURA_PS2_SCREEN_CENTRE_X - (uWidth  >> 1);
        const u_int uY = ASURA_PS2_SCREEN_CENTRE_Y - (uHeight >> 1);

        pxOut = Asura_PS2_2D_Graphics::WriteSpriteStrips( pxOut, uX, uY, uWidth, uHeight, true, 0, 0, uWidth, uHeight );
    }

    if( IsDisplayBufferFixed() )
    {
        pxOut->u64s[0] = reinterpret_cast<u_long&>( s_xDoubleBuffer.draw01.frame1 );
        pxOut->u64s[1] = SCE_GS_FRAME_1;
        ++pxOut;

        pxOut->u64s[0] = SCE_GS_SET_DTHE( false );
        pxOut->u64s[1] = SCE_GS_DTHE;
        ++pxOut;
    }

    Asura_Assert( static_cast<u_int>(pxOut - pxBase) == uQWC, "" );

    Asura_PS2_DMA::NormalTransferFromMem( Asura_PS2_DMA::CHANNEL_GIF, pxBase, uQWC, true, true, true );

    Asura_PS2_SPR_Dealloc( pxBase );
}

int Asura_PS2_BetterGsSyncPath( int iMode, unsigned short uTimeout )
{
    if( iMode )
    {
        return sceGsSyncPath( iMode, uTimeout );
    }
    else
    {
        // To allow you to see what's actually busy...
        // (MP - 30.05.2002) TODO: May need to add proper timeout support
        // here.
        int iBusyStatus = -1;
        do
        {
            iBusyStatus = sceGsSyncPath( 1, 1 );

            int iBit0_DMA1 = (iBusyStatus & (1 << 0));
            int iBit1_DMA2 = (iBusyStatus & (1 << 1));
            int iBit2_VIF1 = (iBusyStatus & (1 << 2));
            int iBit3_VU1  = (iBusyStatus & (1 << 3));
            int iBit4_GIF  = (iBusyStatus & (1 << 4));
        }
        while( iBusyStatus );

        return 0;
    }
}

void Asura_PS2_GS::ClearZBuffer( void )
{
    const u_int uWidth  = GetScreenWidth();
    const u_int uHeight = GetScreenHeight();
    const u_int uTBW    = (uWidth + 63) >> 6;
    const u_int uPSMZ   = GetZBfrPSM();

    // If the screen is a multiple of 64 pixels high we can clear it faster
    // by setting the frame buffer to be half way through the z buffer, then
    // just drawing half screen height strips across the screen, thus
    // clearing the top half of the z buffer with the z writes and the bottom
    // half of the z buffer with the frame writes. If the screen is not a
    // multiple of 64 pixels high we can do most of the screen using this
    // method, and clear the bottom row of pages with a standard clear.
    const bool bNeedExtraClear = ( (uHeight & 63) != 0 );
    const u_int uHalfHeight = (uHeight & ~63) >> 1;

    const u_int uNLOOP    = NUM_QWS_FOR_VIEWPORT_SETUP_PER_CONTEXT + 4 + (Asura_PS2_2D_Graphics::GetNumQWsForSpriteStrips(uWidth, false) << (bNeedExtraClear ? 1 : 0)) + 1;
    const u_int uQWC      = 1 + uNLOOP;
    const u_int uTotalQWs = 1 + uQWC;

    Asura_PS2_QW* const pxBase = Asura_PS2_DeferredRendering::GetVifBuffer( uTotalQWs );
    Asura_PS2_QW* pxOut = pxBase;

    // DMA tag.
    (reinterpret_cast<Asura_PS2_DmaTag*>(pxOut++))->Set( uQWC,
                                                         Asura_PS2_DmaTag::PCE_NOCHANGE,
                                                         Asura_PS2_DmaTag::ID_CNT,
                                                         0,
                                                         false,
                                                         0,
                                                         SCE_VIF1_SET_NOP(false),
                                                         SCE_VIF1_SET_DIRECT(uQWC, false) );

    // GIF tag.
    {
        const u_int uPRIM = SCE_GS_SET_PRIM( SCE_GS_PRIM_SPRITE, // PRIM
                                             0,                  // IIP
                                             false,              // TME
                                             false,              // FGE
                                             false,              // ABE
                                             false,              // AA1
                                             0,                  // FST
                                             0,                  // CTXT
                                             0 );                // FIX

        (reinterpret_cast<Asura_PS2_GifTag*>(pxOut++))->Set( uNLOOP, true, true, uPRIM, SCE_GIF_PACKED, 1, SCE_GIF_PACKED_AD );
    }

    // Ensure viewport is setup correctly.
    pxOut = GetViewportSetupGifCmds( -1, CONTEXT_1, pxOut );

    const u_short usZBP = GetZBfrBasePtr();

    // Setup frame buffer to half way down z-buffer.
    {
        const u_int uHalfZBufferOffset = usZBP + ((uWidth * uHalfHeight) >> 11);

        pxOut->u64s[0] = SCE_GS_SET_FRAME_1( uHalfZBufferOffset, // FBP
                                             uWidth >> 6,        // FBW
                                             uPSMZ,              // PSM
                                             0 );                // FBMSK
        pxOut->u64s[1] = SCE_GS_FRAME_1;
        ++pxOut;
    }

    // Set z buffer to start of z-buffer and ensure Z writes are enabled.
    pxOut->u64s[0] = SCE_GS_SET_ZBUF_1( usZBP,  // ZBP   - Z buffer base pointer as word address / 2048.
                                        uPSMZ,  // PSM   - Z buffer storage format.
                                        0 );    // ZMSK  - Z buffer write mask; 0 => Z buffer is updated.
    pxOut->u64s[1] = SCE_GS_ZBUF_1;
    ++pxOut;

    // Setup pixel test: disable both alpha test and depth test (though we
    // disable the depth test in a roundabout way to work around a known bug.)
    pxOut->u64s[0] = SCE_GS_SET_TEST_1( false,            // ATE
                                        0,                // ATST
                                        0,                // AREF
                                        0,                // AFAIL
                                        false,            // DATE
                                        0,                // DATM
                                        true,             // ZTE
                                        SCE_GS_ZALWAYS ); // ZTST
    pxOut->u64s[1] = SCE_GS_TEST_1;
    ++pxOut;

    // Set RGBA to black for equivalent to Z=0.
    pxOut->u64s[0] = SCE_GS_SET_RGBAQ( 0, 0, 0, 0, 0x3F800000 );
    pxOut->u64s[1] = SCE_GS_RGBAQ;
    ++pxOut;

    // Clear the top 95%-100% of the z-buffer using z+frame writes.
    {
        const u_int uX = ASURA_PS2_SCREEN_CENTRE_X - (uWidth  >> 1);
        const u_int uY = ASURA_PS2_SCREEN_CENTRE_Y - (uHeight >> 1);

        pxOut = Asura_PS2_2D_Graphics::WriteSpriteStrips( pxOut, uX, uY, uWidth, uHalfHeight, false );
    }

    // If the screen isn't a multiple of 64 pixels high, we've got a little
    // bit more to clear at the bottom of the buffer.
    if( bNeedExtraClear )
    {
        const u_int uX = ASURA_PS2_SCREEN_CENTRE_X - (uWidth  >> 1);
        const u_int uY = ASURA_PS2_SCREEN_CENTRE_Y - (uHeight >> 1) + (uHalfHeight << 1);

        pxOut = Asura_PS2_2D_Graphics::WriteSpriteStrips( pxOut, uX, uY, uWidth, uHeight - (uHalfHeight << 1), false );
    }

    pxOut->u64s[0] = SCE_GS_SET_FRAME_1( GetDrawBfrFBP(),      // FBP
                                         uWidth >> 6,          // FBW
                                         GetDrawBfrPSM(),      // PSM
                                         GetRGBAFrameMask() ); // FBMSK
    pxOut->u64s[1] = SCE_GS_FRAME_1;
    ++pxOut;

    Asura_Assert( static_cast<u_int>(pxOut - pxBase) == uTotalQWs, "" );
}

void Asura_PS2_GS::ClearVRAM( void ) 
{
	Asura_PS2_GS::ClearVRAMColour( 0x0 );
}

void Asura_PS2_GS::ClearVRAMColour( const u_int uABGR )
{
    const u_int uWidth  = 1024;
    const u_int uHeight = 1024; 

    const u_int uNLOOP = 6 + Asura_PS2_2D_Graphics::GetNumQWsForSpriteStrips(uWidth, false);
    const u_int uQWC   = 1 + uNLOOP;

    Asura_PS2_QW* const pxBase = Asura_PS2_SPR_Alloc( 0, uQWC );
    Asura_PS2_QW* pxOut = pxBase;

    // GIF tag.
    {
        const u_int uPRIM = SCE_GS_SET_PRIM( SCE_GS_PRIM_SPRITE, // PRIM
                                             0,                  // IIP
                                             false,              // TME
                                             false,              // FGE
                                             false,              // ABE
                                             false,              // AA1
                                             0,                  // FST
                                             0,                  // CTXT
                                             0 );                // FIX

        (reinterpret_cast<Asura_PS2_GifTag*>(pxOut++))->Set( uNLOOP,
                                                             true,
                                                             true,
                                                             uPRIM,
                                                             SCE_GIF_PACKED,
                                                             1,
                                                             SCE_GIF_PACKED_AD );
    }

    // Setup frame buffer.
    pxOut->u64s[0] = SCE_GS_SET_FRAME_1( 0,              // FBP
                                         uWidth >> 6,    // FBW
                                         SCE_GS_PSMCT32, // PSM
                                         0 );            // FBMSK
    pxOut->u64s[1] = SCE_GS_FRAME_1;
    ++pxOut;

    // Disable writes to the Z buffer.
    pxOut->u64s[0] = SCE_GS_SET_ZBUF( 0, 0, 1 );
    pxOut->u64s[1] = SCE_GS_ZBUF_1;
    ++pxOut;

    pxOut->u64s[0] = SCE_GS_SET_XYOFFSET( 0, 0 );
    pxOut->u64s[1] = SCE_GS_XYOFFSET_1;
    ++pxOut;
    pxOut->u64s[0] = SCE_GS_SET_SCISSOR_1( 0, uWidth - 1, 0, uHeight - 1 );
    pxOut->u64s[1] = SCE_GS_SCISSOR_1;
    ++pxOut;

    pxOut->u64s[0] = SCE_GS_SET_TEST_1( false,            // ATE
                                        0,                // ATST
                                        0,                // AREF
                                        0,                // AFAIL
                                        false,            // DATE
                                        0,                // DATM
                                        true,             // ZTE
                                        SCE_GS_ZALWAYS ); // ZTST
    pxOut->u64s[1] = SCE_GS_TEST_1;
    ++pxOut;

    pxOut->u64s[0] = (u_long)( uABGR ) | ( (u_long)(0x3f800000) << 32 );
    pxOut->u64s[1] = SCE_GS_RGBAQ;
    ++pxOut;

    pxOut = Asura_PS2_2D_Graphics::WriteSpriteStrips( pxOut, 0, 0, uWidth, uHeight, false );

    Asura_Assert( static_cast<u_int>(pxOut - pxBase) == uQWC, "" );

    // Just to be paranoid, make sure channel 2 is idle.
    while( *D2_CHCR & D_CHCR_STR_M ) { }

    // Send.
    Asura_PS2_DMA::NormalTransferFromMem( Asura_PS2_DMA::CHANNEL_GIF, pxBase, uQWC, true, true, true );

    Asura_PS2_SPR_Dealloc( pxBase );

    // We've just splatted the entirety of VRAM so it's unlikely anything the
    // texture management thinks it's uploaded has survived.
    Asura_PS2_TextureManagement::InvalidateAllTextureBuffers();
}


void Asura_PS2_GS::DebugClearFrame( u_char ucR, u_char ucG, u_char ucB, u_char ucA )
{
    const u_int uNumQWs     = 1 + (sizeof(sceGsClear) >> 4);
    const u_int uRoundedQWs = (uNumQWs + 3) & ~3;

    static Asura_PS2_QW axBfr[uRoundedQWs] __attribute__ ((aligned(64)));

    Asura_PS2_QW* const pxStart = Asura_PS2_UncachedMem( &axBfr[0] );

    Asura_PS2_GifTag* pxGifTag = reinterpret_cast<Asura_PS2_GifTag*>( pxStart );
    pxGifTag->Set( 6,                   // NLOOP
                   true,                // EOP
                   false,               // PRE
                   0,                   // PRIM
                   SCE_GIF_PACKED,      // FLG
                   1,                   // NREG
                   SCE_GIF_PACKED_AD ); // REG0

    {
        const u_int uWidth  = GetScreenWidth();
        const u_int uHeight = GetScreenHeight();
        const u_int uXStart = (ASURA_PS2_SCREEN_CENTRE_X - (uWidth  >> 1));
        const u_int uYStart = (ASURA_PS2_SCREEN_CENTRE_Y - (uHeight >> 1));

        sceGsClear* pxClearQWs = reinterpret_cast<sceGsClear*>( pxStart + 1 );
        sceGsSetDefClear( pxClearQWs, 1, uXStart, uYStart, uWidth, uHeight, ucR, ucG, ucB, ucA, 0 );
    }

    Asura_PS2_DMA::NormalTransferFromMem( Asura_PS2_DMA::CHANNEL_GIF, Asura_PS2_DMAMem(pxStart), uNumQWs, false, true, true );
}


// functions for use by screen adjust menus
void Asura_PS2_GS::SetScreenOffsets(int iX, int iY)
{
    if (iX < dbg_iMinScreenOffsetX) iX = dbg_iMinScreenOffsetX;
    if (iX > dbg_iMaxScreenOffsetX) iX = dbg_iMaxScreenOffsetX;
    if (iY < dbg_iMinScreenOffsetY) iY = dbg_iMinScreenOffsetY;
    if (iY > dbg_iMaxScreenOffsetY) iY = dbg_iMaxScreenOffsetY;

    g_iDisplayOffsetX = iX;
    g_iDisplayOffsetY = iY;
}

void Asura_PS2_GS::GetScreenOffsets(int& iX, int& iY)
{
    iX = g_iDisplayOffsetX;
    iY = g_iDisplayOffsetY;
}

void Asura_PS2_GS::GetScreenOffsetRanges(int& iMinX, int& iMinY, int& iMaxX, int& iMaxY)
{
    iMinX = dbg_iMinScreenOffsetX;
    iMinY = dbg_iMinScreenOffsetY;
    iMaxX = dbg_iMaxScreenOffsetX;
    iMaxY = dbg_iMaxScreenOffsetY;
}

void Asura_PS2_GS::GetScreenOffsetDefaults(int& iDefaultX, int& iDefaultY)
{
    iDefaultX = dbg_iDefaultScreenOffsetX;
    iDefaultY = dbg_iDefaultScreenOffsetY;
}

void Asura_PS2_GS::SetRGBAFrameMask(unsigned int uFM)
{ 
    // Record the new frame rgba mask
    s_uRGBAFrameMask = uFM;

    // Set the the mask in the drawlist
    Asura_PS2_QW* pxOut = Asura_PS2_DeferredRendering::GetVifBuffer(3);
    pxOut->u32s[0] = PY_DMA_CNT | (2);
    pxOut->u32s[1] = 0;
    pxOut->u32s[2] = SCE_VIF1_SET_NOP(false);
    pxOut->u32s[3] = SCE_VIF1_SET_DIRECT( (2), false );
    pxOut++;
    Asura_PS2_GifTag* const pxGifTag = reinterpret_cast<Asura_PS2_GifTag*>(pxOut);
    pxGifTag->Set( 1, true, false, 0, SCE_GIF_PACKED, 1, SCE_GIF_PACKED_AD );
    pxOut++;
    pxOut->u64s[0] = SCE_GS_SET_FRAME_1( GetDrawBfrFBP(),           // FBP   - Frame buffer base pointer as word address / 2048.
                                         GetScreenWidth()>>6,       // FBW   - Frame buffer width in units of pixels / 64.
                                         GetDrawBfrPSM(),           // PSM   - Frame buffer storage format.
                                         s_uRGBAFrameMask );        // FBMSK - Frame buffer write mask 
    pxOut->u64s[1] = SCE_GS_FRAME_1;
}

#ifndef ASURA_PS2_SONY_SUBMISSION

void Asura_PS2_GS::ShowAlphaChannel( void )
{
    // To display the alpha channel, change TFX to HIGHLIGHT2. That way,
    // Rs=Rt*Rf+Af (similarly for G and B) and As=At. If we then set
    // Rf=Gf=Bf=0 and Af=128, we get Rs=Gs=Bs=128 and As=At, meaning we get
    // Rd=Gd=Bd=At when using an alpha blend of Cd=Cs*As.

    Asura_Render::AllowFullScreenRendering();

    Asura_PlatformRenderStates::CreateDefaultRenderStatePacket( Asura_PlatformRenderStates::CONTEXT_1 );
    Asura_PlatformRenderStates::SetAlphaBlend( SCE_GS_ALPHA_CS, SCE_GS_ALPHA_ZERO, SCE_GS_ALPHA_AS, SCE_GS_ALPHA_ZERO, 0 );
    Asura_PlatformRenderStates::SetPixelTest( true, false, 0, SCE_GS_ALPHA_NEVER, SCE_GS_AFAIL_RGB_ONLY );
    Asura_PlatformRenderStates::ApplyRenderStates();

    const u_int uWidth  = GetScreenWidth();
    const u_int uHeight = GetScreenHeight();

    const u_int uNLOOP    = 8;
    const u_int uQWC      = 1 + uNLOOP;
    const u_int uTotalQWs = 1 + uQWC;

    Asura_PS2_QW* const pxBase = Asura_PS2_DeferredRendering::GetVifBuffer( uTotalQWs );
    Asura_PS2_QW* pxOut = pxBase;

    // DMA tag.
    (reinterpret_cast<Asura_PS2_DmaTag*>(pxOut++))->Set( uQWC,
                                                         Asura_PS2_DmaTag::PCE_NOCHANGE,
                                                         Asura_PS2_DmaTag::ID_CNT,
                                                         false,
                                                         0,
                                                         false,
                                                         SCE_VIF1_SET_NOP(false),
                                                         SCE_VIF1_SET_DIRECT(uQWC, false) );

    // GIF tag.
    {
        const u_int uPRIM = SCE_GS_SET_PRIM( SCE_GS_PRIM_SPRITE, // PRIM
                                             0,                  // IIP
                                             true,               // TME
                                             false,              // FGE
                                             true,               // ABE
                                             false,              // AA1
                                             1,                  // FST
                                             0,                  // CTXT
                                             0 );                // FIX

        (reinterpret_cast<Asura_PS2_GifTag*>(pxOut++))->Set( uNLOOP, true, true, uPRIM, SCE_GIF_PACKED, 1, SCE_GIF_PACKED_AD );
    }

    // Guess we'd better TEXFLUSH to be on the safe side, since we've
    // probably written to the frame buffer recently.
    (pxOut++)->u64s[1] = SCE_GS_TEXFLUSH;

    // TEX0.
    {
        const u_int uTBP = (GetCurDrawBuff() ? ASURA_PS2_FRAMEBFR_1_BASE_PTR : ASURA_PS2_FRAMEBFR_0_BASE_PTR) << 5;
        const u_int uTBW = (uWidth + 63) >> 6;
        const u_int uTW  = Asura_Maths::GetCeilLog2( uWidth );
        const u_int uTH  = Asura_Maths::GetCeilLog2( uHeight );

        pxOut->u64s[0] = SCE_GS_SET_TEX0( uTBP, uTBW, SCE_GS_PSMCT32, uTW, uTH, 1, SCE_GS_HIGHLIGHT2, 0, 0, 0, 0, 0 );
        pxOut->u64s[1] = SCE_GS_TEX0_1;
        ++pxOut;
    }

    // TEX1.
    pxOut->u64s[0] = SCE_GS_SET_TEX1( 0, 0, SCE_GS_NEAREST, SCE_GS_NEAREST, 0, 0, 0 );
    pxOut->u64s[1] = SCE_GS_TEX1_1;
    ++pxOut;

    // RGBAQ.
    pxOut->u64s[0] = SCE_GS_SET_RGBAQ( 0, 0, 0, 128, 0x3F800000 );
    pxOut->u64s[1] = SCE_GS_RGBAQ;
    ++pxOut;

    // TL vtx.
    pxOut->u64s[0] = SCE_GS_SET_UV( 0 << 4, 0 << 4 );
    pxOut->u64s[1] = SCE_GS_UV;
    ++pxOut;
    pxOut->u64s[0] = SCE_GS_SET_XYZ( (ASURA_PS2_SCREEN_CENTRE_X - (uWidth >> 1)) << 4, (ASURA_PS2_SCREEN_CENTRE_Y - (uHeight >> 1)) << 4, 0 );
    pxOut->u64s[1] = SCE_GS_XYZ2;
    ++pxOut;

    // BR vtx.
    pxOut->u64s[0] = SCE_GS_SET_UV( uWidth << 4, uHeight << 4 );
    pxOut->u64s[1] = SCE_GS_UV;
    ++pxOut;
    pxOut->u64s[0] = SCE_GS_SET_XYZ( (ASURA_PS2_SCREEN_CENTRE_X + (uWidth >> 1)) << 4, (ASURA_PS2_SCREEN_CENTRE_Y + (uHeight >> 1)) << 4, 0 );
    pxOut->u64s[1] = SCE_GS_XYZ2;
    ++pxOut;

    Asura_Assert( static_cast<u_int>(pxOut - pxBase) == uTotalQWs, "" );
}

void Asura_PS2_GS::ShowZBuffer( void )
{
    Asura_Assert( GetZBfrPSM() == SCE_GS_PSMZ24, "" );

    Asura_Render::AllowFullScreenRendering();

    Asura_PlatformRenderStates::CreateDefaultRenderStatePacket( Asura_PlatformRenderStates::CONTEXT_1 );
    Asura_PlatformRenderStates::SetPixelTest( true, false, 0, SCE_GS_ALPHA_NEVER, SCE_GS_AFAIL_FB_ONLY );
    Asura_PlatformRenderStates::ApplyRenderStates();

    const u_int uWidth  = GetScreenWidth();
    const u_int uHeight = GetScreenHeight();

    const u_int uNLOOP    = 7;
    const u_int uQWC      = 1 + uNLOOP;
    const u_int uTotalQWs = 1 + uQWC;

    Asura_PS2_QW* const pxBase = Asura_PS2_DeferredRendering::GetVifBuffer( uTotalQWs );
    Asura_PS2_QW* pxOut = pxBase;

    // DMA tag.
    (reinterpret_cast<Asura_PS2_DmaTag*>(pxOut++))->Set( uQWC,
                                                         Asura_PS2_DmaTag::PCE_NOCHANGE,
                                                         Asura_PS2_DmaTag::ID_CNT,
                                                         false,
                                                         0,
                                                         false,
                                                         SCE_VIF1_SET_NOP(false),
                                                         SCE_VIF1_SET_DIRECT(uQWC, false) );

    // GIF tag.
    {
        const u_int uPRIM = SCE_GS_SET_PRIM( SCE_GS_PRIM_SPRITE, // PRIM
                                             0,                  // IIP
                                             true,               // TME
                                             false,              // FGE
                                             false,              // ABE
                                             false,              // AA1
                                             1,                  // FST
                                             0,                  // CTXT
                                             0 );                // FIX

        (reinterpret_cast<Asura_PS2_GifTag*>(pxOut++))->Set( uNLOOP, true, true, uPRIM, SCE_GIF_PACKED, 1, SCE_GIF_PACKED_AD );
    }

    // Guess we'd better TEXFLUSH to be on the safe side, since we've
    // probably written to the frame buffer recently.
    (pxOut++)->u64s[1] = SCE_GS_TEXFLUSH;

    // TEX0.
    {
        const u_int uTBP = GetZBfrBasePtr() << 5;
        const u_int uTBW = (uWidth + 63) >> 6;
        const u_int uTW  = Asura_Maths::GetCeilLog2( uWidth );
        const u_int uTH  = Asura_Maths::GetCeilLog2( uHeight );

        pxOut->u64s[0] = SCE_GS_SET_TEX0( uTBP, uTBW, SCE_GS_PSMZ24, uTW, uTH, false, SCE_GS_DECAL, 0, 0, 0, 0, 0 );
        pxOut->u64s[1] = SCE_GS_TEX0_1;
        ++pxOut;
    }

    // TEX1.
    pxOut->u64s[0] = SCE_GS_SET_TEX1( 0, 0, SCE_GS_NEAREST, SCE_GS_NEAREST, 0, 0, 0 );
    pxOut->u64s[1] = SCE_GS_TEX1_1;
    ++pxOut;

    // TL vtx.
    pxOut->u64s[0] = SCE_GS_SET_UV( 0 << 4, 0 << 4 );
    pxOut->u64s[1] = SCE_GS_UV;
    ++pxOut;
    pxOut->u64s[0] = SCE_GS_SET_XYZ( (ASURA_PS2_SCREEN_CENTRE_X - (uWidth >> 1)) << 4, (ASURA_PS2_SCREEN_CENTRE_Y - (uHeight >> 1)) << 4, 0 );
    pxOut->u64s[1] = SCE_GS_XYZ2;
    ++pxOut;

    // BR vtx.
    pxOut->u64s[0] = SCE_GS_SET_UV( uWidth << 4, uHeight << 4 );
    pxOut->u64s[1] = SCE_GS_UV;
    ++pxOut;
    pxOut->u64s[0] = SCE_GS_SET_XYZ( (ASURA_PS2_SCREEN_CENTRE_X + (uWidth >> 1)) << 4, (ASURA_PS2_SCREEN_CENTRE_Y + (uHeight >> 1)) << 4, 0 );
    pxOut->u64s[1] = SCE_GS_XYZ2;
    ++pxOut;

    Asura_Assert( static_cast<u_int>(pxOut - pxBase) == uTotalQWs, "" );
}

#endif // #ifndef ASURA_PS2_SONY_SUBMISSION

void Asura_PS2_GS::SetZBfrBitDepth( u_short usNewBitDepth )
{
    // Note that we don't bother resampling the old z buffer, etc., here.
    // It's assumed that the caller worries about that kind of thing. See the
    // ChangeZBuffer() method in Asura_PS2_GS_Util.

    s_usZBfrBitDepth = usNewBitDepth;

    // Fix up other internal data.
    const u_short usZBfrPSM = GetZBfrPSM();
    s_xDoubleBuffer.draw01.zbuf1.PSM = usZBfrPSM;
    s_xDoubleBuffer.draw02.zbuf2.PSM = usZBfrPSM;
    s_xDoubleBuffer.draw11.zbuf1.PSM = usZBfrPSM;
    s_xDoubleBuffer.draw12.zbuf2.PSM = usZBfrPSM;
}


void Asura_PS2_GS::SetZBfrBasePtr( u_short usNewZBP )
{
    // Note that we don't bother copying the old z buffer over to the new
    // location, etc., here. It's assumed that the caller worries about that
    // kind of thing. See the ChangeZBuffer() method in Asura_PS2_GS_Util.

    s_usZBfrBasePtr = usNewZBP;

    // Fix up other internal data.
    const u_short usZBfrZBP = GetZBfrBasePtr();
    s_xDoubleBuffer.draw01.zbuf1.ZBP = usZBfrZBP;
    s_xDoubleBuffer.draw02.zbuf2.ZBP = usZBfrZBP;
    s_xDoubleBuffer.draw11.zbuf1.ZBP = usZBfrZBP;
    s_xDoubleBuffer.draw12.zbuf2.ZBP = usZBfrZBP;
}


void Asura_PS2_GS::SetDrawBfrBitDepth( u_short usNewBitDepth )
{
    // Currently this does nothing except set the internal value so that
    // calls to GetDrawBfrPSM(), etc., return the right thing. External code
    // will have to deal with the rest via SetDBuffInfo().
    s_usDrawBfrBitDepth = usNewBitDepth;
}


void Asura_PS2_GS::SetDBuffInfo( const sceGsDBuffDc& xNewDBuffInfo )
{
    // External code will need to deal with communicating these changes to
    // the GS.
    s_xDoubleBuffer = xNewDBuffInfo;
}
