//================ Copyright (c) Valve Corporation. All Rights Reserved. ===========================
//
//	LibGcm implementation of DX
//
//==================================================================================================

#ifndef SPU
#define CELL_GCM_MEMCPY memcpy						// PPU SNC has no such intrinsic
#endif

#include "tier0/platform.h"
#include "tier0/dbg.h"
#include "tier1/strtools.h"
#include "tier1/utlbuffer.h"
#include "dxabstract.h"
#include "materialsystem/imaterialsystem.h"

#include "ps3gcmmemory.h"
#include "gcmtexture.h"
#include "gcmstate.h"
#include "gcmdrawstate.h"

#include "vprof.h"

#include "cgutils.h"

#include "tier0/memdbgon.h"


extern IDirect3DDevice9 *m_pD3DDevice;

//--------------------------------------------------------------------------------------------------
//				Direct3DCreate9
//
// IDirect3D9:: GetAdapterCount
// 				GetAdapterIdentifier
// 				CheckDeviceFormat
// 				GetAdapterModeCount
// 				EnumAdapterModes
// 				CheckDeviceType
// 				GetAdapterDisplayMode
// 				CheckDepthStencilMatch
// 				CheckDeviceMultiSampleType
// 				CreateDevice
//				BeginZcullMeasurement
//				EndZcullMeasurement
//--------------------------------------------------------------------------------------------------

IDirect3D9 *Direct3DCreate9(UINT SDKVersion)
{
	return new IDirect3D9;
}

UINT IDirect3D9::GetAdapterCount()
{	
	return 1;		//FIXME revisit later when we know how many screems there are
}

HRESULT IDirect3D9::GetDeviceCaps(UINT Adapter,D3DDEVTYPE DeviceType,D3DCAPS9* pCaps)
{
	// Generally called from "CShaderDeviceMgrDx8::ComputeCapsFromD3D" in ShaderDeviceDX8.cpp
	
	//cheese: fill in the pCaps record for adapter... we zero most of it and just fill in the fields that we think the caller wants.
	Q_memset( pCaps, 0, sizeof(*pCaps) );
	

    /* Device Info */
	pCaps->DeviceType					=	D3DDEVTYPE_HAL;

    /* Caps from DX7 Draw */
    pCaps->Caps							=	0;									// does anyone look at this ?
	
    pCaps->Caps2						=	D3DCAPS2_DYNAMICTEXTURES;    
    /* Cursor Caps */
    pCaps->CursorCaps					=	0;									// nobody looks at this

    /* 3D Device Caps */
    pCaps->DevCaps						=	D3DDEVCAPS_HWTRANSFORMANDLIGHT;

    pCaps->TextureCaps					=	D3DPTEXTURECAPS_CUBEMAP | D3DPTEXTURECAPS_MIPCUBEMAP | D3DPTEXTURECAPS_NONPOW2CONDITIONAL | D3DPTEXTURECAPS_PROJECTED;
											// D3DPTEXTURECAPS_NOPROJECTEDBUMPENV ?
											// D3DPTEXTURECAPS_POW2 ? 
	// caller looks at POT support like this:
	//		pCaps->m_SupportsNonPow2Textures = 
	//			( !( caps.TextureCaps & D3DPTEXTURECAPS_POW2 ) || 
	//			( caps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL ) );
	// so we should set D3DPTEXTURECAPS_NONPOW2CONDITIONAL bit ?


    pCaps->PrimitiveMiscCaps			=	0;									//only the HDR setup looks at this for D3DPMISCCAPS_SEPARATEALPHABLEND.
		// ? D3DPMISCCAPS_SEPARATEALPHABLEND 
		// ? D3DPMISCCAPS_BLENDOP
		// ? D3DPMISCCAPS_CLIPPLANESCALEDPOINTS
		// ? D3DPMISCCAPS_CLIPTLVERTS D3DPMISCCAPS_COLORWRITEENABLE D3DPMISCCAPS_MASKZ D3DPMISCCAPS_TSSARGTEMP
		
		
    pCaps->RasterCaps					=	D3DPRASTERCAPS_SCISSORTEST
										|	D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS	// ref'd in CShaderDeviceMgrDx8::ComputeCapsFromD3D
										|	D3DPRASTERCAPS_DEPTHBIAS			// ref'd in CShaderDeviceMgrDx8::ComputeCapsFromD3D
										;
		
    pCaps->TextureFilterCaps			=	D3DPTFILTERCAPS_MINFANISOTROPIC | D3DPTFILTERCAPS_MAGFANISOTROPIC;
    
    pCaps->MaxTextureWidth				=	4096;
	pCaps->MaxTextureHeight				=	4096;
    pCaps->MaxVolumeExtent				=	1024;	//guesses

    pCaps->MaxTextureAspectRatio		=	0;		// imply no limit on AR

    pCaps->MaxAnisotropy				=	8;		//guess
    
    pCaps->TextureOpCaps				=	D3DTEXOPCAPS_ADD | D3DTEXOPCAPS_MODULATE2X;	//guess
    DWORD   MaxTextureBlendStages;
    DWORD   MaxSimultaneousTextures;

	pCaps->VertexProcessingCaps			=	D3DVTXPCAPS_TEXGEN_SPHEREMAP;
	
    pCaps->MaxActiveLights				=	8;		// guess
    pCaps->MaxUserClipPlanes			=	0;		// guess until we know better
    pCaps->MaxVertexBlendMatrices		=	0;		// see if anyone cares
    pCaps->MaxVertexBlendMatrixIndex	=	0;		// see if anyone cares

    pCaps->MaxPrimitiveCount			=	32768;	// guess
    pCaps->MaxStreams					=	4;		// guess

    pCaps->VertexShaderVersion			=	0x200;	// model 2.0
    pCaps->MaxVertexShaderConst			=	256;	// number of vertex shader constant registers

    pCaps->PixelShaderVersion			=	0x200;	// model 2.0

    // Here are the DX9 specific ones
    pCaps->DevCaps2						=	0;		// D3DDEVCAPS2_STREAMOFFSET - leave it off
	
    pCaps->PS20Caps.NumInstructionSlots	=	512;	// guess
	// only examined once:
	// pCaps->m_SupportsPixelShaders_2_b = ( ( caps.PixelShaderVersion & 0xffff ) >= 0x0200) && (caps.PS20Caps.NumInstructionSlots >= 512);
	//pCaps->m_SupportsPixelShaders_2_b = 1;
	
	pCaps->NumSimultaneousRTs					=	1;         // Will be at least 1
    pCaps->MaxVertexShader30InstructionSlots	=	0; 
    pCaps->MaxPixelShader30InstructionSlots		=	0;

	return S_OK;
}

HRESULT IDirect3D9::GetAdapterIdentifier(UINT Adapter, DWORD Flags, D3DADAPTER_IDENTIFIER9* pIdentifier)
{
	// Generally called from "CShaderDeviceMgrDx8::ComputeCapsFromD3D" in ShaderDeviceDX8.cpp


	Assert( Adapter==0 );					// only one adapter now
	Assert( Flags == D3DENUM_WHQL_LEVEL );	// we're not handling any other queries than this yet
	
	Q_memset( pIdentifier, 0, sizeof(*pIdentifier) );

	// this came from the shaderapigl effort	
    Q_strncpy( pIdentifier->Driver, "Fake-Video-Card", MAX_DEVICE_IDENTIFIER_STRING );
    Q_strncpy( pIdentifier->Description, "Fake-Video-Card", MAX_DEVICE_IDENTIFIER_STRING );
    pIdentifier->VendorId				= 4318;
    pIdentifier->DeviceId				= 401;
    pIdentifier->SubSysId				= 3358668866;
    pIdentifier->Revision				= 162;

	return S_OK;
}

HRESULT IDirect3D9::CheckDeviceFormat(UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,DWORD Usage,D3DRESOURCETYPE RType,D3DFORMAT CheckFormat)
{
	HRESULT result = -1;	// failure
	
	DWORD	knownUsageMask =	D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP
							|	D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_FILTER | D3DUSAGE_QUERY_SRGBWRITE | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING
							|	D3DUSAGE_QUERY_VERTEXTEXTURE;
	
	Assert ((Usage & knownUsageMask) == Usage);
	
	DWORD	legalUsage = 0;
	switch( AdapterFormat )
	{
		case	D3DFMT_X8R8G8B8:
			switch( RType )
			{
				case	D3DRTYPE_TEXTURE:
					switch( CheckFormat )
					{
						case D3DFMT_DXT1:
						case D3DFMT_DXT3:
						case D3DFMT_DXT5:
													legalUsage	=	D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
													legalUsage	|=	D3DUSAGE_QUERY_SRGBREAD;
													
													//open question: is auto gen of mipmaps is allowed or attempted on any DXT textures.
						break;
						
						case D3DFMT_A8R8G8B8:		legalUsage	=	D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
													legalUsage |=	D3DUSAGE_RENDERTARGET | D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_SRGBWRITE | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING;
						break;
						
						case D3DFMT_R32F:			legalUsage	=	D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
													legalUsage |=	D3DUSAGE_RENDERTARGET | D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_SRGBWRITE | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING;
						break;
						
						case D3DFMT_A16B16G16R16:	legalUsage	=	D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP /* --- OSX specific? --- | D3DUSAGE_QUERY_FILTER --- */;
													legalUsage |=	IsPS3() ? D3DUSAGE_QUERY_FILTER : 0;
													legalUsage |=	D3DUSAGE_RENDERTARGET | D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_SRGBWRITE | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING;
						break;
						
						case D3DFMT_A16B16G16R16F:	legalUsage	=	D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
													legalUsage |=	D3DUSAGE_RENDERTARGET | D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_SRGBWRITE | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING;
						
						case D3DFMT_A32B32G32R32F:	legalUsage	=	D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
													legalUsage |=	D3DUSAGE_RENDERTARGET | D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_SRGBWRITE | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING;
						break;
						
						case D3DFMT_R5G6B5:			legalUsage	=	D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
						break;

						//-----------------------------------------------------------
						// these come in from TestTextureFormat in ColorFormatDX8.cpp which is being driven by InitializeColorInformation...
						// which is going to try all 8 combinations of (vertex texturable / render targetable / filterable ) on every image format it knows.
						 
						case D3DFMT_R8G8B8:			legalUsage	=	D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
													legalUsage	|=	D3DUSAGE_QUERY_SRGBREAD;
						break;
												
						case D3DFMT_X8R8G8B8:		legalUsage	=	D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
													legalUsage	|=	D3DUSAGE_QUERY_SRGBREAD;
						break;

							// one and two channel textures... we'll have to fake these as four channel tex if we want to support them
						case D3DFMT_L8:				legalUsage	=	D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
						break;

						case D3DFMT_A8L8:			legalUsage	=	D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
						break;

						case D3DFMT_A8:				legalUsage	=	D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
						break;
						
							// going to need to go back and double check all of these..
						case D3DFMT_X1R5G5B5:		legalUsage	=	D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
						break;
						
						case D3DFMT_A4R4G4B4:		legalUsage	=	D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
						break;

						case D3DFMT_A1R5G5B5:		legalUsage	=	D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
						break;
						
						case D3DFMT_V8U8:			legalUsage	=	D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
						break;

						case D3DFMT_Q8W8V8U8:		legalUsage	=	D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
							// what the heck is QWVU8 ... ?
						break;

						case D3DFMT_X8L8V8U8:		legalUsage	=	D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_QUERY_FILTER;
							// what the heck is XLVU8 ... ?
						break;

							// formats with depth...
							
						case	D3DFMT_D16:			legalUsage =	D3DUSAGE_DYNAMIC | D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL;
							// just a guess on the legal usages
						break;

						case	D3DFMT_D24S8:		legalUsage =	D3DUSAGE_DYNAMIC | D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL;
							// just a guess on the legal usages
						break;

							// vendor formats... try marking these all invalid for now
						case	D3DFMT_NV_INTZ:
						case	D3DFMT_NV_RAWZ:
						case	D3DFMT_NV_NULL:
						case	D3DFMT_ATI_D16:
						case	D3DFMT_ATI_D24S8:
						case	D3DFMT_ATI_2N:
						case	D3DFMT_ATI_1N:
							legalUsage = 0;
						break;

						//-----------------------------------------------------------
												
						default:
							Assert(!"Unknown check format");
							result = -1;
						break;
					}

					if ((Usage & legalUsage) == Usage)
					{
						//NC(( " --> OK!" ));
						result = S_OK;
					}
					else
					{
						DWORD unsatBits = Usage & (~legalUsage);	// clear the bits of the req that were legal, leaving the illegal ones
						//NC(( " --> NOT OK: flags %8x:%s", unsatBits,GLMDecodeMask( eD3D_USAGE, unsatBits ) ));
						result = -1;
					}
				break;				
				
				case	D3DRTYPE_SURFACE:
					switch( CheckFormat )
					{
					case D3DFMT_D16:
					case D3DFMT_D24S8:		
						legalUsage =	D3DUSAGE_DYNAMIC | D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL;
						if ((Usage & legalUsage) == Usage)
						{
							result = S_OK;
						}
						break;

						case	0x434f5441:
						case	0x41415353:
							result = -1;
						break;
						//** IDirect3D9::CheckDeviceFormat  adapter=0, DeviceType=   1:D3DDEVTYPE_HAL, AdapterFormat=       5:D3DFMT_X8R8G8B8, RType=   1:D3DRTYPE_SURFACE, CheckFormat=434f5441:UNKNOWN
						//** IDirect3D9::CheckDeviceFormat  adapter=0, DeviceType=   1:D3DDEVTYPE_HAL, AdapterFormat=       5:D3DFMT_X8R8G8B8, RType=   1:D3DRTYPE_SURFACE, CheckFormat=41415353:UNKNOWN
						//** IDirect3D9::CheckDeviceFormat  adapter=0, DeviceType=   1:D3DDEVTYPE_HAL, AdapterFormat=       5:D3DFMT_X8R8G8B8, RType=   1:D3DRTYPE_SURFACE, CheckFormat=434f5441:UNKNOWN
						//** IDirect3D9::CheckDeviceFormat  adapter=0, DeviceType=   1:D3DDEVTYPE_HAL, AdapterFormat=       5:D3DFMT_X8R8G8B8, RType=   1:D3DRTYPE_SURFACE, CheckFormat=41415353:UNKNOWN
					}
				break;
				
				default:
					Assert(!"Unknown resource type");
					result = -1;
				break;
			}
		break;
		
		default:
			Assert(!"Unknown adapter format");
			result = -1;
		break;
	}
	
	return result;
}

UINT IDirect3D9::GetAdapterModeCount(UINT Adapter,D3DFORMAT Format)
{
	return 1;
}

HRESULT IDirect3D9::EnumAdapterModes(UINT Adapter,D3DFORMAT Format,UINT Mode,D3DDISPLAYMODE* pMode)
{

	if ( IsPC() )
	{
		pMode->Width		= 1024;
		pMode->Height		= 768;
	}
	else
	{
		pMode->Width = 640;
		pMode->Height = 480;
	}
	pMode->RefreshRate	= 0;		// "adapter default"
	pMode->Format		= Format;

	return S_OK;
}

HRESULT IDirect3D9::CheckDeviceType(UINT Adapter,D3DDEVTYPE DevType,D3DFORMAT AdapterFormat,D3DFORMAT BackBufferFormat,BOOL bWindowed)
{
	return S_OK;
}

HRESULT IDirect3D9::GetAdapterDisplayMode(UINT Adapter,D3DDISPLAYMODE* pMode)
{

	pMode->Width		= 1024;
	pMode->Height		= 768;
	pMode->RefreshRate	= 0;		// "adapter default"
	pMode->Format		= D3DFMT_X8R8G8B8;

	return S_OK;
}

HRESULT IDirect3D9::CheckDepthStencilMatch(UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,D3DFORMAT RenderTargetFormat,D3DFORMAT DepthStencilFormat)
{
	// one known request looks like this:
	// AdapterFormat=5:D3DFMT_X8R8G8B8 || RenderTargetFormat=3:D3DFMT_A8R8G8B8 || DepthStencilFormat=2:D3DFMT_D24S8
	
	// return S_OK for that one combo, Debugger() on anything else
	HRESULT result = -1;	// failure
	
	switch( AdapterFormat )
	{
		case	D3DFMT_X8R8G8B8:
		{
			if ( (RenderTargetFormat == D3DFMT_A8R8G8B8) && (DepthStencilFormat == D3DFMT_D24S8) )
			{
				result = S_OK;
			}
		}
		break;
	}
	
	Assert( result == S_OK );

	return result;
}

HRESULT IDirect3D9::CheckDeviceMultiSampleType(UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT SurfaceFormat,BOOL Windowed,D3DMULTISAMPLE_TYPE MultiSampleType,DWORD* pQualityLevels)
{
	switch( MultiSampleType )
	{
		case D3DMULTISAMPLE_NONE:
			*pQualityLevels = 1;
			return S_OK;
		break;
		
		default:
			if(pQualityLevels)
			{
				*pQualityLevels = 0;
			}
			return D3DERR_NOTAVAILABLE;
		break;
	}
	return D3DERR_NOTAVAILABLE;
}

HRESULT IDirect3D9::CreateDevice(UINT Adapter,D3DDEVTYPE DeviceType,VD3DHWND hFocusWindow,DWORD BehaviorFlags,
								 D3DPRESENT_PARAMETERS* pPresentationParameters,IDirect3DDevice9** ppReturnedDeviceInterface)
{
	// constrain these inputs for the time being
	// BackBufferFormat			-> A8R8G8B8
	// BackBufferCount			-> 1;
	// MultiSampleType			-> D3DMULTISAMPLE_NONE
	// AutoDepthStencilFormat	-> D3DFMT_D24S8
	
	// NULL out the return pointer so if we exit early it is not set
	*ppReturnedDeviceInterface = NULL;
	
	//extern void	UnpackD3DRSITable( void );
	//UnpackD3DRSITable();
	
	// assume success unless something is sour
	HRESULT result = S_OK;
	
	// relax this check for now
	//if (pPresentationParameters->BackBufferFormat != D3DFMT_A8R8G8B8)
	//{
	//	Debugger();
	//	result = -1;
	//}
	
	if (pPresentationParameters->BackBufferCount != 1)
	{
		Debugger();
		result = -1;
	}
	
	if (pPresentationParameters->MultiSampleType != D3DMULTISAMPLE_NONE)
	{
		Debugger();
		result = -1;
	}
	
	if (pPresentationParameters->AutoDepthStencilFormat != D3DFMT_D24S8)
	{
		Debugger();
		result = -1;
	}

	if (result == S_OK)
	{
		// create an IDirect3DDevice9
		// make a GLMContext and set up some drawables

		IDirect3DDevice9Params	devparams;
		memset( &devparams, 0, sizeof(devparams) );
		
		devparams.m_adapter				= Adapter;
		devparams.m_deviceType				= DeviceType;
		devparams.m_focusWindow			= hFocusWindow;
		devparams.m_behaviorFlags			= BehaviorFlags;
		devparams.m_presentationParameters	= *pPresentationParameters;

		IDirect3DDevice9 *dev = new IDirect3DDevice9;
		
		result = dev->Create( &devparams );
		
		if (result == S_OK)
		{
			*ppReturnedDeviceInterface = dev;
		}
	}
	
	return result;
}

//--------------------------------------------------------------------------------------------------
// IDirect3DDevice9::	Create
// 						Release
// 						Reset
// 						SetViewport
// 						BeginScene
// 						EndScene
// 						Present
// 						Ps3Helper_ResetSurfaceToKnownDefaultState
//						ReloadZcullMemory
//--------------------------------------------------------------------------------------------------

HRESULT	IDirect3DDevice9::Create( IDirect3DDevice9Params *params )
{
	HRESULT result = S_OK;

  	// create an IDirect3DDevice9
 	// make a GLMContext and set up some drawables
 	m_params		=	*params;
 
 	V_memset( m_rtSurfaces, 0, sizeof(m_rtSurfaces) );
 	m_dsSurface = NULL;
 
 	m_defaultColorSurface = NULL;
 	m_defaultDepthStencilSurface = NULL;
 
 	// Init GCM
 	int nGcmInitError = g_ps3gcmGlobalState.Init();
 	if( nGcmInitError < CELL_OK )
 	{
 		Debugger();	// bad news
 		Warning( "IDirect3DDevice9::Create error 0x%X", nGcmInitError );
 		return (HRESULT) -1;
 	}
 
	gpGcmDrawState->Init(params);

 	// we create two IDirect3DSurface9's.  These will be known as the internal render target 0 and the depthstencil.
 
 	// color surface
 	result = this->CreateRenderTarget( 
 		m_params.m_presentationParameters.BackBufferWidth,	// width
 		m_params.m_presentationParameters.BackBufferHeight,	// height
 		m_params.m_presentationParameters.BackBufferFormat, // format
 		D3DMULTISAMPLE_NONE,								// FIXME
 		0,													// MSAA quality
 		true,												// lockable ????
 		&m_defaultColorSurface,								// ppSurface
 		(VD3DHANDLE*)this									// shared handle, signal that it is internal RT
 		);

	if (result != S_OK)
	{
		Debugger();
		return result;
	}
	else
	{
		m_defaultColorSurface->AddRef();
	}
 
	if (!m_params.m_presentationParameters.EnableAutoDepthStencil)
	{
		Debugger();	// bad news
	}
 
	result = CreateDepthStencilSurface(
		m_params.m_presentationParameters.BackBufferWidth,	// width
		m_params.m_presentationParameters.BackBufferHeight,	// height
		m_params.m_presentationParameters.AutoDepthStencilFormat,	// format
		D3DMULTISAMPLE_NONE,								// FIXME
		0,													// MSAA quality
		TRUE,												// enable z-buffer discard ????
		&m_defaultDepthStencilSurface,						// ppSurface
		(VD3DHANDLE*)this									// shared handle, signal that it is internal RT
		);
	if (result != S_OK)
	{
		Debugger();
		return result;
	}
	else
	{
		m_defaultDepthStencilSurface->AddRef();
	}
 
	// Set the default surfaces
	(m_rtSurfaces[0] = m_defaultColorSurface)->AddRef();
	(m_dsSurface = m_defaultDepthStencilSurface)->AddRef();
	Ps3Helper_UpdateSurface( 0 );	// submit the change to GCM
 
	// Create internal textures

 	void Ps3gcmInitializeArtificialTexture( int iHandle, IDirect3DBaseTexture9 *pPtr );
 	Ps3gcmInitializeArtificialTexture( PS3GCM_ARTIFICIAL_TEXTURE_HANDLE_INDEX_BACKBUFFER, 
									   ( IDirect3DBaseTexture9 * ) m_defaultColorSurface );
 	Ps3gcmInitializeArtificialTexture( PS3GCM_ARTIFICIAL_TEXTURE_HANDLE_INDEX_DEPTHBUFFER, 
										( IDirect3DBaseTexture9 * ) m_defaultDepthStencilSurface );

	D3DVIEWPORT9 viewport = { 0, 0,
	 		m_params.m_presentationParameters.BackBufferWidth,
	 		m_params.m_presentationParameters.BackBufferHeight,
	 		0.1f, 1000.0f
	 	};
	
	SetViewport( &viewport );

 	Ps3Helper_ResetSurfaceToKnownDefaultState();

	return result;
}

ULONG __stdcall IDirect3DDevice9::Release()
{
 	g_ps3gcmGlobalState.Shutdown();
	return 0;
}

HRESULT IDirect3DDevice9::Reset(D3DPRESENT_PARAMETERS* pPresentationParameters)
{
	// nothing interesting here
	return S_OK;
}

HRESULT IDirect3DDevice9::SetViewport(CONST D3DVIEWPORT9* pViewport)
{
	return gpGcmDrawState->SetViewport(pViewport);
}

HRESULT IDirect3DDevice9::BeginScene()
{
	// 	m_isZPass = false;			// z pres pass off at this time
 	
	g_ps3gcmGlobalState.BeginScene();

	//m_nAntiAliasingStatus = AA_STATUS_NORMAL;			// AA FXAA
 
	return S_OK;
}

HRESULT IDirect3DDevice9::EndScene()
{
	g_ps3gcmGlobalState.EndScene();

	return S_OK;
}


HRESULT IDirect3DDevice9::Present(CONST RECT* pSourceRect,CONST RECT* pDestRect,VD3DHWND hDestWindowOverride,CONST RGNDATA* pDirtyRegion)
{
 	m_nAntiAliasingStatus = AA_STATUS_NORMAL;// we aren't drawing into previous frame, we just set the current frame and we're about to set the surface for drawing

	// Flip frames and Advance display counters

	g_ps3gcmGlobalState.Flip();

 
 	// Set our new default color buffer offset
 	m_defaultColorSurface->m_tex->m_lmBlock.Assign( g_ps3gcmGlobalState.m_display.surfaceColor[g_ps3gcmGlobalState.m_display.surfaceFlipIdx] );
 
 	//
 	// Starting next frame
 	//
 
 	// Bind our default surfaces for the first time this frame here:
 	if ( m_rtSurfaces[0] != m_defaultColorSurface )
 	{
 		m_defaultColorSurface->AddRef();
 		if ( m_rtSurfaces[0] ) m_rtSurfaces[0]->Release();
 		m_rtSurfaces[0] = m_defaultColorSurface;
 	}
 	if ( m_dsSurface != m_defaultDepthStencilSurface )
 	{
 		m_defaultDepthStencilSurface->AddRef();
 		if ( m_dsSurface ) m_dsSurface->Release();
 		m_dsSurface = m_defaultDepthStencilSurface;
 	}
 	Ps3Helper_UpdateSurface( 0 );
 
 	Ps3Helper_ResetSurfaceToKnownDefaultState();

	return S_OK;
}

void IDirect3DDevice9::Ps3Helper_ResetSurfaceToKnownDefaultState()
{
	gpGcmDrawState->ResetSurfaceToKnownDefaultState();
}

//--------------------------------------------------------------------------------------------------
// IDirect3DGcmBufferBase - Lock, unlock, mem mgmt via CPs3gcmBuffer
//--------------------------------------------------------------------------------------------------

HRESULT IDirect3DGcmBufferBase::Lock(UINT OffsetToLock,UINT SizeToLock,void** ppbData,DWORD Flags)
{
	// FIXME would be good to have "can't lock twice" logic

	Assert( !(Flags & D3DLOCK_READONLY) );	// not impl'd
	//	Assert( !(Flags & D3DLOCK_NOSYSLOCK) );	// not impl'd - it triggers though

	if ( Flags & D3DLOCK_DISCARD )
	{
		// When the buffer is being discarded we need to allocate a new
		// instance of the buffer in case the current instance has been
		// in use:
		m_pBuffer->m_lmBlock.FreeAndAllocNew();
		gpGcmDrawState->UpdateVtxBufferOffset(( IDirect3DVertexBuffer9 * )this, m_pBuffer->Offset());
	}
	// We assume that we are always locking in NOOVERWRITE mode otherwise!

	// Return the buffer data pointer at requested offset
	*ppbData = m_pBuffer->m_lmBlock.DataInAnyMemory() + OffsetToLock;

	return S_OK;
}

HRESULT IDirect3DGcmBufferBase::Unlock()
{
	// if this buffer is dirty, we need to invalidate vertex cache when we bind it
	gpGcmDrawState->m_dirtyCachesMask |= CGcmDrawState::kDirtyVxCache;
	return S_OK;
}

//--------------------------------------------------------------------------------------------------
// TEXTURE
// -------
// PreparePs3TextureKey
// IDirect3DDevice9::	CreateTexture
//						CreateCubeTexture
//						CreateVolumeTexture
//						AllocateTextureStorage
//						SetTexture
//						GetTexture
//						FlushTextureCache
//
//--------------------------------------------------------------------------------------------------

static void PreparePs3TextureKey( CPs3gcmTextureLayout::Key_t &key, D3DFORMAT Format, UINT Levels, DWORD Usage )
{
	memset( &key, 0, sizeof(key) );
	key.m_texFormat		= Format;
	if ( Levels > 1 )
	{
		key.m_texFlags |= CPs3gcmTextureLayout::kfMip;
	}
	key.m_nActualMipCount = Levels;

	// http://msdn.microsoft.com/en-us/library/bb172625(VS.85).aspx

	// complain if any usage bits come down that I don't know.
	uint knownUsageBits = (D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_RENDERTARGET | D3DUSAGE_DYNAMIC | D3DUSAGE_TEXTURE_SRGB | D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_TEXTURE_NOD3DMEMORY);
	if ( (Usage & knownUsageBits) != Usage )
	{
		Debugger();
	}

	if (Usage & D3DUSAGE_AUTOGENMIPMAP)
	{
		key.m_texFlags |= CPs3gcmTextureLayout::kfMip | CPs3gcmTextureLayout::kfMipAuto;
	}

	if ( Usage & D3DUSAGE_DEPTHSTENCIL )
	{
		key.m_texFlags |= CPs3gcmTextureLayout::kfTypeRenderable;
		key.m_texFlags |= CPs3gcmTextureLayout::kfTypeDepthStencil;
	}
	else if (Usage & D3DUSAGE_RENDERTARGET)
	{
		key.m_texFlags |= CPs3gcmTextureLayout::kfTypeRenderable;
		key.m_texFlags |= CPs3gcmTextureLayout::kfSrgbEnabled;			// this catches callers of CreateTexture who set the "renderable" option - they get an SRGB tex
	}

	if (Usage & D3DUSAGE_DYNAMIC)
	{
		key.m_texFlags |= CPs3gcmTextureLayout::kfDynamicNoSwizzle;
	}

	if (Usage & D3DUSAGE_TEXTURE_SRGB)
	{
		key.m_texFlags |= CPs3gcmTextureLayout::kfSrgbEnabled;
	}

	if (Usage & D3DUSAGE_TEXTURE_NOD3DMEMORY)
	{
		key.m_texFlags |= CPs3gcmTextureLayout::kfNoD3DMemory;
	}
}

HRESULT IDirect3DDevice9::CreateTexture(UINT Width,UINT Height,UINT Levels,DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,IDirect3DTexture9** ppTexture,VD3DHANDLE* pSharedHandle)
{
	IDirect3DTexture9	*dxtex = new IDirect3DTexture9;
	dxtex->m_restype = D3DRTYPE_TEXTURE;

	dxtex->m_device		= this;

	dxtex->m_descZero.Format	= Format;
	dxtex->m_descZero.Type		= D3DRTYPE_TEXTURE;
	dxtex->m_descZero.Usage		= Usage;
	dxtex->m_descZero.Pool		= Pool;

	dxtex->m_descZero.MultiSampleType		= D3DMULTISAMPLE_NONE;
	dxtex->m_descZero.MultiSampleQuality	= 0;
	dxtex->m_descZero.Width		= Width;
	dxtex->m_descZero.Height	= Height;

	CPs3gcmTextureLayout::Key_t key;
	PreparePs3TextureKey( key, Format, Levels, Usage );
	key.m_size[0] = Width;
	key.m_size[1] = Height;
	key.m_size[2] = 1;
	dxtex->m_tex = CPs3gcmTexture::New( key );

	//
	// Create surface
	//
	dxtex->m_surfZero = new IDirect3DSurface9;

	dxtex->m_surfZero->m_desc	=	dxtex->m_descZero;
	dxtex->m_surfZero->m_tex	=	dxtex->m_tex;
	dxtex->m_surfZero->m_bOwnsTexture = false;
	dxtex->m_surfZero->m_face	=	0;
	dxtex->m_surfZero->m_mip	=	0;

	*ppTexture = dxtex;

	return S_OK;
}

HRESULT IDirect3DDevice9::CreateCubeTexture(UINT EdgeLength,UINT Levels,DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,IDirect3DCubeTexture9** ppCubeTexture,VD3DHANDLE* pSharedHandle)
{

	IDirect3DCubeTexture9	*dxtex = new IDirect3DCubeTexture9;
	dxtex->m_restype = D3DRTYPE_CUBETEXTURE;

	dxtex->m_device			= this;

	dxtex->m_descZero.Format	= Format;
	dxtex->m_descZero.Type		= D3DRTYPE_CUBETEXTURE;
	dxtex->m_descZero.Usage		= Usage;
	dxtex->m_descZero.Pool		= Pool;

	dxtex->m_descZero.MultiSampleType		= D3DMULTISAMPLE_NONE;
	dxtex->m_descZero.MultiSampleQuality	= 0;
	dxtex->m_descZero.Width		= EdgeLength;
	dxtex->m_descZero.Height	= EdgeLength;

	CPs3gcmTextureLayout::Key_t key;
	PreparePs3TextureKey( key, Format, Levels, Usage );
	key.m_texFlags |= CPs3gcmTextureLayout::kfTypeCubeMap;
	key.m_size[0] = EdgeLength;
	key.m_size[1] = EdgeLength;
	key.m_size[2] = 1;
	dxtex->m_tex = CPs3gcmTexture::New( key );

	//
	// Create surfaces
	//
	for( int face = 0; face < 6; face ++)
	{
		dxtex->m_surfZero[face] = new IDirect3DSurface9;

		dxtex->m_surfZero[face]->m_desc	=	dxtex->m_descZero;
		dxtex->m_surfZero[face]->m_tex	=	dxtex->m_tex;
		dxtex->m_surfZero[face]->m_bOwnsTexture = false;
		dxtex->m_surfZero[face]->m_face	=	face;
		dxtex->m_surfZero[face]->m_mip	=	0;
	}

	*ppCubeTexture = dxtex;


	return S_OK;
}

HRESULT IDirect3DDevice9::CreateVolumeTexture(UINT Width,UINT Height,UINT Depth,UINT Levels,DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,IDirect3DVolumeTexture9** ppVolumeTexture,VD3DHANDLE* pSharedHandle)
{
	// set dxtex->m_restype to D3DRTYPE_VOLUMETEXTURE...

	IDirect3DVolumeTexture9	*dxtex = new IDirect3DVolumeTexture9;
	dxtex->m_restype = D3DRTYPE_VOLUMETEXTURE;

	dxtex->m_device			= this;

	dxtex->m_descZero.Format	= Format;
	dxtex->m_descZero.Type		= D3DRTYPE_VOLUMETEXTURE;
	dxtex->m_descZero.Usage		= Usage;
	dxtex->m_descZero.Pool		= Pool;

	dxtex->m_descZero.MultiSampleType		= D3DMULTISAMPLE_NONE;
	dxtex->m_descZero.MultiSampleQuality	= 0;
	dxtex->m_descZero.Width		= Width;
	dxtex->m_descZero.Height	= Height;

	// also a volume specific desc
	dxtex->m_volDescZero.Format		= Format;
	dxtex->m_volDescZero.Type		= D3DRTYPE_VOLUMETEXTURE;
	dxtex->m_volDescZero.Usage		= Usage;
	dxtex->m_volDescZero.Pool		= Pool;

	dxtex->m_volDescZero.Width		= Width;
	dxtex->m_volDescZero.Height		= Height;
	dxtex->m_volDescZero.Depth		= Depth;

	CPs3gcmTextureLayout::Key_t key;
	PreparePs3TextureKey( key, Format, Levels, Usage );
	key.m_size[0] = Width;
	key.m_size[1] = Height;
	key.m_size[2] = Depth;
	dxtex->m_tex = CPs3gcmTexture::New( key );

	//
	// Create surface
	//
	dxtex->m_surfZero = new IDirect3DSurface9;

	dxtex->m_surfZero->m_desc	=	dxtex->m_descZero;
	dxtex->m_surfZero->m_tex	=	dxtex->m_tex;
	dxtex->m_surfZero->m_bOwnsTexture = false;
	dxtex->m_surfZero->m_face	=	0;
	dxtex->m_surfZero->m_mip	=	0;

	*ppVolumeTexture = dxtex;

	return S_OK;
}

bool IDirect3DDevice9::AllocateTextureStorage( IDirect3DBaseTexture9 *pTexture )
{
	// Allocate storage for a texture's bits (if D3DUSAGE_TEXTURE_NOD3DMEMORY was used to defer allocation on creation)
	return pTexture->m_tex->Allocate();
}

HRESULT IDirect3DDevice9::SetTexture( DWORD Stage, IDirect3DBaseTexture9* pTexture )
{
	if( pTexture /*&& pTexture->m_tex->m_lmBlock.Size()*/ )
	{
		gpGcmDrawState->SetTexture(Stage, pTexture->m_tex);

	}
	else
	{
		gpGcmDrawState->ResetTexture(Stage);
	}	
	return S_OK;
}

HRESULT IDirect3DDevice9::GetTexture(DWORD Stage,IDirect3DBaseTexture9** ppTexture)
{
	// if implemented, should it increase the ref count ??
	Debugger();
	return S_OK;
}

void IDirect3DDevice9::FlushTextureCache()
{
	gpGcmDrawState->SetInvalidateTextureCache();
}


//--------------------------------------------------------------------------------------------------
// IDirect3DBaseTexture9::	GetType
// 							GetLevelCount
// 							GetLevelDesc
// 							LockRect
// 							UnlockRect
// IDirect3DCubeTexture9::	GetCubeMapSurface
// 							GetLevelDesc
// IDirect3DVolumeTexture9::LockBox
// 							UnlockBox
// 							GetLevelDesc
//--------------------------------------------------------------------------------------------------

D3DRESOURCETYPE IDirect3DBaseTexture9::GetType()
{
	return m_restype;	//D3DRTYPE_TEXTURE;
}

DWORD IDirect3DBaseTexture9::GetLevelCount()
{
	return m_tex->m_layout->m_mipCount;
}

HRESULT IDirect3DBaseTexture9::GetLevelDesc(UINT Level,D3DSURFACE_DESC *pDesc)
{
	Assert (Level < m_tex->m_layout->m_mipCount);

	D3DSURFACE_DESC result = m_descZero;
	// then mutate it for the level of interest
	
	CPs3gcmTextureLayout const &layout = *m_tex->m_layout;
	int iSlice = layout.SliceIndex( 0, Level );
	CPs3gcmTextureLayout::Slice_t const &slice = layout.m_slices[iSlice];

	result.Width = slice.m_size[0];
	result.Height = slice.m_size[1];
	
	*pDesc = result;

	return S_OK;
}

HRESULT IDirect3DTexture9::LockRect(UINT Level,D3DLOCKED_RECT* pLockedRect,CONST RECT* pRect,DWORD Flags)
{
	Debugger();
	return S_OK;
}

HRESULT IDirect3DTexture9::UnlockRect(UINT Level)
{
	Debugger();
	return S_OK;
}

HRESULT IDirect3DTexture9::GetSurfaceLevel(UINT Level,IDirect3DSurface9** ppSurfaceLevel)
{
	// we create and pass back a surface, and the client is on the hook to release it.  tidy.

	IDirect3DSurface9 *surf = new IDirect3DSurface9;

	CPs3gcmTextureLayout const &layout = *m_tex->m_layout;
	int iSlice = layout.SliceIndex( 0, Level );
	CPs3gcmTextureLayout::Slice_t const &slice = layout.m_slices[iSlice];

	surf->m_desc = m_descZero;
	surf->m_desc.Width = slice.m_size[0];
	surf->m_desc.Height = slice.m_size[1];

	surf->m_tex	= m_tex;
	surf->m_bOwnsTexture = false;
	surf->m_face = 0;
	surf->m_mip = Level;

	*ppSurfaceLevel = surf;

	return S_OK;
}


HRESULT IDirect3DCubeTexture9::GetCubeMapSurface(D3DCUBEMAP_FACES FaceType,UINT Level,IDirect3DSurface9** ppCubeMapSurface)
{
	// we create and pass back a surface, and the client is on the hook to release it...

	IDirect3DSurface9 *surf = new IDirect3DSurface9;

	CPs3gcmTextureLayout const &layout = *m_tex->m_layout;
	int iSlice = layout.SliceIndex( FaceType, Level );
	CPs3gcmTextureLayout::Slice_t const &slice = layout.m_slices[iSlice];

	surf->m_desc = m_descZero;
		surf->m_desc.Width = slice.m_size[0];
		surf->m_desc.Height = slice.m_size[1];
		
	surf->m_tex	= m_tex;
	surf->m_bOwnsTexture = false;
	surf->m_face = FaceType;
	surf->m_mip = Level;

	*ppCubeMapSurface = surf;

	return S_OK;
}

HRESULT IDirect3DCubeTexture9::GetLevelDesc(UINT Level,D3DSURFACE_DESC *pDesc)
{
	Assert (Level < m_tex->m_layout->m_mipCount);

	D3DSURFACE_DESC result = m_descZero;
	// then mutate it for the level of interest
	
	CPs3gcmTextureLayout const &layout = *m_tex->m_layout;
	int iSlice = layout.SliceIndex( 0, Level );
	CPs3gcmTextureLayout::Slice_t const &slice = layout.m_slices[iSlice];

	result.Width = slice.m_size[0];
	result.Height = slice.m_size[1];

	*pDesc = result;

	return S_OK;
}

HRESULT IDirect3DVolumeTexture9::LockBox(UINT Level,D3DLOCKED_BOX* pLockedVolume,CONST D3DBOX* pBox,DWORD Flags)
{
	if ( !m_tex->m_lmBlock.Size() )
	{
		Assert( 0 );
		Warning( "\n\nERROR: (IDirect3DSurface9::LockBox) cannot lock this texture until AllocateTextureStorage is called!!\n\n\n" );
		return S_FALSE;
	}

	CPs3gcmTextureLayout const &layout = *m_tex->m_layout;
	int iSlice = layout.SliceIndex( 0, Level );
	CPs3gcmTextureLayout::Slice_t const &slice = layout.m_slices[iSlice];

	int iOffsetInDataSlab = slice.m_storageOffset;
	int iPitch = layout.SlicePitch( iSlice );
	int iDepthPitch = iPitch * slice.m_size[1];
	Assert( !layout.IsTiledMemory() );

	// Account for locking request on a subrect:
	if ( pBox )
	{
		// Assert that locking the box can yield a pointer to a legitimate byte:
		Assert( !pBox->Left || !layout.IsTiledMemory() );
		Assert( 0 == ( ( pBox->Left * layout.GetFormatPtr()->m_gcmPitchPer4X ) % 4 ) );
		iOffsetInDataSlab += pBox->Left * layout.GetFormatPtr()->m_gcmPitchPer4X / 4;
		iOffsetInDataSlab += pBox->Top * iPitch;
		iOffsetInDataSlab += pBox->Front * iDepthPitch;
	}

	// Set the locked rect data:
	pLockedVolume->pBits = m_tex->Data() + iOffsetInDataSlab;
	pLockedVolume->RowPitch = iPitch;
	pLockedVolume->SlicePitch = iDepthPitch;

	return S_OK;
}

HRESULT IDirect3DVolumeTexture9::UnlockBox(UINT Level)
{
	// Since the texture has just been modified, and this same texture bits may have been used in one of the previous draw calls
	// and may still linger in the texture cache (even if this is a new texture, it may theoretically share bits with some old texture,
	// which was just destroyed, and if we didn't have a lot of texture traffic in the last frame, those bits in texture cache may conceivably 
	// survive until the next draw call)
	gpGcmDrawState->m_dirtyCachesMask |= CGcmDrawState::kDirtyTxCache;
	return S_OK;
}

HRESULT IDirect3DVolumeTexture9::GetLevelDesc( UINT Level, D3DVOLUME_DESC *pDesc )
{
	if (Level > m_tex->m_layout->m_mipCount)
	{
		Debugger();
	}

	D3DVOLUME_DESC result = m_volDescZero;
	// then mutate it for the level of interest

	CPs3gcmTextureLayout const &layout = *m_tex->m_layout;
	int iSlice = layout.SliceIndex( 0, Level );
	CPs3gcmTextureLayout::Slice_t const &slice = layout.m_slices[iSlice];

	result.Width = slice.m_size[0];
	result.Height = slice.m_size[1];
	result.Depth = slice.m_size[2];

	*pDesc = result;

	return S_OK;
}

//--------------------------------------------------------------------------------------------------
// RENDER TARGETS and SURFACES
// IDirect3DDevice9::	CreateRenderTarget
// 						SetRenderTarget
// 						GetRenderTarget
// 						CreateOffscreenPlainSurface
// 						CreateDepthStencilSurface
// 						Ps3Helper_UpdateSurface
// 						DxDeviceForceUpdateRenderTarget
// 						SetDepthStencilSurface
// 						GetDepthStencilSurface
// 						GetRenderTargetData
// 						GetFrontBufferData
// 						StretchRect
//						SetScissorRect
//						SetClipPlane
//--------------------------------------------------------------------------------------------------

HRESULT IDirect3DDevice9::CreateRenderTarget(UINT Width,UINT Height,D3DFORMAT Format,D3DMULTISAMPLE_TYPE MultiSample,DWORD MultisampleQuality,BOOL Lockable,IDirect3DSurface9** ppSurface,VD3DHANDLE* pSharedHandle)
{
	HRESULT result = S_OK;

	IDirect3DSurface9 *surf = new IDirect3DSurface9;
	surf->m_restype = D3DRTYPE_SURFACE;

	surf->m_device		= this;				// always set device on creations!

	CPs3gcmTextureLayout::Key_t key;
	PreparePs3TextureKey( key, Format, 0, 0 );
	key.m_size[0] = Width;
	key.m_size[1] = Height;
	key.m_size[2] = 1;

	key.m_texFlags = CPs3gcmTextureLayout::kfTypeRenderable;
	key.m_texFlags |= CPs3gcmTextureLayout::kfSrgbEnabled;	// all render target tex are SRGB mode

	if ( pSharedHandle == ( VD3DHANDLE* ) this )
	{
		// internal RT, reuse the color buffer
		surf->m_tex = new CPs3gcmTexture;
		surf->m_tex->m_layout = CPs3gcmTextureLayout::New( key );
		surf->m_tex->m_lmBlock.Assign( g_ps3gcmGlobalState.m_display.surfaceColor[ g_ps3gcmGlobalState.m_display.surfaceFlipIdx ] );
	}
	else
	{
		surf->m_tex			= CPs3gcmTexture::New( key );
	}
	surf->m_bOwnsTexture = true;
	surf->m_face		= 0;
	surf->m_mip			= 0;

	//desc
	surf->m_desc.Format				=	Format;
	surf->m_desc.Type				=	D3DRTYPE_SURFACE;
	surf->m_desc.Usage				=	0;					//FIXME ???????????
	surf->m_desc.Pool				=	D3DPOOL_DEFAULT;	//FIXME ???????????
	surf->m_desc.MultiSampleType	=	MultiSample;
	surf->m_desc.MultiSampleQuality	=	MultisampleQuality;
	surf->m_desc.Width				=	Width;
	surf->m_desc.Height				=	Height;

	*ppSurface = (result==S_OK) ? surf : NULL;

	return result;
}

HRESULT IDirect3DDevice9::SetRenderTarget(DWORD RenderTargetIndex,IDirect3DSurface9* pRenderTarget)
{
	if ( pRenderTarget != m_rtSurfaces[RenderTargetIndex] )
	{
		if (pRenderTarget)
			pRenderTarget->AddRef();

		if (m_rtSurfaces[RenderTargetIndex])
			m_rtSurfaces[RenderTargetIndex]->Release();

		m_rtSurfaces[RenderTargetIndex] = pRenderTarget;

		Ps3Helper_UpdateSurface( RenderTargetIndex );
	}

	return S_OK;
}

HRESULT IDirect3DDevice9::GetRenderTarget(DWORD RenderTargetIndex,IDirect3DSurface9** ppRenderTarget)
{
	m_rtSurfaces[ RenderTargetIndex ]->AddRef();	// per http://msdn.microsoft.com/en-us/library/bb174404(VS.85).aspx

	*ppRenderTarget = m_rtSurfaces[ RenderTargetIndex ];

	return S_OK;
}

HRESULT IDirect3DDevice9::CreateOffscreenPlainSurface(UINT Width,UINT Height,D3DFORMAT Format,D3DPOOL Pool,IDirect3DSurface9** ppSurface,VD3DHANDLE* pSharedHandle)
{
	// set surf->m_restype to D3DRTYPE_SURFACE...

	// this is almost identical to CreateRenderTarget..

	HRESULT result = S_OK;

	IDirect3DSurface9 *surf = new IDirect3DSurface9;
	surf->m_restype = D3DRTYPE_SURFACE;

	surf->m_device		= this;				// always set device on creations!

	CPs3gcmTextureLayout::Key_t key;
	PreparePs3TextureKey( key, Format, 0, 0 );
	key.m_size[0] = Width;
	key.m_size[1] = Height;
	key.m_size[2] = 1;

	key.m_texFlags = CPs3gcmTextureLayout::kfTypeRenderable;

	surf->m_tex			= CPs3gcmTexture::New( key );
	surf->m_bOwnsTexture = true;

	surf->m_face		=	0;
	surf->m_mip			=	0;

	//desc
	surf->m_desc.Format				=	Format;
	surf->m_desc.Type				=	D3DRTYPE_SURFACE;
	surf->m_desc.Usage				=	0;
	surf->m_desc.Pool				=	D3DPOOL_DEFAULT;
	surf->m_desc.MultiSampleType	=	D3DMULTISAMPLE_NONE;
	surf->m_desc.MultiSampleQuality	=	0;
	surf->m_desc.Width				=	Width;
	surf->m_desc.Height				=	Height;

	*ppSurface = (result==S_OK) ? surf : NULL;

	return result;
}

HRESULT IDirect3DDevice9::CreateDepthStencilSurface(UINT Width,UINT Height,D3DFORMAT Format,D3DMULTISAMPLE_TYPE MultiSample,DWORD MultisampleQuality,
													BOOL Discard,IDirect3DSurface9** ppSurface,VD3DHANDLE* pSharedHandle)
{
	HRESULT result = S_OK;

	IDirect3DSurface9 *surf = new IDirect3DSurface9;
	surf->m_restype = D3DRTYPE_SURFACE;

	surf->m_device		= this;				// always set device on creations!

	CPs3gcmTextureLayout::Key_t key;
	PreparePs3TextureKey( key, Format, 0, 0 );
	key.m_size[0] = Width;
	key.m_size[1] = Height;
	key.m_size[2] = 1;

	key.m_texFlags = CPs3gcmTextureLayout::kfTypeRenderable | CPs3gcmTextureLayout::kfTypeDepthStencil;

	if ( pSharedHandle == ( VD3DHANDLE* ) this )
	{
		// internal RT, reuse the depth buffer
		surf->m_tex = new CPs3gcmTexture;
		surf->m_tex->m_layout = CPs3gcmTextureLayout::New( key );
		surf->m_tex->m_lmBlock.Assign( g_ps3gcmGlobalState.m_display.surfaceDepth );
	}
	else
	{
		surf->m_tex				= CPs3gcmTexture::New( key );
	}
	surf->m_bOwnsTexture = true;
	surf->m_face			= 0;
	surf->m_mip				= 0;

	//desc

	surf->m_desc.Format				=	Format;
	surf->m_desc.Type				=	D3DRTYPE_SURFACE;
	surf->m_desc.Usage				=	0;					//FIXME ???????????
	surf->m_desc.Pool				=	D3DPOOL_DEFAULT;	//FIXME ???????????
	surf->m_desc.MultiSampleType	=	MultiSample;
	surf->m_desc.MultiSampleQuality	=	MultisampleQuality;
	surf->m_desc.Width				=	Width;
	surf->m_desc.Height				=	Height;

	*ppSurface = (result==S_OK) ? surf : NULL;

	return result;
}


uint s_nUpdateSurfaceCounter = 0, s_nUpdateSurfaceDebug = -1;

void IDirect3DDevice9::Ps3Helper_UpdateSurface( int idx )
{
	CPs3gcmTexture *texC = m_rtSurfaces[idx] ? m_rtSurfaces[idx]->m_tex : NULL;

	// If color buffer is 8x8 or less, we assume this is a dummy color buffer, and Z only the surface

	if (texC)
	{
		if(texC->m_layout->m_key.m_size[0] < 9)
		{
			texC = NULL;
		}
	}

	CPs3gcmTexture *texZ = ( m_dsSurface && !idx ) ? m_dsSurface->m_tex : NULL;
	CPs3gcmTexture *texCZ = texC ? texC : texZ;

	UpdateSurface_t surface, *pSurfaceUpdate=&surface;

	pSurfaceUpdate->m_texC.Assign( texC );
	pSurfaceUpdate->m_texZ.Assign( texZ );
	gpGcmDrawState->Ps3Helper_UpdateSurface(pSurfaceUpdate);
}

void DxDeviceForceUpdateRenderTarget( )
{
	extern IDirect3DDevice9 *m_pD3DDevice;
	m_pD3DDevice->Ps3Helper_UpdateSurface( 0 );
}

HRESULT IDirect3DDevice9::SetDepthStencilSurface(IDirect3DSurface9* pNewZStencil)
{
	if ( pNewZStencil != m_dsSurface )
	{
		if (pNewZStencil)
			pNewZStencil->AddRef();

		if (m_dsSurface)
			m_dsSurface->Release();

		m_dsSurface = pNewZStencil;
		Ps3Helper_UpdateSurface( 0 );
	}

	return S_OK;
}

HRESULT IDirect3DDevice9::GetDepthStencilSurface(IDirect3DSurface9** ppZStencilSurface)
{
	m_dsSurface->AddRef();			// per http://msdn.microsoft.com/en-us/library/bb174384(VS.85).aspx

	*ppZStencilSurface = m_dsSurface;

	return S_OK;
}

HRESULT IDirect3DDevice9::GetRenderTargetData(IDirect3DSurface9* pRenderTarget,IDirect3DSurface9* pDestSurface)
{
	// is it just a blit ?

	this->StretchRect( pRenderTarget, NULL, pDestSurface, NULL, D3DTEXF_NONE ); // is this good enough ???

	return S_OK;
}

HRESULT IDirect3DDevice9::GetFrontBufferData(UINT iSwapChain,IDirect3DSurface9* pDestSurface)
{
	Debugger();
	return S_OK;
}

HRESULT IDirect3DDevice9::StretchRect(IDirect3DSurface9* pSourceSurface,CONST RECT* pSourceRect,IDirect3DSurface9* pDestSurface,CONST RECT* pDestRect,D3DTEXTUREFILTERTYPE Filter)
{
	// find relevant slices in GLM tex

	int nRenderTargetIndex = ( int ) pSourceSurface;
	Assert( nRenderTargetIndex >= -1 && nRenderTargetIndex < 4 );

	//
	// Source texture
	//
	CPs3gcmTexture	*srcTex = NULL;
	if ( nRenderTargetIndex == -1 )
		srcTex = m_dsSurface ? m_dsSurface->m_tex : NULL;
	else
		srcTex = m_rtSurfaces[nRenderTargetIndex] ? m_rtSurfaces[nRenderTargetIndex]->m_tex : NULL;
	if ( !srcTex )
		return S_FALSE;

	CPs3gcmTextureLayout::Slice_t const srcSlice = srcTex->m_layout->m_slices[ 0 ];

	//
	// Destination texture
	//
	CPs3gcmTexture	*dstTex = pDestSurface->m_tex;
	// we're assuming that we always transfer into the main mip, because it was the case so far. not gonna change it now.
	int dstSliceIndex = 0;//dstTex->m_layout->SliceIndex( pDestSurface->m_face, pDestSurface->m_mip );
	CPs3gcmTextureLayout::Slice_t const dstSlice = dstTex->m_layout->m_slices[ dstSliceIndex ];

	//
	// Perform RSX data transfer
	//

	RECT srcSizeRect = {0,0,srcSlice.m_size[0],srcSlice.m_size[1]};
	RECT dstSizeRect = {0,0,dstSlice.m_size[0],dstSlice.m_size[1]};

	if( !pDestRect )
		pDestRect = &dstSizeRect;
	if( !pSourceRect )
		pSourceRect = &srcSizeRect;

	// explicit signed int, so that width/height intermediate values may be negative
	signed int nWidth = pSourceRect->right - pSourceRect->left, nHeight = pSourceRect->bottom-pSourceRect->top;
	if( pDestRect->left + nWidth > dstSizeRect.right )
	{
		nWidth = dstSizeRect.right - pDestRect->left;
	}

	if( pDestRect->top + nHeight > dstSizeRect.bottom )
	{
		nHeight = dstSizeRect.bottom - pDestRect->top;
	}

	if( pSourceRect->left + nWidth > srcSizeRect.right )
	{
		nWidth = srcSizeRect.right - pSourceRect->left;
	}

	if( pSourceRect->top + nHeight > srcSizeRect.bottom )
	{
		nHeight = srcSizeRect.bottom - pSourceRect->top;
	}

	if( nWidth > 0 && nHeight > 0 )
	{
		gpGcmDrawState->SetTransferImage(
			CELL_GCM_TRANSFER_LOCAL_TO_LOCAL,

			dstTex->Offset(),
			dstTex->m_layout->DefaultPitch(),
			pDestRect->left, pDestRect->top,

			srcTex->Offset(),
			srcTex->m_layout->DefaultPitch(),
			pSourceRect->left, pSourceRect->top,
			nWidth, nHeight,

			// The only supported formats are R5G6B5 for a 2-byte transfer and A8R8G8B8 for a 4-byte transfer.
			!srcTex->m_layout->IsTiledMemory() ? srcTex->m_layout->GetFormatPtr()->m_gcmPitchPer4X/4 : 4
			);
	}

	return S_OK;
}

HRESULT IDirect3DDevice9::SetScissorRect(CONST RECT* pRect)
{
// 	SpuDrawScissor_t * pScissor = g_spuGcm.GetDrawQueue()->AllocWithHeader<SpuDrawScissor_t>( SPUDRAWQUEUE_SETSCISSORRECT_METHOD );
// 	V_memcpy( &m_gcmStatePpu.m_scissor[0], &pScissor->x, 4 * sizeof( uint16 ) );

	DrawScissor_t scissor, *pScissor = &scissor;
	// clamping the values to the allowed by RSX. Values outside of this range (e.g. negative width/height) will crash RSX
	// this came up w.r.t. scissor stack optimization, when used with r_portalscissor 1
	// it would be better to do this on SPU, but it would make scissor state on PPU different from SPU
	// we could "& 4095", but it's late in the project, so it seems safer to logically clamp the values
	pScissor->x = clamp( pRect->left, 0, 4095 );
	pScissor->y = clamp( pRect->top, 0, 4095 );
	pScissor->w = clamp( pRect->right  - pRect->left, 0, 4096 );
	pScissor->h = clamp( pRect->bottom - pRect->top, 0, 4096 );

	gpGcmDrawState->SetScissorRect(pScissor);

	return S_OK;
}

HRESULT IDirect3DDevice9::SetClipPlane(DWORD Index,CONST float* pPlane)
{
	Assert(Index<2);
	this->SetVertexShaderConstantF( 253 + Index, pPlane, 1 );	// stash the clip plane values into shader param - translator knows where to look
	return S_OK;
}

//--------------------------------------------------------------------------------------------------
// IDirect3DSurface9::LockRect
//				      UnlockRect
//					  GetDesc
//--------------------------------------------------------------------------------------------------

HRESULT IDirect3DSurface9::LockRect(D3DLOCKED_RECT* pLockedRect,CONST RECT* pRect,DWORD Flags)
{
	if ( !m_tex->m_lmBlock.Size() )
	{
		Assert( 0 );
		Warning( "\n\nERROR: (IDirect3DSurface9::LockRect) cannot lock this texture until AllocateTextureStorage is called!!\n\n\n" );
		return S_FALSE;
	}

	CPs3gcmTextureLayout const &layout = *m_tex->m_layout;
	int iSlice = layout.SliceIndex( this->m_face, this->m_mip );
	CPs3gcmTextureLayout::Slice_t const &slice = layout.m_slices[iSlice];

	int iOffsetInDataSlab = slice.m_storageOffset;
	int iPitch = layout.SlicePitch( iSlice );

	// Account for locking request on a subrect:
	if ( pRect )
	{
		// Assert that locking the rect can yield a pointer to a legitimate byte:
		Assert( !pRect->left || !layout.IsTiledMemory() );
		Assert( 0 == ( ( pRect->left * layout.GetFormatPtr()->m_gcmPitchPer4X ) % 4 ) );
		iOffsetInDataSlab += pRect->left * layout.GetFormatPtr()->m_gcmPitchPer4X / 4;
		iOffsetInDataSlab += pRect->top * iPitch;
	}

	// Set the locked rect data:
	pLockedRect->pBits = m_tex->Data() + iOffsetInDataSlab;
	pLockedRect->Pitch = iPitch;
	
	return S_OK;
}

HRESULT IDirect3DSurface9::UnlockRect()
{
	// Since the texture has just been modified, and this same texture bits may have been used in one of the previous draw calls
	// and may still linger in the texture cache (even if this is a new texture, it may theoretically share bits with some old texture,
	// which was just destroyed, and if we didn't have a lot of texture traffic in the last frame, those bits in texture cache may conceivably 
	// survive until the next draw call)
	gpGcmDrawState->m_dirtyCachesMask |= CGcmDrawState::kDirtyTxCache;
	return S_OK;
}

HRESULT IDirect3DSurface9::GetDesc(D3DSURFACE_DESC *pDesc)
{
	*pDesc = m_desc;
	return S_OK;
}


//--------------------------------------------------------------------------------------------------
// PIXEL SHADERS
//
// IDirect3DDevice9::CreatePixelShader
// IDirect3DPixelShader9::IDirect3DPixelShader9
//						  ~IDirect3DPixelShader9
// IDirect3DDevice9::SetPixelShader
//					 SetPixelShaderConstantF
//--------------------------------------------------------------------------------------------------

//--------------------------------------------------------------------------------------------------
// Util funcs for Cg etc..
//--------------------------------------------------------------------------------------------------

struct DatatypeRec_t
{
	CGtype type;
	CGparameterclass parameterClass;
};


static DatatypeRec_t s_datatypeClassname[] = {
#define CG_DATATYPE_MACRO(name, compiler_name, enum_name, base_enum, nrows, ncols,classname) \
	{ enum_name, classname },
#include <Cg/cg_datatypes.h>
#undef CG_DATATYPE_MACRO
};


CGparameterclass vcgGetTypeClass( CGtype type )
{
	if( type <= CG_TYPE_START_ENUM || type > CG_TYPE_START_ENUM + sizeof( s_datatypeClassname ) / sizeof( s_datatypeClassname[0] ) )
	{	
		return CG_PARAMETERCLASS_UNKNOWN;
	}
	else
	{
		DatatypeRec_t & rec = s_datatypeClassname[type - CG_TYPE_START_ENUM - 1];
		Assert( rec.type == type );
		return rec.parameterClass;
	}
}


static uint fspatchGetLength( CGtype nType )
{
	uint32_t length = 0;
	switch ( nType )
	{
	case CG_FLOAT:
	case CG_BOOL:
	case CG_FLOAT1:
	case CG_BOOL1:
		length = 1;
		break;
	case CG_FLOAT2:
	case CG_BOOL2:
		length = 2;
		break;
	case CG_FLOAT3:
	case CG_BOOL3:
		length = 3;
		break;
	case CG_FLOAT4:
	case CG_BOOL4:
		length = 4;
		break;
	case CG_FLOAT3x3:
	case CG_BOOL3x3:
	case CG_FLOAT3x4:
	case CG_BOOL3x4:
		length = 3;
		break;
	case CG_FLOAT4x4:
	case CG_BOOL4x4:
	case CG_FLOAT4x3:
	case CG_BOOL4x3:
		length = 4;
		break;
	default:
		//DebuggerBreak();
		length = 0;
	}
	return length;
}

// recursive set bit count
uint CountBits32( uint32 a )
{
	uint a1 = ( a & 0x55555555 ) + ( ( a >> 1 ) & 0x55555555 );
	uint a2 = ( a1 & 0x33333333 ) + ( ( a1 >> 2 ) & 0x33333333 );
	uint a3 = ( a2 & 0x0F0F0F0F ) + ( ( a2 >> 4 ) & 0x0F0F0F0F );
	uint a4 = ( a3 & 0x00FF00FF ) + ( ( a3 >> 8 ) & 0x00FF00FF );
	uint a5 =  ( a4 & 0xFFFF ) + ( a4 >> 16 );
	
	#ifdef DBGFLAG_ASSERT
	uint nCheckCount = 0;
	for( uint i  = 0; i < 32; ++i )
		nCheckCount += ( a >> i ) & 1;
	Assert( nCheckCount == a5 );
	#endif
	return a5;
}


//--------------------------------------------------------------------------------------------------
// IDirect3D pixel shader code
//--------------------------------------------------------------------------------------------------


HRESULT IDirect3DDevice9::CreatePixelShader(CONST DWORD* pFunction,IDirect3DPixelShader9** ppShader, const char *pShaderName, char *debugLabel)
{
	CgBinaryProgram *pProg = (CgBinaryProgram *)pFunction;

//	Msg(">>>Pixel Shader : %s at 0x%08x sz 0x%04d no.param 0x%04d \n", pShaderName, pFunction, pProg->ucodeSize, pProg->parameterCount);

	IDirect3DPixelShader9 *newprog = new IDirect3DPixelShader9( ( CgBinaryProgram * ) ( char* ) pFunction );

	Assert( !( 0xF & uint( &newprog->m_data ) ) );

	*ppShader = newprog;

	return S_OK;
}

uint32 g_nPixelShaderTotalSize = 0;
uint32 g_nPixelShaderTotalUcode = 0;

IDirect3DPixelShader9::IDirect3DPixelShader9( CgBinaryProgram* prog )
{
	g_nPixelShaderTotalSize += prog->totalSize;
	g_nPixelShaderTotalUcode += prog->ucodeSize;
	uint nPatchCount = 0;
 	
 	//--------------------------------------------------------------------------------------------------
	// Get Attribute input mask, register count and check revision
	//--------------------------------------------------------------------------------------------------
	
 	CgBinaryFragmentProgram *pCgFragmentProgram = (  CgBinaryFragmentProgram * )( uintp( prog ) + prog->program );
 	m_data.m_attributeInputMask = pCgFragmentProgram->attributeInputMask;

 	// check binary format revision -- offline recompile necessary
 	// -- enforce the correct ucode for nv40/nv47/rsx
 	Assert( prog->binaryFormatRevision == CG_BINARY_FORMAT_REVISION );

	uint registerCount = pCgFragmentProgram->registerCount;
	// NOTE: actual register count can be modified by specifying an artificial e.g. PS3REGCOUNT48 static combo to force it to 48
	Assert( registerCount <= 48 );
	if (registerCount < 2)
	{
		// register count must be [2, 48]
		registerCount = 2;
	}

	//--------------------------------------------------------------------------------------------------
	// Build shader control0 and get tex control info, including number of tex controls
	//--------------------------------------------------------------------------------------------------


	uint8_t controlTxp = CELL_GCM_FALSE;
	uint32 shCtrl0 = ( CELL_GCM_COMMAND_CAST( controlTxp ) << CELL_GCM_SHIFT_SET_SHADER_CONTROL_CONTROL_TXP ) 
		& CELL_GCM_MASK_SET_SHADER_CONTROL_CONTROL_TXP;
	shCtrl0 |= ( 1<<10 ) | ( registerCount << 24 );
	shCtrl0 |= pCgFragmentProgram->depthReplace ? 0xE : 0x0;
	shCtrl0 |= pCgFragmentProgram->outputFromH0 ? 0x00 : 0x40;
	shCtrl0 |= pCgFragmentProgram->pixelKill ? 0x80 : 0x00;

	uint texMask = pCgFragmentProgram->texCoordsInputMask;
	uint texMask2D = pCgFragmentProgram->texCoords2D;
	uint texMaskCentroid = pCgFragmentProgram->texCoordsCentroid;
	uint nTexControls = CountBits32( texMask );
	if( !IsCert() && nTexControls > 16 )
		Error( "Corrupted pixel shader with %d tex controls is requested.\n", nTexControls );

	//--------------------------------------------------------------------------------------------------
	// Walk params, count number of embedded constant patches and build sampler input mask 
	//--------------------------------------------------------------------------------------------------


	m_data.m_samplerInputMask = 0;
	CgBinaryParameter * pParameters = ( CgBinaryParameter * )( uintp( prog ) + prog->parameterArray ) ;
	
	for ( uint nPar = 0; nPar < prog->parameterCount; ++nPar )
	{
		CgBinaryParameter * pPar = pParameters + nPar;
		if( pPar->isReferenced )
		{
			if( vcgGetTypeClass( pPar->type ) == CG_PARAMETERCLASS_SAMPLER )
			{
				Assert( pPar->var == CG_UNIFORM ); // if there are varying textures, I'm not sure what they mean, exactly
				Assert( pPar->direction == CG_IN ); // fragment shaders don't generally output samplers. They take them as parameters.
				Assert( pPar->res >= CG_TEXUNIT0 && pPar->res <= CG_TEXUNIT15 );
				m_data.m_samplerInputMask |= 1 << ( pPar->res - CG_TEXUNIT0 );
			}
			else if ( pPar->embeddedConst )
			{
				const CgBinaryEmbeddedConstant * pEmbedded = ( const CgBinaryEmbeddedConstant* )( uintp( prog ) + pPar->embeddedConst );
				nPatchCount += pEmbedded->ucodeCount;
			}
		}
		else
		{
			Assert( !pPar->embeddedConst );
		}
	}

	//--------------------------------------------------------------------------------------------------
	// Allocate memory layout as : 
	// FpHeader_t
	// uCode
	// Patches
	// Texcontrols
	//--------------------------------------------------------------------------------------------------

	uint nUcodeSize = AlignValue( prog->ucodeSize, 16 );
	uint nTotalSize = AlignValue( sizeof( FpHeader_t ) + nUcodeSize + (sizeof( uint32 ) * nPatchCount) 
									+ (2 * sizeof( uint32 ) * nTexControls) , 16);
	m_data.m_nTotalSize = nTotalSize;
	m_data.m_eaFp = ( FpHeader_t* )MemAlloc_AllocAligned( nTotalSize, 16 );

	//--------------------------------------------------------------------------------------------------
	// header and mictocode
	//--------------------------------------------------------------------------------------------------

	m_data.m_eaFp->m_nUcodeSize = nUcodeSize;
	m_data.m_eaFp->m_nPatchCount = nPatchCount;
	m_data.m_eaFp->m_nShaderControl0 = shCtrl0;
	m_data.m_eaFp->m_nTexControls = nTexControls;
	V_memcpy( m_data.m_eaFp + 1, (void*)( uintp( prog ) + prog->ucode) , prog->ucodeSize );


	//--------------------------------------------------------------------------------------------------
	// Patches : Each patch is : Bits 31&30 hold the patch len - 1. Bits 16-24 constant number , bits 0-16 qw index to patch
	//--------------------------------------------------------------------------------------------------


	uint32 *pPatches = ( uint32* ) ( uintp( m_data.m_eaFp + 1 ) + nUcodeSize ), *pPatchesEnd = pPatches + nPatchCount;
	for ( uint nPar = 0; nPar < prog->parameterCount; ++nPar )
	{
		CgBinaryParameter * pPar = pParameters + nPar;

		if ( pPar->embeddedConst )
		{
			uint nLength = fspatchGetLength( pPar->type );
			uint32 nPatch = ( ( pPar->resIndex ) << 16 ) | ( ( nLength - 1 ) << 30 );
			if( pPar->resIndex > 0xFF )
			{
				Error( "Fragment Program Patch table refers to non-existing virtual register %d\n", pPar->resIndex );
			}

			if( nLength == 0 )
				Error(" Unsupported fragment program parameter type %d\n", pPar->type ); // only 4-element types are supported by the patcher so far
			const CgBinaryEmbeddedConstant * pEmbedded = ( const CgBinaryEmbeddedConstant* )( uintp( prog ) + pPar->embeddedConst );
			for ( uint nEm = 0; nEm < pEmbedded->ucodeCount; ++ nEm )
			{
				uint ucodeOffset = pEmbedded->ucodeOffset[nEm]; // is this the offset from prog structure start?
				if( !IsCert() && ( ucodeOffset & 0xF ) )
				{
					const char * pParname = (const char * )( uintp( prog ) + pPar->name );
					Error( "Patch table too big: offset 0x%X, resIndex %d, parameter %d '%s'\n", ucodeOffset, pPar->resIndex, nPar, pParname );
				}

				Assert( pPatches < pPatchesEnd );
				*( pPatches ++ ) = nPatch | ( ucodeOffset >> 4 );
			}
		}
	}
	Assert( pPatches == pPatchesEnd );

	//--------------------------------------------------------------------------------------------------
	// Tex Controls
	//--------------------------------------------------------------------------------------------------
	
	uint32 * pTexControls = (uint32*)( uintp( m_data.m_eaFp ) + sizeof( FpHeader_t ) + nUcodeSize + (sizeof( uint32 ) * nPatchCount) );
	uint32 * pTexControlsEnd = pTexControls + nTexControls * 2;
	for( uint i = 0; texMask; i++)
	{
		// keep the cached variable in sync
		if (texMask&1) {
			uint32_t hwTexCtrl = ( texMask2D & 1) | ( ( texMaskCentroid & 1 ) << 4 );
			CELL_GCM_METHOD_SET_TEX_COORD_CONTROL( pTexControls, i, hwTexCtrl );
		}

		texMask >>= 1;
		texMask2D >>= 1;
		texMaskCentroid >>= 1;
	}
	Assert( pTexControls == pTexControlsEnd );		// The CELL_GCM macro bumps pTexControls along..
	
}


IDirect3DPixelShader9::~IDirect3DPixelShader9()
{
	MemAlloc_FreeAligned( m_data.m_eaFp );
}


HRESULT IDirect3DDevice9::SetPixelShader( IDirect3DPixelShader9* pShader )
{
	m_pixelShader = pShader;
	
	gpGcmDrawState->m_dirtyCachesMask |= CGcmDrawState::kDirtyPxShader;
	gpGcmDrawState->m_pPixelShaderData = m_pixelShader ? &pShader->m_data : 0;

	return S_OK;
}

HRESULT IDirect3DDevice9::SetPixelShaderConstantF(UINT StartRegister, CONST float* pConstantData, UINT Vector4fCount)
{
	gpGcmDrawState->SetPixelShaderConstantF(StartRegister, (float*)pConstantData, Vector4fCount);
	return S_OK;
}

HRESULT IDirect3DDevice9::SetPixelShaderConstantB(UINT StartRegister,CONST BOOL* pConstantData,UINT  BoolCount)
{
	// Not implemented on PS3!
	return S_OK;
}

HRESULT IDirect3DDevice9::SetPixelShaderConstantI(UINT StartRegister,CONST int* pConstantData,UINT Vector4iCount)
{
	// Not implemented on PS3!
	return S_OK;
}


//--------------------------------------------------------------------------------------------------
// VERTEX SHADERS
//
// IDirect3DDevice9::	CreateVertexShader
// IDirect3DVertexShader9::~IDirect3DVertexShader9
// IDirect3DDevice9::	SetVertexShader
//						SetVertexShaderConstantF
//						SetVertexShaderConstantB
//--------------------------------------------------------------------------------------------------

HRESULT IDirect3DDevice9::CreateVertexShader(CONST DWORD* pFunction,IDirect3DVertexShader9** ppShader, char *debugLabel)
{
	IDirect3DVertexShader9 *newprog = new IDirect3DVertexShader9;
	newprog->m_pProgram = NULL; // don't copy (base member unused)

	//--------------------------------------------------------------------------------------------------
	// get program and in/out attr
	//--------------------------------------------------------------------------------------------------

	const CgBinaryProgram *prog = ( const CgBinaryProgram * )pFunction;
	CgBinaryVertexProgram * binaryVertexProgram = ( CgBinaryVertexProgram* ) ( ( char* )prog + prog->program );

	newprog->m_data.m_attributeInputMask = binaryVertexProgram->attributeInputMask;
	newprog->m_data.m_attributeOutputMask = binaryVertexProgram->attributeOutputMask;
	
	//--------------------------------------------------------------------------------------------------
	// Determine size of VP, allocate command buffer to set VP
	//--------------------------------------------------------------------------------------------------


	uint nReserveWords = AlignValue( cellGcmSetVertexProgramMeasureSizeInline( 0, ( const CGprogram )prog, ( ( uint8* )prog ) + prog->ucode ), 4 );
	if( nReserveWords > 4 * 1024 )
	{
		Error( "Vertex shader too big (%d words): won't fit into a single DMA, tell Sergiy to perform Large DMA transfer everywhere vertex shader command subbuffer is used\n", nReserveWords );
	}
	newprog->m_data.m_nVertexShaderCmdBufferWords = nReserveWords;
	newprog->m_data.m_pVertexShaderCmdBuffer = ( uint32* ) MemAlloc_AllocAligned( nReserveWords * sizeof( uint32 ), 16 );
	

	//--------------------------------------------------------------------------------------------------
	// Use GCM to output SetVertexProgram commands
	//--------------------------------------------------------------------------------------------------

	CellGcmContextData tempCtx;

	tempCtx.current = tempCtx.begin = newprog->m_data.m_pVertexShaderCmdBuffer; 
	tempCtx.end = tempCtx.begin + nReserveWords;
	tempCtx.callback = NULL;
	
	cellGcmSetVertexProgramUnsafeInline( &tempCtx, ( const CGprogram )prog, ( ( uint8* )prog ) + prog->ucode );
	
	Assert( tempCtx.current <= tempCtx.end && tempCtx.end - tempCtx.current < 4 );
	while( tempCtx.current < tempCtx.end )
	{
		*( tempCtx.current++ ) = CELL_GCM_METHOD_NOP; // make it 16-byte aligned
	}
	
	*ppShader = newprog;

	return S_OK;
}

IDirect3DVertexShader9::~IDirect3DVertexShader9()
{
	MemAlloc_FreeAligned( m_data.m_pVertexShaderCmdBuffer );
}

HRESULT IDirect3DDevice9::SetVertexShader( IDirect3DVertexShader9* pVertexShader )
{
	m_vertexShader = pVertexShader;

	gpGcmDrawState->m_dirtyCachesMask |= CGcmDrawState::kDirtyVxShader;
	gpGcmDrawState->m_pVertexShaderData = &pVertexShader->m_data;

	return S_OK;
}

HRESULT IDirect3DDevice9::SetVertexShaderConstantF( UINT StartRegister,CONST float* pConstantData,UINT Vector4fCount )
{
	gpGcmDrawState->SetVertexShaderConstantF(StartRegister, (void*)pConstantData, Vector4fCount);
	return S_OK;
}


HRESULT IDirect3DDevice9::SetVertexShaderConstantB(UINT StartRegister,CONST BOOL* pConstantData,UINT  BoolCount)
{
	gpGcmDrawState->SetVertexShaderConstantB(StartRegister, pConstantData, BoolCount);
	return S_OK;
}

HRESULT IDirect3DDevice9::SetVertexShaderConstantI(UINT StartRegister,CONST int* pConstantData,UINT Vector4iCount)
{
	// Not implemented on PS3!
	return S_OK;
}

//--------------------------------------------------------------------------------------------------
// RENDERSTATES
//IDirect3DDevice9::SetRenderState
//					SetSamplerState
//					SetSamplerStatePart1
//--------------------------------------------------------------------------------------------------

struct	D3D_RSINFO
{
	int					m_class;
	D3DRENDERSTATETYPE	m_state;
	DWORD				m_defval;
	// m_class runs 0-3.
	// 3 = must implement - fully general - "obey"
	// 2 = implement setup to the default value (it has a GL effect but does not change later) "obey once"
	// 1 = "fake implement" setup to the default value no GL effect, debug break if anything but default value comes through - "ignore"
	// 0 = game never ever sets this one, break if someone even tries. "complain"
};

bool		g_D3DRS_INFO_unpacked_ready = false;	// set to true after unpack
D3D_RSINFO	g_D3DRS_INFO_unpacked[ D3DRS_VALUE_LIMIT+1 ];

#ifdef D3D_RSI
#error macro collision... rename this
#else
#define D3D_RSI(nclass,nstate,ndefval)	{ nclass, nstate, ndefval }
#endif

// FP conversions to hex courtesy of http://babbage.cs.qc.cuny.edu/IEEE-754/Decimal.html
#define	CONST_DZERO		0x00000000
#define	CONST_DONE		0x3F800000
#define	CONST_D64		0x42800000
#define	DONT_KNOW_YET	0x31415926


// see http://www.toymaker.info/Games/html/render_states.html

D3D_RSINFO	g_D3DRS_INFO_packed[] = 
{
	// these do not have to be in any particular order.  they get unpacked into the empty array above for direct indexing.

	D3D_RSI(	3,	D3DRS_ZENABLE,						DONT_KNOW_YET			),	// enable Z test (or W buffering)
	D3D_RSI(	3,	D3DRS_ZWRITEENABLE,					DONT_KNOW_YET			),	// enable Z write
	D3D_RSI(	3,	D3DRS_ZFUNC,						DONT_KNOW_YET			),	// select Z func

	D3D_RSI(	3,	D3DRS_COLORWRITEENABLE,				TRUE					),	// see transitiontable.cpp "APPLY_RENDER_STATE_FUNC( D3DRS_COLORWRITEENABLE, ColorWriteEnable )"

	D3D_RSI(	3,	D3DRS_CULLMODE,						D3DCULL_CCW				),	// backface cull control

	D3D_RSI(	3,	D3DRS_ALPHABLENDENABLE,				DONT_KNOW_YET			),	// ->CTransitionTable::ApplySeparateAlphaBlend and ApplyAlphaBlend
	D3D_RSI(	3,	D3DRS_BLENDOP,						D3DBLENDOP_ADD			),
	D3D_RSI(	3,	D3DRS_SRCBLEND,						DONT_KNOW_YET			),
	D3D_RSI(	3,	D3DRS_DESTBLEND,					DONT_KNOW_YET			),

	D3D_RSI(	1,	D3DRS_SEPARATEALPHABLENDENABLE,		FALSE					),	// hit in CTransitionTable::ApplySeparateAlphaBlend
	D3D_RSI(	1,	D3DRS_SRCBLENDALPHA,				D3DBLEND_ONE			),	// going to demote these to class 1 until I figure out if they are implementable
	D3D_RSI(	1,	D3DRS_DESTBLENDALPHA,				D3DBLEND_ZERO			),
	D3D_RSI(	1,	D3DRS_BLENDOPALPHA,					D3DBLENDOP_ADD			),

	// what is the deal with alpha test... looks like it is inited to off.
	D3D_RSI(	3,	D3DRS_ALPHATESTENABLE,				0						),
	D3D_RSI(	3,	D3DRS_ALPHAREF,						0						),
	D3D_RSI(	3,	D3DRS_ALPHAFUNC,					D3DCMP_GREATEREQUAL		),

	D3D_RSI(	3,	D3DRS_STENCILENABLE,				FALSE					),
	D3D_RSI(	3,	D3DRS_STENCILFAIL,					D3DSTENCILOP_KEEP		),
	D3D_RSI(	3,	D3DRS_STENCILZFAIL,					D3DSTENCILOP_KEEP		),
	D3D_RSI(	3,	D3DRS_STENCILPASS,					D3DSTENCILOP_KEEP		),
	D3D_RSI(	3,	D3DRS_STENCILFUNC,					D3DCMP_ALWAYS			),
	D3D_RSI(	3,	D3DRS_STENCILREF,					0						),
	D3D_RSI(	3,	D3DRS_STENCILMASK,					0xFFFFFFFF				),
	D3D_RSI(	3,	D3DRS_STENCILWRITEMASK,				0xFFFFFFFF				),

	D3D_RSI(	3,	D3DRS_TWOSIDEDSTENCILMODE,			FALSE					),
	D3D_RSI(	3,	D3DRS_CCW_STENCILFAIL,				D3DSTENCILOP_KEEP		),
	D3D_RSI(	3,	D3DRS_CCW_STENCILZFAIL,				D3DSTENCILOP_KEEP		),
	D3D_RSI(	3,	D3DRS_CCW_STENCILPASS,				D3DSTENCILOP_KEEP		),
	D3D_RSI(	3,	D3DRS_CCW_STENCILFUNC,				D3DCMP_ALWAYS 			),

	D3D_RSI(	3,	D3DRS_FOGENABLE,					FALSE					),	// see CShaderAPIDx8::FogMode and friends - be ready to do the ARB fog linear option madness
	D3D_RSI(	3,	D3DRS_FOGCOLOR,						0						),
	D3D_RSI(	3,	D3DRS_FOGTABLEMODE,					D3DFOG_NONE				),
	D3D_RSI(	3,	D3DRS_FOGSTART,						CONST_DZERO				),
	D3D_RSI(	3,	D3DRS_FOGEND,						CONST_DONE				),
	D3D_RSI(	3,	D3DRS_FOGDENSITY,					CONST_DZERO				),
	D3D_RSI(	3,	D3DRS_RANGEFOGENABLE,				FALSE					),
	D3D_RSI(	3,	D3DRS_FOGVERTEXMODE,				D3DFOG_NONE				),	// watch out for CShaderAPIDx8::CommitPerPassFogMode....

	D3D_RSI(	3,	D3DRS_MULTISAMPLEANTIALIAS,			TRUE					),
	D3D_RSI(	3,	D3DRS_MULTISAMPLEMASK,				0xFFFFFFFF				),

	D3D_RSI(	3,	D3DRS_SCISSORTESTENABLE,			FALSE					),	// heed IDirect3DDevice9::SetScissorRect

	D3D_RSI(	3,	D3DRS_DEPTHBIAS,					CONST_DZERO				),
	D3D_RSI(	3,	D3DRS_SLOPESCALEDEPTHBIAS,			CONST_DZERO				),

	D3D_RSI(	3,	D3DRS_COLORWRITEENABLE1,			0x0000000f				),
	D3D_RSI(	3,	D3DRS_COLORWRITEENABLE2,			0x0000000f				),
	D3D_RSI(	3,	D3DRS_COLORWRITEENABLE3,			0x0000000f				),

	D3D_RSI(	3,	D3DRS_SRGBWRITEENABLE,				0						),	// heeded but ignored..

	D3D_RSI(	2,	D3DRS_CLIPPING,						TRUE					),	// um, yeah, clipping is enabled (?)
	D3D_RSI(	3,	D3DRS_CLIPPLANEENABLE,				0						),	// mask 1<<n of active user clip planes.

	D3D_RSI(	0,	D3DRS_LIGHTING,						0						),	// strange, someone turns it on then off again. move to class 0 and just ignore it (lie)?

	D3D_RSI(	3,	D3DRS_FILLMODE,						D3DFILL_SOLID			),

	D3D_RSI(	1,	D3DRS_SHADEMODE,					D3DSHADE_GOURAUD		),
	D3D_RSI(	1,	D3DRS_LASTPIXEL,					TRUE					),
	D3D_RSI(	1,	D3DRS_DITHERENABLE,					0						),	//set to false by game, no one sets it to true
	D3D_RSI(	1,	D3DRS_SPECULARENABLE,				FALSE					),
	D3D_RSI(	1,	D3DRS_TEXTUREFACTOR,				0xFFFFFFFF				),	// watch out for CShaderAPIDx8::Color3f et al.
	D3D_RSI(	1,	D3DRS_WRAP0,						0						),
	D3D_RSI(	1,	D3DRS_WRAP1,						0						),
	D3D_RSI(	1,	D3DRS_WRAP2,						0						),
	D3D_RSI(	1,	D3DRS_WRAP3,						0						),
	D3D_RSI(	1,	D3DRS_WRAP4,						0						),
	D3D_RSI(	1,	D3DRS_WRAP5,						0						),
	D3D_RSI(	1,	D3DRS_WRAP6,						0						),
	D3D_RSI(	1,	D3DRS_WRAP7,						0						),
	D3D_RSI(	1,	D3DRS_AMBIENT,						0						),	// FF lighting, no
	D3D_RSI(	1,	D3DRS_COLORVERTEX,					TRUE					),	// FF lighing again
	D3D_RSI(	1,	D3DRS_LOCALVIEWER,					TRUE					),	// FF lighting
	D3D_RSI(	1,	D3DRS_NORMALIZENORMALS,				FALSE					),	// FF mode I think.  CShaderAPIDx8::SetVertexBlendState says it might switch this on when skinning is in play
	D3D_RSI(	1,	D3DRS_DIFFUSEMATERIALSOURCE,		D3DMCS_MATERIAL			),	// hit only in CShaderAPIDx8::ResetRenderState
	D3D_RSI(	1,	D3DRS_SPECULARMATERIALSOURCE,		D3DMCS_COLOR2			),
	D3D_RSI(	1,	D3DRS_AMBIENTMATERIALSOURCE,		D3DMCS_MATERIAL			),
	D3D_RSI(	1,	D3DRS_EMISSIVEMATERIALSOURCE,		D3DMCS_MATERIAL			),
	D3D_RSI(	1,	D3DRS_VERTEXBLEND,					D3DVBF_DISABLE			),	// also being set by CShaderAPIDx8::SetVertexBlendState, so might be FF
	D3D_RSI(	1,	D3DRS_POINTSIZE,					CONST_DONE				),
	D3D_RSI(	1,	D3DRS_POINTSIZE_MIN,				CONST_DONE				),
	D3D_RSI(	1,	D3DRS_POINTSPRITEENABLE,			FALSE					),
	D3D_RSI(	1,	D3DRS_POINTSCALEENABLE,				FALSE					),
	D3D_RSI(	1,	D3DRS_POINTSCALE_A,					CONST_DONE				),
	D3D_RSI(	1,	D3DRS_POINTSCALE_B,					CONST_DZERO				),
	D3D_RSI(	1,	D3DRS_POINTSCALE_C,					CONST_DZERO				),
	D3D_RSI(	1,	D3DRS_PATCHEDGESTYLE,				D3DPATCHEDGE_DISCRETE	),
	D3D_RSI(	1,	D3DRS_DEBUGMONITORTOKEN,			D3DDMT_ENABLE			),
	D3D_RSI(	1,	D3DRS_POINTSIZE_MAX,				CONST_D64				),
	D3D_RSI(	1,	D3DRS_INDEXEDVERTEXBLENDENABLE,		FALSE					),
	D3D_RSI(	1,	D3DRS_TWEENFACTOR,					CONST_DZERO				),
	D3D_RSI(	1,	D3DRS_POSITIONDEGREE,				D3DDEGREE_CUBIC			),
	D3D_RSI(	1,	D3DRS_NORMALDEGREE,					D3DDEGREE_LINEAR		),
	D3D_RSI(	1,	D3DRS_ANTIALIASEDLINEENABLE,		FALSE					),	// just ignore it
	D3D_RSI(	1,	D3DRS_MINTESSELLATIONLEVEL,			CONST_DONE				),
	D3D_RSI(	1,	D3DRS_MAXTESSELLATIONLEVEL,			CONST_DONE				),
	D3D_RSI(	1,	D3DRS_ADAPTIVETESS_X,				CONST_DZERO				),
	D3D_RSI(	1,	D3DRS_ADAPTIVETESS_Y,				CONST_DZERO				),
	D3D_RSI(	1,	D3DRS_ADAPTIVETESS_Z,				CONST_DONE				),
	D3D_RSI(	1,	D3DRS_ADAPTIVETESS_W,				CONST_DZERO				),
	D3D_RSI(	1,	D3DRS_ENABLEADAPTIVETESSELLATION,	FALSE					),
	D3D_RSI(	1,	D3DRS_BLENDFACTOR,					0xffffffff				),
	D3D_RSI(	1,	D3DRS_WRAP8,						0						),
	D3D_RSI(	1,	D3DRS_WRAP9,						0						),
	D3D_RSI(	1,	D3DRS_WRAP10,						0						),
	D3D_RSI(	1,	D3DRS_WRAP11,						0						),
	D3D_RSI(	1,	D3DRS_WRAP12,						0						),
	D3D_RSI(	1,	D3DRS_WRAP13,						0						),
	D3D_RSI(	1,	D3DRS_WRAP14,						0						),
	D3D_RSI(	1,	D3DRS_WRAP15,						0						),
	D3D_RSI(	-1,	(D3DRENDERSTATETYPE)0,				0						)	// terminator
};


uint FindOrInsert( CUtlVector<uint32> &arrDefValues, uint32 nDefValue )
{
	// the def value array is supposed to be VERY short, so linear search is faster than binary
	Assert( arrDefValues.Count() < 16 );
	for( uint i = 0; i < arrDefValues.Count(); ++i )
	{
		if( arrDefValues[i] == nDefValue )
			return i;
	}
	arrDefValues.AddToTail( nDefValue );
	return arrDefValues.Count() - 1 ;
}



void	UnpackD3DRSITable( void )
{
	V_memset (g_D3DRS_INFO_unpacked, 0, sizeof(g_D3DRS_INFO_unpacked) );

	for( D3D_RSINFO *packed = g_D3DRS_INFO_packed; packed->m_class >= 0; packed++ )
	{
		if ( (packed->m_state <0) || (packed->m_state >= D3DRS_VALUE_LIMIT) )
		{
			// bad
			Debugger();
		}
		else
		{
			// dispatch it to the unpacked array
			g_D3DRS_INFO_unpacked[ packed->m_state ] = *packed;
		}
	}

}

HRESULT IDirect3DDevice9::SetRenderState(D3DRENDERSTATETYPE State,DWORD Value)
{
	gpGcmDrawState->SetRenderState(State, Value);
	return S_OK;
}


HRESULT IDirect3DDevice9::SetSamplerState(DWORD Sampler,D3DSAMPLERSTATETYPE Type,DWORD Value)
{
	gpGcmDrawState->SetSamplerState(Sampler, Type, Value);
	return S_OK;
}

//--------------------------------------------------------------------------------------------------
// VERTEX DECLS, STREAMS, BUFFERS, INDICES
// IDirect3DDevice9::	CreateVertexDeclaration
// 						SetVertexDeclaration
// 						CreateVertexBuffer
// 						SetVertexStreamSource
// 						SetStreamSource
//						FlushVertexCache
// 						SetRawHardwareDataStreams
// IDirect3DIndexBuffer9::GetDesc
// IDirect3DDevice9::	CreateIndexBuffer
//						SetIndices
//						ValidateDrawPrimitiveStreams
//--------------------------------------------------------------------------------------------------

// Lookup table used by CreateVertexDeclaration

unsigned char g_D3DDeclFromPSGL_UsageMappingTable[] =
{
	/*0x00*/	0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,
	/*0x10*/	1, ~0, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,
	/*0x20*/	7, ~0, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,
	/*0x30*/	2, ~0, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,
	/*0x40*/	6, ~0, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,
	/*0x50*/	8, 9, 0xA, 0xB,		0xC, 0xD, 0xE, 0xF,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,
	/*0x60*/	~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,
	/*0x70*/	~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,
	/*0x80*/	5, ~0, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,
	/*0x90*/	~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,
	/*0xA0*/	3, 4, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,
	/*0xB0*/	~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,
	/*0xC0*/	~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,
	/*0xD0*/	~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,
	/*0xE0*/	~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,
	/*0xF0*/	~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,		~0, ~0, ~0, ~0,
};


HRESULT IDirect3DDevice9::CreateVertexDeclaration( CONST D3DVERTEXELEMENT9* pVertexElements, IDirect3DVertexDeclaration9** ppDecl)
{
	*ppDecl = NULL;
	
	// the goal here is to arrive at something which lets us quickly generate GLMVertexSetups.

	// the information we don't have, that must be inferred from the decls, is:
	// -> how many unique streams (buffers) are used - pure curiosity
	// -> what the stride and offset is for each decl.  Size you can figure out on the spot, stride requires surveying all the components in each stream first.
	//	so init an array of per-stream offsets to 0.
	//	each one is a cursor that gets bumped by decls.
	uint	streamOffsets[ D3D_MAX_STREAMS ];
	
	memset( streamOffsets, 0, sizeof( streamOffsets ) );

	IDirect3DVertexDeclaration9 *decl9 = new IDirect3DVertexDeclaration9;
	Assert( !( uintp( decl9 ) & 0xF ) );
	
	decl9->m_elemCount = 0;
			
	for (const D3DVERTEXELEMENT9 *src = pVertexElements; (src->Stream != 0xFF); src++)
	{
		// element
		D3DVERTEXELEMENT9_GCM *elem = &decl9->m_elements[ decl9->m_elemCount++ ];

		// copy the D3D decl wholesale.
		elem->m_dxdecl = *src;

		// On PS3:
		// TEXCOORD4 == POSITION1	(this semantic doesn't exist in Cg, see #define in common_vs_fxc.h)
		// TEXCOORD5 == NORMAL1 	(this semantic doesn't exist in Cg, see #define in common_vs_fxc.h)
		// TEXCOORD6 == TANGENT		(Cg remaps this automatically)
		// TEXCOORD7 == BINORMAL	(Cg remaps this automatically)

		if ( elem->m_dxdecl.Usage == D3DDECLUSAGE_TANGENT )
		{
			Assert( elem->m_dxdecl.UsageIndex == 0 );
			elem->m_dxdecl.Usage = D3DDECLUSAGE_TEXCOORD;
			elem->m_dxdecl.UsageIndex = 6;
		}
		else if ( elem->m_dxdecl.Usage == D3DDECLUSAGE_BINORMAL )
		{
			Assert( elem->m_dxdecl.UsageIndex == 0 );
			elem->m_dxdecl.Usage = D3DDECLUSAGE_TEXCOORD;
			elem->m_dxdecl.UsageIndex = 7;
		}
		else if ( elem->m_dxdecl.Usage == D3DDECLUSAGE_POSITION && elem->m_dxdecl.UsageIndex >= 1 )
		{
			Assert( elem->m_dxdecl.UsageIndex == 1 );
			elem->m_dxdecl.Usage = D3DDECLUSAGE_TEXCOORD;
			elem->m_dxdecl.UsageIndex = 4;
		}
		else if ( elem->m_dxdecl.Usage == D3DDECLUSAGE_NORMAL && elem->m_dxdecl.UsageIndex >= 1 )
		{
			Assert( elem->m_dxdecl.UsageIndex == 1 );
			elem->m_dxdecl.Usage = D3DDECLUSAGE_TEXCOORD;
			elem->m_dxdecl.UsageIndex = 5;
		}
				
		// latch current offset in this stream.
		elem->m_gcmdecl.m_offset = streamOffsets[ elem->m_dxdecl.Stream ];
		
		// figure out size of this attr and move the cursor
		// if cursor was on zero, bump the active stream count
		
		int bytes = 0;
		switch( elem->m_dxdecl.Type )
		{
			case D3DDECLTYPE_FLOAT1:	elem->m_gcmdecl.m_datasize = 1; elem->m_gcmdecl.m_datatype = CELL_GCM_VERTEX_F; bytes = 4; break;
			case D3DDECLTYPE_FLOAT2:	elem->m_gcmdecl.m_datasize = 2; elem->m_gcmdecl.m_datatype = CELL_GCM_VERTEX_F; bytes = 8; break;
			//case D3DVSDT_FLOAT3:
			case D3DDECLTYPE_FLOAT3:	elem->m_gcmdecl.m_datasize = 3; elem->m_gcmdecl.m_datatype = CELL_GCM_VERTEX_F; bytes = 12; break;
			//case D3DVSDT_FLOAT4:
			case D3DDECLTYPE_FLOAT4:	elem->m_gcmdecl.m_datasize = 4; elem->m_gcmdecl.m_datatype = CELL_GCM_VERTEX_F; bytes = 16; break;

			case D3DDECLTYPE_SHORT2:	elem->m_gcmdecl.m_datasize = 2; elem->m_gcmdecl.m_datatype = CELL_GCM_VERTEX_S32K; bytes = 4; break;
			case D3DDECLTYPE_UBYTE4:	elem->m_gcmdecl.m_datasize = 4; elem->m_gcmdecl.m_datatype = CELL_GCM_VERTEX_UB256; bytes = 4; break;
			case D3DDECLTYPE_UBYTE4N:	elem->m_gcmdecl.m_datasize = 4; elem->m_gcmdecl.m_datatype = CELL_GCM_VERTEX_UB; bytes = 4; break;

			// case D3DVSDT_UBYTE4:		
			case D3DDECLTYPE_D3DCOLOR:
				// pass 4 UB's but we know this is out of order compared to D3DCOLOR data
				elem->m_gcmdecl.m_datasize = 4; elem->m_gcmdecl.m_datatype = CELL_GCM_VERTEX_UB;
				bytes = 4;
			break;

			default:	Debugger(); return (HRESULT)-1; break;

		}
		
		// write the offset and move the cursor
		streamOffsets[ elem->m_dxdecl.Stream ] += bytes;
		
		// elem count was already bumped.
	}

	// the loop is done, we now know how many active streams there are, how many atribs are active in the declaration,
	// and how big each one is in terms of stride.

	// PS3 has fixed semantics of 16 attributes, to avoid searches later when
	// binding to slots perform the search now once:
	memset( decl9->m_cgAttrSlots, 0, sizeof( decl9->m_cgAttrSlots ) );
	for ( int j = 0; j < decl9->m_elemCount; ++ j )
	{
		D3DVERTEXELEMENT9_GCM	*elem = &decl9->m_elements[ j ];
		unsigned char uchType = ( ( elem->m_dxdecl.Usage & 0xF ) << 4 ) | ( elem->m_dxdecl.UsageIndex & 0xF );
		unsigned char chType = g_D3DDeclFromPSGL_UsageMappingTable[ uchType ];
		if ( chType < ARRAYSIZE( decl9->m_cgAttrSlots ) )
		{
			if ( !decl9->m_cgAttrSlots[chType] )
			{
				decl9->m_cgAttrSlots[chType] = j + 1;
			}
			else
			{
				// An input element has already been mapped to this slot. 
				// This can happen when the vertex decl uses POSITION1/NORMAL1 (flex deltas), which we map to TEXCOORD4/5, and the decl already uses TEXCOORD4/5. 
				// For now we ignore these elements, which it turns out are always unused when the vertex shader actually uses TEXCOORD4/5.
			}
		}
		else
		{
			Assert( false );
		}
	}
	
	*ppDecl = decl9;

	return S_OK;
}

HRESULT IDirect3DDevice9::SetVertexDeclaration(IDirect3DVertexDeclaration9* pDecl)
{
	// we just latch it.  At draw time we combine the current vertex decl with the current stream set and generate a vertex setup for GLM.
	// GLM can see what the differences are and act accordingly to adjust vert attrib bindings.

	m_vertDecl = pDecl;
	
	return S_OK;
}

HRESULT IDirect3DDevice9::SetFVF(DWORD FVF)
{
	Debugger();

	return S_OK;
}

HRESULT IDirect3DDevice9::GetFVF(DWORD* pFVF)
{
	Debugger();

	return S_OK;
}

HRESULT IDirect3DDevice9::CreateVertexBuffer(UINT Length,DWORD Usage,DWORD FVF,D3DPOOL Pool,IDirect3DVertexBuffer9** ppVertexBuffer,VD3DHANDLE* pSharedHandle)
{
	IDirect3DVertexBuffer9 *pNewVertexBuffer = new IDirect3DVertexBuffer9;
	//pNewVertexBuffer->m_restype = D3DRTYPE_VERTEXBUFFER;		hmmmmmmm why are we not derived from d3dresource..
	
	CPs3gcmAllocationType_t eAllocType = kAllocPs3GcmVertexBuffer;
	if ( Usage & D3DUSAGE_EDGE_DMA_INPUT )
		eAllocType = kAllocPs3GcmVertexBufferDma;
	else if ( Usage & D3DUSAGE_DYNAMIC )
		eAllocType = kAllocPs3GcmVertexBufferDynamic;
	pNewVertexBuffer->m_pBuffer = CPs3gcmBuffer::New( Length, eAllocType );
	
	pNewVertexBuffer->m_vtxDesc.Type		= D3DRTYPE_VERTEXBUFFER;
	pNewVertexBuffer->m_vtxDesc.Usage	= Usage;
	pNewVertexBuffer->m_vtxDesc.Pool		= Pool;
	pNewVertexBuffer->m_vtxDesc.Size		= Length;

	*ppVertexBuffer = pNewVertexBuffer;
	
	return S_OK;
}

inline void IDirect3DDevice9::SetVertexStreamSource( uint nStreamIndex, IDirect3DVertexBuffer9* pStreamData,UINT OffsetInBytes,UINT Stride )
{
	gpGcmDrawState->SetVertexStreamSource(nStreamIndex, pStreamData, OffsetInBytes, Stride);
}


HRESULT IDirect3DDevice9::SetStreamSource(UINT StreamNumber,IDirect3DVertexBuffer9* pStreamData,UINT OffsetInBytes,UINT Stride)
{
	// perfectly legal to see a vertex buffer of NULL get passed in here.
	// so we need an array to track these.
	// OK, we are being given the stride, we don't need to calc it..
	
	SetVertexStreamSource( StreamNumber, pStreamData, OffsetInBytes, Stride );
	
	return S_OK;
}


HRESULT IDirect3DDevice9::SetRawHardwareDataStreams( IDirect3DVertexBuffer9** ppRawHardwareDataStreams )
{
// Unused on PS3
// 	if ( ppRawHardwareDataStreams )
// 	{
// 		V_memcpy( gpGcmDrawState->m_arrRawHardwareDataStreams, ppRawHardwareDataStreams, sizeof( gpGcmDrawState->m_arrRawHardwareDataStreams ) );
// 	}
// 	else
// 	{
// 		V_memset( gpGcmDrawState->m_arrRawHardwareDataStreams, 0, sizeof( gpGcmDrawState->m_arrRawHardwareDataStreams ) );
// 	}
	return S_OK;
}

void IDirect3DDevice9::FlushVertexCache()
{
	gpGcmDrawState->SetInvalidateVertexCache();
}

HRESULT IDirect3DIndexBuffer9::GetDesc(D3DINDEXBUFFER_DESC *pDesc)
{
	*pDesc = m_idxDesc;
	return S_OK;
}

// index buffers
HRESULT IDirect3DDevice9::CreateIndexBuffer(UINT Length,DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,IDirect3DIndexBuffer9** ppIndexBuffer,VD3DHANDLE* pSharedHandle)
{
	// it is important to save all the create info, since GetDesc could get called later to query it
	
	IDirect3DIndexBuffer9 *pNewIndexBuffer = new IDirect3DIndexBuffer9;
	
	CPs3gcmAllocationType_t eAllocType = kAllocPs3GcmIndexBuffer;
	if ( Usage & D3DUSAGE_EDGE_DMA_INPUT )
		eAllocType = kAllocPs3GcmIndexBufferDma;
	else if ( Usage & D3DUSAGE_DYNAMIC )
		eAllocType = kAllocPs3GcmIndexBufferDynamic;
	pNewIndexBuffer->m_pBuffer = CPs3gcmBuffer::New( Length, eAllocType );
	
	pNewIndexBuffer->m_idxDesc.Format	= Format;
	pNewIndexBuffer->m_idxDesc.Type		= D3DRTYPE_INDEXBUFFER;
	pNewIndexBuffer->m_idxDesc.Usage	= Usage;
	pNewIndexBuffer->m_idxDesc.Pool		= Pool;
	pNewIndexBuffer->m_idxDesc.Size		= Length;

	*ppIndexBuffer = pNewIndexBuffer;
	return S_OK;
}

HRESULT IDirect3DDevice9::SetIndices( IDirect3DIndexBuffer9* pIndexData )
{
	// just latch it.
	m_indices.m_idxBuffer = pIndexData;

	return S_OK;
}

ConVar r_ps3_validatestreams( "r_ps3_validatestreams", "0", FCVAR_DEVELOPMENTONLY );

HRESULT	IDirect3DDevice9::ValidateDrawPrimitiveStreams( D3DPRIMITIVETYPE Type, UINT baseVertexIndex, UINT MinVertexIndex, UINT NumVertices, UINT startIndex, UINT primCount )
{
	return S_OK;
}

//--------------------------------------------------------------------------------------------------
// DRAW
//
// IDirect3DDevice9::	DrawPrimitive
// 						DrawPrimitiveUP
// 						DrawIndexedPrimitive
// 						Clear
//--------------------------------------------------------------------------------------------------

HRESULT IDirect3DDevice9::DrawPrimitive(D3DPRIMITIVETYPE PrimitiveType,UINT StartVertex,UINT PrimitiveCount)
{
	Debugger();
	return S_OK;
}

void IDirect3DDevice9::DrawPrimitiveUP( D3DPRIMITIVETYPE nPrimitiveType,UINT nPrimitiveCount,
									    CONST void *pVertexStreamZeroData, UINT nVertexStreamZeroStride )
{
	gpGcmDrawState->DrawPrimitiveUP(m_vertDecl, nPrimitiveType, nPrimitiveCount, pVertexStreamZeroData, nVertexStreamZeroStride);
}

HRESULT IDirect3DDevice9::DrawIndexedPrimitive( D3DPRIMITIVETYPE Type,INT BaseVertexIndex,UINT MinVertexIndex,
											    UINT NumVertices,UINT startIndex,UINT nDrawPrimCount )
{
	uint32 offset = m_indices.m_idxBuffer->m_pBuffer->Offset();

	gpGcmDrawState->DrawIndexedPrimitive(offset, m_vertDecl, Type, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, nDrawPrimCount );

	return S_OK;
}


HRESULT IDirect3DDevice9::Clear( DWORD Count, CONST D3DRECT* pRects, DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil )
{
	uint32 depth = ( ( m_dsSurface ) && ( m_dsSurface->m_desc.Format == D3DFMT_D16 ) ) ? 16 : 32;
	
	gpGcmDrawState->ClearSurface(Flags, Color, Z, Stencil, depth );

	return S_OK;
}


HRESULT IDirect3DDevice9::DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType,UINT MinVertexIndex,UINT NumVertices,UINT PrimitiveCount,CONST void* pIndexData,D3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,UINT VertexStreamZeroStride)
{
	Debugger();
	return S_OK;
}

//--------------------------------------------------------------------------------------------------
// Zpass
//--------------------------------------------------------------------------------------------------

void IDirect3DDevice9::BeginZPass( DWORD Flags )
{
// 	Assert( Flags == 0 );
// 	if( !m_isZPass )
// 	{
// 		m_isZPass = g_spuGcm.BeginZPass();
// 	}
}

void IDirect3DDevice9::SetPredication( DWORD PredicationMask )
{
// 	Assert( PredicationMask == 0 || PredicationMask == D3DPRED_ALL_RENDER || PredicationMask == D3DPRED_ALL_Z || PredicationMask == ( D3DPRED_ALL_RENDER | D3DPRED_ALL_Z ) );
// 	g_spuGcm.SetPredication( PredicationMask );
}

HRESULT IDirect3DDevice9::EndZPass()
{
// 	if( m_isZPass )
// 	{
// 		g_spuGcm.EndZPass( true ); // ZPass may have ended prematurely, we still pop the marker
// 		m_isZPass = false;
// 	}
	return S_OK;
}

//--------------------------------------------------------------------------------------------------
// Anti-Aliasing
//--------------------------------------------------------------------------------------------------

ConVar r_mlaa_hints("r_mlaa_hints", "1");

void IDirect3DDevice9::StartRenderingIntoPreviousFramebuffer()
{
// 	g_flipHandler.QmsAdviceBeforeDrawPrevFramebuffer();
// 	m_defaultColorSurface->m_tex->m_lmBlock.Assign( g_ps3gcmGlobalState.m_display.surfaceColor[ g_ps3gcmGlobalState.m_display.PrevSurfaceIndex( 1 ) ] );
// 	if( m_defaultColorSurface == m_rtSurfaces[ 0 ] )
// 	{
// 		Ps3Helper_UpdateSurface( 0 );
// 	}
}

void IDirect3DDevice9::AntiAliasingHint( int nHint )
{
// 	if( 0 && !IsCert() && IsDebug() )
// 	{
// 		const char * pAaHintReadableNames[] = {
// 			"AA_HINT_MESHES",
// 			"AA_HINT_TEXT",
// 			"AA_HINT_DEBUG_TEXT",
// 			"AA_HINT_HEAVY_UI_OVERLAY",
// 			"AA_HINT_ALIASING_PUSH",
// 			"AA_HINT_ALIASING_POP",
// 			"AA_HINT_POSTPROCESS",
// 			"AA_HINT_MOVIE", 
// 			"AA_HINT_MENU"
// 		};
// 
// 		Msg( "AntiAliasingHint( %s )\n", nHint >= ARRAYSIZE( pAaHintReadableNames ) ? "Out Of Range" : pAaHintReadableNames[ nHint ] );
// 	}
// 
// 	switch( nHint )
// 	{
// 		case AA_HINT_HEAVY_UI_OVERLAY:
// 			if( r_mlaa_hints.GetInt() & 2 )
// 			{
// 				g_spuGcm.DrawQueueNormal();
// 				
// 				StartRenderingIntoPreviousFramebuffer();
// 
// 				// from now and until the end of frame, render into previous surface (or in this surface, but deferred to next frame)
// 				// this means we'll have a potential without VGUI rendering and proper post-processing 
// 				m_nAntiAliasingStatus = AA_STATUS_PREV_FRAME;
// 			}
// 			g_spuGcm.DisableMlaa();
// 			//g_spuGcm.DisableMlaaForTwoFrames();
// 			break;
// 			
// 		case AA_HINT_ALIASING_PUSH:
// 			g_spuGcm.DisableMlaaPermanently();
// 			break;
// 
// 		case AA_HINT_ALIASING_POP:
// 			g_flipHandler.EnableMlaaPermannetly();
// 			break;
// 			
// 		case AA_HINT_MOVIE:
// 		case AA_HINT_MENU:
// 			//g_spuGcm.DrawQueueNormal();
// 			g_spuGcm.DisableMlaa();
// 			// if drawing into previous frame, do we need to continue that? both ways will probably work
// 		break;
// 			
// 		case AA_HINT_MESHES:
// 			if( g_flipHandler.IsMlaaEnabled() && m_nAntiAliasingStatus != AA_STATUS_NORMAL )
// 			{
// 				// switch back to default surface now...
// 				if( g_spuGcm.m_bUseDeferredDrawQueue )
// 				{
// 					g_spuGcm.DrawQueueNormal();
// 					if( m_nAntiAliasingStatus == AA_STATUS_PREV_FRAME )
// 					{
// 						// the first time this frame we need to set deferred queue surface
// 						Ps3Helper_UpdateSurface( 0 );
// 					}
// 				}
// 				else
// 				{
// 					m_defaultColorSurface->m_tex->m_lmBlock.Assign( g_ps3gcmGlobalState.m_display.surfaceColor[ g_ps3gcmGlobalState.m_display.surfaceFlipIdx ] );
// 					if( m_defaultColorSurface == m_rtSurfaces[ 0 ] )
// 					{
// 						Ps3Helper_UpdateSurface( 0 );
// 					}
// 					// from now and until the end of frame, render into previous surface
// 					// this means we'll have a potential without VGUI rendering and proper post-processing when we 
// 				}
// 				m_nAntiAliasingStatus = AA_STATUS_NORMAL;
// 				GCM_PERF_MARKER( "AntiAliasing_ON" );
// 			}
// 		break;
// 
// 		case AA_HINT_DEBUG_TEXT:
// 			if( g_flipHandler.IsMlaaEnabled() && m_nAntiAliasingStatus != AA_STATUS_PREV_FRAME && r_mlaa_hints.GetBool() )
// 			{
// 				// switch not normal ( non-deferred ) drawing in case we peruse deferred drawing
// 				if( g_spuGcm.m_bUseDeferredDrawQueue )
// 				{
// 					g_spuGcm.DrawQueueNormal();
// 				}
// 
// 				StartRenderingIntoPreviousFramebuffer();
// 				
// 				m_nAntiAliasingStatus = AA_STATUS_PREV_FRAME;
// 			}
// 			break;
// 		
// 		case AA_HINT_TEXT:
// 		case AA_HINT_POSTPROCESS:
// 			if( g_flipHandler.IsMlaaEnabled() && m_nAntiAliasingStatus != AA_STATUS_DEFERRED && r_mlaa_hints.GetBool() )
// 			{
// 				GCM_PERF_MARKER("AntiAliasing_OFF");
// 				// switch back to default surface now...
// 				if( g_spuGcm.m_bUseDeferredDrawQueue )
// 				{
// 					if( g_spuGcm.DrawQueueDeferred().isFirstInFrame ) // this doesn't do actual rendering, so we don't need to switch render surface to previous frame
// 					{
// 						// this is the first time this frame, so record switching the surface
// 						// even if the surface is not framebuffer, we still need to record it
// 						g_spuGcm.OpenDeferredChunk( SPUDRAWQUEUE_DEFERRED_GCMFLUSH_DRAW_METHOD );
// 						Ps3Helper_UpdateSurface( 0 );
// 						g_spuGcm.OpenDeferredChunk( );
// 					}
// 					if( g_spuGcm.IsDeferredDrawQueue() ) 
// 					{
// 						// we should've succeeded; if we didn't it means we ran out of memory or something. TODO: test the failure code path
// 						m_nAntiAliasingStatus = AA_STATUS_DEFERRED;
// 					}
// 				}
// 				else
// 				{
// 					StartRenderingIntoPreviousFramebuffer();
// 
// 					// from now and until the end of frame, render into previous surface (or in this surface, but deferred to next frame)
// 					// this means we'll have a potential without VGUI rendering and proper post-processing 
// 					m_nAntiAliasingStatus = AA_STATUS_PREV_FRAME;
// 				}
// 			}
// 		break;
// 		
// 	}
}

//--------------------------------------------------------------------------------------------------
// IDirect3DDevice9::	CreateQuery
// 						QueryGlobalStateFence_t::PrepareForQuery
// 						QueryGlobalStateOcclusion_t::PrepareForQuery
// IDirect3DQuery9::Issue
//					GetData
//--------------------------------------------------------------------------------------------------

IDirect3DQuery9::QueryGlobalStateOcclusion_t IDirect3DQuery9::s_GlobalStateOcclusion;

uint32 IDirect3DQuery9::QueryGlobalStateOcclusion_t::PrepareForQuery()
{
	uint32 uiQuery = (m_queryIdx ++) % kMaxQueries;
	if ( !m_Values[uiQuery] )
		m_Values[uiQuery] = cellGcmGetReportDataAddress( uiQuery + QueryGlobalStateOcclusion_t::kGcmQueryBase );
	m_Values[ uiQuery ]->zero = ~0;
	return uiQuery;
}

IDirect3DQuery9::QueryGlobalStateFence_t IDirect3DQuery9::s_GlobalStateFence;

uint32 IDirect3DQuery9::QueryGlobalStateFence_t::PrepareForQuery()
{
	uint32 uiQuery = (m_queryIdx ++) % kMaxQueries;
	if ( !m_Values[uiQuery] )
		m_Values[uiQuery] = cellGcmGetLabelAddress( uiQuery + QueryGlobalStateFence_t::kGcmLabelBase );
	(*m_Values[uiQuery]) = ~0;
	return uiQuery;
}

HRESULT IDirect3DDevice9::CreateQuery(D3DQUERYTYPE Type,IDirect3DQuery9** ppQuery)
{
	IDirect3DQuery9	*newquery = new IDirect3DQuery9;
	newquery->m_type = Type;
	newquery->m_queryIdx = ~0;

	switch ( Type )
	{
	case	D3DQUERYTYPE_OCCLUSION:				/* D3DISSUE_BEGIN, D3DISSUE_END */
		// newquery->m_query = newquery->s_GlobalStateOcclusion.PrepareForQuery();
		break;

	case	D3DQUERYTYPE_EVENT:					/* D3DISSUE_END */
		// newquery->m_query = newquery->s_GlobalStateFence.PrepareForQuery();
		break;

	case	D3DQUERYTYPE_RESOURCEMANAGER:		/* D3DISSUE_END */
	case	D3DQUERYTYPE_TIMESTAMP:				/* D3DISSUE_END */
	case	D3DQUERYTYPE_TIMESTAMPFREQ:			/* D3DISSUE_END */
	case	D3DQUERYTYPE_INTERFACETIMINGS:		/* D3DISSUE_BEGIN, D3DISSUE_END */
	case	D3DQUERYTYPE_PIXELTIMINGS:			/* D3DISSUE_BEGIN, D3DISSUE_END */
	case	D3DQUERYTYPE_CACHEUTILIZATION:		/* D3DISSUE_BEGIN, D3DISSUE_END */
		Assert( !"Un-implemented query type" );
		break;

	default:
		Assert( !"Unknown query type" );
		break;
	}

	*ppQuery = newquery;

	return S_OK;
}

HRESULT IDirect3DQuery9::Issue(DWORD dwIssueFlags)
{
	// Flags field for Issue
	//	#define D3DISSUE_END (1 << 0) // Tells the runtime to issue the end of a query, changing it's state to "non-signaled".
	//	#define D3DISSUE_BEGIN (1 << 1) // Tells the runtime to issue the beginng of a query.

	if (dwIssueFlags & D3DISSUE_BEGIN)
	{
		switch( m_type )
		{
		case	D3DQUERYTYPE_OCCLUSION:
			if ( !( m_queryIdx & kQueryFinished ) )
			{
				// Query is still pending!
				Assert( 0 );
				return S_OK;
			}
			m_queryIdx = s_GlobalStateOcclusion.PrepareForQuery();

			gpGcmDrawState->SetZpassPixelCountEnable( CELL_GCM_TRUE ); 
			gpGcmDrawState->SetClearReport( CELL_GCM_ZPASS_PIXEL_CNT );
			break;

		default:
			Assert(!"Can't use D3DISSUE_BEGIN on this query");
			break;
		}
	}

	if (dwIssueFlags & D3DISSUE_END)
	{
		switch( m_type )
		{
		case	D3DQUERYTYPE_OCCLUSION:
			if ( !!( m_queryIdx & kQueryFinished ) )
			{
				// Query has finished earlier!
				Assert( 0 );
				return S_OK;
			}
			gpGcmDrawState->SetReport ( CELL_GCM_ZPASS_PIXEL_CNT, m_queryIdx + QueryGlobalStateOcclusion_t::kGcmQueryBase );
			gpGcmDrawState->SetZpassPixelCountEnable ( CELL_GCM_FALSE );
			m_queryIdx |= kQueryFinished;	// mark the query as finished
			break;

		case	D3DQUERYTYPE_EVENT:
			// End is very weird with respect to Events (fences).
			// DX9 docs say to use End to put the fence in the stream.  So we map End to GLM's Start.
			// http://msdn.microsoft.com/en-us/library/ee422167(VS.85).aspx
			m_queryIdx = s_GlobalStateFence.PrepareForQuery();
			gpGcmDrawState->SetWriteBackEndLabel ( m_queryIdx + QueryGlobalStateFence_t::kGcmLabelBase, 0 );	// drop "set fence" into stream
			m_queryIdx |= kQueryFinished;
			break;
		}
	}
	return S_OK;
}

HRESULT IDirect3DQuery9::GetData(void* pData,DWORD dwSize,DWORD dwGetDataFlags)
{
 	HRESULT	result = -1;

	// GetData is not always called with the flush bit.

	// if an answer is not yet available - return S_FALSE.
	// if an answer is available - return S_OK and write the answer into *pData.
	bool flush = (dwGetDataFlags & D3DGETDATA_FLUSH) != 0;	// aka spin until done

	// hmmm both of these paths are the same, maybe we could fold them up
	if ( ( m_queryIdx == kQueryUninitialized ) || !( m_queryIdx & kQueryFinished ) )
	{
		Assert(!"Can't GetData before start-stop");
		if ( pData ) { *(int32*)(pData) = 0; }
		result = -1;
	}
	else
	{
		switch( m_type )
		{
		case	D3DQUERYTYPE_OCCLUSION: {
			// expectation - caller already did an issue begin (start) and an issue end (stop).
			// we can probe using IsDone.
			union RptData {
				CellGcmReportData data;
				vector int vFetch;
			};
			RptData volatile const *rpt = reinterpret_cast< RptData volatile const * >( s_GlobalStateOcclusion.m_Values[ m_queryIdx & kQueryValueMask ] );
			RptData rptValue;
			rptValue.vFetch = rpt->vFetch;
			if ( rptValue.data.zero && flush )
			{
//
// Disabled out the wait for (flush) of occlusion query
// c_pixel_vis, seems to flush queries every couple of seconds, and it seems pointless on PS3
// Flushing the GPU and waiting for the report to write it's value seems a bad situation on PS3
// We can literally stall the CPU for 10ms
// Need to test this on levels with many coronas etc.. But in that case we need a bigger query list
// and to look closer at the higher level code
//
				// Flush GPU right up to current point - Endframe call does this...
// 				gpGcmDrawState->EndFrame();
// 				gpGcmDrawState->CmdBufferFlush();
// 
//  				while ( ( ( rptValue.vFetch = rpt->vFetch ), rptValue.data.zero )
//  					&& ( ThreadSleep(1), 1 ) ) // yield CPU when spin-waiting
//  					continue;

				rptValue.data.zero = 0;
			}
			if ( !rptValue.data.zero )
			{
				if (pData)
				{
					*(int32*)pData = rptValue.data.value;
				}
				result = S_OK;
			}
			else
			{
				result = S_FALSE;
			}
										} break;

		case	D3DQUERYTYPE_EVENT: {
			// expectation - caller already did an issue end (for fence => start) but has not done anything that would call Stop.
			// that's ok because Stop is a no-op for fences.
			uint32 volatile const& lbl = *s_GlobalStateFence.m_Values[ m_queryIdx & kQueryValueMask ];
			uint32 lblValue = lbl;
			if ( lblValue && flush )
			{
				// Flush GPU right up to current point - Endframe call does this...
				gpGcmDrawState->EndFrame();
				gpGcmDrawState->CmdBufferFlush();

 				while ( ( (lblValue = lbl) != 0 )
 					&& ( ThreadSleep(1), 1 ) ) // yield CPU when spin-waiting
 					continue;
			}
			if ( !lblValue )
			{
				*(uint*)pData = 0;
				result = S_OK;
			}
			else
			{
				result = S_FALSE;
			}
									} break;
		}
	}

	return result;
}



//--------------------------------------------------------------------------------------------------
// MISC
//--------------------------------------------------------------------------------------------------

BOOL IDirect3DDevice9::ShowCursor(BOOL bShow)
{
	// FIXME NOP
	//Debugger();
	return TRUE;
}

HRESULT IDirect3DDevice9::SetTransform(D3DTRANSFORMSTATETYPE State,CONST D3DMATRIX* pMatrix)
{
	Debugger();
	return S_OK;
}

HRESULT IDirect3DDevice9::SetTextureStageState(DWORD Stage,D3DTEXTURESTAGESTATETYPE Type,DWORD Value)
{
	Debugger();
	return S_OK;
}

HRESULT IDirect3DDevice9::ValidateDevice(DWORD* pNumPasses)
{
	Debugger();
	return S_OK;
}

HRESULT IDirect3DDevice9::SetMaterial(CONST D3DMATERIAL9* pMaterial)
{
	return S_OK;
}


HRESULT IDirect3DDevice9::LightEnable(DWORD Index,BOOL Enable)
{
	Debugger();
	return S_OK;
}


HRESULT IDirect3DDevice9::GetDeviceCaps(D3DCAPS9* pCaps)
{
	Debugger();
	return S_OK;
}


HRESULT IDirect3DDevice9::TestCooperativeLevel()
{
	// game calls this to see if device was lost.
	// last I checked the device was still attached to the computer.
	// so, return OK.

	return S_OK;
}


HRESULT IDirect3DDevice9::EvictManagedResources()
{
	return S_OK;
}

HRESULT IDirect3DDevice9::SetLight(DWORD Index,CONST D3DLIGHT9*)
{
	Debugger();
	return S_OK;
}

void IDirect3DDevice9::SetGammaRamp(UINT iSwapChain,DWORD Flags,CONST D3DGAMMARAMP* pRamp)
{
}

void D3DPERF_SetOptions( DWORD dwOptions )
{
}

HRESULT D3DXCompileShader(
						  LPCSTR                          pSrcData,
						  UINT                            SrcDataLen,
						  CONST D3DXMACRO*                pDefines,
						  LPD3DXINCLUDE                   pInclude,
						  LPCSTR                          pFunctionName,
						  LPCSTR                          pProfile,
						  DWORD                           Flags,
						  LPD3DXBUFFER*                   ppShader,
						  LPD3DXBUFFER*                   ppErrorMsgs,
						  LPD3DXCONSTANTTABLE*            ppConstantTable)
{
	return S_OK;
}

//--------------------------------------------------------------------------------------------------
// D3DX funcs
//--------------------------------------------------------------------------------------------------

void* ID3DXBuffer::GetBufferPointer()
{
	Debugger();
	return NULL;
}

DWORD ID3DXBuffer::GetBufferSize()
{
	Debugger();
	return 0;
}

// matrix stack...

HRESULT D3DXCreateMatrixStack( DWORD Flags, LPD3DXMATRIXSTACK* ppStack)
{
	
	*ppStack = new ID3DXMatrixStack;
	
	(*ppStack)->Create();
	
	return S_OK;
}

HRESULT	ID3DXMatrixStack::Create()
{
	m_stack.EnsureCapacity( 16 );	// 1KB ish
	m_stack.AddToTail();
	m_stackTop = 0;				// top of stack is at index 0 currently
	
	LoadIdentity();
	
	return S_OK;
}

D3DXMATRIX* ID3DXMatrixStack::GetTop()
{
	return (D3DXMATRIX*)&m_stack[ m_stackTop ];
}

void ID3DXMatrixStack::Push()
{
	D3DMATRIX temp = m_stack[ m_stackTop ];
	m_stack.AddToTail( temp );
	m_stackTop ++;
}

void ID3DXMatrixStack::Pop()
{
	int elem = m_stackTop--;
	m_stack.Remove( elem );
}

void ID3DXMatrixStack::LoadIdentity()
{
	D3DXMATRIX *mat = GetTop();

	D3DXMatrixIdentity( mat );
}

void ID3DXMatrixStack::LoadMatrix( const D3DXMATRIX *pMat )
{
	*(GetTop()) = *pMat;
}


void ID3DXMatrixStack::MultMatrix( const D3DXMATRIX *pMat )
{

	// http://msdn.microsoft.com/en-us/library/bb174057(VS.85).aspx
	//	This method right-multiplies the given matrix to the current matrix
	//	(transformation is about the current world origin).
	//		m_pstack[m_currentPos] = m_pstack[m_currentPos] * (*pMat);
	//	This method does not add an item to the stack, it replaces the current
	//  matrix with the product of the current matrix and the given matrix.


	Debugger();
}

void ID3DXMatrixStack::MultMatrixLocal( const D3DXMATRIX *pMat )
{
	//	http://msdn.microsoft.com/en-us/library/bb174058(VS.85).aspx
	//	This method left-multiplies the given matrix to the current matrix
	//	(transformation is about the local origin of the object).
	//		m_pstack[m_currentPos] = (*pMat) * m_pstack[m_currentPos];
	//	This method does not add an item to the stack, it replaces the current
	//	matrix with the product of the given matrix and the current matrix.


	Debugger();
}

HRESULT ID3DXMatrixStack::ScaleLocal(FLOAT x, FLOAT y, FLOAT z)
{
	//	http://msdn.microsoft.com/en-us/library/bb174066(VS.85).aspx
	//	Scale the current matrix about the object origin.
	//	This method left-multiplies the current matrix with the computed
	//	scale matrix. The transformation is about the local origin of the object.
	//
	//	D3DXMATRIX tmp;
	//	D3DXMatrixScaling(&tmp, x, y, z);
	//	m_stack[m_currentPos] = tmp * m_stack[m_currentPos];

	Debugger();

	return S_OK;
}


HRESULT ID3DXMatrixStack::RotateAxisLocal(CONST D3DXVECTOR3* pV, FLOAT Angle)
{
	//	http://msdn.microsoft.com/en-us/library/bb174062(VS.85).aspx
	//	Left multiply the current matrix with the computed rotation
	//	matrix, counterclockwise about the given axis with the given angle.
	//	(rotation is about the local origin of the object)

	//	D3DXMATRIX tmp;
	//	D3DXMatrixRotationAxis( &tmp, pV, angle );
	//	m_stack[m_currentPos] = tmp * m_stack[m_currentPos];
	//	Because the rotation is left-multiplied to the matrix stack, the rotation
	//	is relative to the object's local coordinate space.
	
	Debugger();

	return S_OK;
}

HRESULT ID3DXMatrixStack::TranslateLocal(FLOAT x, FLOAT y, FLOAT z)
{
	//	http://msdn.microsoft.com/en-us/library/bb174068(VS.85).aspx
	//	Left multiply the current matrix with the computed translation
	//	matrix. (transformation is about the local origin of the object)

	//	D3DXMATRIX tmp;
	//	D3DXMatrixTranslation( &tmp, x, y, z );
	//	m_stack[m_currentPos] = tmp * m_stack[m_currentPos];

	Debugger();

	return S_OK;
}


const char* D3DXGetPixelShaderProfile( IDirect3DDevice9 *pDevice )
{
	Debugger();
	return "";
}


D3DXMATRIX* D3DXMatrixMultiply( D3DXMATRIX *pOut, CONST D3DXMATRIX *pM1, CONST D3DXMATRIX *pM2 )
{
	D3DXMATRIX temp;
	
	for( int i=0; i<4; i++)
	{
		for( int j=0; j<4; j++)
		{
			temp.m[i][j]	=	(pM1->m[ i ][ 0 ] * pM2->m[ 0 ][ j ])
							+	(pM1->m[ i ][ 1 ] * pM2->m[ 1 ][ j ])
							+	(pM1->m[ i ][ 2 ] * pM2->m[ 2 ][ j ])
							+	(pM1->m[ i ][ 3 ] * pM2->m[ 3 ][ j ]);
		}
	}
	*pOut = temp;
	return pOut;
}

D3DXVECTOR3* D3DXVec3TransformCoord( D3DXVECTOR3 *pOut, CONST D3DXVECTOR3 *pV, CONST D3DXMATRIX *pM )		// http://msdn.microsoft.com/en-us/library/ee417622(VS.85).aspx
{
	// this one is tricky because
	// "Transforms a 3D vector by a given matrix, projecting the result back into w = 1".
	// but the vector has no W attached to it coming in, so we have to go through the motions of figuring out what w' would be
	// assuming the input vector had a W of 1.
	
	// dot product of [a b c 1] against w column
	float wp = (pM->m[3][0] * pV->x) + (pM->m[3][1] * pV->y) + (pM->m[3][2] * pV->z) + (pM->m[3][3]);
	
	if (wp == 0.0f )
	{
		// do something to avoid dividing by zero..
		Debugger();
	}
	else
	{
		// unclear on whether I should include the fake W in the sum (last term) before dividing by wp... hmmmm
		// leave it out for now and see how well it works
		pOut->x = ((pM->m[0][0] * pV->x) + (pM->m[0][1] * pV->y) + (pM->m[0][2] * pV->z) /* + (pM->m[0][3]) */ ) / wp;
		pOut->y = ((pM->m[1][0] * pV->x) + (pM->m[1][1] * pV->y) + (pM->m[1][2] * pV->z) /* + (pM->m[1][3]) */ ) / wp;
		pOut->z = ((pM->m[2][0] * pV->x) + (pM->m[2][1] * pV->y) + (pM->m[2][2] * pV->z) /* + (pM->m[2][3]) */ ) / wp;
	}

	return pOut;
}


void D3DXMatrixIdentity( D3DXMATRIX *mat )
{
	for( int i=0; i<4; i++)
	{
		for( int j=0; j<4; j++)
		{
			mat->m[i][j] = (i==j) ? 1.0f : 0.0f;	// 1's on the diagonal.
		}
	}
}

D3DXMATRIX* D3DXMatrixTranslation( D3DXMATRIX *pOut, FLOAT x, FLOAT y, FLOAT z )
{
	D3DXMatrixIdentity( pOut );
	pOut->m[3][0] = x;
	pOut->m[3][1] = y;
	pOut->m[3][2] = z;
	return pOut;
}

D3DXMATRIX* D3DXMatrixInverse( D3DXMATRIX *pOut, FLOAT *pDeterminant, CONST D3DXMATRIX *pM )
{
	Assert( sizeof( D3DXMATRIX ) == (16 * sizeof(float) ) );
	Assert( sizeof( VMatrix ) == (16 * sizeof(float) ) );
	Assert( pDeterminant == NULL );	// homey don't play that
	
	VMatrix *origM = (VMatrix*)pM;
	VMatrix *destM = (VMatrix*)pOut;
	
	bool success = MatrixInverseGeneral( *origM, *destM );
	Assert( success );
	
	return pOut;
}


D3DXMATRIX* D3DXMatrixTranspose( D3DXMATRIX *pOut, CONST D3DXMATRIX *pM )
{
	if (pOut != pM)
	{
		for( int i=0; i<4; i++)
		{
			for( int j=0; j<4; j++)
			{
				pOut->m[i][j] = pM->m[j][i];
			}
		}
	}
	else
	{
		D3DXMATRIX temp = *pM;
		D3DXMatrixTranspose( pOut, &temp );
	}

	return NULL;
}


D3DXPLANE* D3DXPlaneNormalize( D3DXPLANE *pOut, CONST D3DXPLANE *pP)
{
	// not very different from normalizing a vector.
	// figure out the square root of the sum-of-squares of the x,y,z components
	// make sure that's non zero
	// then divide all four components by that value
	// or return some dummy plane like 0,0,1,0 if it fails
	
	float	len = sqrt( (pP->a * pP->a) + (pP->b * pP->b) + (pP->c * pP->c) );
	if (len > 1e-10)	//FIXME need a real epsilon here ?
	{
		pOut->a = pP->a / len;		pOut->b = pP->b / len;		pOut->c = pP->c / len;		pOut->d = pP->d / len;
	}
	else
	{
		pOut->a = 0.0f;				pOut->b = 0.0f;				pOut->c = 1.0f;				pOut->d = 0.0f;
	}
	return pOut;
}


D3DXVECTOR4* D3DXVec4Transform( D3DXVECTOR4 *pOut, CONST D3DXVECTOR4 *pV, CONST D3DXMATRIX *pM )
{
	VMatrix *mat = (VMatrix*)pM;
	Vector4D *vIn = (Vector4D*)pV;
	Vector4D *vOut = (Vector4D*)pOut;

	Vector4DMultiply( *mat, *vIn, *vOut );

	return pOut;
}



D3DXVECTOR4* D3DXVec4Normalize( D3DXVECTOR4 *pOut, CONST D3DXVECTOR4 *pV )
{
	Vector4D *vIn = (Vector4D*) pV;
	Vector4D *vOut = (Vector4D*) pOut;

	*vOut = *vIn;
	Vector4DNormalize( *vOut );
	
	return pOut;
}

D3DXMATRIX* D3DXMatrixOrthoOffCenterRH( D3DXMATRIX *pOut, FLOAT l, FLOAT r, FLOAT b, FLOAT t, FLOAT zn,FLOAT zf )
{
	Debugger();
	return NULL;
}


D3DXMATRIX* D3DXMatrixPerspectiveRH( D3DXMATRIX *pOut, FLOAT w, FLOAT h, FLOAT zn, FLOAT zf )
{
	Debugger();
	return NULL;
}


D3DXMATRIX* D3DXMatrixPerspectiveOffCenterRH( D3DXMATRIX *pOut, FLOAT l, FLOAT r, FLOAT b, FLOAT t, FLOAT zn, FLOAT zf )
{
	Debugger();
	return NULL;
}


D3DXPLANE* D3DXPlaneTransform( D3DXPLANE *pOut, CONST D3DXPLANE *pP, CONST D3DXMATRIX *pM )
{
	Debugger();
	return NULL;
}


//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------

D3DXMATRIX D3DXMATRIX::operator*( const D3DXMATRIX &o ) const
{
	D3DXMATRIX result;

	D3DXMatrixMultiply( &result, this, &o );	// this = lhs    o = rhs    result = this * o

	return result;
}

D3DXMATRIX::operator FLOAT* ()
{
	return (float*)this;
}

float& D3DXMATRIX::operator()( int row, int column )
{
	return m[row][column];
}

const float& D3DXMATRIX::operator()( int row, int column ) const
{
	return m[row][column];
}

// ------------------------------------------------------------------------------------------------------------------------------ //


float& D3DXPLANE::operator[]( int i )
{
	return ((float*)this)[i];
}

bool D3DXPLANE::operator==( const D3DXPLANE &o )
{
	return a == o.a && b == o.b && c == o.c && d == o.d;
}

bool D3DXPLANE::operator!=( const D3DXPLANE &o )
{
	return !( *this == o );
}

D3DXPLANE::operator float*()
{
	return (float*)this;
}

D3DXPLANE::operator const float*() const
{
	return (const float*)this;
}

// ------------------------------------------------------------------------------------------------------------------------------ //


D3DXVECTOR2::operator FLOAT* ()
{
	return (float*)this;
}

D3DXVECTOR2::operator CONST FLOAT* () const
{
	return (const float*)this;
}

// ------------------------------------------------------------------------------------------------------------------------------ //


D3DXVECTOR3::D3DXVECTOR3( float a, float b, float c )
{
	x = a;
	y = b;
	z = c;
}

D3DXVECTOR3::operator FLOAT* ()
{
	return (float*)this;
}

D3DXVECTOR3::operator CONST FLOAT* () const
{
	return (const float*)this;
}

// ------------------------------------------------------------------------------------------------------------------------------ //



D3DXVECTOR4::D3DXVECTOR4( float a, float b, float c, float d )
{
	x = a;
	y = b;
	z = c;
	w = d;
}

// ------------------------------------------------------------------------------------------------------------------------------ //

DWORD IDirect3DResource9::SetPriority(DWORD PriorityNew)
{
	//	Debugger();
	return 0;
}

//--------------------------------------------------------------------------------------------------
// Screen shot for VX console
//--------------------------------------------------------------------------------------------------

// returns a pointer to the screen shot frame buffer and some associated header info.
// returns NULL on failure (which it can't right now)

char *GetScreenShotInfoForVX( IDirect3DDevice9 *pDevice, uint32 *uWidth, uint32 *uHeight, uint32 *uPitch, uint32 *colour )
{
	const CPs3gcmTextureLayout & layout = *pDevice->m_defaultColorSurface->m_tex->m_layout;
	*uWidth = layout.m_key.m_size[0];
	*uHeight = layout.m_key.m_size[1];
	*uPitch = g_ps3gcmGlobalState.m_nSurfaceRenderPitch;  //  layout.DefaultPitch();
	switch ( layout.GetFormatPtr()->m_gcmFormat )
	{
	case CELL_GCM_TEXTURE_A8R8G8B8 :
	case CELL_GCM_TEXTURE_D8R8G8B8:
	case CELL_GCM_SURFACE_A8R8G8B8:
		*colour =  IMaterialSystem::kX8R8G8B8;
		break;
	case CELL_GCM_SURFACE_A8B8G8R8:
		*colour =  IMaterialSystem::kX8B8G8R8;
		break;
	case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT:
		*colour =  IMaterialSystem::kR16G16B16X16;
		break;
	default:
		*colour = (IMaterialSystem::VRAMScreenShotInfoColorFormat_t) 0;
	}
	// send oldest buffer
	return g_ps3gcmGlobalState.m_display.surfaceColor[ (g_ps3gcmGlobalState.m_display.surfaceFlipIdx + 1) & 1 ].DataInAnyMemory();
}

//--------------------------------------------------------------------------------------------------
// Windows Stubs
//--------------------------------------------------------------------------------------------------

void GlobalMemoryStatus( MEMORYSTATUS *pOut )
{
	pOut->dwTotalPhys = (1<<31);
}

void Sleep( unsigned int ms )
{
	Debugger();
	ThreadSleep( ms );
}

bool IsIconic( VD3DHWND hWnd )
{
	return false;
}

void GetClientRect( VD3DHWND hWnd, RECT *destRect )
{
	destRect->left = 0;
	destRect->top = 0;
	destRect->right = g_ps3gcmGlobalState.m_nRenderSize[0];
	destRect->bottom = g_ps3gcmGlobalState.m_nRenderSize[1];
}

BOOL ClientToScreen( VD3DHWND hWnd, LPPOINT pPoint )
{
	Debugger();
	return true;
}

void* GetCurrentThread()
{
	Debugger();
	return 0;
}

void SetThreadAffinityMask( void *hThread, int nMask )
{
	Debugger();
}

bool operator==( const struct _GUID &lhs, const struct _GUID &rhs )
{
	Debugger();
	return memcmp( &lhs, &rhs, sizeof( GUID ) ) == 0;
}