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