Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3568 lines
111 KiB

//================ 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;
}