summaryrefslogtreecommitdiff
path: root/materialsystem/shaderapidx9
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /materialsystem/shaderapidx9
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'materialsystem/shaderapidx9')
-rw-r--r--materialsystem/shaderapidx9/ShaderShadowDx10.h176
-rw-r--r--materialsystem/shaderapidx9/TransitionTable.cpp1924
-rw-r--r--materialsystem/shaderapidx9/TransitionTable.h407
-rw-r--r--materialsystem/shaderapidx9/colorformatdx8.cpp727
-rw-r--r--materialsystem/shaderapidx9/colorformatdx8.h60
-rw-r--r--materialsystem/shaderapidx9/cvballoctracker.cpp764
-rw-r--r--materialsystem/shaderapidx9/d3d_async.cpp825
-rw-r--r--materialsystem/shaderapidx9/d3d_async.h1567
-rw-r--r--materialsystem/shaderapidx9/dx9hook.h1289
-rw-r--r--materialsystem/shaderapidx9/dynamicib.h1056
-rw-r--r--materialsystem/shaderapidx9/dynamicvb.h1098
-rw-r--r--materialsystem/shaderapidx9/gpubufferallocator.cpp480
-rw-r--r--materialsystem/shaderapidx9/gpubufferallocator.h146
-rw-r--r--materialsystem/shaderapidx9/hardwareconfig.cpp1311
-rw-r--r--materialsystem/shaderapidx9/hardwareconfig.h286
-rw-r--r--materialsystem/shaderapidx9/imeshdx8.h98
-rw-r--r--materialsystem/shaderapidx9/inputlayoutdx10.cpp214
-rw-r--r--materialsystem/shaderapidx9/inputlayoutdx10.h35
-rw-r--r--materialsystem/shaderapidx9/ivertexbufferdx8.h34
-rw-r--r--materialsystem/shaderapidx9/locald3dtypes.h191
-rw-r--r--materialsystem/shaderapidx9/meshbase.cpp419
-rw-r--r--materialsystem/shaderapidx9/meshbase.h309
-rw-r--r--materialsystem/shaderapidx9/meshdx10.cpp775
-rw-r--r--materialsystem/shaderapidx9/meshdx10.h282
-rw-r--r--materialsystem/shaderapidx9/meshdx8.cpp5980
-rw-r--r--materialsystem/shaderapidx9/recording.cpp157
-rw-r--r--materialsystem/shaderapidx9/recording.h198
-rw-r--r--materialsystem/shaderapidx9/shaderapi_global.h105
-rw-r--r--materialsystem/shaderapidx9/shaderapibase.cpp42
-rw-r--r--materialsystem/shaderapidx9/shaderapibase.h86
-rw-r--r--materialsystem/shaderapidx9/shaderapidx10.cpp1461
-rw-r--r--materialsystem/shaderapidx9/shaderapidx10.h940
-rw-r--r--materialsystem/shaderapidx9/shaderapidx10.vpc174
-rw-r--r--materialsystem/shaderapidx9/shaderapidx10_global.h19
-rw-r--r--materialsystem/shaderapidx9/shaderapidx8.cpp14354
-rw-r--r--materialsystem/shaderapidx9/shaderapidx8.h118
-rw-r--r--materialsystem/shaderapidx9/shaderapidx8_global.h100
-rw-r--r--materialsystem/shaderapidx9/shaderapidx9.vpc146
-rw-r--r--materialsystem/shaderapidx9/shaderdevicebase.cpp1256
-rw-r--r--materialsystem/shaderapidx9/shaderdevicebase.h234
-rw-r--r--materialsystem/shaderapidx9/shaderdevicedx10.cpp1002
-rw-r--r--materialsystem/shaderapidx9/shaderdevicedx10.h254
-rw-r--r--materialsystem/shaderapidx9/shaderdevicedx8.cpp3707
-rw-r--r--materialsystem/shaderapidx9/shaderdevicedx8.h382
-rw-r--r--materialsystem/shaderapidx9/shadershadowdx10.cpp227
-rw-r--r--materialsystem/shaderapidx9/shadershadowdx8.cpp1826
-rw-r--r--materialsystem/shaderapidx9/shadershadowdx8.h176
-rw-r--r--materialsystem/shaderapidx9/stubd3ddevice.h809
-rw-r--r--materialsystem/shaderapidx9/texturedx8.cpp1545
-rw-r--r--materialsystem/shaderapidx9/texturedx8.h110
-rw-r--r--materialsystem/shaderapidx9/textureheap.cpp1258
-rw-r--r--materialsystem/shaderapidx9/textureheap.h42
-rw-r--r--materialsystem/shaderapidx9/vertexdecl.cpp576
-rw-r--r--materialsystem/shaderapidx9/vertexdecl.h32
-rw-r--r--materialsystem/shaderapidx9/vertexshaderdx8.cpp3783
-rw-r--r--materialsystem/shaderapidx9/vertexshaderdx8.h135
-rw-r--r--materialsystem/shaderapidx9/winutils.cpp93
-rw-r--r--materialsystem/shaderapidx9/winutils.h21
-rw-r--r--materialsystem/shaderapidx9/wmi.cpp182
-rw-r--r--materialsystem/shaderapidx9/wmi.h17
-rw-r--r--materialsystem/shaderapidx9/xbox/xbox.def3
61 files changed, 56023 insertions, 0 deletions
diff --git a/materialsystem/shaderapidx9/ShaderShadowDx10.h b/materialsystem/shaderapidx9/ShaderShadowDx10.h
new file mode 100644
index 0000000..ff987c0
--- /dev/null
+++ b/materialsystem/shaderapidx9/ShaderShadowDx10.h
@@ -0,0 +1,176 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#ifndef SHADERSHADOWDX10_H
+#define SHADERSHADOWDX10_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "shaderapi/ishaderapi.h"
+#include "shaderapi/ishadershadow.h"
+
+
+//-----------------------------------------------------------------------------
+// The empty shader shadow
+//-----------------------------------------------------------------------------
+class CShaderShadowDx10 : public IShaderShadow
+{
+public:
+ CShaderShadowDx10();
+ virtual ~CShaderShadowDx10();
+
+ // Sets the default *shadow* state
+ void SetDefaultState();
+
+ // Methods related to depth buffering
+ void DepthFunc( ShaderDepthFunc_t depthFunc );
+ void EnableDepthWrites( bool bEnable );
+ void EnableDepthTest( bool bEnable );
+ void EnablePolyOffset( PolygonOffsetMode_t nOffsetMode );
+
+ // Suppresses/activates color writing
+ void EnableColorWrites( bool bEnable );
+ void EnableAlphaWrites( bool bEnable );
+
+ // Methods related to alpha blending
+ void EnableBlending( bool bEnable );
+ void BlendFunc( ShaderBlendFactor_t srcFactor, ShaderBlendFactor_t dstFactor );
+
+ // Alpha testing
+ void EnableAlphaTest( bool bEnable );
+ void AlphaFunc( ShaderAlphaFunc_t alphaFunc, float alphaRef /* [0-1] */ );
+
+ // Wireframe/filled polygons
+ void PolyMode( ShaderPolyModeFace_t face, ShaderPolyMode_t polyMode );
+
+ // Back face culling
+ void EnableCulling( bool bEnable );
+
+ // constant color + transparency
+ void EnableConstantColor( bool bEnable );
+
+ // Indicates the vertex format for use with a vertex shader
+ // The flags to pass in here come from the VertexFormatFlags_t enum
+ // If pTexCoordDimensions is *not* specified, we assume all coordinates
+ // are 2-dimensional
+ void VertexShaderVertexFormat( unsigned int flags,
+ int numTexCoords, int* pTexCoordDimensions,
+ int userDataSize );
+
+ // Indicates we're going to light the model
+ void EnableLighting( bool bEnable );
+ void EnableSpecular( bool bEnable );
+
+ // vertex blending
+ void EnableVertexBlend( bool bEnable );
+
+ // per texture unit stuff
+ void OverbrightValue( TextureStage_t stage, float value );
+ void EnableTexture( Sampler_t stage, bool bEnable );
+ void EnableTexGen( TextureStage_t stage, bool bEnable );
+ void TexGen( TextureStage_t stage, ShaderTexGenParam_t param );
+
+ // alternate method of specifying per-texture unit stuff, more flexible and more complicated
+ // Can be used to specify different operation per channel (alpha/color)...
+ void EnableCustomPixelPipe( bool bEnable );
+ void CustomTextureStages( int stageCount );
+ void CustomTextureOperation( TextureStage_t stage, ShaderTexChannel_t channel,
+ ShaderTexOp_t op, ShaderTexArg_t arg1, ShaderTexArg_t arg2 );
+
+ // indicates what per-vertex data we're providing
+ void DrawFlags( unsigned int drawFlags );
+
+ // A simpler method of dealing with alpha modulation
+ void EnableAlphaPipe( bool bEnable );
+ void EnableConstantAlpha( bool bEnable );
+ void EnableVertexAlpha( bool bEnable );
+ void EnableTextureAlpha( TextureStage_t stage, bool bEnable );
+
+ // GR - Separate alpha blending
+ void EnableBlendingSeparateAlpha( bool bEnable );
+ void BlendFuncSeparateAlpha( ShaderBlendFactor_t srcFactor, ShaderBlendFactor_t dstFactor );
+
+ // Sets the vertex and pixel shaders
+ void SetVertexShader( const char *pFileName, int vshIndex );
+ void SetPixelShader( const char *pFileName, int pshIndex );
+
+ // Convert from linear to gamma color space on writes to frame buffer.
+ void EnableSRGBWrite( bool bEnable )
+ {
+ }
+
+ void EnableSRGBRead( Sampler_t stage, bool bEnable )
+ {
+ }
+
+ virtual void FogMode( ShaderFogMode_t fogMode )
+ {
+ }
+ virtual void SetDiffuseMaterialSource( ShaderMaterialSource_t materialSource )
+ {
+ }
+
+ virtual void SetMorphFormat( MorphFormat_t flags )
+ {
+ }
+
+ virtual void EnableStencil( bool bEnable )
+ {
+ }
+ virtual void StencilFunc( ShaderStencilFunc_t stencilFunc )
+ {
+ }
+ virtual void StencilPassOp( ShaderStencilOp_t stencilOp )
+ {
+ }
+ virtual void StencilFailOp( ShaderStencilOp_t stencilOp )
+ {
+ }
+ virtual void StencilDepthFailOp( ShaderStencilOp_t stencilOp )
+ {
+ }
+ virtual void StencilReference( int nReference )
+ {
+ }
+ virtual void StencilMask( int nMask )
+ {
+ }
+ virtual void StencilWriteMask( int nMask )
+ {
+ }
+
+ virtual void DisableFogGammaCorrection( bool bDisable )
+ {
+ //FIXME: empty for now.
+ }
+ virtual void FogMode( ShaderFogMode_t fogMode, bool bVertexFog )
+ {
+ //FIXME: empty for now.
+ }
+
+ // Alpha to coverage
+ void EnableAlphaToCoverage( bool bEnable );
+
+ void SetShadowDepthFiltering( Sampler_t stage );
+
+ // More alpha blending state
+ void BlendOp( ShaderBlendOp_t blendOp );
+ void BlendOpSeparateAlpha( ShaderBlendOp_t blendOp );
+
+ bool m_IsTranslucent;
+ bool m_IsAlphaTested;
+ bool m_bIsDepthWriteEnabled;
+ bool m_bUsesVertexAndPixelShaders;
+};
+
+
+extern CShaderShadowDx10* g_pShaderShadowDx10;
+
+#endif // SHADERSHADOWDX10_H \ No newline at end of file
diff --git a/materialsystem/shaderapidx9/TransitionTable.cpp b/materialsystem/shaderapidx9/TransitionTable.cpp
new file mode 100644
index 0000000..ab12389
--- /dev/null
+++ b/materialsystem/shaderapidx9/TransitionTable.cpp
@@ -0,0 +1,1924 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#define DISABLE_PROTECTED_THINGS
+#include "togl/rendermechanism.h"
+#include "TransitionTable.h"
+#include "recording.h"
+#include "shaderapidx8.h"
+#include "shaderapi/ishaderutil.h"
+#include "tier1/convar.h"
+#include "materialsystem/imaterialsystemhardwareconfig.h"
+#include "vertexshaderdx8.h"
+#include "tier0/vprof.h"
+#include "shaderdevicedx8.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+enum
+{
+ TEXTURE_STAGE_BIT_COUNT = 4,
+ TEXTURE_STAGE_MAX_STAGE = 1 << TEXTURE_STAGE_BIT_COUNT,
+ TEXTURE_STAGE_MASK = TEXTURE_STAGE_MAX_STAGE - 1,
+
+ TEXTURE_OP_BIT_COUNT = 7 - TEXTURE_STAGE_BIT_COUNT,
+ TEXTURE_OP_SHIFT = TEXTURE_STAGE_BIT_COUNT,
+ TEXTURE_OP_MASK = ((1 << TEXTURE_OP_BIT_COUNT) - 1) << TEXTURE_OP_SHIFT,
+};
+
+
+//-----------------------------------------------------------------------------
+// Texture op compressing/uncompressing
+//-----------------------------------------------------------------------------
+inline unsigned char TextureOp( TextureStateFunc_t func, int stage )
+{
+ // This fails if we've added too many texture stages states to fit in a byte.
+ COMPILE_TIME_ASSERT( TEXTURE_STATE_COUNT < (1 << TEXTURE_OP_BIT_COUNT) );
+ Assert( stage < TEXTURE_STAGE_MAX_STAGE );
+
+ return ((func << TEXTURE_OP_SHIFT) & TEXTURE_OP_MASK) | (stage & TEXTURE_STAGE_MASK);
+}
+
+inline void GetTextureOp( unsigned char nBits, TextureStateFunc_t *pFunc, int *pStage )
+{
+ *pStage = (nBits & TEXTURE_STAGE_MASK);
+ *pFunc = (TextureStateFunc_t)((nBits & TEXTURE_OP_MASK) >> TEXTURE_OP_SHIFT);
+}
+
+
+//-----------------------------------------------------------------------------
+// Stats
+//-----------------------------------------------------------------------------
+static int s_pRenderTransitions[RENDER_STATE_COUNT];
+static int s_pTextureTransitions[TEXTURE_STATE_COUNT][TEXTURE_STAGE_MAX_STAGE];
+
+
+//-----------------------------------------------------------------------------
+// Singleton
+//-----------------------------------------------------------------------------
+CTransitionTable *g_pTransitionTable = NULL;
+
+#ifdef DEBUG_BOARD_STATE
+inline ShadowState_t& BoardState()
+{
+ return g_pTransitionTable->BoardState();
+}
+#endif
+
+inline CTransitionTable::CurrentState_t& CurrentState()
+{
+ return g_pTransitionTable->CurrentState();
+}
+
+
+//-----------------------------------------------------------------------------
+// Less functions
+//-----------------------------------------------------------------------------
+bool CTransitionTable::ShadowStateDictLessFunc::Less( const CTransitionTable::ShadowStateDictEntry_t &src1, const CTransitionTable::ShadowStateDictEntry_t &src2, void *pCtx )
+{
+ return src1.m_nChecksum < src2.m_nChecksum;
+}
+
+bool CTransitionTable::SnapshotDictLessFunc::Less( const CTransitionTable::SnapshotDictEntry_t &src1, const CTransitionTable::SnapshotDictEntry_t &src2, void *pCtx )
+{
+ return src1.m_nChecksum < src2.m_nChecksum;
+}
+
+bool CTransitionTable::UniqueSnapshotLessFunc::Less( const CTransitionTable::TransitionList_t &src1, const CTransitionTable::TransitionList_t &src2, void *pCtx )
+{
+ return src1.m_NumOperations > src2.m_NumOperations;
+}
+
+
+//-----------------------------------------------------------------------------
+// Constructor, destructor
+//-----------------------------------------------------------------------------
+CTransitionTable::CTransitionTable() : m_DefaultStateSnapshot(-1),
+ m_CurrentShadowId(-1), m_CurrentSnapshotId(-1), m_TransitionOps( 0, 8192 ), m_ShadowStateList( 0, 256 ),
+ m_TransitionTable( 0, 256 ), m_SnapshotList( 0, 256 ),
+ m_ShadowStateDict(0, 256 ),
+ m_SnapshotDict( 0, 256 ),
+ m_UniqueTransitions( 0, 4096 )
+{
+ Assert( !g_pTransitionTable );
+ g_pTransitionTable = this;
+
+#ifdef DEBUG_BOARD_STATE
+ memset( &m_BoardState, 0, sizeof( m_BoardState ) );
+ memset( &m_BoardShaderState, 0, sizeof( m_BoardShaderState ) );
+#endif
+}
+
+CTransitionTable::~CTransitionTable()
+{
+ Assert( g_pTransitionTable == this );
+ g_pTransitionTable = NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Initialization, shutdown
+//-----------------------------------------------------------------------------
+bool CTransitionTable::Init( )
+{
+ return true;
+}
+
+void CTransitionTable::Shutdown( )
+{
+ Reset();
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates a shadow, adding an entry into the shadow list and transition table
+//-----------------------------------------------------------------------------
+StateSnapshot_t CTransitionTable::CreateStateSnapshot( ShadowStateId_t shadowStateId, const ShadowShaderState_t& currentShaderState )
+{
+ StateSnapshot_t snapshotId = m_SnapshotList.AddToTail();
+
+ // Copy our snapshot into the list
+ SnapshotShaderState_t &shaderState = m_SnapshotList[snapshotId];
+ shaderState.m_ShadowStateId = shadowStateId;
+ memcpy( &shaderState.m_ShaderState, &currentShaderState, sizeof(ShadowShaderState_t) );
+ memset( shaderState.m_ShaderState.m_nReserved, 0, sizeof( shaderState.m_ShaderState.m_nReserved ) );
+ shaderState.m_nReserved = 0; // needed to get a good CRC
+ shaderState.m_nReserved2 = 0;
+
+ // Insert entry into the lookup table
+ SnapshotDictEntry_t insert;
+
+ CRC32_Init( &insert.m_nChecksum );
+ CRC32_ProcessBuffer( &insert.m_nChecksum, &shaderState, sizeof(SnapshotShaderState_t) );
+ CRC32_Final( &insert.m_nChecksum );
+
+ insert.m_nSnapshot = snapshotId;
+ m_SnapshotDict.Insert( insert );
+
+ return snapshotId;
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates a shadow, adding an entry into the shadow list and transition table
+//-----------------------------------------------------------------------------
+CTransitionTable::ShadowStateId_t CTransitionTable::CreateShadowState( const ShadowState_t &currentState )
+{
+ int newShaderState = m_ShadowStateList.AddToTail();
+
+ // Copy our snapshot into the list
+ memcpy( &m_ShadowStateList[newShaderState], &currentState, sizeof(ShadowState_t) );
+
+ // all existing states must transition to the new state
+ int i;
+ for ( i = 0; i < newShaderState; ++i )
+ {
+ // Add a new transition to all existing states
+ int newElem = m_TransitionTable[i].AddToTail();
+ m_TransitionTable[i][newElem].m_FirstOperation = INVALID_TRANSITION_OP;
+ m_TransitionTable[i][newElem].m_NumOperations = 0;
+ }
+
+ // Add a new vector for this transition
+ int newTransitionElem = m_TransitionTable.AddToTail();
+ m_TransitionTable[newTransitionElem].EnsureCapacity( 32 );
+ Assert( newShaderState == newTransitionElem );
+
+ for ( i = 0; i <= newShaderState; ++i )
+ {
+ // Add a new transition from all existing states
+ int newElem = m_TransitionTable[newShaderState].AddToTail();
+ m_TransitionTable[newShaderState][newElem].m_FirstOperation = INVALID_TRANSITION_OP;
+ m_TransitionTable[newShaderState][newElem].m_NumOperations = 0;
+ }
+
+ // Insert entry into the lookup table
+ ShadowStateDictEntry_t insert;
+
+ CRC32_Init( &insert.m_nChecksum );
+ CRC32_ProcessBuffer( &insert.m_nChecksum, &m_ShadowStateList[newShaderState], sizeof(ShadowState_t) );
+ CRC32_Final( &insert.m_nChecksum );
+
+ insert.m_nShadowStateId = newShaderState;
+ m_ShadowStateDict.Insert( insert );
+
+ return newShaderState;
+}
+
+
+//-----------------------------------------------------------------------------
+// Finds a snapshot, if it exists. Or creates a new one if it doesn't.
+//-----------------------------------------------------------------------------
+CTransitionTable::ShadowStateId_t CTransitionTable::FindShadowState( const ShadowState_t& currentState ) const
+{
+ ShadowStateDictEntry_t find;
+
+ CRC32_Init( &find.m_nChecksum );
+ CRC32_ProcessBuffer( &find.m_nChecksum, &currentState, sizeof(ShadowState_t) );
+ CRC32_Final( &find.m_nChecksum );
+
+ int nDictCount = m_ShadowStateDict.Count();
+ int i = m_ShadowStateDict.FindLessOrEqual( find );
+ if ( i < 0 )
+ return (ShadowStateId_t)-1;
+
+ for ( ; i < nDictCount; ++i )
+ {
+ const ShadowStateDictEntry_t &entry = m_ShadowStateDict[i];
+
+ // Didn't find a match
+ if ( entry.m_nChecksum > find.m_nChecksum )
+ break;
+
+ if ( entry.m_nChecksum != find.m_nChecksum )
+ continue;
+
+ ShadowStateId_t nShadowState = entry.m_nShadowStateId;
+ if (!memcmp(&m_ShadowStateList[nShadowState], &currentState, sizeof(ShadowState_t) ))
+ return nShadowState;
+ }
+
+ // Need to create a new one
+ return (ShadowStateId_t)-1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Finds a snapshot, if it exists. Or creates a new one if it doesn't.
+//-----------------------------------------------------------------------------
+StateSnapshot_t CTransitionTable::FindStateSnapshot( ShadowStateId_t id, const ShadowShaderState_t& currentState ) const
+{
+ SnapshotShaderState_t temp;
+ temp.m_ShaderState = currentState;
+ temp.m_ShadowStateId = id;
+ memset( temp.m_ShaderState.m_nReserved, 0, sizeof( temp.m_ShaderState.m_nReserved ) );
+ temp.m_nReserved = 0; // needed to get a good CRC
+ temp.m_nReserved2 = 0;
+
+ SnapshotDictEntry_t find;
+
+ CRC32_Init( &find.m_nChecksum );
+ CRC32_ProcessBuffer( &find.m_nChecksum, &temp, sizeof(temp) );
+ CRC32_Final( &find.m_nChecksum );
+
+ int nDictCount = m_SnapshotDict.Count();
+ int i = m_SnapshotDict.FindLessOrEqual( find );
+ if ( i < 0 )
+ return (StateSnapshot_t)-1;
+
+ for ( ; i < nDictCount; ++i )
+ {
+ // Didn't find a match
+ if ( m_SnapshotDict[i].m_nChecksum > find.m_nChecksum )
+ break;
+
+ if ( m_SnapshotDict[i].m_nChecksum != find.m_nChecksum )
+ continue;
+
+ StateSnapshot_t nShapshot = m_SnapshotDict[i].m_nSnapshot;
+ if ( (id == m_SnapshotList[nShapshot].m_ShadowStateId) &&
+ !memcmp(&m_SnapshotList[nShapshot].m_ShaderState, &currentState, sizeof(ShadowShaderState_t)) )
+ {
+ return nShapshot;
+ }
+ }
+
+ // Need to create a new one
+ return (StateSnapshot_t)-1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Used to clear the transition table when we know it's become invalid.
+//-----------------------------------------------------------------------------
+void CTransitionTable::Reset()
+{
+ m_ShadowStateList.RemoveAll();
+ m_SnapshotList.RemoveAll();
+ m_TransitionTable.RemoveAll();
+ m_TransitionOps.RemoveAll();
+ m_ShadowStateDict.RemoveAll();
+ m_SnapshotDict.RemoveAll();
+ m_UniqueTransitions.RemoveAll();
+ m_CurrentShadowId = -1;
+ m_CurrentSnapshotId = -1;
+ m_DefaultStateSnapshot = -1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the texture stage state
+//-----------------------------------------------------------------------------
+#ifdef _WIN32
+#pragma warning( disable : 4189 )
+#endif
+
+static inline void SetTextureStageState( int stage, D3DTEXTURESTAGESTATETYPE state, DWORD val )
+{
+#if !defined( _X360 )
+ Assert( !g_pShaderDeviceDx8->IsDeactivated() );
+ Dx9Device()->SetTextureStageState( stage, state, val );
+#endif
+}
+
+//Moved to a #define so every instance of this skips unsupported render states at compile time
+#define SetSamplerState( _stage, _state, _val ) \
+ { \
+ if ( (_state != D3DSAMP_NOTSUPPORTED) ) \
+ { \
+ Assert( !g_pShaderDeviceDx8->IsDeactivated() ); \
+ Dx9Device()->SetSamplerState( _stage, _state, _val ); \
+ } \
+ }
+
+//Moved to a #define so every instance of this skips unsupported render states at compile time
+#define SetRenderState( _state, _val ) \
+ { \
+ if ( _state != D3DRS_NOTSUPPORTED ) \
+ { \
+ Assert( !g_pShaderDeviceDx8->IsDeactivated() ); \
+ Dx9Device()->SetRenderState( _state, _val ); \
+ } \
+ }
+
+#ifdef DX_TO_GL_ABSTRACTION
+ #define SetRenderStateConstMacro( state, val ) { if ( state != D3DRS_NOTSUPPORTED ) Dx9Device()->SetRenderStateConstInline( state, val ); }
+#else
+ #define SetRenderStateConstMacro( state, val ) SetRenderState( state, val )
+#endif
+
+#ifdef _WIN32
+#pragma warning( default : 4189 )
+#endif
+
+//-----------------------------------------------------------------------------
+// Methods that actually apply the state
+//-----------------------------------------------------------------------------
+#ifdef DEBUG_BOARD_STATE
+
+static bool g_SpewTransitions = false;
+
+#define UPDATE_BOARD_RENDER_STATE( _d3dState, _state ) \
+ { \
+ BoardState().m_ ## _state = shaderState.m_ ## _state; \
+ if (g_SpewTransitions) \
+ { \
+ char buf[128]; \
+ sprintf( buf, "Apply %s : %d\n", #_d3dState, shaderState.m_ ## _state ); \
+ Plat_DebugString(buf); \
+ } \
+ }
+
+#define UPDATE_BOARD_TEXTURE_STAGE_STATE( _d3dState, _state, _stage ) \
+ { \
+ BoardState().m_TextureStage[_stage].m_ ## _state = shaderState.m_TextureStage[_stage].m_ ## _state; \
+ if (g_SpewTransitions) \
+ { \
+ char buf[128]; \
+ sprintf( buf, "Apply Tex %s (%d): %d\n", #_d3dState, _stage, shaderState.m_TextureStage[_stage].m_ ## _state ); \
+ Plat_DebugString(buf); \
+ } \
+ }
+
+#define UPDATE_BOARD_SAMPLER_STATE( _d3dState, _state, _stage ) \
+ { \
+ BoardState().m_SamplerState[_stage].m_ ## _state = shaderState.m_SamplerState[_stage].m_ ## _state; \
+ if (g_SpewTransitions) \
+ { \
+ char buf[128]; \
+ sprintf( buf, "Apply SamplerSate %s (%d): %d\n", #_d3dState, stage, shaderState.m_SamplerState[_stage].m_ ## _state ); \
+ Plat_DebugString(buf); \
+ } \
+ }
+
+#else
+
+#define UPDATE_BOARD_RENDER_STATE( _d3dState, _state ) {}
+#define UPDATE_BOARD_TEXTURE_STAGE_STATE( _d3dState, _state, _stage ) {}
+#define UPDATE_BOARD_SAMPLER_STATE( _d3dState, _state, _stage ) {}
+
+#endif
+
+
+#define APPLY_RENDER_STATE_FUNC( _d3dState, _state ) \
+ void Apply ## _state( const ShadowState_t& shaderState, int arg ) \
+ { \
+ SetRenderState( _d3dState, shaderState.m_ ## _state ); \
+ UPDATE_BOARD_RENDER_STATE( _d3dState, _state ); \
+ }
+
+#define APPLY_TEXTURE_STAGE_STATE_FUNC( _d3dState, _state ) \
+ void Apply ## _state( const ShadowState_t& shaderState, int stage ) \
+ { \
+ SetTextureStageState( stage, _d3dState, shaderState.m_TextureStage[stage].m_ ## _state ); \
+ UPDATE_BOARD_TEXTURE_STAGE_STATE( _d3dState, _state, stage ); \
+ }
+
+#define APPLY_SAMPLER_STATE_FUNC( _d3dState, _state ) \
+ void Apply ## _state( const ShadowState_t& shaderState, int stage ) \
+ { \
+ SetSamplerState( stage, _d3dState, shaderState.m_SamplerState[stage].m_ ## _state ); \
+ UPDATE_BOARD_SAMPLER_STATE( _d3dState, _state, stage ); \
+ }
+
+
+// Special overridden sampler state to turn on Fetch4 on ATI hardware (and 360?)
+void ApplyFetch4Enable( const ShadowState_t& shaderState, int stage )
+{
+ if ( ShaderAPI()->SupportsFetch4() )
+ {
+ SetSamplerState( stage, ATISAMP_FETCH4, shaderState.m_SamplerState[stage].m_Fetch4Enable ? ATI_FETCH4_ENABLE : ATI_FETCH4_DISABLE );
+ }
+
+ UPDATE_BOARD_SAMPLER_STATE( ATISAMP_FETCH4, Fetch4Enable, stage );
+}
+
+#ifdef DX_TO_GL_ABSTRACTION
+void ApplyShadowFilterEnable( const ShadowState_t& shaderState, int stage )
+{
+ SetSamplerState( stage, D3DSAMP_SHADOWFILTER, shaderState.m_SamplerState[stage].m_ShadowFilterEnable );
+
+ UPDATE_BOARD_SAMPLER_STATE( D3DSAMP_SHADOWFILTER, ShadowFilterEnable, stage );
+}
+#endif
+
+
+//APPLY_RENDER_STATE_FUNC( D3DRS_ZWRITEENABLE, ZWriteEnable )
+//APPLY_RENDER_STATE_FUNC( D3DRS_COLORWRITEENABLE, ColorWriteEnable )
+APPLY_RENDER_STATE_FUNC( D3DRS_FILLMODE, FillMode )
+APPLY_RENDER_STATE_FUNC( D3DRS_LIGHTING, Lighting )
+APPLY_RENDER_STATE_FUNC( D3DRS_SPECULARENABLE, SpecularEnable )
+APPLY_RENDER_STATE_FUNC( D3DRS_DIFFUSEMATERIALSOURCE, DiffuseMaterialSource )
+APPLY_TEXTURE_STAGE_STATE_FUNC( D3DTSS_TEXCOORDINDEX, TexCoordIndex )
+
+
+void ApplyZWriteEnable( const ShadowState_t& shaderState, int arg )
+{
+ SetRenderStateConstMacro( D3DRS_ZWRITEENABLE, shaderState.m_ZWriteEnable );
+#if defined( _X360 )
+ //SetRenderStateConstMacro( D3DRS_HIZWRITEENABLE, shaderState.m_ZWriteEnable ? D3DHIZ_AUTOMATIC : D3DHIZ_DISABLE );
+#endif
+
+ UPDATE_BOARD_RENDER_STATE( D3DRS_ZWRITEENABLE, ZWriteEnable );
+}
+
+void ApplyColorWriteEnable( const ShadowState_t& shaderState, int arg )
+{
+ SetRenderState( D3DRS_COLORWRITEENABLE, shaderState.m_ColorWriteEnable );
+ g_pTransitionTable->CurrentState().m_ColorWriteEnable = shaderState.m_ColorWriteEnable;
+
+ UPDATE_BOARD_RENDER_STATE( D3DRS_COLORWRITEENABLE, ColorWriteEnable );
+}
+
+void ApplySRGBReadEnable( const ShadowState_t& shaderState, int stage )
+{
+# if ( !defined( _X360 ) )
+ {
+ SetSamplerState( stage, D3DSAMP_SRGBTEXTURE, shaderState.m_SamplerState[stage].m_SRGBReadEnable );
+ }
+# else
+ {
+ ShaderAPI()->ApplySRGBReadState( stage, shaderState.m_SamplerState[stage].m_SRGBReadEnable );
+ }
+# endif
+
+ UPDATE_BOARD_SAMPLER_STATE( D3DSAMP_SRGBTEXTURE, SRGBReadEnable, stage );
+}
+
+
+void ApplySRGBWriteEnable( const ShadowState_t& shadowState, int stageUnused )
+{
+ g_pTransitionTable->ApplySRGBWriteEnable( shadowState );
+}
+
+
+void CTransitionTable::ApplySRGBWriteEnable( const ShadowState_t& shaderState )
+{
+ // ApplySRGBWriteEnable set to true means that the shader is writing linear values.
+ if ( CurrentState().m_bLinearColorSpaceFrameBufferEnable )
+ {
+ // The shader had better be writing linear values since we can't convert to gamma here.
+ // Can't leave this assert here since there are cases where the shader is doing the right thing.
+ // This is good to test occasionally to make sure that the shaders are doing the right thing.
+ // Assert( shaderState.m_SRGBWriteEnable );
+
+ // render target is linear
+ SetRenderStateConstMacro( D3DRS_SRGBWRITEENABLE, 0 );
+ ShaderAPI()->EnabledSRGBWrite( false );
+
+ // fog isn't fixed-function with linear frame buffers, so don't bother with that here.
+ }
+ else
+ {
+ // render target is gamma
+
+ // SRGBWrite enable can affect the space in which fog color is defined
+ if ( HardwareConfig()->NeedsShaderSRGBConversion() )
+ {
+ if ( HardwareConfig()->SupportsPixelShaders_2_b() ) //in 2b supported devices, we never actually enable SRGB writes, but instead handle the conversion in the pixel shader. But we want all other code to be unaware.
+ {
+ SetRenderStateConstMacro( D3DRS_SRGBWRITEENABLE, 0 );
+ }
+ else
+ {
+ SetRenderStateConstMacro( D3DRS_SRGBWRITEENABLE, shaderState.m_SRGBWriteEnable );
+ }
+ }
+ else
+ {
+ SetRenderStateConstMacro( D3DRS_SRGBWRITEENABLE, shaderState.m_SRGBWriteEnable );
+ }
+
+ ShaderAPI()->EnabledSRGBWrite( shaderState.m_SRGBWriteEnable );
+
+ if ( HardwareConfig()->SpecifiesFogColorInLinearSpace() )
+ {
+ ShaderAPI()->ApplyFogMode( shaderState.m_FogMode, shaderState.m_SRGBWriteEnable, shaderState.m_bDisableFogGammaCorrection );
+ }
+ }
+
+#ifdef _DEBUG
+ BoardState().m_SRGBWriteEnable = shaderState.m_SRGBWriteEnable;
+ if (g_SpewTransitions)
+ {
+ char buf[128];
+ sprintf( buf, "Apply %s : %d\n", "D3DRS_SRGBWRITEENABLE", shaderState.m_SRGBWriteEnable );
+ Plat_DebugString(buf);
+ }
+#endif
+}
+
+void ApplyDisableFogGammaCorrection( const ShadowState_t& shadowState, int stageUnused )
+{
+ ShaderAPI()->ApplyFogMode( shadowState.m_FogMode, shadowState.m_SRGBWriteEnable, shadowState.m_bDisableFogGammaCorrection );
+
+#ifdef DEBUG_BOARD_STATE
+ g_pTransitionTable->BoardState().m_bDisableFogGammaCorrection = shadowState.m_bDisableFogGammaCorrection;
+#endif
+}
+
+
+
+
+void ApplyDepthTest( const ShadowState_t& state, int stage )
+{
+ g_pTransitionTable->ApplyDepthTest( state );
+}
+
+void CTransitionTable::SetZEnable( D3DZBUFFERTYPE nEnable )
+{
+ if (m_CurrentState.m_ZEnable != nEnable )
+ {
+ SetRenderStateConstMacro( D3DRS_ZENABLE, nEnable );
+#if defined( _X360 )
+ //SetRenderState( D3DRS_HIZENABLE, nEnable ? D3DHIZ_AUTOMATIC : D3DHIZ_DISABLE );
+#endif
+ m_CurrentState.m_ZEnable = nEnable;
+ }
+}
+
+void CTransitionTable::SetZFunc( D3DCMPFUNC nCmpFunc )
+{
+ if (m_CurrentState.m_ZFunc != nCmpFunc )
+ {
+ SetRenderStateConstMacro( D3DRS_ZFUNC, nCmpFunc );
+ m_CurrentState.m_ZFunc = nCmpFunc;
+ }
+}
+
+void CTransitionTable::ApplyDepthTest( const ShadowState_t& state )
+{
+ SetZEnable( state.m_ZEnable );
+ if (state.m_ZEnable != D3DZB_FALSE)
+ {
+ SetZFunc( state.m_ZFunc );
+ }
+ if (m_CurrentState.m_ZBias != state.m_ZBias)
+ {
+ ShaderAPI()->ApplyZBias( state );
+ m_CurrentState.m_ZBias = (PolygonOffsetMode_t) state.m_ZBias; // Cast two bits from m_ZBias
+ }
+
+#ifdef DEBUG_BOARD_STATE
+ // This isn't quite true, but it's necessary for other error checking to work
+ BoardState().m_ZEnable = state.m_ZEnable;
+ BoardState().m_ZFunc = state.m_ZFunc;
+ BoardState().m_ZBias = state.m_ZBias;
+#endif
+}
+
+void ApplyAlphaTest( const ShadowState_t& state, int stage )
+{
+ g_pTransitionTable->ApplyAlphaTest( state );
+}
+
+void CTransitionTable::ApplyAlphaTest( const ShadowState_t& state )
+{
+ if (m_CurrentState.m_AlphaTestEnable != state.m_AlphaTestEnable)
+ {
+ SetRenderStateConstMacro( D3DRS_ALPHATESTENABLE, state.m_AlphaTestEnable );
+ m_CurrentState.m_AlphaTestEnable = state.m_AlphaTestEnable;
+ }
+
+ if (state.m_AlphaTestEnable)
+ {
+ // Set the blend state here...
+ if (m_CurrentState.m_AlphaFunc != state.m_AlphaFunc)
+ {
+ SetRenderStateConstMacro( D3DRS_ALPHAFUNC, state.m_AlphaFunc );
+ m_CurrentState.m_AlphaFunc = state.m_AlphaFunc;
+ }
+
+ if (m_CurrentState.m_AlphaRef != state.m_AlphaRef)
+ {
+ SetRenderStateConstMacro( D3DRS_ALPHAREF, state.m_AlphaRef );
+ m_CurrentState.m_AlphaRef = state.m_AlphaRef;
+ }
+ }
+
+#ifdef DEBUG_BOARD_STATE
+ // This isn't quite true, but it's necessary for other error checking to work
+ BoardState().m_AlphaTestEnable = state.m_AlphaTestEnable;
+ BoardState().m_AlphaFunc = state.m_AlphaFunc;
+ BoardState().m_AlphaRef = state.m_AlphaRef;
+#endif
+}
+
+void ApplyAlphaBlend( const ShadowState_t& state, int stage )
+{
+ g_pTransitionTable->ApplyAlphaBlend( state );
+}
+
+void CTransitionTable::ApplyAlphaBlend( const ShadowState_t& state )
+{
+ if (m_CurrentState.m_AlphaBlendEnable != state.m_AlphaBlendEnable)
+ {
+ SetRenderStateConstMacro( D3DRS_ALPHABLENDENABLE, state.m_AlphaBlendEnable );
+ m_CurrentState.m_AlphaBlendEnable = state.m_AlphaBlendEnable;
+ }
+
+ if (state.m_AlphaBlendEnable)
+ {
+ // Set the blend state here...
+ if (m_CurrentState.m_SrcBlend != state.m_SrcBlend)
+ {
+ SetRenderStateConstMacro( D3DRS_SRCBLEND, state.m_SrcBlend );
+ m_CurrentState.m_SrcBlend = state.m_SrcBlend;
+ }
+
+ if (m_CurrentState.m_DestBlend != state.m_DestBlend)
+ {
+ SetRenderStateConstMacro( D3DRS_DESTBLEND, state.m_DestBlend );
+ m_CurrentState.m_DestBlend = state.m_DestBlend;
+ }
+
+ if (m_CurrentState.m_BlendOp != state.m_BlendOp )
+ {
+ SetRenderStateConstMacro( D3DRS_BLENDOP, state.m_BlendOp );
+ m_CurrentState.m_BlendOp = state.m_BlendOp;
+ }
+ }
+
+#ifdef DEBUG_BOARD_STATE
+ // This isn't quite true, but it's necessary for other error checking to work
+ BoardState().m_AlphaBlendEnable = state.m_AlphaBlendEnable;
+ BoardState().m_SrcBlend = state.m_SrcBlend;
+ BoardState().m_DestBlend = state.m_DestBlend;
+ BoardState().m_BlendOp = state.m_BlendOp;
+#endif
+}
+
+void ApplySeparateAlphaBlend( const ShadowState_t& state, int stage )
+{
+ g_pTransitionTable->ApplySeparateAlphaBlend( state );
+}
+
+void CTransitionTable::ApplySeparateAlphaBlend( const ShadowState_t& state )
+{
+ if (m_CurrentState.m_SeparateAlphaBlendEnable != state.m_SeparateAlphaBlendEnable)
+ {
+ SetRenderStateConstMacro( D3DRS_SEPARATEALPHABLENDENABLE, state.m_SeparateAlphaBlendEnable );
+ m_CurrentState.m_SeparateAlphaBlendEnable = state.m_SeparateAlphaBlendEnable;
+ }
+
+ if (state.m_SeparateAlphaBlendEnable)
+ {
+ // Set the blend state here...
+ if (m_CurrentState.m_SrcBlendAlpha != state.m_SrcBlendAlpha)
+ {
+ SetRenderStateConstMacro( D3DRS_SRCBLENDALPHA, state.m_SrcBlendAlpha );
+ m_CurrentState.m_SrcBlendAlpha = state.m_SrcBlendAlpha;
+ }
+
+ if (m_CurrentState.m_DestBlendAlpha != state.m_DestBlendAlpha)
+ {
+ SetRenderStateConstMacro( D3DRS_DESTBLENDALPHA, state.m_DestBlendAlpha );
+ m_CurrentState.m_DestBlendAlpha = state.m_DestBlendAlpha;
+ }
+
+ if (m_CurrentState.m_BlendOpAlpha != state.m_BlendOpAlpha )
+ {
+ SetRenderStateConstMacro( D3DRS_BLENDOPALPHA, state.m_BlendOpAlpha );
+ m_CurrentState.m_BlendOpAlpha = state.m_BlendOpAlpha;
+ }
+ }
+
+#ifdef DEBUG_BOARD_STATE
+ // This isn't quite true, but it's necessary for other error checking to work
+ BoardState().m_SeparateAlphaBlendEnable = state.m_SeparateAlphaBlendEnable;
+ BoardState().m_SrcBlendAlpha = state.m_SrcBlendAlpha;
+ BoardState().m_DestBlendAlpha = state.m_DestBlendAlpha;
+ BoardState().m_BlendOpAlpha = state.m_BlendOpAlpha;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Applies alpha texture op
+//-----------------------------------------------------------------------------
+void ApplyColorTextureStage( const ShadowState_t& state, int stage )
+{
+ g_pTransitionTable->ApplyColorTextureStage( state, stage );
+}
+
+void ApplyAlphaTextureStage( const ShadowState_t& state, int stage )
+{
+ g_pTransitionTable->ApplyAlphaTextureStage( state, stage );
+}
+
+void CTransitionTable::ApplyColorTextureStage( const ShadowState_t& state, int stage )
+{
+ D3DTEXTUREOP op = state.m_TextureStage[stage].m_ColorOp;
+ int arg1 = state.m_TextureStage[stage].m_ColorArg1;
+ int arg2 = state.m_TextureStage[stage].m_ColorArg2;
+
+ if (m_CurrentState.m_TextureStage[stage].m_ColorOp != op)
+ {
+ SetTextureStageState( stage, D3DTSS_COLOROP, op );
+ m_CurrentState.m_TextureStage[stage].m_ColorOp = op;
+ }
+
+ if (op != D3DTOP_DISABLE)
+ {
+ if (m_CurrentState.m_TextureStage[stage].m_ColorArg1 != arg1)
+ {
+ SetTextureStageState( stage, D3DTSS_COLORARG1, arg1 );
+ m_CurrentState.m_TextureStage[stage].m_ColorArg1 = arg1;
+ }
+ if (m_CurrentState.m_TextureStage[stage].m_ColorArg2 != arg2)
+ {
+ SetTextureStageState( stage, D3DTSS_COLORARG2, arg2 );
+ m_CurrentState.m_TextureStage[stage].m_ColorArg2 = arg2;
+ }
+ }
+
+#ifdef DEBUG_BOARD_STATE
+ // This isn't quite true, but it's necessary for other error checking to work
+ BoardState().m_TextureStage[stage].m_ColorOp = op;
+ BoardState().m_TextureStage[stage].m_ColorArg1 = arg1;
+ BoardState().m_TextureStage[stage].m_ColorArg2 = arg2;
+#endif
+}
+
+void CTransitionTable::ApplyAlphaTextureStage( const ShadowState_t& state, int stage )
+{
+ D3DTEXTUREOP op = state.m_TextureStage[stage].m_AlphaOp;
+ int arg1 = state.m_TextureStage[stage].m_AlphaArg1;
+ int arg2 = state.m_TextureStage[stage].m_AlphaArg2;
+
+ if (m_CurrentState.m_TextureStage[stage].m_AlphaOp != op)
+ {
+ SetTextureStageState( stage, D3DTSS_ALPHAOP, op );
+ m_CurrentState.m_TextureStage[stage].m_AlphaOp = op;
+ }
+
+ if (op != D3DTOP_DISABLE)
+ {
+ if (m_CurrentState.m_TextureStage[stage].m_AlphaArg1 != arg1)
+ {
+ SetTextureStageState( stage, D3DTSS_ALPHAARG1, arg1 );
+ m_CurrentState.m_TextureStage[stage].m_AlphaArg1 = arg1;
+ }
+ if (m_CurrentState.m_TextureStage[stage].m_AlphaArg2 != arg2)
+ {
+ SetTextureStageState( stage, D3DTSS_ALPHAARG2, arg2 );
+ m_CurrentState.m_TextureStage[stage].m_AlphaArg2 = arg2;
+ }
+ }
+
+#ifdef DEBUG_BOARD_STATE
+ // This isn't quite true, but it's necessary for other error checking to work
+ BoardState().m_TextureStage[stage].m_AlphaOp = op;
+ BoardState().m_TextureStage[stage].m_AlphaArg1 = arg1;
+ BoardState().m_TextureStage[stage].m_AlphaArg2 = arg2;
+#endif
+}
+
+
+void ApplyActivateFixedFunction( const ShadowState_t& state, int stage )
+{
+ int nStageCount = HardwareConfig()->GetTextureStageCount();
+ for ( int i = 0; i < nStageCount; ++i )
+ {
+ g_pTransitionTable->ApplyColorTextureStage( state, i );
+ g_pTransitionTable->ApplyAlphaTextureStage( state, i );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Enables textures
+//-----------------------------------------------------------------------------
+void ApplyTextureEnable( const ShadowState_t& state, int stage )
+{
+ // This may well enable/disable textures that are already enabled/disabled
+ // but the ShaderAPI will handle that
+ int i;
+ int nSamplerCount = HardwareConfig()->GetSamplerCount();
+ for ( i = 0; i < nSamplerCount; ++i )
+ {
+ ShaderAPI()->ApplyTextureEnable( state, i );
+
+#ifdef DEBUG_BOARD_STATE
+ BoardState().m_SamplerState[i].m_TextureEnable = state.m_SamplerState[i].m_TextureEnable;
+#endif
+ }
+
+ // Needed to prevent mat_dxlevel assertions
+#ifdef DEBUG_BOARD_STATE
+ for ( i = nSamplerCount; i < MAX_SAMPLERS; ++i )
+ {
+ BoardState().m_SamplerState[i].m_TextureEnable = false;
+ }
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// All transitions below this point depend on dynamic render state
+// FIXME: Eliminate these virtual calls?
+//-----------------------------------------------------------------------------
+void ApplyCullEnable( const ShadowState_t& state, int arg )
+{
+ ShaderAPI()->ApplyCullEnable( state.m_CullEnable );
+
+#ifdef DEBUG_BOARD_STATE
+ BoardState().m_CullEnable = state.m_CullEnable;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+void ApplyAlphaToCoverage( const ShadowState_t& state, int arg )
+{
+ ShaderAPI()->ApplyAlphaToCoverage( state.m_EnableAlphaToCoverage );
+
+#ifdef DEBUG_BOARD_STATE
+ BoardState().m_EnableAlphaToCoverage = state.m_EnableAlphaToCoverage;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+void ApplyVertexBlendEnable( const ShadowState_t& state, int stage )
+{
+ ShaderAPI()->SetVertexBlendState( state.m_VertexBlendEnable ? -1 : 0 );
+
+#ifdef DEBUG_BOARD_STATE
+ BoardState().m_VertexBlendEnable = state.m_VertexBlendEnable;
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Outputs the fog mode string
+//-----------------------------------------------------------------------------
+#ifdef RECORDING
+const char *ShaderFogModeToString( ShaderFogMode_t fogMode )
+{
+ switch( fogMode )
+ {
+ case SHADER_FOGMODE_DISABLED:
+ return "SHADER_FOGMODE_DISABLED";
+ case SHADER_FOGMODE_OO_OVERBRIGHT:
+ return "SHADER_FOGMODE_OO_OVERBRIGHT";
+ case SHADER_FOGMODE_BLACK:
+ return "SHADER_FOGMODE_BLACK";
+ case SHADER_FOGMODE_GREY:
+ return "SHADER_FOGMODE_GREY";
+ case SHADER_FOGMODE_FOGCOLOR:
+ return "SHADER_FOGMODE_FOGCOLOR";
+ case SHADER_FOGMODE_WHITE:
+ return "SHADER_FOGMODE_WHITE";
+ case SHADER_FOGMODE_NUMFOGMODES:
+ return "SHADER_FOGMODE_NUMFOGMODES";
+ default:
+ return "ERROR";
+ }
+}
+#endif
+
+// Uses GetConfig().overbright and GetSceneFogMode, so
+// will have to fix up the state manually when those change.
+void ApplyFogMode( const ShadowState_t& state, int arg )
+{
+#ifdef RECORDING
+ char buf[1024];
+ sprintf( buf, "ApplyFogMode( %s )", ShaderFogModeToString( state.m_FogMode ) );
+ RECORD_DEBUG_STRING( buf );
+#endif
+
+ ShaderAPI()->ApplyFogMode( state.m_FogMode, state.m_SRGBWriteEnable, state.m_bDisableFogGammaCorrection );
+
+#ifdef DEBUG_BOARD_STATE
+ BoardState().m_FogMode = state.m_FogMode;
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Function tables mapping enum to function
+//-----------------------------------------------------------------------------
+ApplyStateFunc_t s_pRenderFunctionTable[] =
+{
+ ApplyDepthTest,
+ ApplyZWriteEnable,
+ ApplyColorWriteEnable,
+ ApplyAlphaTest,
+ ApplyFillMode,
+ ApplyLighting,
+ ApplySpecularEnable,
+ ApplySRGBWriteEnable,
+ ApplyAlphaBlend,
+ ApplySeparateAlphaBlend,
+ ApplyCullEnable,
+ ApplyVertexBlendEnable,
+ ApplyFogMode,
+ ApplyActivateFixedFunction,
+ ApplyTextureEnable, // Enables textures on *all* stages
+ ApplyDiffuseMaterialSource,
+ ApplyDisableFogGammaCorrection,
+ ApplyAlphaToCoverage,
+};
+
+ApplyStateFunc_t s_pTextureFunctionTable[] =
+{
+ ApplyTexCoordIndex,
+ ApplySRGBReadEnable,
+ ApplyFetch4Enable,
+#ifdef DX_TO_GL_ABSTRACTION
+ ApplyShadowFilterEnable,
+#endif
+ // Fixed function states
+ ApplyColorTextureStage,
+ ApplyAlphaTextureStage,
+};
+
+
+//-----------------------------------------------------------------------------
+// Creates an entry in the state transition table
+//-----------------------------------------------------------------------------
+inline void CTransitionTable::AddTransition( RenderStateFunc_t func )
+{
+ int nElem = m_TransitionOps.AddToTail();
+ TransitionOp_t &op = m_TransitionOps[nElem];
+ op.m_nInfo.m_bIsTextureCode = false;
+ op.m_nInfo.m_nOpCode = func;
+
+ // Stats
+// ++s_pRenderTransitions[ func ];
+}
+
+inline void CTransitionTable::AddTextureTransition( TextureStateFunc_t func, int stage )
+{
+ int nElem = m_TransitionOps.AddToTail();
+ TransitionOp_t &op = m_TransitionOps[nElem];
+ op.m_nInfo.m_bIsTextureCode = true;
+ op.m_nInfo.m_nOpCode = TextureOp( func, stage );
+
+ // Stats
+// ++s_pTextureTransitions[ func ][stage];
+}
+
+#define ADD_RENDER_STATE_TRANSITION( _state ) \
+ if (bForce || (toState.m_ ## _state != fromState.m_ ## _state)) \
+ { \
+ AddTransition( RENDER_STATE_ ## _state ); \
+ ++numOps; \
+ }
+
+#define ADD_TEXTURE_STAGE_STATE_TRANSITION( _stage, _state )\
+ if (bForce || (toState.m_TextureStage[_stage].m_ ## _state != fromState.m_TextureStage[_stage].m_ ## _state)) \
+ { \
+ Assert( _stage < MAX_TEXTURE_STAGES ); \
+ AddTextureTransition( TEXTURE_STATE_ ## _state, _stage ); \
+ ++numOps; \
+ }
+
+#define ADD_SAMPLER_STATE_TRANSITION( _stage, _state )\
+ if (bForce || (toState.m_SamplerState[_stage].m_ ## _state != fromState.m_SamplerState[_stage].m_ ## _state)) \
+ { \
+ Assert( _stage < MAX_SAMPLERS ); \
+ AddTextureTransition( TEXTURE_STATE_ ## _state, _stage ); \
+ ++numOps; \
+ }
+
+int CTransitionTable::CreateNormalTransitions( const ShadowState_t& fromState, const ShadowState_t& toState, bool bForce )
+{
+ int numOps = 0;
+
+ // Special case for alpha blending to eliminate extra transitions
+ bool blendEnableDifferent = (toState.m_AlphaBlendEnable != fromState.m_AlphaBlendEnable);
+ bool srcBlendDifferent = toState.m_AlphaBlendEnable && (toState.m_SrcBlend != fromState.m_SrcBlend);
+ bool destBlendDifferent = toState.m_AlphaBlendEnable && (toState.m_DestBlend != fromState.m_DestBlend);
+ bool blendOpDifferent = toState.m_AlphaBlendEnable && ( toState.m_BlendOp != fromState.m_BlendOp );
+ if (bForce || blendOpDifferent || blendEnableDifferent || srcBlendDifferent || destBlendDifferent)
+ {
+ AddTransition( RENDER_STATE_AlphaBlend );
+ ++numOps;
+ }
+
+ // Shouldn't have m_SeparateAlphaBlendEnable set unless m_AlphaBlendEnable is also set.
+ Assert ( toState.m_AlphaBlendEnable || !toState.m_SeparateAlphaBlendEnable );
+ bool blendSeparateAlphaEnableDifferent = (toState.m_SeparateAlphaBlendEnable != fromState.m_SeparateAlphaBlendEnable);
+ bool srcBlendAlphaDifferent = toState.m_SeparateAlphaBlendEnable && (toState.m_SrcBlendAlpha != fromState.m_SrcBlendAlpha);
+ bool destBlendAlphaDifferent = toState.m_SeparateAlphaBlendEnable && (toState.m_DestBlendAlpha != fromState.m_DestBlendAlpha);
+ bool blendOpAlphaDifferent = toState.m_SeparateAlphaBlendEnable && ( toState.m_BlendOpAlpha != fromState.m_BlendOpAlpha );
+ if (bForce || blendOpAlphaDifferent || blendSeparateAlphaEnableDifferent || srcBlendAlphaDifferent || destBlendAlphaDifferent)
+ {
+ AddTransition( RENDER_STATE_SeparateAlphaBlend );
+ ++numOps;
+ }
+
+ bool bAlphaTestEnableDifferent = (toState.m_AlphaTestEnable != fromState.m_AlphaTestEnable);
+ bool bAlphaFuncDifferent = toState.m_AlphaTestEnable && (toState.m_AlphaFunc != fromState.m_AlphaFunc);
+ bool bAlphaRefDifferent = toState.m_AlphaTestEnable && (toState.m_AlphaRef != fromState.m_AlphaRef);
+ if (bForce || bAlphaTestEnableDifferent || bAlphaFuncDifferent || bAlphaRefDifferent)
+ {
+ AddTransition( RENDER_STATE_AlphaTest );
+ ++numOps;
+ }
+
+ bool bDepthTestEnableDifferent = (toState.m_ZEnable != fromState.m_ZEnable);
+ bool bDepthFuncDifferent = (toState.m_ZEnable != D3DZB_FALSE) && (toState.m_ZFunc != fromState.m_ZFunc);
+ bool bDepthBiasDifferent = (toState.m_ZBias != fromState.m_ZBias);
+ if (bForce || bDepthTestEnableDifferent || bDepthFuncDifferent || bDepthBiasDifferent)
+ {
+ AddTransition( RENDER_STATE_DepthTest );
+ ++numOps;
+ }
+
+ if ( bForce || (toState.m_UsingFixedFunction && !fromState.m_UsingFixedFunction) )
+ {
+ AddTransition( RENDER_STATE_ActivateFixedFunction );
+ ++numOps;
+ }
+
+ if ( bForce || (toState.m_bDisableFogGammaCorrection != fromState.m_bDisableFogGammaCorrection) )
+ {
+ AddTransition( RENDER_STATE_DisableFogGammaCorrection );
+ ++numOps;
+ }
+
+ int nStageCount = HardwareConfig()->GetTextureStageCount();
+ int i;
+ for ( i = 0; i < nStageCount; ++i )
+ {
+ // Special case for texture stage ops to eliminate extra transitions
+ // NOTE: If we're forcing transitions, then ActivateFixedFunction above will take care of all these transitions
+ if ( !bForce && toState.m_UsingFixedFunction && fromState.m_UsingFixedFunction )
+ {
+ const TextureStageShadowState_t& fromTexture = fromState.m_TextureStage[i];
+ const TextureStageShadowState_t& toTexture = toState.m_TextureStage[i];
+
+ bool fromEnabled = (fromTexture.m_ColorOp != D3DTOP_DISABLE);
+ bool toEnabled = (toTexture.m_ColorOp != D3DTOP_DISABLE);
+ if ( fromEnabled || toEnabled )
+ {
+ bool opDifferent = (toTexture.m_ColorOp != fromTexture.m_ColorOp);
+ bool arg1Different = (toTexture.m_ColorArg1 != fromTexture.m_ColorArg1);
+ bool arg2Different = (toTexture.m_ColorArg2 != fromTexture.m_ColorArg2);
+ if (opDifferent || arg1Different || arg2Different )
+ {
+ AddTextureTransition( TEXTURE_STATE_ColorTextureStage, i );
+ ++numOps;
+ }
+ }
+
+ fromEnabled = (fromTexture.m_AlphaOp != D3DTOP_DISABLE);
+ toEnabled = (toTexture.m_AlphaOp != D3DTOP_DISABLE);
+ if ( fromEnabled || toEnabled )
+ {
+ bool opDifferent = (toTexture.m_AlphaOp != fromTexture.m_AlphaOp);
+ bool arg1Different = (toTexture.m_AlphaArg1 != fromTexture.m_AlphaArg1);
+ bool arg2Different = (toTexture.m_AlphaArg2 != fromTexture.m_AlphaArg2);
+ if (opDifferent || arg1Different || arg2Different )
+ {
+ AddTextureTransition( TEXTURE_STATE_AlphaTextureStage, i );
+ ++numOps;
+ }
+ }
+ }
+
+ ADD_TEXTURE_STAGE_STATE_TRANSITION( i, TexCoordIndex );
+ }
+
+ int nSamplerCount = HardwareConfig()->GetSamplerCount();
+ for ( int i = 0; i < nSamplerCount; ++i )
+ {
+ ADD_SAMPLER_STATE_TRANSITION( i, SRGBReadEnable );
+ ADD_SAMPLER_STATE_TRANSITION( i, Fetch4Enable );
+#ifdef DX_TO_GL_ABSTRACTION
+ ADD_SAMPLER_STATE_TRANSITION( i, ShadowFilterEnable );
+#endif
+ }
+
+ return numOps;
+}
+
+void CTransitionTable::CreateTransitionTableEntry( int to, int from )
+{
+ // You added or removed a state to the enums but not to the function table lists!
+ COMPILE_TIME_ASSERT( sizeof(s_pRenderFunctionTable) == sizeof(ApplyStateFunc_t) * RENDER_STATE_COUNT );
+ COMPILE_TIME_ASSERT( sizeof(s_pTextureFunctionTable) == sizeof(ApplyStateFunc_t) * TEXTURE_STATE_COUNT );
+
+ // If from < 0, that means add *all* transitions into it.
+ unsigned int firstElem = m_TransitionOps.Count();
+ unsigned short numOps = 0;
+
+ const ShadowState_t& toState = m_ShadowStateList[to];
+ const ShadowState_t& fromState = (from >= 0) ? m_ShadowStateList[from] : m_ShadowStateList[to];
+ bool bForce = (from < 0);
+
+ ADD_RENDER_STATE_TRANSITION( ZWriteEnable )
+ ADD_RENDER_STATE_TRANSITION( ColorWriteEnable )
+ ADD_RENDER_STATE_TRANSITION( FillMode )
+ ADD_RENDER_STATE_TRANSITION( Lighting )
+ ADD_RENDER_STATE_TRANSITION( SpecularEnable )
+ ADD_RENDER_STATE_TRANSITION( SRGBWriteEnable )
+ ADD_RENDER_STATE_TRANSITION( DiffuseMaterialSource )
+
+ // Some code for the non-trivial transitions
+ numOps += CreateNormalTransitions( fromState, toState, bForce );
+
+ // NOTE: From here on down are transitions that depend on dynamic state
+ // and which can therefore not appear in the state block
+ ADD_RENDER_STATE_TRANSITION( CullEnable )
+ ADD_RENDER_STATE_TRANSITION( EnableAlphaToCoverage )
+ ADD_RENDER_STATE_TRANSITION( VertexBlendEnable )
+
+ // NOTE! : Have to do the extra check for changes in m_UsingFixedFunction
+ // since d3d fog state is different if you are using fixed function vs.
+ // using a vsh/psh.
+ // This code is derived from: ADD_RENDER_STATE_TRANSITION( FogMode )
+ // If ADD_RENDER_STATE_TRANSITION ever changes, this needs to be updated!
+ // This is another reason to try to have very little fixed function in the dx8/dx9 path.
+ if( bForce || (toState.m_FogMode != fromState.m_FogMode ) ||
+ ( toState.m_UsingFixedFunction != fromState.m_UsingFixedFunction ) )
+ {
+ AddTransition( RENDER_STATE_FogMode );
+ ++numOps;
+ }
+
+ bool bDifferentTexturesEnabled = false;
+ int nSamplerCount = HardwareConfig()->GetSamplerCount();
+ for ( int i = 0; i < nSamplerCount; ++i )
+ {
+ if ( toState.m_SamplerState[i].m_TextureEnable != fromState.m_SamplerState[i].m_TextureEnable )
+ {
+ bDifferentTexturesEnabled = true;
+ break;
+ }
+ }
+
+ if ( bForce || bDifferentTexturesEnabled )
+ {
+ AddTransition( RENDER_STATE_TextureEnable );
+ ++numOps;
+ }
+
+ // Look for identical transition lists, and use those instead...
+ TransitionList_t& transition = (from >= 0) ?
+ m_TransitionTable[to][from] : m_DefaultTransition;
+ Assert( numOps <= 255 );
+ transition.m_NumOperations = numOps;
+
+ // This condition can happen, and is valid. It occurs when we snapshot
+ // state but do not generate a transition function for that state
+ if (numOps == 0)
+ {
+ transition.m_FirstOperation = INVALID_TRANSITION_OP;
+ return;
+ }
+
+ // An optimization to try to early out of the identical transition check
+ // taking advantage of the fact that the matrix is usually diagonal.
+ unsigned int nFirstTest = INVALID_TRANSITION_OP;
+ if (from >= 0)
+ {
+ TransitionList_t &diagonalList = m_TransitionTable[from][to];
+ if ( diagonalList.m_NumOperations == numOps )
+ {
+ nFirstTest = diagonalList.m_FirstOperation;
+ }
+ }
+
+ unsigned int identicalListFirstElem = FindIdenticalTransitionList( firstElem, numOps, nFirstTest );
+ if (identicalListFirstElem == INVALID_TRANSITION_OP)
+ {
+ transition.m_FirstOperation = firstElem;
+ m_UniqueTransitions.Insert( transition );
+ Assert( (int)firstElem + (int)numOps < 16777215 );
+
+ if( (int)firstElem + (int)numOps >= 16777215 )
+ {
+ Warning("**** WARNING: Transition table overflow. Grab Brian\n");
+ }
+ }
+ else
+ {
+ // Remove the transitions ops we made; use the duplicate copy
+ transition.m_FirstOperation = identicalListFirstElem;
+ m_TransitionOps.RemoveMultiple( firstElem, numOps );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Tests a snapshot to see if it can be used
+//-----------------------------------------------------------------------------
+
+#define PERFORM_RENDER_STATE_TRANSITION( _state, _func ) \
+ ::Apply ## _func( _state, 0 );
+#define PERFORM_TEXTURE_STAGE_STATE_TRANSITION( _state, _stage, _func ) \
+ ::Apply ## _func( _state, _stage );
+#define PERFORM_SAMPLER_STATE_TRANSITION( _state, _stage, _func ) \
+ ::Apply ## _func( _state, _stage );
+
+bool CTransitionTable::TestShadowState( const ShadowState_t& state, const ShadowShaderState_t &shaderState )
+{
+ PERFORM_RENDER_STATE_TRANSITION( state, DepthTest )
+ PERFORM_RENDER_STATE_TRANSITION( state, ZWriteEnable )
+ PERFORM_RENDER_STATE_TRANSITION( state, ColorWriteEnable )
+ PERFORM_RENDER_STATE_TRANSITION( state, AlphaTest )
+ PERFORM_RENDER_STATE_TRANSITION( state, FillMode )
+ PERFORM_RENDER_STATE_TRANSITION( state, Lighting )
+ PERFORM_RENDER_STATE_TRANSITION( state, SpecularEnable )
+ PERFORM_RENDER_STATE_TRANSITION( state, SRGBWriteEnable )
+ PERFORM_RENDER_STATE_TRANSITION( state, AlphaBlend )
+ PERFORM_RENDER_STATE_TRANSITION( state, SeparateAlphaBlend )
+ PERFORM_RENDER_STATE_TRANSITION( state, CullEnable )
+ PERFORM_RENDER_STATE_TRANSITION( state, AlphaToCoverage )
+ PERFORM_RENDER_STATE_TRANSITION( state, VertexBlendEnable )
+ PERFORM_RENDER_STATE_TRANSITION( state, FogMode )
+ PERFORM_RENDER_STATE_TRANSITION( state, ActivateFixedFunction )
+ PERFORM_RENDER_STATE_TRANSITION( state, TextureEnable )
+ PERFORM_RENDER_STATE_TRANSITION( state, DiffuseMaterialSource )
+
+ int i;
+ int nStageCount = HardwareConfig()->GetTextureStageCount();
+ for ( i = 0; i < nStageCount; ++i )
+ {
+ PERFORM_TEXTURE_STAGE_STATE_TRANSITION( state, i, ColorTextureStage );
+ PERFORM_TEXTURE_STAGE_STATE_TRANSITION( state, i, AlphaTextureStage );
+ PERFORM_TEXTURE_STAGE_STATE_TRANSITION( state, i, TexCoordIndex );
+ }
+
+ int nSamplerCount = HardwareConfig()->GetSamplerCount();
+ for ( i = 0; i < nSamplerCount; ++i )
+ {
+ PERFORM_SAMPLER_STATE_TRANSITION( state, i, SRGBReadEnable );
+ PERFORM_SAMPLER_STATE_TRANSITION( state, i, Fetch4Enable );
+#ifdef DX_TO_GL_ABSTRACTION
+ PERFORM_SAMPLER_STATE_TRANSITION( state, i, ShadowFilterEnable );
+#endif
+ }
+
+ // Just make sure we've got a good snapshot
+ RECORD_COMMAND( DX8_VALIDATE_DEVICE, 0 );
+
+#if !defined( _X360 )
+ DWORD numPasses;
+ HRESULT hr = Dx9Device()->ValidateDevice( &numPasses );
+ bool ok = !FAILED(hr);
+#else
+ bool ok = true;
+#endif
+
+ // Now set the board state to match the default state
+ ApplyTransition( m_DefaultTransition, m_DefaultStateSnapshot );
+
+ ShaderManager()->SetVertexShader( shaderState.m_VertexShader );
+ ShaderManager()->SetPixelShader( shaderState.m_PixelShader );
+
+ return ok;
+}
+
+//-----------------------------------------------------------------------------
+// Finds identical transition lists and shares them
+//-----------------------------------------------------------------------------
+unsigned int CTransitionTable::FindIdenticalTransitionList( unsigned int firstElem,
+ unsigned short numOps, unsigned int nFirstTest ) const
+{
+ VPROF("CTransitionTable::FindIdenticalTransitionList");
+ // As it turns out, this works most of the time
+ if ( nFirstTest != INVALID_TRANSITION_OP )
+ {
+ const TransitionOp_t *pCurrOp = &m_TransitionOps[firstElem];
+ const TransitionOp_t *pTestOp = &m_TransitionOps[nFirstTest];
+ if ( !memcmp( pCurrOp, pTestOp, numOps * sizeof(TransitionOp_t) ) )
+ return nFirstTest;
+ }
+
+ // Look for a common list
+ const TransitionOp_t &op = m_TransitionOps[firstElem];
+
+ int nCount = m_UniqueTransitions.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ const TransitionList_t &list = m_UniqueTransitions[i];
+
+ // We can early out here because we've sorted the unique transitions
+ // descending by count
+ if ( list.m_NumOperations < numOps )
+ return INVALID_TRANSITION_OP;
+
+ // If we don't find a match in the first
+ int nPotentialMatch;
+ int nLastTest = list.m_FirstOperation + list.m_NumOperations - numOps;
+ for ( nPotentialMatch = list.m_FirstOperation; nPotentialMatch <= nLastTest; ++nPotentialMatch )
+ {
+ // Find the first match
+ const TransitionOp_t &testOp = m_TransitionOps[nPotentialMatch];
+ if ( testOp.m_nBits == op.m_nBits )
+ break;
+ }
+
+ // No matches found, continue
+ if ( nPotentialMatch > nLastTest )
+ continue;
+
+ // Ok, found a match of the first op, lets see if they all match
+ if ( numOps == 1 )
+ return nPotentialMatch;
+
+ const TransitionOp_t *pCurrOp = &m_TransitionOps[firstElem + 1];
+ const TransitionOp_t *pTestOp = &m_TransitionOps[nPotentialMatch + 1];
+ if ( !memcmp( pCurrOp, pTestOp, (numOps - 1) * sizeof(TransitionOp_t) ) )
+ return nPotentialMatch;
+ }
+ return INVALID_TRANSITION_OP;
+}
+
+
+//-----------------------------------------------------------------------------
+// Create startup snapshot
+//-----------------------------------------------------------------------------
+void CTransitionTable::TakeDefaultStateSnapshot( )
+{
+ if (m_DefaultStateSnapshot == -1)
+ {
+ m_DefaultStateSnapshot = TakeSnapshot();
+
+ // This will create a transition which sets *all* shadowed state
+ CreateTransitionTableEntry( m_DefaultStateSnapshot, -1 );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Applies the transition list
+//-----------------------------------------------------------------------------
+void CTransitionTable::ApplyTransitionList( int snapshot, int nFirstOp, int nOpCount )
+{
+ VPROF("CTransitionTable::ApplyTransitionList");
+ // Don't bother if there's nothing to do
+ if (nOpCount > 0)
+ {
+ // Trying to avoid function overhead here
+ ShadowState_t& shadowState = m_ShadowStateList[snapshot];
+ TransitionOp_t* pTransitionOp = &m_TransitionOps[nFirstOp];
+
+ for (int i = 0; i < nOpCount; ++i )
+ {
+ // invoke the transition method
+ if ( pTransitionOp->m_nInfo.m_bIsTextureCode )
+ {
+ TextureStateFunc_t code;
+ int nStage;
+ GetTextureOp( pTransitionOp->m_nInfo.m_nOpCode, &code, &nStage );
+ (*s_pTextureFunctionTable[code])( shadowState, nStage );
+ }
+ else
+ {
+ (*s_pRenderFunctionTable[pTransitionOp->m_nInfo.m_nOpCode])( shadowState, 0 );
+ }
+ ++pTransitionOp;
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Apply startup snapshot
+//-----------------------------------------------------------------------------
+#ifdef _WIN32
+#pragma warning( disable : 4189 )
+#endif
+
+void CTransitionTable::ApplyTransition( TransitionList_t& list, int snapshot )
+{
+ VPROF("CTransitionTable::ApplyTransition");
+ if ( g_pShaderDeviceDx8->IsDeactivated() )
+ return;
+
+ // Transition lists when using state blocks have 2 parts: the first
+ // is the stateblock part, which is states that are not related to
+ // dynamic state at all; followed by states that *are* affected by dynamic state
+ int nFirstOp = list.m_FirstOperation;
+ int nOpCount = list.m_NumOperations;
+
+ ApplyTransitionList( snapshot, nFirstOp, nOpCount );
+
+ // Semi-hacky code to override what the transitions are doing
+ PerformShadowStateOverrides();
+
+ // Set the current snapshot id
+ m_CurrentShadowId = snapshot;
+
+#ifdef DEBUG_BOARD_STATE
+ // Copy over the board states that aren't explicitly in the transition table
+ // so the assertion works...
+
+ int i;
+ int nSamplerCount = HardwareConfig()->GetSamplerCount();
+ for ( i = nSamplerCount; i < MAX_SAMPLERS; ++i )
+ {
+ m_BoardState.m_SamplerState[i].m_TextureEnable =
+ CurrentShadowState()->m_SamplerState[i].m_TextureEnable;
+ }
+
+ int nTextureStageCount = HardwareConfig()->GetTextureStageCount();
+ for ( i = nTextureStageCount; i < MAX_TEXTURE_STAGES; ++i )
+ {
+ memcpy( &m_BoardState.m_TextureStage[i], &CurrentShadowState()->m_TextureStage[i], sizeof(TextureStageShadowState_t) );
+ }
+ m_BoardState.m_UsingFixedFunction = CurrentShadowState()->m_UsingFixedFunction;
+
+ // State blocks bypass the code that sets the board state
+#ifdef _DEBUG
+ // NOTE: A memcmp here isn't enough since we don't set alpha args in cases where the op is nothing.
+ // Assert( !memcmp( &m_BoardState, &CurrentShadowState(), sizeof(m_BoardState) ) );
+ const ShadowState_t &testState1 = *CurrentShadowState();
+ ShadowState_t testState2 = m_BoardState;
+
+ if ( testState1.m_ZEnable == D3DZB_FALSE )
+ {
+ testState2.m_ZBias = testState1.m_ZBias;
+ testState2.m_ZFunc = testState1.m_ZFunc;
+ }
+
+ if ( !testState1.m_AlphaTestEnable )
+ {
+ testState2.m_AlphaRef = testState1.m_AlphaRef;
+ testState2.m_AlphaFunc = testState1.m_AlphaFunc;
+ }
+ for( i = 0; i < nTextureStageCount; i++ )
+ {
+ if ( !testState1.m_UsingFixedFunction )
+ {
+ testState2.m_TextureStage[i].m_ColorOp = testState1.m_TextureStage[i].m_ColorOp;
+ testState2.m_TextureStage[i].m_ColorArg1 = testState1.m_TextureStage[i].m_ColorArg1;
+ testState2.m_TextureStage[i].m_ColorArg2 = testState1.m_TextureStage[i].m_ColorArg2;
+ testState2.m_TextureStage[i].m_AlphaOp = testState1.m_TextureStage[i].m_AlphaOp;
+ testState2.m_TextureStage[i].m_AlphaArg1 = testState1.m_TextureStage[i].m_AlphaArg1;
+ testState2.m_TextureStage[i].m_AlphaArg2 = testState1.m_TextureStage[i].m_AlphaArg2;
+ }
+ else
+ {
+ if ( testState1.m_TextureStage[i].m_ColorOp == D3DTOP_DISABLE )
+ {
+ testState2.m_TextureStage[i].m_ColorArg1 = testState1.m_TextureStage[i].m_ColorArg1;
+ testState2.m_TextureStage[i].m_ColorArg2 = testState1.m_TextureStage[i].m_ColorArg2;
+ }
+ if ( testState1.m_TextureStage[i].m_AlphaOp == D3DTOP_DISABLE )
+ {
+ testState2.m_TextureStage[i].m_AlphaArg1 = testState1.m_TextureStage[i].m_AlphaArg1;
+ testState2.m_TextureStage[i].m_AlphaArg2 = testState1.m_TextureStage[i].m_AlphaArg2;
+ }
+ }
+ }
+
+ Assert( !memcmp( &testState1, &testState2, sizeof( testState1 ) ) );
+#endif
+#endif
+}
+
+#ifdef _WIN32
+#pragma warning( default : 4189 )
+#endif
+
+//-----------------------------------------------------------------------------
+// Takes a snapshot, hooks it into the material
+//-----------------------------------------------------------------------------
+StateSnapshot_t CTransitionTable::TakeSnapshot( )
+{
+ // Do any final computation of the shadow state
+ ShaderShadow()->ComputeAggregateShadowState();
+
+ // Get the current snapshot
+ const ShadowState_t& currentState = ShaderShadow()->GetShadowState();
+
+ // Create a new snapshot
+ ShadowStateId_t shadowStateId = FindShadowState( currentState );
+ if (shadowStateId == -1)
+ {
+ // Create entry in state transition table
+ shadowStateId = CreateShadowState( currentState );
+
+ // Now create new transition entries
+ for (int to = 0; to < shadowStateId; ++to)
+ {
+ CreateTransitionTableEntry( to, shadowStateId );
+ }
+
+ for (int from = 0; from < shadowStateId; ++from)
+ {
+ CreateTransitionTableEntry( shadowStateId, from );
+ }
+ }
+
+ const ShadowShaderState_t& currentShaderState = ShaderShadow()->GetShadowShaderState();
+ StateSnapshot_t snapshotId = FindStateSnapshot( shadowStateId, currentShaderState );
+ if (snapshotId == -1)
+ {
+ // Create entry in state transition table
+ snapshotId = CreateStateSnapshot( shadowStateId, currentShaderState );
+ }
+
+ return snapshotId;
+}
+
+
+//-----------------------------------------------------------------------------
+// Apply shader state (stuff that doesn't lie in the transition table)
+//-----------------------------------------------------------------------------
+void CTransitionTable::ApplyShaderState( const ShadowState_t &shadowState, const ShadowShaderState_t &shaderState )
+{
+ VPROF("CTransitionTable::ApplyShaderState");
+ // Don't bother testing against the current state because there
+ // could well be dynamic state modifiers affecting this too....
+ if ( !shadowState.m_UsingFixedFunction )
+ {
+ // FIXME: Improve early-binding of vertex shader index
+ ShaderManager()->SetVertexShader( shaderState.m_VertexShader );
+ ShaderManager()->SetPixelShader( shaderState.m_PixelShader );
+
+#ifdef DEBUG_BOARD_STATE
+ BoardShaderState().m_VertexShader = shaderState.m_VertexShader;
+ BoardShaderState().m_PixelShader = shaderState.m_PixelShader;
+ BoardShaderState().m_nStaticVshIndex = shaderState.m_nStaticVshIndex;
+ BoardShaderState().m_nStaticPshIndex = shaderState.m_nStaticPshIndex;
+#endif
+ }
+ else
+ {
+ ShaderManager()->SetVertexShader( INVALID_SHADER );
+ ShaderManager()->SetPixelShader( INVALID_SHADER );
+#if defined( _X360 )
+ // no fixed function support
+ Assert( 0 );
+#endif
+
+#ifdef DEBUG_BOARD_STATE
+ BoardShaderState().m_VertexShader = INVALID_SHADER;
+ BoardShaderState().m_PixelShader = INVALID_SHADER;
+ BoardShaderState().m_nStaticVshIndex = 0;
+ BoardShaderState().m_nStaticPshIndex = 0;
+#endif
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Makes the board state match the snapshot
+//-----------------------------------------------------------------------------
+void CTransitionTable::UseSnapshot( StateSnapshot_t snapshotId )
+{
+ VPROF("CTransitionTable::UseSnapshot");
+ ShadowStateId_t id = m_SnapshotList[snapshotId].m_ShadowStateId;
+ if (m_CurrentSnapshotId != snapshotId)
+ {
+ // First apply things that are in the transition table
+ if ( m_CurrentShadowId != id )
+ {
+ TransitionList_t& transition = m_TransitionTable[id][m_CurrentShadowId];
+ ApplyTransition( transition, id );
+ }
+
+ // NOTE: There is an opportunity here to set non-dynamic state that we don't
+ // store in the transition list if we ever need it.
+
+ m_CurrentSnapshotId = snapshotId;
+ }
+
+ // NOTE: This occurs regardless of whether the snapshot changed because it depends
+ // on dynamic state (namely, the dynamic vertex + pixel shader index)
+ // Followed by things that are not
+ ApplyShaderState( m_ShadowStateList[id], m_SnapshotList[snapshotId].m_ShaderState );
+
+#ifdef _DEBUG
+ // NOTE: We can't ship with this active because mod makers may well violate this rule
+ // We don't want no stinking fixed-function on hardware that has vertex and pixel shaders. .
+ // This could cause a serious perf hit.
+ if( HardwareConfig()->SupportsVertexAndPixelShaders() )
+ {
+// Assert( !CurrentShadowState().m_UsingFixedFunction );
+ }
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Cause the board to match the default state snapshot
+//-----------------------------------------------------------------------------
+void CTransitionTable::UseDefaultState( )
+{
+ VPROF("CTransitionTable::UseDefaultState");
+ // Need to blat these out because they are tested during transitions
+ m_CurrentState.m_AlphaBlendEnable = false;
+ m_CurrentState.m_SrcBlend = D3DBLEND_ONE;
+ m_CurrentState.m_DestBlend = D3DBLEND_ZERO;
+ m_CurrentState.m_BlendOp = D3DBLENDOP_ADD;
+ SetRenderStateConstMacro( D3DRS_ALPHABLENDENABLE, m_CurrentState.m_AlphaBlendEnable );
+ SetRenderStateConstMacro( D3DRS_SRCBLEND, m_CurrentState.m_SrcBlend );
+ SetRenderStateConstMacro( D3DRS_DESTBLEND, m_CurrentState.m_DestBlend );
+ SetRenderStateConstMacro( D3DRS_BLENDOP, m_CurrentState.m_BlendOp );
+
+ m_CurrentState.m_SeparateAlphaBlendEnable = false;
+ m_CurrentState.m_SrcBlendAlpha = D3DBLEND_ONE;
+ m_CurrentState.m_DestBlendAlpha = D3DBLEND_ZERO;
+ m_CurrentState.m_BlendOpAlpha = D3DBLENDOP_ADD;
+ SetRenderStateConstMacro( D3DRS_SEPARATEALPHABLENDENABLE, m_CurrentState.m_SeparateAlphaBlendEnable );
+ SetRenderStateConstMacro( D3DRS_SRCBLENDALPHA, m_CurrentState.m_SrcBlendAlpha );
+ SetRenderStateConstMacro( D3DRS_DESTBLENDALPHA, m_CurrentState.m_DestBlendAlpha );
+ SetRenderStateConstMacro( D3DRS_BLENDOPALPHA, m_CurrentState.m_BlendOpAlpha );
+
+ m_CurrentState.m_ZEnable = D3DZB_TRUE;
+ m_CurrentState.m_ZFunc = D3DCMP_LESSEQUAL;
+ m_CurrentState.m_ZBias = SHADER_POLYOFFSET_DISABLE;
+ SetRenderStateConstMacro( D3DRS_ZENABLE, m_CurrentState.m_ZEnable );
+#if defined( _X360 )
+ //SetRenderStateConstMacro( D3DRS_HIZENABLE, m_CurrentState.m_ZEnable ? D3DHIZ_AUTOMATIC : D3DHIZ_DISABLE );
+#endif
+ SetRenderStateConstMacro( D3DRS_ZFUNC, m_CurrentState.m_ZFunc );
+
+ m_CurrentState.m_AlphaTestEnable = false;
+ m_CurrentState.m_AlphaFunc = D3DCMP_GREATEREQUAL;
+ m_CurrentState.m_AlphaRef = 0;
+ SetRenderStateConstMacro( D3DRS_ALPHATESTENABLE, m_CurrentState.m_AlphaTestEnable );
+ SetRenderStateConstMacro( D3DRS_ALPHAFUNC, m_CurrentState.m_AlphaFunc );
+ SetRenderStateConstMacro( D3DRS_ALPHAREF, m_CurrentState.m_AlphaRef );
+
+ int nTextureStages = ShaderAPI()->GetActualTextureStageCount();
+ for ( int i = 0; i < nTextureStages; ++i)
+ {
+ TextureStage(i).m_ColorOp = D3DTOP_DISABLE;
+ TextureStage(i).m_ColorArg1 = D3DTA_TEXTURE;
+ TextureStage(i).m_ColorArg2 = (i == 0) ? D3DTA_DIFFUSE : D3DTA_CURRENT;
+ TextureStage(i).m_AlphaOp = D3DTOP_DISABLE;
+ TextureStage(i).m_AlphaArg1 = D3DTA_TEXTURE;
+ TextureStage(i).m_AlphaArg2 = (i == 0) ? D3DTA_DIFFUSE : D3DTA_CURRENT;
+
+ SetTextureStageState( i, D3DTSS_COLOROP, TextureStage(i).m_ColorOp );
+ SetTextureStageState( i, D3DTSS_COLORARG1, TextureStage(i).m_ColorArg1 );
+ SetTextureStageState( i, D3DTSS_COLORARG2, TextureStage(i).m_ColorArg2 );
+ SetTextureStageState( i, D3DTSS_ALPHAOP, TextureStage(i).m_AlphaOp );
+ SetTextureStageState( i, D3DTSS_ALPHAARG1, TextureStage(i).m_AlphaArg1 );
+ SetTextureStageState( i, D3DTSS_ALPHAARG2, TextureStage(i).m_AlphaArg2 );
+ }
+
+ int nSamplerCount = ShaderAPI()->GetActualSamplerCount();
+ for ( int i = 0; i < nSamplerCount; ++i)
+ {
+ SetSamplerState( i, D3DSAMP_SRGBTEXTURE, SamplerState(i).m_SRGBReadEnable );
+
+ // Set default Fetch4 state on parts which support it
+ if ( ShaderAPI()->SupportsFetch4() )
+ {
+ SetSamplerState( i, ATISAMP_FETCH4, SamplerState(i).m_Fetch4Enable ? ATI_FETCH4_ENABLE : ATI_FETCH4_DISABLE );
+ }
+
+#ifdef DX_TO_GL_ABSTRACTION
+ SetSamplerState( i, D3DSAMP_SHADOWFILTER, SamplerState(i).m_ShadowFilterEnable );
+#endif
+ }
+
+ // Disable z overrides...
+ m_CurrentState.m_bOverrideDepthEnable = false;
+ m_CurrentState.m_bOverrideAlphaWriteEnable = false;
+ m_CurrentState.m_bOverrideColorWriteEnable = false;
+ m_CurrentState.m_ForceDepthFuncEquals = false;
+ m_CurrentState.m_bLinearColorSpaceFrameBufferEnable = false;
+ ApplyTransition( m_DefaultTransition, m_DefaultStateSnapshot );
+
+ ShaderManager()->SetVertexShader( INVALID_SHADER );
+ ShaderManager()->SetPixelShader( INVALID_SHADER );
+
+ m_CurrentSnapshotId = -1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Snapshotted state overrides
+//-----------------------------------------------------------------------------
+void CTransitionTable::ForceDepthFuncEquals( bool bEnable )
+{
+ if( bEnable != m_CurrentState.m_ForceDepthFuncEquals )
+ {
+ // Do this so that we can call this from within the rendering code
+ // See OverrideDepthEnable + PerformShadowStateOverrides for a version
+ // that isn't expected to be called from within rendering code
+ if( !ShaderAPI()->IsRenderingMesh() )
+ {
+ ShaderAPI()->FlushBufferedPrimitives();
+ }
+
+ m_CurrentState.m_ForceDepthFuncEquals = bEnable;
+
+ if( bEnable )
+ {
+ SetZFunc( D3DCMP_EQUAL );
+ }
+ else
+ {
+ if ( CurrentShadowState() )
+ {
+ SetZFunc( CurrentShadowState()->m_ZFunc );
+ }
+ }
+ }
+}
+
+void CTransitionTable::OverrideDepthEnable( bool bEnable, bool bDepthEnable )
+{
+ if ( bEnable != m_CurrentState.m_bOverrideDepthEnable )
+ {
+ ShaderAPI()->FlushBufferedPrimitives();
+ m_CurrentState.m_bOverrideDepthEnable = bEnable;
+ m_CurrentState.m_OverrideZWriteEnable = bDepthEnable ? D3DZB_TRUE : D3DZB_FALSE;
+
+ if ( m_CurrentState.m_bOverrideDepthEnable )
+ {
+ SetZEnable( D3DZB_TRUE );
+ SetRenderStateConstMacro( D3DRS_ZWRITEENABLE, m_CurrentState.m_OverrideZWriteEnable );
+#if defined( _X360 )
+ //SetRenderStateConstMacro( D3DRS_HIZWRITEENABLE, m_CurrentState.m_OverrideZWriteEnable ? D3DHIZ_AUTOMATIC : D3DHIZ_DISABLE );
+#endif
+ }
+ else
+ {
+ if ( CurrentShadowState() )
+ {
+ SetZEnable( CurrentShadowState()->m_ZEnable );
+ SetRenderStateConstMacro( D3DRS_ZWRITEENABLE, CurrentShadowState()->m_ZWriteEnable );
+#if defined( _X360 )
+ //SetRenderStateConstMacro( D3DRS_HIZWRITEENABLE, CurrentShadowState()->m_ZWriteEnable ? D3DHIZ_AUTOMATIC : D3DHIZ_DISABLE );
+#endif
+ }
+ }
+ }
+}
+
+void CTransitionTable::OverrideAlphaWriteEnable( bool bOverrideEnable, bool bAlphaWriteEnable )
+{
+ if ( bOverrideEnable != m_CurrentState.m_bOverrideAlphaWriteEnable )
+ {
+ ShaderAPI()->FlushBufferedPrimitives();
+ m_CurrentState.m_bOverrideAlphaWriteEnable = bOverrideEnable;
+ m_CurrentState.m_bOverriddenAlphaWriteValue = bAlphaWriteEnable;
+
+ DWORD dwSetValue = m_CurrentState.m_ColorWriteEnable;
+ if ( m_CurrentState.m_bOverrideAlphaWriteEnable )
+ {
+ if( m_CurrentState.m_bOverriddenAlphaWriteValue )
+ {
+ dwSetValue |= D3DCOLORWRITEENABLE_ALPHA;
+ }
+ else
+ {
+ dwSetValue &= ~D3DCOLORWRITEENABLE_ALPHA;
+ }
+ }
+ else
+ {
+ if ( CurrentShadowState() )
+ {
+ //probably being paranoid, but only copy the alpha flag from the shadow state
+ dwSetValue &= ~D3DCOLORWRITEENABLE_ALPHA;
+ dwSetValue |= CurrentShadowState()->m_ColorWriteEnable & D3DCOLORWRITEENABLE_ALPHA;
+ }
+ }
+
+ if( dwSetValue != m_CurrentState.m_ColorWriteEnable )
+ {
+ m_CurrentState.m_ColorWriteEnable = dwSetValue;
+ SetRenderState( D3DRS_COLORWRITEENABLE, m_CurrentState.m_ColorWriteEnable );
+ }
+ }
+}
+
+void CTransitionTable::OverrideColorWriteEnable( bool bOverrideEnable, bool bColorWriteEnable )
+{
+ if ( bOverrideEnable != m_CurrentState.m_bOverrideColorWriteEnable )
+ {
+ ShaderAPI()->FlushBufferedPrimitives();
+ m_CurrentState.m_bOverrideColorWriteEnable = bOverrideEnable;
+ m_CurrentState.m_bOverriddenColorWriteValue = bColorWriteEnable;
+
+ DWORD dwSetValue = m_CurrentState.m_ColorWriteEnable;
+ if ( m_CurrentState.m_bOverrideColorWriteEnable )
+ {
+ if( m_CurrentState.m_bOverriddenColorWriteValue )
+ {
+ dwSetValue |= (D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE);
+ }
+ else
+ {
+ dwSetValue &= ~(D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE);
+ }
+ }
+ else
+ {
+ if ( CurrentShadowState() )
+ {
+ //probably being paranoid, but only copy the alpha flag from the shadow state
+ dwSetValue &= ~(D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE);
+ dwSetValue |= CurrentShadowState()->m_ColorWriteEnable & (D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE);
+ }
+ }
+
+ if( dwSetValue != m_CurrentState.m_ColorWriteEnable )
+ {
+ m_CurrentState.m_ColorWriteEnable = dwSetValue;
+ SetRenderState( D3DRS_COLORWRITEENABLE, m_CurrentState.m_ColorWriteEnable );
+ }
+ }
+}
+
+void CTransitionTable::EnableLinearColorSpaceFrameBuffer( bool bEnable )
+{
+ if ( m_CurrentState.m_bLinearColorSpaceFrameBufferEnable != bEnable && CurrentShadowState() )
+ {
+ ShaderAPI()->FlushBufferedPrimitives();
+ m_CurrentState.m_bLinearColorSpaceFrameBufferEnable = bEnable;
+ ApplySRGBWriteEnable( *CurrentShadowState() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Perform state block overrides
+//-----------------------------------------------------------------------------
+void CTransitionTable::PerformShadowStateOverrides( )
+{
+ VPROF("CTransitionTable::PerformShadowStateOverrides");
+ // Deal with funky overrides here, because the state blocks can't...
+ if ( m_CurrentState.m_ForceDepthFuncEquals )
+ {
+ SetZFunc( D3DCMP_EQUAL );
+ }
+
+ if ( m_CurrentState.m_bOverrideDepthEnable )
+ {
+ SetZEnable( D3DZB_TRUE );
+ SetRenderStateConstMacro( D3DRS_ZWRITEENABLE, m_CurrentState.m_OverrideZWriteEnable );
+#if defined( _X360 )
+ //SetRenderStateConstMacro( D3DRS_HIZWRITEENABLE, m_CurrentState.m_OverrideZWriteEnable ? D3DHIZ_AUTOMATIC : D3DHIZ_DISABLE );
+#endif
+ }
+
+ if ( m_CurrentState.m_bOverrideAlphaWriteEnable )
+ {
+ DWORD dwSetValue = m_CurrentState.m_ColorWriteEnable & ~D3DCOLORWRITEENABLE_ALPHA;
+ dwSetValue |= m_CurrentState.m_bOverriddenAlphaWriteValue ? D3DCOLORWRITEENABLE_ALPHA : 0;
+ if ( dwSetValue != m_CurrentState.m_ColorWriteEnable )
+ {
+ m_CurrentState.m_ColorWriteEnable = dwSetValue;
+ SetRenderState( D3DRS_COLORWRITEENABLE, m_CurrentState.m_ColorWriteEnable );
+ }
+ }
+
+ if ( m_CurrentState.m_bOverrideColorWriteEnable )
+ {
+ DWORD dwSetValue = m_CurrentState.m_ColorWriteEnable & ~(D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE);
+ dwSetValue |= m_CurrentState.m_bOverriddenColorWriteValue ? (D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE) : 0;
+ if ( dwSetValue != m_CurrentState.m_ColorWriteEnable )
+ {
+ m_CurrentState.m_ColorWriteEnable = dwSetValue;
+ SetRenderState( D3DRS_COLORWRITEENABLE, m_CurrentState.m_ColorWriteEnable );
+ }
+ }
+}
diff --git a/materialsystem/shaderapidx9/TransitionTable.h b/materialsystem/shaderapidx9/TransitionTable.h
new file mode 100644
index 0000000..730943b
--- /dev/null
+++ b/materialsystem/shaderapidx9/TransitionTable.h
@@ -0,0 +1,407 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#ifndef TRANSITION_TABLE_H
+#define TRANSITION_TABLE_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "utlvector.h"
+#include "shadershadowdx8.h"
+#include "UtlSortVector.h"
+#include "checksum_crc.h"
+#include "shaderapi/ishaderapi.h"
+
+// Required for DEBUG_BOARD_STATE
+#include "shaderapidx8_global.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+struct IDirect3DStateBlock9;
+//-----------------------------------------------------------------------------
+// Enumeration for ApplyStateFunc_ts
+//-----------------------------------------------------------------------------
+// Any function that does not require a texture stage
+// NOTE: If you change this, change the function table s_pRenderFunctionTable[] below!!
+enum RenderStateFunc_t
+{
+ RENDER_STATE_DepthTest = 0,
+ RENDER_STATE_ZWriteEnable,
+ RENDER_STATE_ColorWriteEnable,
+ RENDER_STATE_AlphaTest,
+ RENDER_STATE_FillMode,
+ RENDER_STATE_Lighting,
+ RENDER_STATE_SpecularEnable,
+ RENDER_STATE_SRGBWriteEnable,
+ RENDER_STATE_AlphaBlend,
+ RENDER_STATE_SeparateAlphaBlend,
+ RENDER_STATE_CullEnable,
+ RENDER_STATE_VertexBlendEnable,
+ RENDER_STATE_FogMode,
+ RENDER_STATE_ActivateFixedFunction,
+ RENDER_STATE_TextureEnable,
+ RENDER_STATE_DiffuseMaterialSource,
+ RENDER_STATE_DisableFogGammaCorrection,
+ RENDER_STATE_EnableAlphaToCoverage,
+
+ RENDER_STATE_COUNT,
+};
+
+
+// Any function that requires a texture stage
+// NOTE: If you change this, change the function table s_pTextureFunctionTable[] below!!
+enum TextureStateFunc_t
+{
+ TEXTURE_STATE_TexCoordIndex = 0,
+ TEXTURE_STATE_SRGBReadEnable,
+ TEXTURE_STATE_Fetch4Enable,
+#ifdef DX_TO_GL_ABSTRACTION
+ TEXTURE_STATE_ShadowFilterEnable,
+#endif
+ // Fixed function states
+ TEXTURE_STATE_ColorTextureStage,
+ TEXTURE_STATE_AlphaTextureStage,
+ TEXTURE_STATE_COUNT
+};
+
+
+//-----------------------------------------------------------------------------
+// Types related to transition table entries
+//-----------------------------------------------------------------------------
+typedef void (*ApplyStateFunc_t)( const ShadowState_t& shadowState, int arg );
+
+
+//-----------------------------------------------------------------------------
+// The DX8 implementation of the transition table
+//-----------------------------------------------------------------------------
+class CTransitionTable
+{
+public:
+ struct CurrentTextureStageState_t
+ {
+ D3DTEXTUREOP m_ColorOp;
+ int m_ColorArg1;
+ int m_ColorArg2;
+ D3DTEXTUREOP m_AlphaOp;
+ int m_AlphaArg1;
+ int m_AlphaArg2;
+ };
+ struct CurrentSamplerState_t
+ {
+ bool m_SRGBReadEnable;
+ bool m_Fetch4Enable;
+ bool m_ShadowFilterEnable;
+ };
+ struct CurrentState_t
+ {
+ // Everything in this 'CurrentState' structure is a state whose value we don't care about
+ // under certain circumstances, (which therefore can diverge from the shadow state),
+ // or states which we override in the dynamic pass.
+
+ // Alpha state
+ bool m_AlphaBlendEnable;
+ D3DBLEND m_SrcBlend;
+ D3DBLEND m_DestBlend;
+ D3DBLENDOP m_BlendOp;
+
+ // GR - Separate alpha state
+ bool m_SeparateAlphaBlendEnable;
+ D3DBLEND m_SrcBlendAlpha;
+ D3DBLEND m_DestBlendAlpha;
+ D3DBLENDOP m_BlendOpAlpha;
+
+ // Depth testing states
+ D3DZBUFFERTYPE m_ZEnable;
+ D3DCMPFUNC m_ZFunc;
+ PolygonOffsetMode_t m_ZBias;
+
+ // Alpha testing states
+ bool m_AlphaTestEnable;
+ D3DCMPFUNC m_AlphaFunc;
+ int m_AlphaRef;
+
+ bool m_ForceDepthFuncEquals;
+ bool m_bOverrideDepthEnable;
+ D3DZBUFFERTYPE m_OverrideZWriteEnable;
+
+ bool m_bOverrideAlphaWriteEnable;
+ bool m_bOverriddenAlphaWriteValue;
+ bool m_bOverrideColorWriteEnable;
+ bool m_bOverriddenColorWriteValue;
+ DWORD m_ColorWriteEnable;
+
+ bool m_bLinearColorSpaceFrameBufferEnable;
+
+ bool m_StencilEnable;
+ D3DCMPFUNC m_StencilFunc;
+ int m_StencilRef;
+ int m_StencilMask;
+ DWORD m_StencilFail;
+ DWORD m_StencilZFail;
+ DWORD m_StencilPass;
+ int m_StencilWriteMask;
+
+ // Texture stage state
+ CurrentTextureStageState_t m_TextureStage[MAX_TEXTURE_STAGES];
+ CurrentSamplerState_t m_SamplerState[MAX_SAMPLERS];
+ };
+
+public:
+ // constructor, destructor
+ CTransitionTable( );
+ virtual ~CTransitionTable();
+
+ // Initialization, shutdown
+ bool Init( );
+ void Shutdown( );
+
+ // Resets the snapshots...
+ void Reset();
+
+ // Takes a snapshot
+ StateSnapshot_t TakeSnapshot( );
+
+ // Take startup snapshot
+ void TakeDefaultStateSnapshot( );
+
+ // Makes the board state match the snapshot
+ void UseSnapshot( StateSnapshot_t snapshotId );
+
+ // Cause the board to match the default state snapshot
+ void UseDefaultState();
+
+ // Snapshotted state overrides
+ void ForceDepthFuncEquals( bool bEnable );
+ void OverrideDepthEnable( bool bEnable, bool bDepthEnable );
+ void OverrideAlphaWriteEnable( bool bOverrideEnable, bool bAlphaWriteEnable );
+ void OverrideColorWriteEnable( bool bOverrideEnable, bool bColorWriteEnable );
+ void EnableLinearColorSpaceFrameBuffer( bool bEnable );
+
+ // Returns a particular snapshot
+ const ShadowState_t &GetSnapshot( StateSnapshot_t snapshotId ) const;
+ const ShadowShaderState_t &GetSnapshotShader( StateSnapshot_t snapshotId ) const;
+
+ // Gets the current shadow state
+ const ShadowState_t *CurrentShadowState() const;
+ const ShadowShaderState_t *CurrentShadowShaderState() const;
+
+ // Return the current shapshot
+ int CurrentSnapshot() const { return m_CurrentSnapshotId; }
+
+ CurrentState_t& CurrentState() { return m_CurrentState; }
+
+#ifdef DEBUG_BOARD_STATE
+ ShadowState_t& BoardState() { return m_BoardState; }
+ ShadowShaderState_t& BoardShaderState() { return m_BoardShaderState; }
+#endif
+
+ // The following are meant to be used by the transition table only
+public:
+ // Applies alpha blending
+ void ApplyAlphaBlend( const ShadowState_t& state );
+ // GR - separate alpha blend
+ void ApplySeparateAlphaBlend( const ShadowState_t& state );
+ void ApplyAlphaTest( const ShadowState_t& state );
+ void ApplyDepthTest( const ShadowState_t& state );
+
+ // Applies alpha texture op
+ void ApplyColorTextureStage( const ShadowState_t& state, int stage );
+ void ApplyAlphaTextureStage( const ShadowState_t& state, int stage );
+
+ void ApplySRGBWriteEnable( const ShadowState_t& state );
+private:
+ enum
+ {
+ INVALID_TRANSITION_OP = 0xFFFFFF
+ };
+
+ typedef short ShadowStateId_t;
+
+ // For the transition table
+ struct TransitionList_t
+ {
+ unsigned int m_FirstOperation : 24;
+ unsigned int m_NumOperations : 8;
+ };
+
+ union TransitionOp_t
+ {
+ unsigned char m_nBits;
+ struct
+ {
+ unsigned char m_nOpCode : 7;
+ unsigned char m_bIsTextureCode : 1;
+ } m_nInfo;
+ };
+
+ struct SnapshotShaderState_t
+ {
+ ShadowShaderState_t m_ShaderState;
+ ShadowStateId_t m_ShadowStateId;
+ unsigned short m_nReserved; // Pad to 2 ints
+ unsigned int m_nReserved2;
+ };
+
+ struct ShadowStateDictEntry_t
+ {
+ CRC32_t m_nChecksum;
+ ShadowStateId_t m_nShadowStateId;
+ };
+
+ struct SnapshotDictEntry_t
+ {
+ CRC32_t m_nChecksum;
+ StateSnapshot_t m_nSnapshot;
+ };
+
+ class ShadowStateDictLessFunc
+ {
+ public:
+ bool Less( const ShadowStateDictEntry_t &src1, const ShadowStateDictEntry_t &src2, void *pCtx );
+ };
+
+ class SnapshotDictLessFunc
+ {
+ public:
+ bool Less( const SnapshotDictEntry_t &src1, const SnapshotDictEntry_t &src2, void *pCtx );
+ };
+
+ class UniqueSnapshotLessFunc
+ {
+ public:
+ bool Less( const TransitionList_t &src1, const TransitionList_t &src2, void *pCtx );
+ };
+
+ CurrentTextureStageState_t &TextureStage( int stage ) { return m_CurrentState.m_TextureStage[stage]; }
+ const CurrentTextureStageState_t &TextureStage( int stage ) const { return m_CurrentState.m_TextureStage[stage]; }
+
+ CurrentSamplerState_t &SamplerState( int stage ) { return m_CurrentState.m_SamplerState[stage]; }
+ const CurrentSamplerState_t &SamplerState( int stage ) const { return m_CurrentState.m_SamplerState[stage]; }
+
+ // creates state snapshots
+ ShadowStateId_t CreateShadowState( const ShadowState_t &currentState );
+ StateSnapshot_t CreateStateSnapshot( ShadowStateId_t shadowStateId, const ShadowShaderState_t& currentShaderState );
+
+ // finds state snapshots
+ ShadowStateId_t FindShadowState( const ShadowState_t& currentState ) const;
+ StateSnapshot_t FindStateSnapshot( ShadowStateId_t id, const ShadowShaderState_t& currentState ) const;
+
+ // Finds identical transition lists
+ unsigned int FindIdenticalTransitionList( unsigned int firstElem,
+ unsigned short numOps, unsigned int nFirstTest ) const;
+
+ // Adds a transition
+ void AddTransition( RenderStateFunc_t func );
+ void AddTextureTransition( TextureStateFunc_t func, int stage );
+
+ // Apply a transition
+ void ApplyTransition( TransitionList_t& list, int snapshot );
+
+ // Creates an entry in the transition table
+ void CreateTransitionTableEntry( int to, int from );
+
+ // Checks if a state is valid
+ bool TestShadowState( const ShadowState_t& state, const ShadowShaderState_t &shaderState );
+
+ // Perform state block overrides
+ void PerformShadowStateOverrides( );
+
+ // Applies the transition list
+ void ApplyTransitionList( int snapshot, int nFirstOp, int nOpCount );
+
+ // Apply shader state (stuff that doesn't lie in the transition table)
+ void ApplyShaderState( const ShadowState_t &shadowState, const ShadowShaderState_t &shaderState );
+
+ // Wrapper for the non-standard transitions for stateblock + non-stateblock cases
+ int CreateNormalTransitions( const ShadowState_t& fromState, const ShadowState_t& toState, bool bForce );
+
+ // State setting methods
+ void SetZEnable( D3DZBUFFERTYPE nEnable );
+ void SetZFunc( D3DCMPFUNC nCmpFunc );
+
+private:
+ // Sets up the default state
+ StateSnapshot_t m_DefaultStateSnapshot;
+ TransitionList_t m_DefaultTransition;
+ ShadowState_t m_DefaultShadowState;
+
+ // The current snapshot id
+ ShadowStateId_t m_CurrentShadowId;
+ StateSnapshot_t m_CurrentSnapshotId;
+
+ // Maintains a list of all used snapshot transition states
+ CUtlVector< ShadowState_t > m_ShadowStateList;
+
+ // Lookup table for fast snapshot finding
+ CUtlSortVector< ShadowStateDictEntry_t, ShadowStateDictLessFunc > m_ShadowStateDict;
+
+ // The snapshot transition table
+ CUtlVector< CUtlVector< TransitionList_t > > m_TransitionTable;
+
+ // List of unique transitions
+ CUtlSortVector< TransitionList_t, UniqueSnapshotLessFunc > m_UniqueTransitions;
+
+ // Stores all state transition operations
+ CUtlVector< TransitionOp_t > m_TransitionOps;
+
+ // Stores all state for a particular snapshot
+ CUtlVector< SnapshotShaderState_t > m_SnapshotList;
+
+ // Lookup table for fast snapshot finding
+ CUtlSortVector< SnapshotDictEntry_t, SnapshotDictLessFunc > m_SnapshotDict;
+
+ // The current board state.
+ CurrentState_t m_CurrentState;
+
+#ifdef DEBUG_BOARD_STATE
+ // Maintains the total shadow state
+ ShadowState_t m_BoardState;
+ ShadowShaderState_t m_BoardShaderState;
+#endif
+};
+
+
+//-----------------------------------------------------------------------------
+// Inline methods
+//-----------------------------------------------------------------------------
+inline const ShadowState_t &CTransitionTable::GetSnapshot( StateSnapshot_t snapshotId ) const
+{
+ Assert( (snapshotId >= 0) && (snapshotId < m_SnapshotList.Count()) );
+ return m_ShadowStateList[m_SnapshotList[snapshotId].m_ShadowStateId];
+}
+
+inline const ShadowShaderState_t &CTransitionTable::GetSnapshotShader( StateSnapshot_t snapshotId ) const
+{
+ Assert( (snapshotId >= 0) && (snapshotId < m_SnapshotList.Count()) );
+ return m_SnapshotList[snapshotId].m_ShaderState;
+}
+
+inline const ShadowState_t *CTransitionTable::CurrentShadowState() const
+{
+ if ( m_CurrentShadowId == -1 )
+ return NULL;
+
+ Assert( (m_CurrentShadowId >= 0) && (m_CurrentShadowId < m_ShadowStateList.Count()) );
+ return &m_ShadowStateList[m_CurrentShadowId];
+}
+
+inline const ShadowShaderState_t *CTransitionTable::CurrentShadowShaderState() const
+{
+ if ( m_CurrentShadowId == -1 )
+ return NULL;
+
+ Assert( (m_CurrentShadowId >= 0) && (m_CurrentShadowId < m_ShadowStateList.Count()) );
+ return &m_SnapshotList[m_CurrentShadowId].m_ShaderState;
+}
+
+
+#endif // TRANSITION_TABLE_H
diff --git a/materialsystem/shaderapidx9/colorformatdx8.cpp b/materialsystem/shaderapidx9/colorformatdx8.cpp
new file mode 100644
index 0000000..daf3e50
--- /dev/null
+++ b/materialsystem/shaderapidx9/colorformatdx8.cpp
@@ -0,0 +1,727 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#define DISABLE_PROTECTED_THINGS
+#include "togl/rendermechanism.h"
+#include "locald3dtypes.h"
+#include "colorformatdx8.h"
+#include "shaderapidx8_global.h"
+#include "bitmap/imageformat.h"
+#include "shaderapi/ishaderutil.h"
+#include "tier0/dbg.h"
+#include "tier1/strtools.h"
+#include "shaderdevicedx8.h"
+
+
+// Must be last
+#include "tier0/memdbgon.h"
+
+
+//-----------------------------------------------------------------------------
+// Figures out what texture formats we support
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// globals
+//-----------------------------------------------------------------------------
+
+// Texture formats supported by DX driver[vertextexture][render target][non filterable]
+static D3DFORMAT g_D3DColorFormat[NUM_IMAGE_FORMATS][2][2][2];
+static UINT g_DisplayAdapter;
+static D3DDEVTYPE g_DeviceType;
+static ImageFormat g_DeviceFormat;
+static bool g_bSupportsD24S8;
+static bool g_bSupportsD24X8;
+static bool g_bSupportsD16;
+static bool g_bSupportsD24X4S4;
+static bool g_bSupportsD15S1;
+
+//-----------------------------------------------------------------------------
+// Determines what formats we actually *do* support
+//-----------------------------------------------------------------------------
+static bool TestTextureFormat( D3DFORMAT format, bool bIsRenderTarget,
+ bool bIsVertexTexture, bool bIsFilterableRequired )
+{
+ int nUsage = bIsRenderTarget ? D3DUSAGE_RENDERTARGET : 0;
+ if ( bIsVertexTexture )
+ {
+ // vertex textures never need filtering
+ nUsage |= D3DUSAGE_QUERY_VERTEXTEXTURE;
+ }
+ if ( bIsFilterableRequired )
+ {
+ nUsage |= D3DUSAGE_QUERY_FILTER;
+ }
+
+ HRESULT hr;
+
+ // IHV depth texture formats require a slightly different check...
+ if ( !IsX360() && bIsRenderTarget && ( ( format == NVFMT_RAWZ ) || ( format == NVFMT_INTZ ) ||
+ ( format == D3DFMT_D16 ) || ( format == D3DFMT_D24S8 ) ||
+ ( format == ATIFMT_D16 ) || ( format == ATIFMT_D24S8 ) ) )
+ {
+ hr = D3D()->CheckDeviceFormat(
+ g_DisplayAdapter, g_DeviceType, ImageLoader::ImageFormatToD3DFormat( g_DeviceFormat ),
+ D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, format );
+ }
+ else if ( !IsX360() || !bIsRenderTarget )
+ {
+ // See if we can do it!
+ hr = D3D()->CheckDeviceFormat(
+ g_DisplayAdapter, g_DeviceType, ImageLoader::ImageFormatToD3DFormat( g_DeviceFormat ),
+ nUsage, D3DRTYPE_TEXTURE, format );
+ }
+ else // 360
+ {
+ // 360 can only validate render targets as surface display format
+ hr = D3D()->CheckDeviceFormat( g_DisplayAdapter, g_DeviceType, format, 0, D3DRTYPE_SURFACE, format );
+ }
+
+ return SUCCEEDED( hr );
+}
+
+D3DFORMAT GetNearestD3DColorFormat( ImageFormat fmt,
+ bool isRenderTarget, bool bIsVertexTexture,
+ bool bIsFilterableRequired)
+{
+ switch(fmt)
+ {
+ case IMAGE_FORMAT_RGBA8888:
+ case IMAGE_FORMAT_ABGR8888:
+ case IMAGE_FORMAT_ARGB8888:
+ case IMAGE_FORMAT_BGRA8888:
+ if (TestTextureFormat(D3DFMT_A8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_A8R8G8B8;
+ if (TestTextureFormat(D3DFMT_A4R4G4B4, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_A4R4G4B4;
+ break;
+
+#if defined( _X360 )
+ case IMAGE_FORMAT_LINEAR_RGBA8888:
+ case IMAGE_FORMAT_LINEAR_ABGR8888:
+ case IMAGE_FORMAT_LINEAR_ARGB8888:
+ case IMAGE_FORMAT_LINEAR_BGRA8888:
+ // same as above - all xxxx8888 RGBA ordering funnels to d3d a8r8g8b8
+ if ( TestTextureFormat( D3DFMT_LIN_A8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
+ return D3DFMT_LIN_A8R8G8B8;
+ break;
+#endif
+
+#if defined( _X360 )
+ case IMAGE_FORMAT_LINEAR_BGRX8888:
+ if ( TestTextureFormat( D3DFMT_LIN_X8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
+ return D3DFMT_LIN_X8R8G8B8;
+ break;
+#endif
+
+ case IMAGE_FORMAT_BGRX8888:
+ // We want this format to return exactly it's equivalent so that
+ // when we create render targets to blit to from the framebuffer,
+ // the CopyRect won't fail due to format mismatches.
+ if (TestTextureFormat(D3DFMT_X8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_X8R8G8B8;
+
+ // fall through. . . .
+ case IMAGE_FORMAT_RGB888:
+ case IMAGE_FORMAT_BGR888:
+#if !defined( _X360 )
+ if (TestTextureFormat(D3DFMT_R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_R8G8B8;
+#endif
+ if (TestTextureFormat(D3DFMT_X8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_X8R8G8B8;
+ if (TestTextureFormat(D3DFMT_A8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_A8R8G8B8;
+ if (TestTextureFormat(D3DFMT_R5G6B5, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_R5G6B5;
+ if (TestTextureFormat(D3DFMT_X1R5G5B5, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_X1R5G5B5;
+ if (TestTextureFormat(D3DFMT_A1R5G5B5, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_A1R5G5B5;
+ break;
+
+ case IMAGE_FORMAT_BGR565:
+ case IMAGE_FORMAT_RGB565:
+ if (TestTextureFormat(D3DFMT_R5G6B5, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_R5G6B5;
+ if (TestTextureFormat(D3DFMT_X1R5G5B5, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_X1R5G5B5;
+ if (TestTextureFormat(D3DFMT_A1R5G5B5, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_A1R5G5B5;
+#if !defined( _X360 )
+ if (TestTextureFormat(D3DFMT_R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_R8G8B8;
+#endif
+ if (TestTextureFormat(D3DFMT_X8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_X8R8G8B8;
+ if (TestTextureFormat(D3DFMT_A8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_A8R8G8B8;
+ break;
+
+ case IMAGE_FORMAT_BGRX5551:
+ if (TestTextureFormat(D3DFMT_X1R5G5B5, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_X1R5G5B5;
+ if (TestTextureFormat(D3DFMT_A1R5G5B5, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_A1R5G5B5;
+ if (TestTextureFormat(D3DFMT_R5G6B5, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_R5G6B5;
+#if !defined( _X360 )
+ if (TestTextureFormat(D3DFMT_R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_R8G8B8;
+#endif
+ if (TestTextureFormat(D3DFMT_X8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_X8R8G8B8;
+ if (TestTextureFormat(D3DFMT_A8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_A8R8G8B8;
+ break;
+
+#if defined( _X360 )
+ case IMAGE_FORMAT_LINEAR_BGRX5551:
+ if ( TestTextureFormat( D3DFMT_LIN_X1R5G5B5, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
+ return D3DFMT_LIN_X1R5G5B5;
+ break;
+#endif
+
+ case IMAGE_FORMAT_BGRA5551:
+ if (TestTextureFormat(D3DFMT_A1R5G5B5, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_A1R5G5B5;
+ if (TestTextureFormat(D3DFMT_A4R4G4B4, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_A4R4G4B4;
+ if (TestTextureFormat(D3DFMT_A8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_A8R8G8B8;
+ break;
+
+ case IMAGE_FORMAT_BGRA4444:
+ if (TestTextureFormat(D3DFMT_A4R4G4B4, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_A4R4G4B4;
+ if (TestTextureFormat(D3DFMT_A8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_A8R8G8B8;
+ break;
+
+ case IMAGE_FORMAT_I8:
+ if (TestTextureFormat(D3DFMT_L8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_L8;
+ if (TestTextureFormat(D3DFMT_A8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_A8R8G8B8;
+ break;
+
+#if defined( _X360 )
+ case IMAGE_FORMAT_LINEAR_I8:
+ if ( TestTextureFormat( D3DFMT_LIN_L8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
+ return D3DFMT_LIN_L8;
+ break;
+#endif
+
+ case IMAGE_FORMAT_IA88:
+ if (TestTextureFormat(D3DFMT_A8L8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_A8L8;
+ if (TestTextureFormat(D3DFMT_A8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_A8R8G8B8;
+ break;
+
+ case IMAGE_FORMAT_A8:
+ if (TestTextureFormat(D3DFMT_A8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_A8;
+ if (TestTextureFormat(D3DFMT_A8R8G8B8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_A8R8G8B8;
+ break;
+
+ case IMAGE_FORMAT_DXT1:
+ case IMAGE_FORMAT_DXT1_ONEBITALPHA:
+ case IMAGE_FORMAT_DXT1_RUNTIME:
+ if (TestTextureFormat(D3DFMT_DXT1, isRenderTarget, bIsVertexTexture, bIsFilterableRequired))
+ return D3DFMT_DXT1;
+ break;
+
+ case IMAGE_FORMAT_DXT3:
+ if (TestTextureFormat(D3DFMT_DXT3, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ))
+ return D3DFMT_DXT3;
+ break;
+
+ case IMAGE_FORMAT_DXT5:
+ case IMAGE_FORMAT_DXT5_RUNTIME:
+ if (TestTextureFormat(D3DFMT_DXT5, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ))
+ return D3DFMT_DXT5;
+ break;
+
+ case IMAGE_FORMAT_UV88:
+ if (TestTextureFormat(D3DFMT_V8U8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ))
+ return D3DFMT_V8U8;
+ break;
+
+ case IMAGE_FORMAT_UVWQ8888:
+ if (TestTextureFormat(D3DFMT_Q8W8V8U8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ))
+ return D3DFMT_Q8W8V8U8;
+ break;
+
+ case IMAGE_FORMAT_UVLX8888:
+ if (TestTextureFormat(D3DFMT_X8L8V8U8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ))
+ return D3DFMT_X8L8V8U8;
+ break;
+
+ case IMAGE_FORMAT_RGBA16161616F:
+ if ( TestTextureFormat( D3DFMT_A16B16G16R16F, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
+ return D3DFMT_A16B16G16R16F;
+ if ( TestTextureFormat( D3DFMT_A16B16G16R16, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
+ return D3DFMT_A16B16G16R16;
+ break;
+
+ case IMAGE_FORMAT_RGBA16161616:
+ if ( TestTextureFormat( D3DFMT_A16B16G16R16, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
+ return D3DFMT_A16B16G16R16;
+ if ( TestTextureFormat( D3DFMT_A16B16G16R16F, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
+ return D3DFMT_A16B16G16R16F;
+ break;
+
+#if defined( _X360 )
+ case IMAGE_FORMAT_LINEAR_RGBA16161616:
+ if ( TestTextureFormat( D3DFMT_LIN_A16B16G16R16, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
+ return D3DFMT_LIN_A16B16G16R16;
+ break;
+#endif
+
+ case IMAGE_FORMAT_R32F:
+ if ( TestTextureFormat( D3DFMT_R32F, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
+ return D3DFMT_R32F;
+ break;
+
+ case IMAGE_FORMAT_RGBA32323232F:
+ if ( TestTextureFormat( D3DFMT_A32B32G32R32F, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
+ return D3DFMT_A32B32G32R32F;
+ break;
+
+#if defined( _X360 )
+ case IMAGE_FORMAT_X360_DST16:
+ return D3DFMT_D16;
+
+ case IMAGE_FORMAT_X360_DST24:
+ return D3DFMT_D24S8;
+
+ case IMAGE_FORMAT_X360_DST24F:
+ return D3DFMT_D24FS8;
+
+ case IMAGE_FORMAT_LE_BGRX8888:
+ return D3DFMT_LE_X8R8G8B8;
+
+ case IMAGE_FORMAT_LE_BGRA8888:
+ return D3DFMT_LE_A8R8G8B8;
+#endif
+
+ // nVidia overloads DST formats as texture formats
+ case IMAGE_FORMAT_NV_DST16:
+ if ( TestTextureFormat( D3DFMT_D16, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
+ return D3DFMT_D16;
+ break;
+
+ case IMAGE_FORMAT_NV_DST24:
+ if ( TestTextureFormat( D3DFMT_D24S8, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
+ return D3DFMT_D24S8;
+ break;
+ case IMAGE_FORMAT_NV_INTZ:
+ if ( TestTextureFormat( NVFMT_INTZ, isRenderTarget, bIsVertexTexture, false ) )
+ return NVFMT_INTZ;
+ break;
+
+ case IMAGE_FORMAT_NV_RAWZ:
+ if ( TestTextureFormat( NVFMT_RAWZ, isRenderTarget, bIsVertexTexture, false ) )
+ return NVFMT_RAWZ;
+ break;
+
+ case IMAGE_FORMAT_NV_NULL:
+ if ( TestTextureFormat( NVFMT_NULL, isRenderTarget, bIsVertexTexture, false ) )
+ return NVFMT_NULL;
+ break;
+
+ case IMAGE_FORMAT_ATI_DST16:
+ if ( TestTextureFormat( ATIFMT_D16, isRenderTarget, bIsVertexTexture, false ) )
+ return ATIFMT_D16;
+ break;
+
+ case IMAGE_FORMAT_ATI_DST24:
+ if ( TestTextureFormat( ATIFMT_D24S8, isRenderTarget, bIsVertexTexture, false ) )
+ return ATIFMT_D24S8;
+ break;
+
+ case IMAGE_FORMAT_ATI2N:
+ if ( TestTextureFormat( ATIFMT_ATI2N, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
+ return ATIFMT_ATI2N;
+ break;
+
+ case IMAGE_FORMAT_ATI1N:
+ if ( TestTextureFormat( ATIFMT_ATI1N, isRenderTarget, bIsVertexTexture, bIsFilterableRequired ) )
+ return ATIFMT_ATI1N;
+ break;
+ }
+
+ return D3DFMT_UNKNOWN;
+}
+
+void InitializeColorInformation( UINT displayAdapter, D3DDEVTYPE deviceType,
+ ImageFormat displayFormat )
+{
+ g_DisplayAdapter = displayAdapter;
+ g_DeviceType = deviceType;
+ g_DeviceFormat = displayFormat;
+
+ int fmt = 0;
+ while ( fmt < NUM_IMAGE_FORMATS )
+ {
+ for ( int nVertexTexture = 0; nVertexTexture <= 1; ++nVertexTexture )
+ {
+ for ( int nRenderTarget = 0; nRenderTarget <= 1; ++nRenderTarget )
+ {
+ for ( int nFilterable = 0; nFilterable <= 1; ++nFilterable )
+ {
+ g_D3DColorFormat[fmt][nVertexTexture][nRenderTarget][nFilterable] =
+ GetNearestD3DColorFormat( (ImageFormat)fmt, nRenderTarget != 0, nVertexTexture != 0, nFilterable != 0 );
+ }
+ }
+ }
+ ++fmt;
+ }
+
+ // Check the depth formats
+ HRESULT hr = D3D()->CheckDeviceFormat(
+ g_DisplayAdapter, g_DeviceType, ImageLoader::ImageFormatToD3DFormat( g_DeviceFormat ),
+ D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24S8 );
+ g_bSupportsD24S8 = !FAILED(hr);
+
+ hr = D3D()->CheckDeviceFormat(
+ g_DisplayAdapter, g_DeviceType, ImageLoader::ImageFormatToD3DFormat( g_DeviceFormat ),
+ D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24X8 );
+ g_bSupportsD24X8 = !FAILED(hr);
+
+ hr = D3D()->CheckDeviceFormat(
+ g_DisplayAdapter, g_DeviceType, ImageLoader::ImageFormatToD3DFormat( g_DeviceFormat ),
+ D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D16 );
+ g_bSupportsD16 = !FAILED(hr);
+
+#if !defined( _X360 )
+ hr = D3D()->CheckDeviceFormat(
+ g_DisplayAdapter, g_DeviceType, ImageLoader::ImageFormatToD3DFormat( g_DeviceFormat ),
+ D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24X4S4 );
+ g_bSupportsD24X4S4 = !FAILED(hr);
+#else
+ g_bSupportsD24X4S4 = false;
+#endif
+
+#if !defined( _X360 )
+ hr = D3D()->CheckDeviceFormat(
+ g_DisplayAdapter, g_DeviceType, ImageLoader::ImageFormatToD3DFormat( g_DeviceFormat ),
+ D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D15S1 );
+ g_bSupportsD15S1 = !FAILED(hr);
+#else
+ g_bSupportsD15S1 = false;
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns true if compressed textures are supported
+//-----------------------------------------------------------------------------
+bool D3DSupportsCompressedTextures()
+{
+ return (g_D3DColorFormat[IMAGE_FORMAT_DXT1][0][0][0] != D3DFMT_UNKNOWN) &&
+ (g_D3DColorFormat[IMAGE_FORMAT_DXT3][0][0][0] != D3DFMT_UNKNOWN) &&
+ (g_D3DColorFormat[IMAGE_FORMAT_DXT5][0][0][0] != D3DFMT_UNKNOWN);
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns closest supported format
+//-----------------------------------------------------------------------------
+ImageFormat FindNearestSupportedFormat( ImageFormat format, bool bIsVertexTexture, bool bIsRenderTarget, bool bFilterableRequired )
+{
+ return ImageLoader::D3DFormatToImageFormat( g_D3DColorFormat[format][bIsVertexTexture][bIsRenderTarget][bFilterableRequired] );
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns true if compressed textures are supported
+//-----------------------------------------------------------------------------
+bool D3DSupportsDepthTexture(D3DFORMAT format)
+{
+ // See if we can do it!
+ HRESULT hr = D3D()->CheckDeviceFormat(
+ g_DisplayAdapter, g_DeviceType, ImageLoader::ImageFormatToD3DFormat(g_DeviceFormat),
+ D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, format);
+
+ return !FAILED(hr);
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns true if the depth format is compatible with the display
+//-----------------------------------------------------------------------------
+static inline bool IsDepthFormatCompatible( int nAdapter, ImageFormat displayFormat, ImageFormat renderTargetFormat, D3DFORMAT depthFormat )
+{
+ D3DFORMAT d3dDisplayFormat = ImageLoader::ImageFormatToD3DFormat( displayFormat );
+ D3DFORMAT d3dRenderTargetFormat = ImageLoader::ImageFormatToD3DFormat( renderTargetFormat );
+
+ // Verify that the depth format is compatible.
+ HRESULT hr = D3D()->CheckDepthStencilMatch( nAdapter, DX8_DEVTYPE,
+ d3dDisplayFormat, d3dRenderTargetFormat, depthFormat);
+ return !FAILED(hr);
+}
+
+//-----------------------------------------------------------------------------
+// Finds the nearest supported depth buffer format
+//-----------------------------------------------------------------------------
+D3DFORMAT FindNearestSupportedDepthFormat( int nAdapter, ImageFormat displayFormat, ImageFormat renderTargetFormat, D3DFORMAT depthFormat )
+{
+ // This is the default case, used for rendering to the main render target
+ Assert( displayFormat != IMAGE_FORMAT_UNKNOWN && renderTargetFormat != IMAGE_FORMAT_UNKNOWN );
+
+ switch (depthFormat)
+ {
+#if defined( _X360 )
+ case D3DFMT_D24FS8:
+ return D3DFMT_D24FS8;
+
+ case D3DFMT_LIN_D24S8:
+ if ( g_bSupportsD24S8 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_LIN_D24S8 ) )
+ return D3DFMT_LIN_D24S8;
+#endif
+ case D3DFMT_D24S8:
+ if ( g_bSupportsD24S8 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D24S8 ) )
+ return D3DFMT_D24S8;
+#if !defined( _X360 )
+ if ( g_bSupportsD24X4S4 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D24X4S4 ) )
+ return D3DFMT_D24X4S4;
+ if ( g_bSupportsD15S1 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D15S1 ) )
+ return D3DFMT_D15S1;
+#endif
+ if ( g_bSupportsD24X8 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D24X8 ) )
+ return D3DFMT_D24X8;
+ if ( g_bSupportsD16 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D16 ) )
+ return D3DFMT_D16;
+ break;
+
+ case D3DFMT_D24X8:
+ if ( g_bSupportsD24X8 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D24X8 ) )
+ return D3DFMT_D24X8;
+ if ( g_bSupportsD24S8 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D24S8 ) )
+ return D3DFMT_D24S8;
+#if !defined( _X360 )
+ if ( g_bSupportsD24X4S4 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D24X4S4 ) )
+ return D3DFMT_D24X4S4;
+#endif
+ if ( g_bSupportsD16 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D16 ) )
+ return D3DFMT_D16;
+#if !defined( _X360 )
+ if ( g_bSupportsD15S1 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D15S1 ) )
+ return D3DFMT_D15S1;
+#endif
+ break;
+
+ case D3DFMT_D16:
+ if ( g_bSupportsD16 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D16 ) )
+ return D3DFMT_D16;
+#if !defined( _X360 )
+ if ( g_bSupportsD15S1 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D15S1 ) )
+ return D3DFMT_D15S1;
+#endif
+ if ( g_bSupportsD24X8 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D24X8 ) )
+ return D3DFMT_D24X8;
+ if ( g_bSupportsD24S8 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D24S8 ) )
+ return D3DFMT_D24S8;
+#if !defined( _X360 )
+ if ( g_bSupportsD24X4S4 && IsDepthFormatCompatible( nAdapter, displayFormat, renderTargetFormat, D3DFMT_D24X4S4 ) )
+ return D3DFMT_D24X4S4;
+#endif
+ break;
+ }
+
+ Assert( 0 );
+ return D3DFMT_D16;
+}
+
+
+//-----------------------------------------------------------------------------
+// Is a display buffer valid?
+//-----------------------------------------------------------------------------
+static inline bool IsFrameBufferFormatValid( UINT displayAdapter, D3DDEVTYPE deviceType,
+ D3DFORMAT displayFormat, D3DFORMAT backBufferFormat, bool bIsWindowed )
+{
+ HRESULT hr = D3D()->CheckDeviceType( displayAdapter, deviceType, displayFormat,
+ backBufferFormat, bIsWindowed );
+ return !FAILED(hr);
+}
+
+
+//-----------------------------------------------------------------------------
+// Finds the nearest supported frame buffer format
+//-----------------------------------------------------------------------------
+ImageFormat FindNearestSupportedBackBufferFormat( UINT displayAdapter,
+ D3DDEVTYPE deviceType, ImageFormat displayFormat, ImageFormat backBufferFormat, bool bIsWindowed )
+{
+ D3DFORMAT d3dDisplayFormat = ImageLoader::ImageFormatToD3DFormat( displayFormat );
+ switch (backBufferFormat)
+ {
+ case IMAGE_FORMAT_RGBA8888:
+ case IMAGE_FORMAT_ABGR8888:
+ case IMAGE_FORMAT_ARGB8888:
+ case IMAGE_FORMAT_BGRA8888:
+ case IMAGE_FORMAT_BGRA4444: // This is not supported ever; bump up to 32 bit
+ if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_A8R8G8B8, bIsWindowed ))
+ return IMAGE_FORMAT_BGRA8888;
+
+ // Bye, bye dest alpha
+ if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_X8R8G8B8, bIsWindowed ))
+ return IMAGE_FORMAT_BGRX8888;
+
+ if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_R5G6B5, bIsWindowed ))
+ return IMAGE_FORMAT_BGR565;
+
+ if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_A1R5G5B5, bIsWindowed ))
+ return IMAGE_FORMAT_BGRA5551;
+
+ if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_X1R5G5B5, bIsWindowed ))
+ return IMAGE_FORMAT_BGRX5551;
+
+ return IMAGE_FORMAT_UNKNOWN;
+
+ case IMAGE_FORMAT_RGB888:
+ case IMAGE_FORMAT_BGR888:
+ case IMAGE_FORMAT_RGB888_BLUESCREEN:
+ case IMAGE_FORMAT_BGRX8888:
+ if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_X8R8G8B8, bIsWindowed ))
+ return IMAGE_FORMAT_BGRX8888;
+
+ if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_A8R8G8B8, bIsWindowed ))
+ return IMAGE_FORMAT_BGRA8888;
+
+ if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_R5G6B5, bIsWindowed ))
+ return IMAGE_FORMAT_BGR565;
+
+ if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_A1R5G5B5, bIsWindowed ))
+ return IMAGE_FORMAT_BGRA5551;
+
+ if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_X1R5G5B5, bIsWindowed ))
+ return IMAGE_FORMAT_BGRX5551;
+
+ return IMAGE_FORMAT_UNKNOWN;
+
+ case IMAGE_FORMAT_RGB565:
+ case IMAGE_FORMAT_BGR565:
+ if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_R5G6B5, bIsWindowed ))
+ return IMAGE_FORMAT_BGR565;
+
+ if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_A1R5G5B5, bIsWindowed ))
+ return IMAGE_FORMAT_BGRA5551;
+
+ if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_X1R5G5B5, bIsWindowed ))
+ return IMAGE_FORMAT_BGRX5551;
+
+ if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_X8R8G8B8, bIsWindowed ))
+ return IMAGE_FORMAT_BGRX8888;
+
+ if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_A8R8G8B8, bIsWindowed ))
+ return IMAGE_FORMAT_BGRA8888;
+
+ return IMAGE_FORMAT_UNKNOWN;
+
+ case IMAGE_FORMAT_BGRX5551:
+ if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_X1R5G5B5, bIsWindowed ))
+ return IMAGE_FORMAT_BGRX5551;
+
+ if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_A1R5G5B5, bIsWindowed ))
+ return IMAGE_FORMAT_BGRA5551;
+
+ if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_R5G6B5, bIsWindowed ))
+ return IMAGE_FORMAT_BGR565;
+
+ if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_X8R8G8B8, bIsWindowed ))
+ return IMAGE_FORMAT_BGRX8888;
+
+ if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_A8R8G8B8, bIsWindowed ))
+ return IMAGE_FORMAT_BGRA8888;
+
+ return IMAGE_FORMAT_UNKNOWN;
+
+ case IMAGE_FORMAT_BGRA5551:
+ if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_A1R5G5B5, bIsWindowed ))
+ return IMAGE_FORMAT_BGRA5551;
+
+ if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_X1R5G5B5, bIsWindowed ))
+ return IMAGE_FORMAT_BGRX5551;
+
+ if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_R5G6B5, bIsWindowed ))
+ return IMAGE_FORMAT_BGR565;
+
+ if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_A8R8G8B8, bIsWindowed ))
+ return IMAGE_FORMAT_BGRA8888;
+
+ if (IsFrameBufferFormatValid( displayAdapter, deviceType, d3dDisplayFormat, D3DFMT_X8R8G8B8, bIsWindowed ))
+ return IMAGE_FORMAT_BGRX8888;
+
+ return IMAGE_FORMAT_UNKNOWN;
+ }
+
+ return IMAGE_FORMAT_UNKNOWN;
+}
+
+#if defined( _X360 )
+const char *D3DFormatName( D3DFORMAT d3dFormat )
+{
+ if ( IS_D3DFORMAT_SRGB( d3dFormat ) )
+ {
+ // sanitize the format from possible sRGB state for comparison purposes
+ d3dFormat = MAKE_NON_SRGB_FMT( d3dFormat );
+ }
+
+ switch ( d3dFormat )
+ {
+ case D3DFMT_A8R8G8B8:
+ return "D3DFMT_A8R8G8B8";
+ case D3DFMT_LIN_A8R8G8B8:
+ return "D3DFMT_LIN_A8R8G8B8";
+ case D3DFMT_X8R8G8B8:
+ return "D3DFMT_X8R8G8B8";
+ case D3DFMT_LIN_X8R8G8B8:
+ return "D3DFMT_LIN_X8R8G8B8";
+ case D3DFMT_R5G6B5:
+ return "D3DFMT_R5G6B5";
+ case D3DFMT_X1R5G5B5:
+ return "D3DFMT_X1R5G5B5";
+ case D3DFMT_A1R5G5B5:
+ return "D3DFMT_A1R5G5B5";
+ case D3DFMT_A4R4G4B4:
+ return "D3DFMT_A4R4G4B4";
+ case D3DFMT_L8:
+ return "D3DFMT_L8";
+ case D3DFMT_A8L8:
+ return "D3DFMT_A8L8";
+ case D3DFMT_A8:
+ return "D3DFMT_A8";
+ case D3DFMT_DXT1:
+ return "D3DFMT_DXT1";
+ case D3DFMT_DXT3:
+ return "D3DFMT_DXT3";
+ case D3DFMT_DXT5:
+ return "D3DFMT_DXT5";
+ case D3DFMT_V8U8:
+ return "D3DFMT_V8U8";
+ case D3DFMT_Q8W8V8U8:
+ return "D3DFMT_Q8W8V8U8";
+ case D3DFMT_D16:
+ return "D3DFMT_D16";
+ case D3DFMT_D24S8:
+ return "D3DFMT_D24S8";
+ case D3DFMT_D24FS8:
+ return "D3DFMT_D24FS8";
+ case D3DFMT_LIN_D24S8:
+ return "D3DFMT_LIN_D24S8";
+ case D3DFMT_A16B16G16R16:
+ return "D3DFMT_A16B16G16R16";
+ case D3DFMT_LIN_A16B16G16R16:
+ return "D3DFMT_LIN_A16B16G16R16";
+ }
+ return "???";
+}
+#endif
diff --git a/materialsystem/shaderapidx9/colorformatdx8.h b/materialsystem/shaderapidx9/colorformatdx8.h
new file mode 100644
index 0000000..20e9973
--- /dev/null
+++ b/materialsystem/shaderapidx9/colorformatdx8.h
@@ -0,0 +1,60 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#ifndef COLORFORMATDX8_H
+#define COLORFORMATDX8_H
+
+#include <pixelwriter.h>
+#include "togl/rendermechanism.h"
+
+// FOURCC formats for ATI shadow depth textures
+#define ATIFMT_D16 ((D3DFORMAT)(MAKEFOURCC('D','F','1','6')))
+#define ATIFMT_D24S8 ((D3DFORMAT)(MAKEFOURCC('D','F','2','4')))
+
+// FOURCC formats for ATI2N and ATI1N compressed textures (360 and DX10 parts also do these)
+#define ATIFMT_ATI2N ((D3DFORMAT) MAKEFOURCC('A', 'T', 'I', '2'))
+#define ATIFMT_ATI1N ((D3DFORMAT) MAKEFOURCC('A', 'T', 'I', '1'))
+
+// FOURCC formats for nVidia shadow depth textures
+#define NVFMT_RAWZ ((D3DFORMAT)(MAKEFOURCC('R','A','W','Z')))
+#define NVFMT_INTZ ((D3DFORMAT)(MAKEFOURCC('I','N','T','Z')))
+
+// FOURCC format for nVidia null texture format
+#define NVFMT_NULL ((D3DFORMAT)(MAKEFOURCC('N','U','L','L')))
+
+
+//-----------------------------------------------------------------------------
+// Finds the nearest supported frame buffer format
+//-----------------------------------------------------------------------------
+ImageFormat FindNearestSupportedBackBufferFormat( unsigned int displayAdapter, D3DDEVTYPE deviceType,
+ ImageFormat displayFormat, ImageFormat backBufferFormat, bool bIsWindowed );
+
+//-----------------------------------------------------------------------------
+// Initializes the color format informat; call it every time display mode changes
+//-----------------------------------------------------------------------------
+void InitializeColorInformation( unsigned int displayAdapter, D3DDEVTYPE deviceType,
+ ImageFormat displayFormat );
+
+//-----------------------------------------------------------------------------
+// Returns true if compressed textures are supported
+//-----------------------------------------------------------------------------
+bool D3DSupportsCompressedTextures();
+
+//-----------------------------------------------------------------------------
+// Returns closest supported format
+//-----------------------------------------------------------------------------
+ImageFormat FindNearestSupportedFormat( ImageFormat format, bool bIsVertexTexture, bool bIsRenderTarget, bool bFilterableRequired );
+
+//-----------------------------------------------------------------------------
+// Finds the nearest supported depth buffer format
+//-----------------------------------------------------------------------------
+D3DFORMAT FindNearestSupportedDepthFormat( int nAdapter, ImageFormat displayFormat, ImageFormat renderTargetFormat, D3DFORMAT depthFormat );
+
+const char *D3DFormatName( D3DFORMAT d3dFormat );
+
+#endif // COLORFORMATDX8_H
diff --git a/materialsystem/shaderapidx9/cvballoctracker.cpp b/materialsystem/shaderapidx9/cvballoctracker.cpp
new file mode 100644
index 0000000..8c3cdd0
--- /dev/null
+++ b/materialsystem/shaderapidx9/cvballoctracker.cpp
@@ -0,0 +1,764 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: tracks VB allocations (and compressed/uncompressed vertex memory usage)
+//
+//===========================================================================//
+
+#include "materialsystem/imaterial.h"
+#include "imeshdx8.h"
+#include "convar.h"
+#include "tier1/utlhash.h"
+#include "tier1/utlstack.h"
+
+#include "materialsystem/ivballoctracker.h"
+
+
+//-----------------------------------------------------------------------------
+//
+// Types
+//
+//-----------------------------------------------------------------------------
+
+#if ENABLE_VB_ALLOC_TRACKER
+
+// FIXME: combine this into the lower bits of VertexFormat_t
+typedef uint64 VertexElementMap_t;
+
+enum Saving_t
+{
+ SAVING_COMPRESSION = 0,
+ SAVING_REMOVAL = 1,
+ SAVING_ALIGNMENT = 2
+};
+
+struct ElementData
+{
+ VertexElement_t element;
+ int uncompressed; // uncompressed vertex size
+ int currentCompressed; // current compressed vertex element size
+ int idealCompressed; // ideal future compressed vertex element size
+ const char *name;
+};
+
+class CounterData
+{
+public:
+ CounterData() : m_memCount( 0 ), m_vertCount( 0 ), m_paddingCount( 0 )
+ {
+ for ( int i = 0; i < VERTEX_ELEMENT_NUMELEMENTS; i++ )
+ {
+ m_elementsCompressed[ i ] = 0;
+ m_elementsUncompressed[ i ] = 0;
+ }
+ m_AllocatorName[ 0 ] = 0;
+ }
+
+ static const int MAX_NAME_SIZE = 128;
+ int m_memCount;
+ int m_vertCount;
+ int m_paddingCount;
+ int m_elementsCompressed[ VERTEX_ELEMENT_NUMELEMENTS ]; // Number of compressed verts using each element
+ int m_elementsUncompressed[ VERTEX_ELEMENT_NUMELEMENTS ]; // Number of uncompressed verts using each element
+ char m_AllocatorName[ MAX_NAME_SIZE ];
+};
+
+class AllocData
+{
+public:
+ AllocData( void * buffer, int bufferSize, VertexFormat_t fmt, int numVerts, int allocatorHash )
+ : m_buffer( buffer ), m_bufferSize( bufferSize ), m_fmt( fmt ), m_numVerts( numVerts ), m_allocatorHash( allocatorHash ) {}
+ AllocData() : m_buffer( NULL ), m_bufferSize( 0 ), m_fmt( 0 ), m_numVerts( 0 ), m_allocatorHash( 0 ) {}
+
+ VertexFormat_t m_fmt;
+ void * m_buffer;
+ int m_bufferSize;
+ int m_numVerts;
+ short m_allocatorHash;
+};
+
+typedef CUtlHashFixed < CounterData, 64 > CCounterTable;
+typedef CUtlHashFixed < AllocData, 4096 > CAllocTable;
+typedef CUtlStack < short > CAllocNameHashes;
+
+#endif // ENABLE_VB_ALLOC_TRACKER
+
+
+class CVBAllocTracker : public IVBAllocTracker
+{
+public:
+ virtual void CountVB( void * buffer, bool isDynamic, int bufferSize, int vertexSize, VertexFormat_t fmt );
+ virtual void UnCountVB( void * buffer );
+ virtual bool TrackMeshAllocations( const char * allocatorName );
+
+ void DumpVBAllocs();
+
+#if ENABLE_VB_ALLOC_TRACKER
+
+public:
+ CVBAllocTracker() : m_bSuperSpew( false ) { m_MeshAllocatorName[0] = 0; }
+
+private:
+
+ UtlHashFixedHandle_t TrackAlloc( void * buffer, int bufferSize, VertexFormat_t fmt, int numVerts, short allocatorHash );
+ bool KillAlloc( void * buffer, int & bufferSize, VertexFormat_t & fmt, int & numVerts, short & allocatorHash );
+
+ UtlHashFixedHandle_t GetCounterHandle( const char * allocatorName, short allocatorHash );
+
+ void SpewElements( const char * allocatorName, short nameHash );
+ int ComputeVertexSize( VertexElementMap_t map, VertexFormat_t fmt, bool compressed );
+ VertexElementMap_t ComputeElementMap( VertexFormat_t fmt, int vertexSize, bool isDynamic );
+ void UpdateElements( CounterData & data, VertexFormat_t fmt, int numVerts, int vertexSize,
+ bool isDynamic, bool isCompressed );
+
+ int ComputeAlignmentWastage( int bufferSize );
+ void AddSaving( int & alreadySaved, int & yetToSave, const char *allocatorName, VertexElement_t element, Saving_t savingType );
+ void SpewExpectedSavings( void );
+ void UpdateData( const char * allocatorName, short allocatorKey, int bufferSize, VertexFormat_t fmt,
+ int numVerts, int vertexSize, bool isDynamic, bool isCompressed );
+
+ const char * GetNameString( int allocatorKey );
+ void SpewData( const char * allocatorName, short nameHash = 0 );
+ void SpewDataSometimes( int inc );
+
+
+ static const int SPEW_RATE = 64;
+ static const int MAX_ALLOCATOR_NAME_SIZE = 128;
+ char m_MeshAllocatorName[ MAX_ALLOCATOR_NAME_SIZE ];
+ bool m_bSuperSpew;
+
+ CCounterTable m_VBCountTable;
+ CAllocTable m_VBAllocTable;
+ CAllocNameHashes m_VBTableNameHashes;
+
+ // We use a mutex since allocation tracking is accessed from multiple loading threads.
+ // CThreadFastMutex is used as contention is expected to be low during loading.
+ CThreadFastMutex m_VBAllocMutex;
+#endif // ENABLE_VB_ALLOC_TRACKER
+};
+
+
+//-----------------------------------------------------------------------------
+//
+// Global data
+//
+//-----------------------------------------------------------------------------
+
+#if ENABLE_VB_ALLOC_TRACKER
+
+// FIXME: do this in a better way:
+static const ElementData positionElement = { VERTEX_ELEMENT_POSITION, 12, 12, 8, "POSITION " }; // (UNDONE: need vertex shader to scale, may cause cracking w/ static props)
+static const ElementData normalElement = { VERTEX_ELEMENT_NORMAL, 12, 4, 4, "NORMAL " }; // (UNDONE: PC (2x16-byte Ravi method) or 360 (D3DDECLTYPE_HEND3N))
+static const ElementData colorElement = { VERTEX_ELEMENT_COLOR, 4, 4, 4, "COLOR " }; // (already minimal)
+static const ElementData specularElement = { VERTEX_ELEMENT_SPECULAR, 4, 4, 4, "SPECULAR " }; // (already minimal)
+static const ElementData tangentSElement = { VERTEX_ELEMENT_TANGENT_S, 12, 12, 4, "TANGENT_S " }; // (all-but-unused)
+static const ElementData tangentTElement = { VERTEX_ELEMENT_TANGENT_T, 12, 12, 4, "TANGENT_T " }; // (all-but-unused)
+static const ElementData wrinkleElement = { VERTEX_ELEMENT_WRINKLE, 4, 4, 0, "WRINKLE " }; // (UNDONE: compress it as a SHORTN in Position.w - is it [0,1]?)
+static const ElementData boneIndexElement = { VERTEX_ELEMENT_BONEINDEX, 4, 4, 4, "BONEINDEX " }; // (already minimal)
+static const ElementData boneWeight1Element = { VERTEX_ELEMENT_BONEWEIGHTS1, 4, 4, 4, "BONEWEIGHT1 " }; // (unused)
+static const ElementData boneWeight2Element = { VERTEX_ELEMENT_BONEWEIGHTS2, 8, 8, 4, "BONEWEIGHT2 " }; // (UNDONE: take care w.r.t cracking in flex regions)
+static const ElementData boneWeight3Element = { VERTEX_ELEMENT_BONEWEIGHTS3, 12, 12, 8, "BONEWEIGHT3 " }; // (unused)
+static const ElementData boneWeight4Element = { VERTEX_ELEMENT_BONEWEIGHTS4, 16, 16, 8, "BONEWEIGHT4 " }; // (unused)
+static const ElementData userData1Element = { VERTEX_ELEMENT_USERDATA1, 4, 4, 4, "USERDATA1 " }; // (unused)
+static const ElementData userData2Element = { VERTEX_ELEMENT_USERDATA2, 8, 8, 4, "USERDATA2 " }; // (unused)
+static const ElementData userData3Element = { VERTEX_ELEMENT_USERDATA3, 12, 12, 4, "USERDATA3 " }; // (unused)
+#if ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_SEPARATETANGENTS_SHORT2 )
+static const ElementData userData4Element = { VERTEX_ELEMENT_USERDATA4, 16, 4, 4, "USERDATA4 " }; // (UNDONE: PC (2x16-byte Ravi method) or 360 (D3DDECLTYPE_HEND3N))
+#else // ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 )
+static const ElementData userData4Element = { VERTEX_ELEMENT_USERDATA4, 16, 0, 0, "USERDATA4 " }; // (UNDONE: PC (2x16-byte Ravi method) or 360 (D3DDECLTYPE_HEND3N))
+#endif
+static const ElementData texCoord1D0Element = { VERTEX_ELEMENT_TEXCOORD1D_0, 4, 4, 4, "TEXCOORD1D_0" }; // (not worth compressing)
+static const ElementData texCoord1D1Element = { VERTEX_ELEMENT_TEXCOORD1D_1, 4, 4, 4, "TEXCOORD1D_1" }; // (not worth compressing)
+static const ElementData texCoord1D2Element = { VERTEX_ELEMENT_TEXCOORD1D_2, 4, 4, 4, "TEXCOORD1D_2" }; // (not worth compressing)
+static const ElementData texCoord1D3Element = { VERTEX_ELEMENT_TEXCOORD1D_3, 4, 4, 4, "TEXCOORD1D_3" }; // (not worth compressing)
+static const ElementData texCoord1D4Element = { VERTEX_ELEMENT_TEXCOORD1D_4, 4, 4, 4, "TEXCOORD1D_4" }; // (not worth compressing)
+static const ElementData texCoord1D5Element = { VERTEX_ELEMENT_TEXCOORD1D_5, 4, 4, 4, "TEXCOORD1D_5" }; // (not worth compressing)
+static const ElementData texCoord1D6Element = { VERTEX_ELEMENT_TEXCOORD1D_6, 4, 4, 4, "TEXCOORD1D_6" }; // (not worth compressing)
+static const ElementData texCoord1D7Element = { VERTEX_ELEMENT_TEXCOORD1D_7, 4, 4, 4, "TEXCOORD1D_7" }; // (not worth compressing)
+static const ElementData texCoord2D0Element = { VERTEX_ELEMENT_TEXCOORD2D_0, 8, 8, 4, "TEXCOORD2D_0" }; // (UNDONE: need vertex shader to take scale, account for clamping)
+static const ElementData texCoord2D1Element = { VERTEX_ELEMENT_TEXCOORD2D_1, 8, 8, 4, "TEXCOORD2D_1" }; // (UNDONE: need vertex shader to take scale, account for clamping)
+static const ElementData texCoord2D2Element = { VERTEX_ELEMENT_TEXCOORD2D_2, 8, 8, 4, "TEXCOORD2D_2" }; // (all-but-unused)
+static const ElementData texCoord2D3Element = { VERTEX_ELEMENT_TEXCOORD2D_3, 8, 8, 4, "TEXCOORD2D_3" }; // (unused)
+static const ElementData texCoord2D4Element = { VERTEX_ELEMENT_TEXCOORD2D_4, 8, 8, 4, "TEXCOORD2D_4" }; // (unused)
+static const ElementData texCoord2D5Element = { VERTEX_ELEMENT_TEXCOORD2D_5, 8, 8, 4, "TEXCOORD2D_5" }; // (unused)
+static const ElementData texCoord2D6Element = { VERTEX_ELEMENT_TEXCOORD2D_6, 8, 8, 4, "TEXCOORD2D_6" }; // (unused)
+static const ElementData texCoord2D7Element = { VERTEX_ELEMENT_TEXCOORD2D_7, 8, 8, 4, "TEXCOORD2D_7" }; // (unused)
+static const ElementData texCoord3D0Element = { VERTEX_ELEMENT_TEXCOORD3D_0, 12, 12, 8, "TEXCOORD3D_0" }; // FIXME: used how much? (UNDONE: need vertex shader to take scale, account for clamping)
+static const ElementData texCoord3D1Element = { VERTEX_ELEMENT_TEXCOORD3D_1, 12, 12, 8, "TEXCOORD3D_1" }; // FIXME: used how much? (UNDONE: need vertex shader to take scale, account for clamping)
+static const ElementData texCoord3D2Element = { VERTEX_ELEMENT_TEXCOORD3D_2, 12, 12, 8, "TEXCOORD3D_2" }; // FIXME: used how much? (UNDONE: need vertex shader to take scale, account for clamping)
+static const ElementData texCoord3D3Element = { VERTEX_ELEMENT_TEXCOORD3D_3, 12, 12, 8, "TEXCOORD3D_3" }; // FIXME: used how much? (UNDONE: need vertex shader to take scale, account for clamping)
+static const ElementData texCoord3D4Element = { VERTEX_ELEMENT_TEXCOORD3D_4, 12, 12, 8, "TEXCOORD3D_4" }; // FIXME: used how much? (UNDONE: need vertex shader to take scale, account for clamping)
+static const ElementData texCoord3D5Element = { VERTEX_ELEMENT_TEXCOORD3D_5, 12, 12, 8, "TEXCOORD3D_5" }; // FIXME: used how much? (UNDONE: need vertex shader to take scale, account for clamping)
+static const ElementData texCoord3D6Element = { VERTEX_ELEMENT_TEXCOORD3D_6, 12, 12, 8, "TEXCOORD3D_6" }; // FIXME: used how much? (UNDONE: need vertex shader to take scale, account for clamping)
+static const ElementData texCoord3D7Element = { VERTEX_ELEMENT_TEXCOORD3D_7, 12, 12, 8, "TEXCOORD3D_7" }; // FIXME: used how much? (UNDONE: need vertex shader to take scale, account for clamping)
+static const ElementData texCoord4D0Element = { VERTEX_ELEMENT_TEXCOORD4D_0, 16, 16, 8, "TEXCOORD4D_0" }; // FIXME: used how much? (UNDONE: need vertex shader to take scale, account for clamping)
+static const ElementData texCoord4D1Element = { VERTEX_ELEMENT_TEXCOORD4D_1, 16, 16, 8, "TEXCOORD4D_1" }; // FIXME: used how much? (UNDONE: need vertex shader to take scale, account for clamping)
+static const ElementData texCoord4D2Element = { VERTEX_ELEMENT_TEXCOORD4D_2, 16, 16, 8, "TEXCOORD4D_2" }; // FIXME: used how much? (UNDONE: need vertex shader to take scale, account for clamping)
+static const ElementData texCoord4D3Element = { VERTEX_ELEMENT_TEXCOORD4D_3, 16, 16, 8, "TEXCOORD4D_3" }; // FIXME: used how much? (UNDONE: need vertex shader to take scale, account for clamping)
+static const ElementData texCoord4D4Element = { VERTEX_ELEMENT_TEXCOORD4D_4, 16, 16, 8, "TEXCOORD4D_4" }; // FIXME: used how much? (UNDONE: need vertex shader to take scale, account for clamping)
+static const ElementData texCoord4D5Element = { VERTEX_ELEMENT_TEXCOORD4D_5, 16, 16, 8, "TEXCOORD4D_5" }; // FIXME: used how much? (UNDONE: need vertex shader to take scale, account for clamping)
+static const ElementData texCoord4D6Element = { VERTEX_ELEMENT_TEXCOORD4D_6, 16, 16, 8, "TEXCOORD4D_6" }; // FIXME: used how much? (UNDONE: need vertex shader to take scale, account for clamping)
+static const ElementData texCoord4D7Element = { VERTEX_ELEMENT_TEXCOORD4D_7, 16, 16, 8, "TEXCOORD4D_7" }; // FIXME: used how much? (UNDONE: need vertex shader to take scale, account for clamping)
+static const ElementData elementTable[ VERTEX_ELEMENT_NUMELEMENTS ] = { positionElement,
+ normalElement,
+ colorElement,
+ specularElement,
+ tangentSElement,
+ tangentTElement,
+ wrinkleElement,
+ boneIndexElement,
+ boneWeight1Element, boneWeight2Element, boneWeight3Element, boneWeight4Element,
+ userData1Element, userData2Element, userData3Element, userData4Element,
+ texCoord1D0Element, texCoord1D1Element, texCoord1D2Element, texCoord1D3Element, texCoord1D4Element, texCoord1D5Element, texCoord1D6Element, texCoord1D7Element,
+ texCoord2D0Element, texCoord2D1Element, texCoord2D2Element, texCoord2D3Element, texCoord2D4Element, texCoord2D5Element, texCoord2D6Element, texCoord2D7Element,
+ texCoord3D0Element, texCoord3D1Element, texCoord3D2Element, texCoord3D3Element, texCoord3D4Element, texCoord3D5Element, texCoord3D6Element, texCoord3D7Element,
+ texCoord4D0Element, texCoord4D1Element, texCoord4D2Element, texCoord4D3Element, texCoord4D4Element, texCoord4D5Element, texCoord4D6Element, texCoord4D7Element,
+ };
+
+static ConVar mem_vballocspew( "mem_vballocspew", "0", FCVAR_CHEAT, "How often to spew vertex buffer allocation stats - 1: every alloc, 2+: every 2+ allocs, 0: off" );
+
+#endif // ENABLE_VB_ALLOC_TRACKER
+
+//-----------------------------------------------------------------------------
+// Singleton instance exposed to the engine
+//-----------------------------------------------------------------------------
+
+CVBAllocTracker g_VBAllocTrackerShaderAPI;
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CVBAllocTracker, IVBAllocTracker,
+ VB_ALLOC_TRACKER_INTERFACE_VERSION, g_VBAllocTrackerShaderAPI );
+
+//-----------------------------------------------------------------------------
+//
+// VB alloc-tracking code starts here
+//
+//-----------------------------------------------------------------------------
+
+#if ENABLE_VB_ALLOC_TRACKER
+
+UtlHashFixedHandle_t CVBAllocTracker::TrackAlloc( void * buffer, int bufferSize, VertexFormat_t fmt, int numVerts, short allocatorHash )
+{
+ AllocData newData( buffer, bufferSize, fmt, numVerts, allocatorHash );
+ UtlHashFixedHandle_t handle = m_VBAllocTable.Insert( (int)buffer, newData );
+ if ( handle == m_VBAllocTable.InvalidHandle() )
+ {
+ Warning( "[VBMEM] VBMemAllocTable hash collision (grow table).\n" );
+ }
+ return handle;
+}
+
+bool CVBAllocTracker::KillAlloc( void * buffer, int & bufferSize, VertexFormat_t & fmt, int & numVerts, short & allocatorHash )
+{
+ UtlHashFixedHandle_t handle = m_VBAllocTable.Find( (int)buffer );
+ if ( handle != m_VBAllocTable.InvalidHandle() )
+ {
+ AllocData & data = m_VBAllocTable.Element( handle );
+ bufferSize = data.m_bufferSize;
+ fmt = data.m_fmt;
+ numVerts = data.m_numVerts;
+ allocatorHash = data.m_allocatorHash;
+ m_VBAllocTable.Remove( handle );
+ return true;
+ }
+ Warning( "[VBMEM] VBMemAllocTable failed to find alloc entry...\n" );
+ return false;
+}
+
+UtlHashFixedHandle_t CVBAllocTracker::GetCounterHandle( const char * allocatorName, short allocatorHash )
+{
+ UtlHashFixedHandle_t handle = m_VBCountTable.Find( allocatorHash );
+ if ( handle == m_VBCountTable.InvalidHandle() )
+ {
+ CounterData newData;
+ Assert( ( allocatorName != NULL ) && ( allocatorName[0] != 0 ) );
+ V_strncpy( newData.m_AllocatorName, allocatorName, CounterData::MAX_NAME_SIZE );
+ handle = m_VBCountTable.Insert( allocatorHash, newData );
+ m_VBTableNameHashes.Push( allocatorHash );
+ }
+ if ( handle == m_VBCountTable.InvalidHandle() )
+ {
+ Warning( "[VBMEM] CounterData hash collision (grow table).\n" );
+ }
+ return handle;
+}
+
+void CheckForElementTableUpdates( const ElementData & element )
+{
+ // Ensure that 'elementTable' gets updated if VertexElement_t ever changes:
+ int tableIndex = &element - &( elementTable[0] );
+ Assert( tableIndex == element.element );
+ if ( tableIndex != element.element )
+ {
+ static int timesToSpew = 20;
+ if ( timesToSpew > 0 )
+ {
+ Warning( "VertexElement_t structure has changed, ElementData table in cvballoctracker needs updating!\n" );
+ timesToSpew--;
+ }
+ }
+}
+
+void CVBAllocTracker::SpewElements( const char * allocatorName, short nameHash )
+{
+ short allocatorHash = allocatorName ? HashString( allocatorName ) : nameHash;
+ UtlHashFixedHandle_t handle = GetCounterHandle( allocatorName, allocatorHash );
+ if ( handle != m_VBCountTable.InvalidHandle() )
+ {
+ CounterData & data = m_VBCountTable.Element( handle );
+ int originalSum = 0, currentSum = 0, idealSum = 0;
+ for (int i = 0;i < VERTEX_ELEMENT_NUMELEMENTS;i++)
+ {
+ CheckForElementTableUpdates( elementTable[ i ] );
+ int numCompressed = data.m_elementsCompressed[ i ];
+ int numUncompressed = data.m_elementsUncompressed[ i ];
+ int numVerts = numCompressed + numUncompressed;
+ originalSum += numVerts*elementTable[ i ].uncompressed;
+ currentSum += numCompressed*elementTable[ i ].currentCompressed + numUncompressed*elementTable[ i ].uncompressed;
+ idealSum += numVerts*elementTable[ i ].idealCompressed;
+ }
+
+ if ( originalSum > 0 )
+ {
+ Msg( "[VBMEM] ----elements (%s)----:\n", data.m_AllocatorName);
+ for (int i = 0;i < VERTEX_ELEMENT_NUMELEMENTS;i++)
+ {
+ // We count vertices (converted to bytes via elementTable)
+ int numCompressed = data.m_elementsCompressed[ i ];
+ int numUncompressed = data.m_elementsUncompressed[ i ];
+ int numVerts = numCompressed + numUncompressed;
+ const ElementData & elementData = elementTable[ i ];
+ if ( numVerts > 0 )
+ {
+ Msg( " element: %5.2f MB 'U', %5.2f MB 'C', %5.2f MB 'I', %6.2f MB 'D', %s\n",
+ numVerts*elementData.uncompressed / ( 1024.0f*1024.0f ),
+ ( numCompressed*elementData.currentCompressed + numUncompressed*elementData.uncompressed ) / ( 1024.0f*1024.0f ),
+ numVerts*elementData.idealCompressed / ( 1024.0f*1024.0f ),
+ -( numCompressed*elementData.currentCompressed + numUncompressed*elementData.uncompressed - numVerts*elementData.idealCompressed ) / ( 1024.0f*1024.0f ),
+ elementData.name );
+ }
+ }
+ Msg( "[VBMEM] total: %5.2f MB 'U', %5.2f MB 'C', %5.2f MB 'I', %6.2f MB 'D'\n",
+ originalSum / ( 1024.0f*1024.0f ),
+ currentSum / ( 1024.0f*1024.0f ),
+ idealSum / ( 1024.0f*1024.0f ),
+ -( currentSum - idealSum ) / ( 1024.0f*1024.0f ) );
+ Msg( "[VBMEM] ----elements (%s)----:\n", data.m_AllocatorName);
+ }
+ }
+}
+
+int CVBAllocTracker::ComputeVertexSize( VertexElementMap_t map, VertexFormat_t fmt, bool compressed )
+{
+ int vertexSize = 0;
+ for ( int i = 0;i < VERTEX_ELEMENT_NUMELEMENTS;i++ )
+ {
+ const ElementData & element = elementTable[ i ];
+ CheckForElementTableUpdates( element );
+ VertexElementMap_t LSB = 1;
+ if ( map & ( LSB << i ) )
+ {
+ vertexSize += compressed ? element.currentCompressed : element.uncompressed;
+ }
+ }
+
+ // On PC (see CVertexBufferBase::ComputeVertexDescription() in meshbase.cpp)
+ // vertex strides are aligned to 16 bytes:
+ bool bCacheAlign = ( fmt & VERTEX_FORMAT_USE_EXACT_FORMAT ) == 0;
+ if ( bCacheAlign && ( vertexSize > 16 ) && IsPC() )
+ {
+ vertexSize = (vertexSize + 0xF) & (~0xF);
+ }
+
+ return vertexSize;
+}
+
+VertexElementMap_t CVBAllocTracker::ComputeElementMap( VertexFormat_t fmt, int vertexSize, bool isDynamic )
+{
+ VertexElementMap_t map = 0, LSB = 1;
+ if ( fmt & VERTEX_POSITION ) map |= LSB << VERTEX_ELEMENT_POSITION;
+ if ( fmt & VERTEX_NORMAL ) map |= LSB << VERTEX_ELEMENT_NORMAL;
+ if ( fmt & VERTEX_COLOR ) map |= LSB << VERTEX_ELEMENT_COLOR;
+ if ( fmt & VERTEX_SPECULAR ) map |= LSB << VERTEX_ELEMENT_SPECULAR;
+ if ( fmt & VERTEX_TANGENT_S ) map |= LSB << VERTEX_ELEMENT_TANGENT_S;
+ if ( fmt & VERTEX_TANGENT_T ) map |= LSB << VERTEX_ELEMENT_TANGENT_T;
+ if ( fmt & VERTEX_WRINKLE ) map |= LSB << VERTEX_ELEMENT_WRINKLE;
+ if ( fmt & VERTEX_BONE_INDEX) map |= LSB << VERTEX_ELEMENT_BONEINDEX;
+ int numBones = NumBoneWeights( fmt );
+ if ( numBones > 0 ) map |= LSB << ( VERTEX_ELEMENT_BONEWEIGHTS1 + numBones - 1 );
+ int userDataSize = UserDataSize( fmt );
+ if ( userDataSize > 0 ) map |= LSB << ( VERTEX_ELEMENT_USERDATA1 + userDataSize - 1 );
+ for ( int i = 0; i < VERTEX_MAX_TEXTURE_COORDINATES; ++i )
+ {
+ VertexElement_t texCoordElements[4] = { VERTEX_ELEMENT_TEXCOORD1D_0, VERTEX_ELEMENT_TEXCOORD2D_0, VERTEX_ELEMENT_TEXCOORD3D_0, VERTEX_ELEMENT_TEXCOORD4D_0 };
+ int nCoordSize = TexCoordSize( i, fmt );
+ if ( nCoordSize > 0 )
+ {
+ Assert( i < 4 );
+ if ( i < 4 )
+ {
+ map |= LSB << ( texCoordElements[ nCoordSize - 1 ] + i );
+ }
+ }
+ }
+
+ if ( map == 0 )
+ {
+ if ( !isDynamic )
+ {
+ // We expect all (non-dynamic) VB allocs to specify a vertex format
+ // Warning("[VBMEM] unknown vertex format\n");
+ return 0;
+ }
+ }
+ else
+ {
+ if ( vertexSize != 0 )
+ {
+ // Make sure elementTable above matches external computations of vertex size
+ // FIXME: make this assert dependent on whether the current VB is compressed or not
+ VertexCompressionType_t compressionType = CompressionType( fmt );
+ bool isCompressedAlloc = ( compressionType == VERTEX_COMPRESSION_ON );
+ // FIXME: once we've finalised which elements we're compressing for ship, update
+ // elementTable to reflect that and re-enable this assert for compressed verts
+ if ( !isCompressedAlloc )
+ {
+ Assert( vertexSize == ComputeVertexSize( map, fmt, isCompressedAlloc ) );
+ }
+ }
+ }
+
+ return map;
+}
+
+void CVBAllocTracker::UpdateElements( CounterData & data, VertexFormat_t fmt, int numVerts, int vertexSize,
+ bool isDynamic, bool isCompressed )
+{
+ VertexElementMap_t map = ComputeElementMap( fmt, vertexSize, isDynamic );
+ if ( map != 0 )
+ {
+ for (int i = 0;i < VERTEX_ELEMENT_NUMELEMENTS;i++)
+ {
+ // Count vertices (get bytes from our elements table)
+ VertexElementMap_t LSB = 1;
+ if ( map & ( LSB << i ) )
+ {
+ if ( isCompressed )
+ data.m_elementsCompressed[ i ] += numVerts;
+ else
+ data.m_elementsUncompressed[ i ] += numVerts;
+ }
+ }
+ }
+}
+
+int CVBAllocTracker::ComputeAlignmentWastage( int bufferSize )
+{
+ if ( !IsX360() )
+ return 0;
+
+ // VBs are 4KB-aligned on 360, so we waste thiiiiiis much:
+ return ( ( 4096 - (bufferSize & 4095)) & 4095 );
+}
+
+void CVBAllocTracker::AddSaving( int & alreadySaved, int & yetToSave, const char *allocatorName, VertexElement_t element, Saving_t savingType )
+{
+ UtlHashFixedHandle_t handle = GetCounterHandle( allocatorName, HashString( allocatorName ) );
+ if ( handle != m_VBCountTable.InvalidHandle() )
+ {
+ CheckForElementTableUpdates( elementTable[ element ] );
+ CounterData & counterData = m_VBCountTable.Element( handle );
+ const ElementData & elementData = elementTable[ element ];
+ int numVerts = counterData.m_vertCount;
+ int numCompressed = counterData.m_elementsCompressed[ element ];
+ int numUncompressed = counterData.m_elementsUncompressed[ element ];
+ switch( savingType )
+ {
+ case SAVING_COMPRESSION:
+ alreadySaved += numCompressed*( elementData.uncompressed - elementData.currentCompressed );
+ yetToSave += numUncompressed*( elementData.uncompressed - elementData.currentCompressed );
+ break;
+ case SAVING_REMOVAL:
+ alreadySaved += elementData.uncompressed*( numVerts - ( numUncompressed + numCompressed ) );
+ yetToSave += numUncompressed*elementData.uncompressed + numCompressed*elementData.uncompressed;
+ break;
+ case SAVING_ALIGNMENT:
+ yetToSave += counterData.m_paddingCount;
+ break;
+ default:
+ Assert(0);
+ break;
+ }
+ }
+}
+
+void CVBAllocTracker::SpewExpectedSavings( void )
+{
+ int alreadySaved = 0, yetToSave = 0;
+
+ // We have removed bone weights+indices from static props
+ AddSaving( alreadySaved, yetToSave, "R_StudioCreateStaticMeshes (prop_static)", VERTEX_ELEMENT_BONEWEIGHTS2, SAVING_REMOVAL );
+ AddSaving( alreadySaved, yetToSave, "R_StudioCreateStaticMeshes (prop_static)", VERTEX_ELEMENT_BONEINDEX, SAVING_REMOVAL );
+ // We have removed vertex colors from all models (color should only ever be in stream1, for static vertex lighting)
+ AddSaving( alreadySaved, yetToSave, "R_StudioCreateStaticMeshes (prop_dynamic)", VERTEX_ELEMENT_COLOR, SAVING_REMOVAL );
+ AddSaving( alreadySaved, yetToSave, "R_StudioCreateStaticMeshes (prop_static)", VERTEX_ELEMENT_COLOR, SAVING_REMOVAL );
+ AddSaving( alreadySaved, yetToSave, "R_StudioCreateStaticMeshes (character)", VERTEX_ELEMENT_COLOR, SAVING_REMOVAL );
+
+ // We expect to compress texcoords (DONE: normals+tangents, boneweights) for all studiomdls
+ AddSaving( alreadySaved, yetToSave, "R_StudioCreateStaticMeshes (prop_dynamic)", VERTEX_ELEMENT_NORMAL, SAVING_COMPRESSION );
+ AddSaving( alreadySaved, yetToSave, "R_StudioCreateStaticMeshes (prop_static)", VERTEX_ELEMENT_NORMAL, SAVING_COMPRESSION );
+ AddSaving( alreadySaved, yetToSave, "R_StudioCreateStaticMeshes (character)", VERTEX_ELEMENT_NORMAL, SAVING_COMPRESSION );
+ AddSaving( alreadySaved, yetToSave, "R_StudioCreateStaticMeshes (prop_dynamic)", VERTEX_ELEMENT_USERDATA4, SAVING_COMPRESSION );
+ AddSaving( alreadySaved, yetToSave, "R_StudioCreateStaticMeshes (prop_static)", VERTEX_ELEMENT_USERDATA4, SAVING_COMPRESSION );
+ AddSaving( alreadySaved, yetToSave, "R_StudioCreateStaticMeshes (character)", VERTEX_ELEMENT_USERDATA4, SAVING_COMPRESSION );
+ AddSaving( alreadySaved, yetToSave, "R_StudioCreateStaticMeshes (prop_dynamic)", VERTEX_ELEMENT_TEXCOORD2D_0, SAVING_COMPRESSION );
+ AddSaving( alreadySaved, yetToSave, "R_StudioCreateStaticMeshes (prop_static)", VERTEX_ELEMENT_TEXCOORD2D_0, SAVING_COMPRESSION );
+ AddSaving( alreadySaved, yetToSave, "R_StudioCreateStaticMeshes (character)", VERTEX_ELEMENT_TEXCOORD2D_0, SAVING_COMPRESSION );
+ AddSaving( alreadySaved, yetToSave, "R_StudioCreateStaticMeshes (character)", VERTEX_ELEMENT_BONEWEIGHTS1, SAVING_COMPRESSION );
+ AddSaving( alreadySaved, yetToSave, "R_StudioCreateStaticMeshes (character)", VERTEX_ELEMENT_BONEWEIGHTS2, SAVING_COMPRESSION );
+ AddSaving( alreadySaved, yetToSave, "R_StudioCreateStaticMeshes (prop_dynamic)", VERTEX_ELEMENT_BONEWEIGHTS1, SAVING_COMPRESSION );
+ AddSaving( alreadySaved, yetToSave, "R_StudioCreateStaticMeshes (prop_dynamic)", VERTEX_ELEMENT_BONEWEIGHTS2, SAVING_COMPRESSION );
+
+ // UNDONE: compress bone weights for studiomdls? (issue: possible flex artifacts, but 2xSHORTN probably ok)
+ // UNDONE: compress positions (+wrinkle) for studiomdls? (issue: possible flex artifacts)
+ // UNDONE: disable tangents for non-bumped models (issue: forcedmaterialoverride support... don't think that needs tangents, though
+ // however, if we use UBYTE4 normal+tangent encoding, removing tangents saves nothing)
+
+ if ( IsX360() )
+ {
+ // We expect to avoid 4-KB-alignment wastage for color meshes, by allocating them
+ // out of a single, shared VB and adding per-mesh offsets in vertex shaders
+ AddSaving( alreadySaved, yetToSave, "CColorMeshData::CreateResource", VERTEX_ELEMENT_USERDATA4, SAVING_ALIGNMENT );
+ }
+
+ Msg("[VBMEM]\n");
+ Msg("[VBMEM] Total expected memory saving by disabling/compressing vertex elements: %6.2f MB\n", yetToSave / ( 1024.0f*1024.0f ) );
+ Msg("[VBMEM] ( total memory already saved: %6.2f MB)\n", alreadySaved / ( 1024.0f*1024.0f ) );
+ Msg("[VBMEM] - compression of model texcoords, [DONE: normals+tangents, bone weights]\n" );
+ Msg("[VBMEM] - avoidance of 4-KB alignment wastage for color meshes (on 360)\n" );
+ Msg("[VBMEM] - [DONE: removal of unneeded bone weights+indices on models]\n" );
+ Msg("[VBMEM]\n");
+}
+
+void CVBAllocTracker::UpdateData( const char * allocatorName, short allocatorKey, int bufferSize, VertexFormat_t fmt,
+ int numVerts, int vertexSize, bool isDynamic, bool isCompressed )
+{
+ UtlHashFixedHandle_t handle = GetCounterHandle( allocatorName, allocatorKey );
+ if ( handle != m_VBCountTable.InvalidHandle() )
+ {
+ CounterData & data = m_VBCountTable.Element( handle );
+ data.m_memCount += bufferSize;
+ Assert( data.m_memCount >= 0 );
+ data.m_vertCount += numVerts;
+ Assert( data.m_vertCount >= 0 );
+ data.m_paddingCount += ( bufferSize < 0 ? -1 : +1 )*ComputeAlignmentWastage( abs( bufferSize ) );
+ UpdateElements( data, fmt, numVerts, vertexSize, isDynamic, isCompressed );
+ }
+}
+
+const char * CVBAllocTracker::GetNameString( int allocatorKey )
+{
+ UtlHashFixedHandle_t handle = GetCounterHandle( NULL, allocatorKey );
+ if ( handle != m_VBCountTable.InvalidHandle() )
+ {
+ CounterData & data = m_VBCountTable.Element( handle );
+ return data.m_AllocatorName;
+ }
+ return "null";
+}
+
+void CVBAllocTracker::SpewData( const char * allocatorName, short nameHash )
+{
+ short allocatorHash = allocatorName ? HashString( allocatorName ) : nameHash;
+ UtlHashFixedHandle_t handle = GetCounterHandle( allocatorName, allocatorHash );
+ if ( handle != m_VBCountTable.InvalidHandle() )
+ {
+ CounterData & data = m_VBCountTable.Element( handle );
+ if ( data.m_memCount > 0 )
+ {
+ Msg("[VBMEM] running mem usage: (%5.2f M-verts) %6.2f MB | '%s'\n",
+ data.m_vertCount / ( 1024.0f*1024.0f ),
+ data.m_memCount / ( 1024.0f*1024.0f ),
+ data.m_AllocatorName );
+ }
+ if ( data.m_paddingCount > 0 )
+ {
+ Msg("[VBMEM] 4KB VB alignment wastage: %6.2f MB | '%s'\n",
+ data.m_paddingCount / ( 1024.0f*1024.0f ),
+ data.m_AllocatorName );
+ }
+ }
+}
+
+void CVBAllocTracker::SpewDataSometimes( int inc )
+{
+ static int count = 0;
+
+ if ( inc < 0 ) count += inc;
+ Assert( count >= 0 );
+
+ int period = mem_vballocspew.GetInt();
+ if ( period >= 1 )
+ {
+ if ( ( count % period ) == 0 )
+ {
+ Msg( "[VBMEM] Status after %d VB allocs:\n", count );
+ //#define ROUND_UP( _x_ ) ( ( ( _x_ ) + 31 ) & 31 )
+ //Msg( "[VBMEM] Conservative estimate of mem used to track allocs: %d\n", 4096*ROUND_UP( 4 + sizeof( CUtlPtrLinkedList<AllocData> ) ) + count*ROUND_UP( sizeof( AllocData ) + 8 ) );
+ SpewData( "total_static" );
+ SpewData( "unknown" );
+ }
+ }
+
+ if ( inc > 0 ) count += inc;
+}
+
+void CVBAllocTracker::DumpVBAllocs()
+{
+ m_VBAllocMutex.Lock();
+
+ Msg("[VBMEM] ----running totals----\n" );
+ for ( int i = ( m_VBTableNameHashes.Count() - 1 ); i >= 0; i-- )
+ {
+ short nameHash = m_VBTableNameHashes.Element( i );
+ SpewElements( NULL, nameHash );
+ }
+
+ Msg("[VBMEM]\n");
+ Msg("[VBMEM] 'U' - original memory usage (all vertices uncompressed)\n" );
+ Msg("[VBMEM] 'C' - current memory usage (some compression)\n" );
+ Msg("[VBMEM] 'I' - ideal memory usage (all verts maximally compressed)\n" );
+ Msg("[VBMEM] 'D' - difference between C and I (-> how much more compression could save)\n" );
+ Msg("[VBMEM] 'W' - memory wasted due to 4-KB vertex buffer alignment\n" );
+ Msg("[VBMEM]\n");
+ for ( int i = ( m_VBTableNameHashes.Count() - 1 ); i >= 0; i-- )
+ {
+ short nameHash = m_VBTableNameHashes.Element( i );
+ SpewData( NULL, nameHash );
+ }
+ SpewExpectedSavings();
+ Msg("[VBMEM] ----running totals----\n" );
+
+ m_VBAllocMutex.Unlock();
+}
+
+#endif // ENABLE_VB_ALLOC_TRACKER
+
+void CVBAllocTracker::CountVB( void * buffer, bool isDynamic, int bufferSize, int vertexSize, VertexFormat_t fmt )
+{
+#if ENABLE_VB_ALLOC_TRACKER
+ m_VBAllocMutex.Lock();
+
+ // Update VB memory counts for the relevant allocation type
+ // (NOTE: we have 'unknown', 'dynamic' and 'total' counts)
+ const char * allocatorName = ( m_MeshAllocatorName[0] == 0 ) ? "unknown" : m_MeshAllocatorName;
+ if ( isDynamic ) allocatorName = "total_dynamic";
+ int numVerts = ( vertexSize > 0 ) ? ( bufferSize / vertexSize ) : 0;
+ short totalStaticKey = HashString( "total_static" );
+ short key = HashString( allocatorName );
+ bool isCompressed = ( VERTEX_COMPRESSION_NONE != CompressionType( fmt ) );
+
+ if ( m_MeshAllocatorName[0] == 0 )
+ {
+ Warning("[VBMEM] unknown allocation!\n");
+ }
+
+ // Add to the VB memory counters
+ TrackAlloc( buffer, bufferSize, fmt, numVerts, key );
+ if ( !isDynamic )
+ {
+ // Keep dynamic allocs out of the total (dynamic VBs don't get compressed)
+ UpdateData( "total_static", totalStaticKey, bufferSize, fmt, numVerts, vertexSize, isDynamic, isCompressed );
+ }
+ UpdateData( allocatorName, key, bufferSize, fmt, numVerts, vertexSize, isDynamic, isCompressed );
+
+ if ( m_bSuperSpew )
+ {
+ // Spew every alloc
+ Msg( "[VBMEM] VB-alloc | %6.2f MB | %s | %s\n", bufferSize / ( 1024.0f*1024.0f ), ( isDynamic ? "DYNamic" : " STAtic" ), allocatorName );
+ SpewData( allocatorName );
+ }
+ SpewDataSometimes( +1 );
+
+ m_VBAllocMutex.Unlock();
+#endif // ENABLE_VB_ALLOC_TRACKER
+}
+
+void CVBAllocTracker::UnCountVB( void * buffer )
+{
+#if ENABLE_VB_ALLOC_TRACKER
+ m_VBAllocMutex.Lock();
+
+ short totalKey = HashString( "total_static" );
+ short dynamicKey = HashString( "total_dynamic" );
+ int bufferSize;
+ VertexFormat_t fmt;
+ int numVerts;
+ short key;
+
+ // We have to store allocation data because the caller often doesn't know what it alloc'd :o/
+ if ( KillAlloc( buffer, bufferSize, fmt, numVerts, key ) )
+ {
+ bool isCompressed = ( VERTEX_COMPRESSION_NONE != CompressionType( fmt ) );
+ bool isDynamic = ( key == dynamicKey );
+
+ // Subtract from the VB memory counters
+ if ( !isDynamic )
+ {
+ UpdateData( NULL, totalKey, -bufferSize, fmt, -numVerts, 0, isDynamic, isCompressed );
+ }
+ UpdateData( NULL, key, -bufferSize, fmt, -numVerts, 0, isDynamic, isCompressed );
+
+ const char * nameString = GetNameString( key );
+
+ if ( m_bSuperSpew )
+ {
+ Msg( "[VBMEM] VB-free | %6.2f MB | %s | %s\n", bufferSize / ( 1024.0f*1024.0f ), ( isDynamic ? "DYNamic" : " STAtic" ), nameString );
+ SpewData( nameString );
+ }
+ SpewDataSometimes( -1 );
+ }
+
+ m_VBAllocMutex.Unlock();
+#endif // ENABLE_VB_ALLOC_TRACKER
+}
+
+bool CVBAllocTracker::TrackMeshAllocations( const char * allocatorName )
+{
+#if ENABLE_VB_ALLOC_TRACKER
+ // Tracks mesh allocations by name (set this before an alloc, clear it after)
+
+ if ( m_MeshAllocatorName[ 0 ] )
+ {
+ return true;
+ }
+
+ m_VBAllocMutex.Lock();
+
+ if ( allocatorName )
+ {
+ Assert( m_MeshAllocatorName[0] == 0 );
+ V_strncpy( m_MeshAllocatorName, allocatorName, MAX_ALLOCATOR_NAME_SIZE );
+ }
+ else
+ {
+ m_MeshAllocatorName[0] = 0;
+ }
+
+ m_VBAllocMutex.Unlock();
+#endif // ENABLE_VB_ALLOC_TRACKER
+
+ return false;
+}
+
+#ifndef RETAIL
+
+static void CC_DumpVBMemAllocs()
+{
+#if ( ENABLE_VB_ALLOC_TRACKER == 0 )
+ Warning( "ENABLE_VB_ALLOC_TRACKER must be 1 to enable VB mem alloc tracking\n");
+#else
+ g_VBAllocTrackerShaderAPI.DumpVBAllocs();
+#endif
+}
+
+static ConCommand mem_dumpvballocs( "mem_dumpvballocs", CC_DumpVBMemAllocs, "Dump VB memory allocation stats.", FCVAR_CHEAT );
+
+#endif // RETAIL
diff --git a/materialsystem/shaderapidx9/d3d_async.cpp b/materialsystem/shaderapidx9/d3d_async.cpp
new file mode 100644
index 0000000..6c9cf8b
--- /dev/null
+++ b/materialsystem/shaderapidx9/d3d_async.cpp
@@ -0,0 +1,825 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// methods for muti-core dx9 threading
+//===========================================================================//
+
+#ifdef D3D_ASYNC_SUPPORTED
+
+#include "glmgr/dxabstract.h"
+#include "utlsymbol.h"
+#include "utlvector.h"
+#include "utldict.h"
+#include "utlbuffer.h"
+#include "UtlStringMap.h"
+#include "locald3dtypes.h"
+#include "shaderapidx8_global.h"
+#include "recording.h"
+#include "tier0/vprof.h"
+#include "materialsystem/imaterialsystem.h"
+#include "materialsystem/imaterialsystemhardwareconfig.h"
+#include "shaderapidx8.h"
+#include "materialsystem/IShader.h"
+#include "utllinkedlist.h"
+#include "IShaderSystem.h"
+#include "tier0/fasttimer.h"
+#include <stdlib.h>
+#include "convar.h"
+#include "materialsystem/shader_vcs_version.h"
+#include "datacache/idatacache.h"
+#include "winutils.h"
+
+#include "tier0/memdbgon.h"
+
+#if SHADERAPI_USE_SMP
+
+// Set this to 1 to get vprof nodes for playing back the command stream. This is good for counting calls in a frame, etc.
+#define SHADERAPI_VPROF_BUFFER_PLAYBACK 1
+
+#if SHADERAPI_VPROF_BUFFER_PLAYBACK && SHADERAPI_BUFFER_D3DCALLS
+#define VPROF_BUFFER_PLAYBACK(name) VPROF(name)
+#else
+#define VPROF_BUFFER_PLAYBACK(name) ((void)0)
+#endif
+
+template<class T, int QSIZE> class FixedWorkQueue
+{
+ T Data[QSIZE];
+ char pad0[256];
+ volatile int n_added;
+ int write_index;
+ char pad1[256]; // make sure these don't share cache lines
+ volatile int n_removed;
+ int read_index;
+
+public:
+ FixedWorkQueue(void)
+ {
+ read_index=write_index=0;
+ n_added=n_removed=0;
+ }
+
+ int IsEmpty(void)
+ {
+ return (n_added==n_removed);
+ }
+
+ int IsFull(void)
+ {
+ return (n_added-n_removed)>=QSIZE;
+ }
+
+ T GetWorkUnit(void)
+ {
+ if (IsEmpty())
+ return 0;
+ return Data[read_index];
+ }
+
+ void MarkUnitDone(void)
+ {
+ n_removed++;
+ read_index=(read_index+1) % QSIZE;
+ }
+
+ void AddWorkUnit(T unit)
+ {
+#if SHADERAPI_BUFFER_D3DCALLS
+ Assert( !IsFull() );
+#else
+ while (IsFull())
+ Sleep(0);
+#endif
+ Data[write_index]=unit;
+ n_added++;
+ write_index=(write_index+1) % QSIZE;
+ }
+};
+
+
+#if SHADERAPI_BUFFER_D3DCALLS
+#define N_PUSH_BUFFERS 5000
+#else
+#define N_PUSH_BUFFERS 500
+#endif
+static volatile PushBuffer *PushBuffers[N_PUSH_BUFFERS];
+FixedWorkQueue<PushBuffer *, N_PUSH_BUFFERS> PBQueue;
+
+
+
+#ifdef WIN32
+void __cdecl OurThreadInit( void * ourthis )
+#else
+unsigned int OurThreadInit( void * ourthis )
+#endif
+{
+ (( D3DDeviceWrapper *) ourthis )->RunThread();
+#ifndef WIN32
+ return 0;
+#endif
+}
+
+void D3DDeviceWrapper::RunThread( void )
+{
+ SetThreadAffinityMask(GetCurrentThread(), 2);
+ for(;;)
+ {
+ PushBuffer *Pbuf=PBQueue.GetWorkUnit();
+ if (! Pbuf)
+ {
+ ; //Sleep(0);
+ }
+ else
+ {
+ ExecutePushBuffer( Pbuf );
+ PBQueue.MarkUnitDone();
+ Pbuf->m_State = PUSHBUFFER_AVAILABLE;
+ }
+ }
+}
+
+#if SHADERAPI_BUFFER_D3DCALLS
+void D3DDeviceWrapper::ExecuteAllWork( void )
+{
+ if( !m_bBufferingD3DCalls )
+ return;
+ VPROF_BUDGET( "ExecuteAllWork", "ExecuteAllWork" );
+ SubmitPushBufferAndGetANewOne();
+ PushBuffer *Pbuf;
+ while( ( Pbuf = PBQueue.GetWorkUnit() ) != NULL )
+ {
+ ExecutePushBuffer( Pbuf );
+ PBQueue.MarkUnitDone();
+ Pbuf->m_State = PUSHBUFFER_AVAILABLE;
+ }
+ m_bBufferingD3DCalls = false;
+}
+#endif
+
+#if SHADERAPI_BUFFER_D3DCALLS
+#define MAXIMUM_NUMBER_OF_BUFFERS_LOCKED_AT_ONCE 1600
+#else
+#define MAXIMUM_NUMBER_OF_BUFFERS_LOCKED_AT_ONCE 16
+#endif
+
+struct RememberedPointer
+{
+ void *m_pKey;
+ void *m_pRememberedPtr;
+} RememberedPointerHistory[MAXIMUM_NUMBER_OF_BUFFERS_LOCKED_AT_ONCE];
+
+void D3DDeviceWrapper::SetASyncMode( bool onoff )
+{
+#if SHADERAPI_BUFFER_D3DCALLS
+ if ( onoff )
+ {
+ m_bBufferingD3DCalls = true;
+ // allocate push buffers if we need to
+ if ( PushBuffers[0] == NULL )
+ {
+ for(int i=0; i<N_PUSH_BUFFERS; i++)
+ PushBuffers[i]=new PushBuffer;
+ }
+ // create thread and init communications
+ memset( RememberedPointerHistory,0,sizeof(RememberedPointerHistory) );
+ }
+#else
+ if ( onoff )
+ {
+ if (! m_pASyncThreadHandle )
+ {
+ // allocate push buffers if we need to
+ if ( PushBuffers[0] == NULL )
+ {
+ for(int i=0; i<N_PUSH_BUFFERS; i++)
+ PushBuffers[i]=new PushBuffer;
+ }
+ // create thread and init communications
+ memset( RememberedPointerHistory,0,sizeof(RememberedPointerHistory) );
+ SetThreadAffinityMask(GetCurrentThread(), 1);
+#ifdef WIN32
+ m_pASyncThreadHandle = _beginthread( OurThreadInit, 128*1024, this );
+#else
+ m_pASyncThreadHandle = (uintptr_t)CreateSimpleThread( OurThreadInit, this, 128*1024 );
+#endif
+ }
+ }
+ else
+ {
+ Synchronize();
+ }
+#endif
+}
+
+
+PushBuffer *D3DDeviceWrapper::FindFreePushBuffer( PushBufferState newstate )
+{
+ VPROF_BUFFER_PLAYBACK( "D3DDeviceWrapper::FindFreePushBuffer" );
+ for(;;)
+ {
+ for(int i=0;i<N_PUSH_BUFFERS;i++)
+ {
+ if (PushBuffers[i]->m_State == PUSHBUFFER_AVAILABLE )
+ {
+ PushBuffers[i]->m_State = newstate;
+ return (PushBuffer *) PushBuffers[i];
+ }
+ }
+ // hmm, out of push buffers. better sleep and try again later
+ SubmitPushBufferAndGetANewOne();
+ Sleep(0);
+ }
+}
+
+void D3DDeviceWrapper::GetPushBuffer( void )
+{
+ VPROF_BUFFER_PLAYBACK( "D3DDeviceWrapper::GetPushBuffer" );
+ m_pCurPushBuffer = FindFreePushBuffer( PUSHBUFFER_BEING_FILLED );
+ m_pOutputPtr = m_pCurPushBuffer->m_BufferData;
+ m_PushBufferFreeSlots = PUSHBUFFER_NELEMS - 1; // leave room for end marker
+}
+
+void D3DDeviceWrapper::SubmitPushBufferAndGetANewOne( void )
+{
+ VPROF_BUFFER_PLAYBACK( "D3DDeviceWrapper::SubmitPushBufferAndGetANewOne" );
+
+ // submit the current push buffer
+ if ( m_pCurPushBuffer )
+ {
+ if (m_pOutputPtr == m_pCurPushBuffer->m_BufferData) // haven't done anyting, don't bother
+ return;
+ *(m_pOutputPtr) = PBCMD_END; // mark end
+ m_pCurPushBuffer->m_State = PUSHBUFFER_SUBMITTED;
+ // here, enqueue for task
+ PBQueue.AddWorkUnit( m_pCurPushBuffer );
+ }
+ GetPushBuffer();
+}
+
+void D3DDeviceWrapper::SubmitIfNotBusy( void )
+{
+ VPROF_BUFFER_PLAYBACK( "D3DDeviceWrapper::SubmitIfNotBusy" );
+ if ( PBQueue.IsEmpty() )
+ SubmitPushBufferAndGetANewOne();
+}
+
+
+void D3DDeviceWrapper::Synchronize( void )
+{
+#if SHADERAPI_BUFFER_D3DCALLS
+ if( m_bBufferingD3DCalls )
+ {
+ Assert( 0 );
+ Error( "Synchronize not supported with SHADERAPI_BUFFER_D3DCALLS" );
+ }
+ return;
+#endif
+ if ( ASyncMode())
+ {
+ SubmitPushBufferAndGetANewOne();
+ // here, wait for queue to become empty
+ while (! PBQueue.IsEmpty() )
+ {
+ // Sleep(1);
+ }
+ }
+}
+
+void D3DDeviceWrapper::AsynchronousLock( IDirect3DIndexBuffer9* ib,
+ size_t offset, size_t size, void **ptr,
+ DWORD flags,
+ LockedBufferContext *lb)
+{
+ VPROF_BUFFER_PLAYBACK( "D3DDeviceWrapper::AsynchronousLock index" );
+
+ if ( size <= sizeof( PushBuffers[0]->m_BufferData ))
+ {
+ // can use one of our pushbuffers for this
+ lb->m_pPushBuffer = FindFreePushBuffer( PUSHBUFFER_BEING_USED_FOR_LOCKEDDATA );
+ *(ptr) = lb->m_pPushBuffer->m_BufferData;
+ Assert( *ptr );
+ lb->m_pMallocedMemory = NULL;
+ }
+ else // out of buffer space or size too big
+ {
+ lb->m_pPushBuffer = NULL;
+ lb->m_pMallocedMemory = new uint8 [ size ];
+ *(ptr) = lb->m_pMallocedMemory;
+ }
+ // now, push lock commands
+ AllocatePushBufferSpace( 1+N_DWORDS_IN_PTR+3 );
+ *(m_pOutputPtr++)=PBCMD_ASYNC_LOCK_IB;
+ *((LPDIRECT3DINDEXBUFFER *) m_pOutputPtr)=ib;
+ m_pOutputPtr+=N_DWORDS_IN_PTR;
+ *(m_pOutputPtr++)=offset;
+ *(m_pOutputPtr++)=size;
+ *(m_pOutputPtr++)=flags;
+}
+
+void D3DDeviceWrapper::AsynchronousLock( IDirect3DVertexBuffer9* vb,
+ size_t offset, size_t size, void **ptr,
+ DWORD flags,
+ LockedBufferContext *lb)
+{
+ VPROF_BUFFER_PLAYBACK( "D3DDeviceWrapper::AsynchronousLock vertex" );
+ // we have commands in flight. Need to use temporary memory for this lock.
+ // if the size needed is < the amount of space in a push buffer, we can use
+ // a push buffer for the buffer. Otherwise, we're going to malloc one.
+ if ( size <= sizeof( PushBuffers[0]->m_BufferData ))
+ {
+ // can use one of our pushbuffers for this
+ lb->m_pPushBuffer = FindFreePushBuffer( PUSHBUFFER_BEING_USED_FOR_LOCKEDDATA );
+ *(ptr) = lb->m_pPushBuffer->m_BufferData;
+ Assert( *ptr );
+ lb->m_pMallocedMemory = NULL;
+ }
+ else // out of buffer space or size too big
+ {
+ lb->m_pPushBuffer = NULL;
+ lb->m_pMallocedMemory = new uint8 [ size ];
+ *(ptr) = lb->m_pMallocedMemory;
+ }
+ // now, push lock commands
+ AllocatePushBufferSpace( 1+N_DWORDS_IN_PTR+3 );
+ *(m_pOutputPtr++)=PBCMD_ASYNC_LOCK_VB;
+ *((LPDIRECT3DVERTEXBUFFER *) m_pOutputPtr)=vb;
+ m_pOutputPtr+=N_DWORDS_IN_PTR;
+ *(m_pOutputPtr++)=offset;
+ *(m_pOutputPtr++)=size;
+ *(m_pOutputPtr++)=flags;
+}
+
+
+
+inline void RememberLockedPointer( void *key, void *value )
+{
+ VPROF_BUFFER_PLAYBACK( "RememberLockedPointer" );
+ int repl=-1;
+ int i;
+ for(i=0;i<MAXIMUM_NUMBER_OF_BUFFERS_LOCKED_AT_ONCE;i++)
+ {
+ if ( RememberedPointerHistory[i].m_pKey==key )
+ break;
+ if ( (repl == -1 ) && (RememberedPointerHistory[i].m_pRememberedPtr == 0 ) )
+ repl=i;
+ }
+ if (i != MAXIMUM_NUMBER_OF_BUFFERS_LOCKED_AT_ONCE )
+ {
+ RememberedPointerHistory[i].m_pRememberedPtr = value;
+ if ( value==NULL )
+ RememberedPointerHistory[i].m_pKey = NULL;
+ }
+ else
+ {
+ if (repl == -1 )
+ {
+ Assert( 0 );
+ }
+ else
+ {
+ RememberedPointerHistory[repl].m_pKey = key;
+ RememberedPointerHistory[repl].m_pRememberedPtr = value;
+ }
+ }
+}
+
+inline void *RecallLockedPointer( void *key )
+{
+ VPROF_BUFFER_PLAYBACK( "RecallLockedPointer" );
+
+ for(int i=0;i<MAXIMUM_NUMBER_OF_BUFFERS_LOCKED_AT_ONCE;i++)
+ if ( RememberedPointerHistory[i].m_pKey == key )
+ return RememberedPointerHistory[i].m_pRememberedPtr;
+ return NULL;
+
+}
+
+void D3DDeviceWrapper::HandleAsynchronousLockVBCommand( uint32 const *dptr )
+{
+ dptr++;
+ LPDIRECT3DVERTEXBUFFER vb=*((LPDIRECT3DVERTEXBUFFER *) dptr);
+ dptr+=N_DWORDS_IN_PTR;
+ uint32 offset=*(dptr++);
+ uint32 size=*(dptr++);
+ uint32 flags=*(dptr++);
+ void *locked_ptr=0;
+ vb->Lock( offset, size, &locked_ptr, flags );
+ RememberLockedPointer( vb, locked_ptr );
+}
+
+void D3DDeviceWrapper::HandleAsynchronousUnLockVBCommand( uint32 const *dptr )
+{
+ dptr++;
+ LPDIRECT3DVERTEXBUFFER vb=*((LPDIRECT3DVERTEXBUFFER *) dptr);
+ dptr+=N_DWORDS_IN_PTR;
+ LockedBufferContext lb=*((LockedBufferContext *) dptr);
+ dptr+=N_DWORDS( LockedBufferContext );
+ size_t unlock_size=*( dptr++ );
+ void *locked_data=RecallLockedPointer( vb );
+ Assert( locked_data );
+ if (lb.m_pPushBuffer)
+ {
+ Assert( ! lb.m_pMallocedMemory );
+ if ( locked_data )
+ memcpy( locked_data, lb.m_pPushBuffer->m_BufferData, unlock_size );
+ lb.m_pPushBuffer->m_State = PUSHBUFFER_AVAILABLE;
+ }
+ else if ( lb.m_pMallocedMemory )
+ {
+ Assert( ! lb.m_pPushBuffer );
+ if ( locked_data )
+ memcpy( locked_data, lb.m_pMallocedMemory, unlock_size );
+ delete[] ((uint8 *) lb.m_pMallocedMemory);
+ }
+ // now, actually unlock
+ RememberLockedPointer( vb, NULL );
+ vb->Unlock();
+}
+
+void D3DDeviceWrapper::HandleAsynchronousLockIBCommand( uint32 const *dptr )
+{
+ dptr++;
+ LPDIRECT3DINDEXBUFFER ib=*((LPDIRECT3DINDEXBUFFER *) dptr);
+ Assert( ib );
+ dptr+=N_DWORDS_IN_PTR;
+ uint32 offset=*(dptr++);
+ uint32 size=*(dptr++);
+ uint32 flags=*(dptr++);
+ void *locked_ptr=0;
+ ib->Lock( offset, size, &locked_ptr, flags );
+ RememberLockedPointer( ib, locked_ptr );
+}
+
+void D3DDeviceWrapper::HandleAsynchronousUnLockIBCommand( uint32 const *dptr )
+{
+ dptr++;
+ LPDIRECT3DINDEXBUFFER ib=*((LPDIRECT3DINDEXBUFFER *) dptr);
+ dptr+=N_DWORDS_IN_PTR;
+ LockedBufferContext lb=*((LockedBufferContext *) dptr);
+ dptr+=N_DWORDS( LockedBufferContext );
+ size_t unlock_size=*( dptr++ );
+ void *locked_data=RecallLockedPointer( ib );
+ Assert( locked_data );
+ if (lb.m_pPushBuffer)
+ {
+ Assert( ! lb.m_pMallocedMemory );
+ if ( locked_data )
+ memcpy( locked_data, lb.m_pPushBuffer->m_BufferData, unlock_size );
+ lb.m_pPushBuffer->m_State = PUSHBUFFER_AVAILABLE;
+ }
+ else if ( lb.m_pMallocedMemory )
+ {
+ Assert( ! lb.m_pPushBuffer );
+ if ( locked_data )
+ memcpy( locked_data, lb.m_pMallocedMemory, unlock_size );
+ delete[] ((uint8 *) lb.m_pMallocedMemory);
+ }
+ // now, actually unlock
+ RememberLockedPointer( ib, NULL );
+ ib->Unlock();
+
+}
+
+
+static inline void *FetchPtr( uint32 const *mem)
+{
+ void **p=(void **) mem;
+ return *p;
+}
+
+#define CALC_STATS 1
+#if CALC_STATS
+int n_commands_executed=0;
+int n_pbs_executed=0;
+#endif
+
+void D3DDeviceWrapper::ExecutePushBuffer( PushBuffer const* pb)
+{
+ VPROF_BUFFER_PLAYBACK( "D3DDeviceWrapper::ExecutePushBuffer" );
+ uint32 const *dptr=pb->m_BufferData;
+ n_pbs_executed++;
+ for(;;)
+ {
+ n_commands_executed++;
+ switch( dptr[0] )
+ {
+ case PBCMD_END:
+ {
+ VPROF_BUFFER_PLAYBACK( "END" );
+ n_commands_executed--; // doesn't count
+ return;
+ }
+
+ case PBCMD_SET_RENDERSTATE:
+ {
+ VPROF_BUFFER_PLAYBACK( "SET_RENDERSTATE" );
+ Dx9Device()->SetRenderState((D3DRENDERSTATETYPE) dptr[1],dptr[2]);
+ dptr+=3;
+ break;
+ }
+
+ case PBCMD_SET_SAMPLER_STATE:
+ {
+ VPROF_BUFFER_PLAYBACK( "SET_SAMPLER_STATE" );
+ Dx9Device()->SetSamplerState(dptr[1], (D3DSAMPLERSTATETYPE) dptr[2], dptr[3]);
+ dptr+=4;
+ break;
+ }
+
+ case PBCMD_DRAWPRIM:
+ {
+ VPROF_BUFFER_PLAYBACK( "DRAWPRIM" );
+
+ tmZone( TELEMETRY_LEVEL2, TMZF_NONE, "Dx9Device()->DrawPrimitive" );
+
+ Dx9Device()->DrawPrimitive( (D3DPRIMITIVETYPE) dptr[1], dptr[2], dptr[3] );
+ dptr+=4;
+ break;
+ }
+
+ case PBCMD_DRAWINDEXEDPRIM:
+ {
+ VPROF_BUFFER_PLAYBACK( "DRAWINDEXEDPRIM" );
+
+ tmZone( TELEMETRY_LEVEL2, TMZF_NONE, "Dx9Device()->DrawIndexedPrimitive" );
+
+ Dx9Device()->DrawIndexedPrimitive( (D3DPRIMITIVETYPE) dptr[1], dptr[2], dptr[3],
+ dptr[4], dptr[5], dptr[6]);
+ dptr+=7;
+ break;
+ }
+
+ case PBCMD_SET_STREAM_SOURCE:
+ {
+ VPROF_BUFFER_PLAYBACK( "SET_STREAM_SOURCE" );
+ Dx9Device()->SetStreamSource( dptr[1],(IDirect3DVertexBuffer9 *) FetchPtr(dptr+2),
+ dptr[3],dptr[4] );
+ dptr += 4+N_DWORDS( IDirect3DVertexBuffer9 * );
+ break;
+ }
+
+ case PBCMD_SET_TEXTURE:
+ {
+ VPROF_BUFFER_PLAYBACK( "SET_TEXTURE" );
+ Dx9Device()->SetTexture( dptr[1],(IDirect3DBaseTexture *) FetchPtr(dptr+2));
+ dptr += 2+N_DWORDS_IN_PTR;
+ break;
+ }
+
+ case PBCMD_SET_RENDER_TARGET:
+ {
+ VPROF_BUFFER_PLAYBACK( "SET_RENDER_TARGET" );
+ Dx9Device()->SetRenderTarget( dptr[1],(IDirect3DSurface *) FetchPtr(dptr+2));
+ dptr += 2+N_DWORDS_IN_PTR;
+ break;
+ }
+
+ case PBCMD_SET_PIXEL_SHADER:
+ {
+ VPROF_BUFFER_PLAYBACK( "SET_PIXEL_SHADER" );
+ Dx9Device()->SetPixelShader( (IDirect3DPixelShader9 *) FetchPtr(dptr+1));
+ dptr += 1+N_DWORDS_IN_PTR;
+ break;
+ }
+
+ case PBCMD_SET_INDICES:
+ {
+ VPROF_BUFFER_PLAYBACK( "SET_INDICES" );
+ Dx9Device()->SetIndices( (IDirect3DIndexBuffer9*) FetchPtr(dptr+1));
+ dptr += 1+N_DWORDS_IN_PTR;
+ break;
+ }
+
+ case PBCMD_SET_DEPTH_STENCIL_SURFACE:
+ {
+ VPROF_BUFFER_PLAYBACK( "SET_DEPTH_STENCIL_SURFACE" );
+ Dx9Device()->SetDepthStencilSurface( (IDirect3DSurface9*) FetchPtr(dptr+1));
+ dptr += 1+N_DWORDS_IN_PTR;
+ break;
+ }
+
+ case PBCMD_SETVIEWPORT:
+ {
+ VPROF_BUFFER_PLAYBACK( "SETVIEWPORT" );
+ Dx9Device()->SetViewport( (D3DVIEWPORT9 const *) (dptr+1) );
+ dptr += 1+N_DWORDS(D3DVIEWPORT9);
+ break;
+ }
+
+ case PBCMD_SET_VERTEX_SHADER:
+ {
+ VPROF_BUFFER_PLAYBACK( "SET_VERTEX_SHADER" );
+ Dx9Device()->SetVertexShader( (IDirect3DVertexShader9 *) FetchPtr(dptr+1));
+ dptr += 1+N_DWORDS_IN_PTR;
+ break;
+ }
+
+ case PBCMD_ASYNC_LOCK_VB:
+ {
+ VPROF_BUFFER_PLAYBACK( "ASYNC_LOCK_VB" );
+ HandleAsynchronousLockVBCommand(dptr);
+ dptr+=1+N_DWORDS_IN_PTR+3;
+ break;
+ }
+
+ case PBCMD_ASYNC_UNLOCK_VB:
+ {
+ VPROF_BUFFER_PLAYBACK( "ASYNC_UNLOCK_VB" );
+ HandleAsynchronousUnLockVBCommand( dptr );
+ dptr+=1+N_DWORDS_IN_PTR+N_DWORDS( LockedBufferContext )+1;
+ break;
+ }
+
+ case PBCMD_ASYNC_LOCK_IB:
+ {
+ VPROF_BUFFER_PLAYBACK( "ASYNC_LOCK_IB" );
+ HandleAsynchronousLockIBCommand(dptr);
+ dptr+=1+N_DWORDS_IN_PTR+3;
+ break;
+ }
+
+ case PBCMD_ASYNC_UNLOCK_IB:
+ {
+ VPROF_BUFFER_PLAYBACK( "ASYNC_UNLOCK_IB" );
+ HandleAsynchronousUnLockIBCommand( dptr );
+ dptr+=1+N_DWORDS_IN_PTR+N_DWORDS( LockedBufferContext )+1;
+ break;
+ }
+
+ case PBCMD_UNLOCK_VB:
+ {
+ VPROF_BUFFER_PLAYBACK( "UNLOCK_VB" );
+ IDirect3DVertexBuffer9 *p=(IDirect3DVertexBuffer9 *) FetchPtr(dptr+1);
+ p->Unlock();
+ dptr += 1+N_DWORDS_IN_PTR;
+ break;
+ }
+ case PBCMD_UNLOCK_IB:
+ {
+ VPROF_BUFFER_PLAYBACK( "UNLOCK_IB" );
+ IDirect3DIndexBuffer9 *p=(IDirect3DIndexBuffer9 *) FetchPtr(dptr+1);
+ p->Unlock();
+ dptr += 1+N_DWORDS_IN_PTR;
+ break;
+ }
+ case PBCMD_SET_VERTEX_SHADER_CONSTANT:
+ {
+ VPROF_BUFFER_PLAYBACK( "SET_VERTEX_SHADER_CONSTANT" );
+ Dx9Device()->SetVertexShaderConstantF( dptr[1], (float const *) dptr+3, dptr[2]);
+ dptr += 3+4*dptr[2];
+ break;
+ }
+ case PBCMD_SET_BOOLEAN_VERTEX_SHADER_CONSTANT:
+ {
+ VPROF_BUFFER_PLAYBACK( "SET_BOOLEAN_VERTEX_SHADER_CONSTANT" );
+ Dx9Device()->SetVertexShaderConstantB( dptr[1], (int const *) dptr+3, dptr[2]);
+ dptr += 3+dptr[2];
+ break;
+ }
+
+ case PBCMD_SET_INTEGER_VERTEX_SHADER_CONSTANT:
+ {
+ VPROF_BUFFER_PLAYBACK( "SET_INTEGER_VERTEX_SHADER_CONSTANT" );
+ Dx9Device()->SetVertexShaderConstantI( dptr[1], (int const *) dptr+3, dptr[2]);
+ dptr += 3+4*dptr[2];
+ break;
+ }
+
+ case PBCMD_SET_PIXEL_SHADER_CONSTANT:
+ {
+ VPROF_BUFFER_PLAYBACK( "SET_PIXEL_SHADER_CONSTANT" );
+ Dx9Device()->SetPixelShaderConstantF( dptr[1], (float const *) dptr+3, dptr[2]);
+ dptr += 3+4*dptr[2];
+ break;
+ }
+ case PBCMD_SET_BOOLEAN_PIXEL_SHADER_CONSTANT:
+ {
+ VPROF_BUFFER_PLAYBACK( "SET_BOOLEAN_PIXEL_SHADER_CONSTANT" );
+ Dx9Device()->SetPixelShaderConstantB( dptr[1], (int const *) dptr+3, dptr[2]);
+ dptr += 3+dptr[2];
+ break;
+ }
+
+ case PBCMD_SET_INTEGER_PIXEL_SHADER_CONSTANT:
+ {
+ VPROF_BUFFER_PLAYBACK( "SET_INTEGER_PIXEL_SHADER_CONSTANT" );
+ Dx9Device()->SetPixelShaderConstantI( dptr[1], (int const *) dptr+3, dptr[2]);
+ dptr += 3+4*dptr[2];
+ break;
+ }
+
+ case PBCMD_BEGIN_SCENE:
+ {
+ VPROF_BUFFER_PLAYBACK( "BEGIN_SCENE" );
+ Dx9Device()->BeginScene();
+ dptr++;
+ break;
+ }
+
+ case PBCMD_END_SCENE:
+ {
+ VPROF_BUFFER_PLAYBACK( "END_SCENE" );
+ Dx9Device()->EndScene();
+ dptr++;
+ break;
+ }
+
+ case PBCMD_CLEAR:
+ {
+ VPROF_BUFFER_PLAYBACK( "CLEAR" );
+ dptr++;
+ int count=*(dptr++);
+ D3DRECT const *pRects=0;
+ if (count)
+ {
+ pRects=(D3DRECT const *) dptr;
+ dptr+=count*N_DWORDS( D3DRECT );
+ }
+ int flags=*(dptr++);
+ D3DCOLOR color=*((D3DCOLOR const *) (dptr++));
+ float z=*((float const *) (dptr++));
+ int stencil=*(dptr++);
+ Dx9Device()->Clear( count, pRects, flags, color, z, stencil );
+ break;
+ }
+
+ case PBCMD_SET_VERTEXDECLARATION:
+ {
+ VPROF_BUFFER_PLAYBACK( "SET_VERTEXDECLARATION" );
+ Dx9Device()->SetVertexDeclaration( (IDirect3DVertexDeclaration9 *) FetchPtr(dptr+1));
+ dptr += 1+N_DWORDS_IN_PTR;
+ break;
+ }
+
+ case PBCMD_SETCLIPPLANE:
+ {
+ VPROF_BUFFER_PLAYBACK( "SETCLIPPLANE" );
+ Dx9Device()->SetClipPlane( dptr[1], (float const *) dptr+2 );
+ dptr+=6;
+ }
+ break;
+
+ case PBCMD_STRETCHRECT:
+ {
+ VPROF_BUFFER_PLAYBACK( "STRETCHRECT" );
+ dptr++;
+ IDirect3DSurface9 *pSourceSurface=(IDirect3DSurface9 *) FetchPtr(dptr);
+ dptr+=N_DWORDS_IN_PTR;
+ RECT const *pSourceRect=0;
+ if (*(dptr++))
+ pSourceRect=(RECT const *) dptr;
+ dptr += N_DWORDS( RECT );
+ IDirect3DSurface9 *pDestSurface= (IDirect3DSurface9 *) FetchPtr( dptr );
+ dptr += N_DWORDS_IN_PTR;
+ RECT const *pDestRect=0;
+ if (*(dptr++))
+ pDestRect=(RECT const *) dptr;
+ dptr += N_DWORDS( RECT );
+ D3DTEXTUREFILTERTYPE Filter = (D3DTEXTUREFILTERTYPE) *(dptr++);
+ Dx9Device()->StretchRect( pSourceSurface, pSourceRect,
+ pDestSurface, pDestRect,
+ Filter );
+ }
+ break;
+
+
+ case PBCMD_PRESENT:
+ {
+ VPROF_BUFFER_PLAYBACK( "PRESENT" );
+ dptr++;
+ RECT const *pSourceRect=0;
+ if (* (dptr++) )
+ pSourceRect=(RECT const *) dptr;
+ dptr+=N_DWORDS( RECT );
+ RECT const *pDestRect = 0;
+ if (* (dptr++) )
+ pDestRect=(RECT const *) dptr;
+ dptr+=N_DWORDS( RECT );
+ VD3DHWND hDestWindowOverride = (VD3DHWND) *(dptr++);
+ RGNDATA const *pDirtyRegion=0;
+ if ( *(dptr++) )
+ pDirtyRegion= (RGNDATA const *) dptr;
+ dptr+=N_DWORDS( RGNDATA );
+
+ tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "!D3DPresent" );
+
+ Dx9Device()->Present( pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion );
+ break;
+ }
+
+ case PBCMD_SET_SCISSOR_RECT:
+ {
+ VPROF_BUFFER_PLAYBACK( "SET_SCISSOR_RECT" );
+ dptr++;
+ const RECT *pRect = ( RECT * )FetchPtr( dptr );
+ dptr += sizeof( RECT );
+ Dx9Device()->SetScissorRect( pRect );
+ }
+ }
+ }
+}
+
+#endif
+
+#endif // D3D_ASYNC_SUPPORTED
diff --git a/materialsystem/shaderapidx9/d3d_async.h b/materialsystem/shaderapidx9/d3d_async.h
new file mode 100644
index 0000000..7deb2f3
--- /dev/null
+++ b/materialsystem/shaderapidx9/d3d_async.h
@@ -0,0 +1,1567 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#ifdef D3D_ASYNC_SUPPORTED
+
+#ifndef D3DASYNC_H
+#define D3DASYNC_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+// Set this to 1 to allow d3d calls to be buffered and played back on another thread
+// Slamming this off - it's causing very hot D3D9 function calls to not be inlined and contain a bunch of unused code. (Does this code even work/add real value any more?)
+#define SHADERAPI_USE_SMP 0
+
+// Set this to 1 to allow buffering of the whole frame to memory and then playback (singlethreaded).
+// This is for debugging only and is used to test the performance of just calling D3D and rendering without other CPU overhead.
+#define SHADERAPI_BUFFER_D3DCALLS 0
+
+#if SHADERAPI_BUFFER_D3DCALLS && !SHADERAPI_USE_SMP
+# error "SHADERAPI_USE_SMP must be 1 for SHADERAPI_BUFFER_D3DCALLS to work!"
+#endif
+
+#include "recording.h"
+#include "strtools.h"
+#include "glmgr/dxabstract.h"
+
+#ifdef NDEBUG
+#define DO_D3D(x) Dx9Device()->x
+#else
+#define DO_D3D(x) Dx9Device()->x
+//#define DO_D3D(x) { HRESULT hr=Dx9Device()->x; Assert( !FAILED(hr) ); }
+#endif
+
+#define PUSHBUFFER_NELEMS 4096
+
+enum PushBufferState
+{
+ PUSHBUFFER_AVAILABLE,
+ PUSHBUFFER_BEING_FILLED,
+ PUSHBUFFER_SUBMITTED,
+ PUSHBUFFER_BEING_USED_FOR_LOCKEDDATA,
+};
+
+class PushBuffer
+{
+ friend class D3DDeviceWrapper;
+
+ volatile PushBufferState m_State;
+ uint32 m_BufferData[PUSHBUFFER_NELEMS];
+public:
+ PushBuffer(void)
+ {
+ m_State = PUSHBUFFER_AVAILABLE;
+ }
+};
+
+// When running multithreaded, lock for write calls actually return a pointer to temporary memory
+// buffer. When the buffer is later unlocked by the caller, data must be queued with the Unlock()
+// that lets the d3d thread know how much data to copy from where. One possible optimization for
+// things which write a lot of data into lock buffers woudl be to proviude a way for the caller to
+// occasionally check if the Lock() has been dequeued. If so, the the data pushed so far could be
+// copied asynchronously into the buffer, while the caller would be told to switch to writing
+// directly to the vertex buffer.
+//
+// another possibility would be lock()ing in advance for large ones, such as the world renderer,
+// or keeping multiple locked vb's open for meshbuilder.
+
+struct LockedBufferContext
+{
+ PushBuffer *m_pPushBuffer; // if a push buffer was used to hold
+ // the temporary data, this will be non-null
+ void *m_pMallocedMemory; // if memory had to be malloc'd, this will be set.
+
+ size_t m_MallocSize; // # of bytes malloced if mallocedmem ptr non-null
+
+ LockedBufferContext( void )
+ {
+ m_pPushBuffer = NULL;
+ m_pMallocedMemory = NULL;
+ }
+
+};
+
+
+
+// push buffer commands follow
+enum PushBufferCommand
+{
+ PBCMD_END, // at end of push buffer
+ PBCMD_SET_RENDERSTATE, // state, val
+ PBCMD_SET_TEXTURE, // stage, txtr
+ PBCMD_DRAWPRIM, // prim type, start v, nprims
+ PBCMD_DRAWINDEXEDPRIM, // prim type, baseidx, minidx, numv, starti, pcount
+ PBCMD_SET_PIXEL_SHADER, // shaderptr
+ PBCMD_SET_VERTEX_SHADER, // shaderptr
+ PBCMD_SET_PIXEL_SHADER_CONSTANT, // startreg, nregs, data...
+ PBCMD_SET_BOOLEAN_PIXEL_SHADER_CONSTANT, // startreg, nregs, data...
+ PBCMD_SET_INTEGER_PIXEL_SHADER_CONSTANT, // startreg, nregs, data...
+ PBCMD_SET_VERTEX_SHADER_CONSTANT, // startreg, nregs, data...
+ PBCMD_SET_BOOLEAN_VERTEX_SHADER_CONSTANT, // startreg, nregs, data...
+ PBCMD_SET_INTEGER_VERTEX_SHADER_CONSTANT, // startreg, nregs, data...
+ PBCMD_SET_RENDER_TARGET, // idx, targetptr
+ PBCMD_SET_DEPTH_STENCIL_SURFACE, // surfptr
+ PBCMD_SET_STREAM_SOURCE, // idx, sptr, ofs, stride
+ PBCMD_SET_INDICES, // idxbuffer
+ PBCMD_SET_SAMPLER_STATE, // stage, state, val
+ PBCMD_UNLOCK_VB, // vptr
+ PBCMD_UNLOCK_IB, // idxbufptr
+ PBCMD_SETVIEWPORT, // vp_struct
+ PBCMD_CLEAR, // count, n rect structs, flags, color, z, stencil
+ PBCMD_SET_VERTEXDECLARATION, // vdeclptr
+ PBCMD_BEGIN_SCENE, //
+ PBCMD_END_SCENE, //
+ PBCMD_PRESENT, // complicated..see code
+ PBCMD_SETCLIPPLANE, // idx, 4 floats
+ PBCMD_STRETCHRECT, // see code
+ PBCMD_ASYNC_LOCK_VB, // see code
+ PBCMD_ASYNC_UNLOCK_VB,
+ PBCMD_ASYNC_LOCK_IB, // see code
+ PBCMD_ASYNC_UNLOCK_IB,
+ PBCMD_SET_SCISSOR_RECT, // RECT
+};
+
+
+
+#define N_DWORDS( x ) (( sizeof(x)+3)/sizeof( DWORD ))
+#define N_DWORDS_IN_PTR (N_DWORDS( void * ))
+
+class D3DDeviceWrapper
+{
+private:
+ IDirect3DDevice9 *m_pD3DDevice;
+ bool m_bSupportsTessellation;
+ int m_nCurrentTessLevel;
+ TessellationMode_t m_nTessellationMode;
+
+#if SHADERAPI_USE_SMP
+ uintptr_t m_pASyncThreadHandle;
+ PushBuffer *m_pCurPushBuffer;
+ uint32 *m_pOutputPtr;
+ size_t m_PushBufferFreeSlots;
+#endif
+
+#if SHADERAPI_BUFFER_D3DCALLS
+ bool m_bBufferingD3DCalls;
+# define SHADERAPI_BUFFER_MAXRENDERTARGETS 4
+ IDirect3DSurface9 *m_StoredRenderTargets[SHADERAPI_BUFFER_MAXRENDERTARGETS];
+#endif
+
+ PushBuffer *FindFreePushBuffer( PushBufferState newstate ); // find a free push buffer and change its state
+
+ void GetPushBuffer(void); // set us up to point at a new push buffer
+ void SubmitPushBufferAndGetANewOne(void); // submit the current push buffer
+ void ExecutePushBuffer( PushBuffer const *pb);
+
+#if SHADERAPI_USE_SMP
+ void Synchronize(void); // wait for all commands to be done
+#else
+ FORCEINLINE void Synchronize(void)
+ {
+ }
+#endif
+
+
+ void SubmitIfNotBusy(void);
+
+#if SHADERAPI_USE_SMP
+ template<class T> FORCEINLINE void PushStruct( PushBufferCommand cmd, T const *str )
+ {
+ int nwords=N_DWORDS( T );
+ AllocatePushBufferSpace( 1+ nwords );
+ m_pOutputPtr[0]=cmd;
+ memcpy( m_pOutputPtr+1, str, sizeof( T ) );
+ m_pOutputPtr += 1+nwords;
+ }
+
+ FORCEINLINE void AllocatePushBufferSpace(size_t nSlots)
+ {
+ // check for N slots of space, and decrement amount of space left
+ if ( nSlots>m_PushBufferFreeSlots ) // out of room?
+ {
+ SubmitPushBufferAndGetANewOne();
+ }
+ m_PushBufferFreeSlots -= nSlots;
+ }
+
+ // simple methods for pushing a few words into output buffer
+ FORCEINLINE void Push( PushBufferCommand cmd )
+ {
+ AllocatePushBufferSpace(1);
+ m_pOutputPtr[0]=cmd;
+ m_pOutputPtr++;
+ }
+
+ FORCEINLINE void Push( PushBufferCommand cmd, int arg1)
+ {
+ AllocatePushBufferSpace(2);
+ m_pOutputPtr[0]=cmd;
+ m_pOutputPtr[1]=arg1;
+ m_pOutputPtr += 2;
+ }
+
+ FORCEINLINE void Push( PushBufferCommand cmd, void *ptr )
+ {
+ AllocatePushBufferSpace(1+N_DWORDS_IN_PTR);
+ *(m_pOutputPtr++)=cmd;
+ *((void **) m_pOutputPtr)=ptr;
+ m_pOutputPtr+=N_DWORDS_IN_PTR;
+ }
+
+ FORCEINLINE void Push( PushBufferCommand cmd, void *ptr, void *ptr1 )
+ {
+ AllocatePushBufferSpace(1+2*N_DWORDS_IN_PTR);
+ *(m_pOutputPtr++)=cmd;
+ *((void **) m_pOutputPtr)=ptr;
+ m_pOutputPtr+=N_DWORDS_IN_PTR;
+ *((void **) m_pOutputPtr)=ptr1;
+ m_pOutputPtr+=N_DWORDS_IN_PTR;
+ }
+
+ FORCEINLINE void Push( PushBufferCommand cmd, void *arg1, uint32 arg2, uint32 arg3, uint32 arg4,
+ void *arg5)
+ {
+ AllocatePushBufferSpace(1+N_DWORDS_IN_PTR+1+1+1+N_DWORDS_IN_PTR);
+ *(m_pOutputPtr++)=cmd;
+ *((void **) m_pOutputPtr)=arg1;
+ m_pOutputPtr+=N_DWORDS_IN_PTR;
+ *(m_pOutputPtr++)=arg2;
+ *(m_pOutputPtr++)=arg3;
+ *(m_pOutputPtr++)=arg4;
+ *((void **) m_pOutputPtr)=arg5;
+ m_pOutputPtr+=N_DWORDS_IN_PTR;
+
+ }
+
+ FORCEINLINE void Push( PushBufferCommand cmd, uint32 arg1, void *ptr )
+ {
+ AllocatePushBufferSpace(2+N_DWORDS_IN_PTR);
+ *(m_pOutputPtr++)=cmd;
+ *(m_pOutputPtr++)=arg1;
+ *((void **) m_pOutputPtr)=ptr;
+ m_pOutputPtr+=N_DWORDS_IN_PTR;
+ }
+
+ FORCEINLINE void Push( PushBufferCommand cmd, uint32 arg1, void *ptr, int arg2, int arg3 )
+ {
+ AllocatePushBufferSpace( 4+N_DWORDS_IN_PTR );
+ *(m_pOutputPtr++)=cmd;
+ *(m_pOutputPtr++)=arg1;
+ *((void **) m_pOutputPtr)=ptr;
+ m_pOutputPtr+=N_DWORDS_IN_PTR;
+ m_pOutputPtr[0]=arg2;
+ m_pOutputPtr[1]=arg3;
+ m_pOutputPtr += 2;
+ }
+
+ FORCEINLINE void Push( PushBufferCommand cmd, int arg1, int arg2)
+ {
+ AllocatePushBufferSpace(3);
+ m_pOutputPtr[0]=cmd;
+ m_pOutputPtr[1]=arg1;
+ m_pOutputPtr[2]=arg2;
+ m_pOutputPtr += 3;
+ }
+
+ FORCEINLINE void Push( PushBufferCommand cmd, int arg1, int arg2, int arg3)
+ {
+ AllocatePushBufferSpace(4);
+ m_pOutputPtr[0]=cmd;
+ m_pOutputPtr[1]=arg1;
+ m_pOutputPtr[2]=arg2;
+ m_pOutputPtr[3]=arg3;
+ m_pOutputPtr += 4;
+ }
+
+ FORCEINLINE void Push( PushBufferCommand cmd, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6 )
+ {
+ AllocatePushBufferSpace(7);
+ m_pOutputPtr[0]=cmd;
+ m_pOutputPtr[1]=arg1;
+ m_pOutputPtr[2]=arg2;
+ m_pOutputPtr[3]=arg3;
+ m_pOutputPtr[4]=arg4;
+ m_pOutputPtr[5]=arg5;
+ m_pOutputPtr[6]=arg6;
+ m_pOutputPtr += 7;
+ }
+
+#else
+ template<class T> FORCEINLINE void PushStruct( PushBufferCommand cmd, T const *str )
+ {
+ }
+
+ FORCEINLINE void AllocatePushBufferSpace(size_t nSlots)
+ {
+ }
+
+ // simple methods for pushing a few words into output buffer
+ FORCEINLINE void Push( PushBufferCommand cmd )
+ {
+ }
+
+ FORCEINLINE void Push( PushBufferCommand cmd, int arg1)
+ {
+ }
+
+ FORCEINLINE void Push( PushBufferCommand cmd, void *ptr )
+ {
+ }
+
+ FORCEINLINE void Push( PushBufferCommand cmd, void *ptr, void *ptr1 )
+ {
+ }
+
+ FORCEINLINE void Push( PushBufferCommand cmd, void *arg1, uint32 arg2, uint32 arg3, uint32 arg4,
+ void *arg5)
+ {
+ }
+
+ FORCEINLINE void Push( PushBufferCommand cmd, uint32 arg1, void *ptr )
+ {
+ }
+
+ FORCEINLINE void Push( PushBufferCommand cmd, uint32 arg1, void *ptr, int arg2, int arg3 )
+ {
+ }
+
+ FORCEINLINE void Push( PushBufferCommand cmd, int arg1, int arg2)
+ {
+ }
+
+ FORCEINLINE void Push( PushBufferCommand cmd, int arg1, int arg2, int arg3)
+ {
+ }
+
+ FORCEINLINE void Push( PushBufferCommand cmd, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6 )
+ {
+ }
+
+#endif
+
+ FORCEINLINE bool ASyncMode(void) const
+ {
+#if SHADERAPI_USE_SMP
+# if SHADERAPI_BUFFER_D3DCALLS
+ return m_bBufferingD3DCalls;
+# else
+ return (m_pASyncThreadHandle != 0 );
+# endif
+#else
+ return false;
+#endif
+ }
+
+ FORCEINLINE IDirect3DDevice9* Dx9Device(void) const
+ {
+ return m_pD3DDevice;
+ }
+
+ void AsynchronousLock( IDirect3DVertexBuffer9* vb, size_t offset, size_t size, void **ptr,
+ DWORD flags,
+ LockedBufferContext *lb);
+
+ void AsynchronousLock( IDirect3DIndexBuffer9* ib, size_t offset, size_t size, void **ptr,
+ DWORD flags,
+ LockedBufferContext *lb);
+
+ // handlers for push buffer contexts
+ void HandleAsynchronousLockVBCommand( uint32 const *dptr );
+ void HandleAsynchronousUnLockVBCommand( uint32 const *dptr );
+ void HandleAsynchronousLockIBCommand( uint32 const *dptr );
+ void HandleAsynchronousUnLockIBCommand( uint32 const *dptr );
+
+public:
+
+#if SHADERAPI_BUFFER_D3DCALLS
+ void ExecuteAllWork( void );
+#endif
+ void RunThread( void ); // this is what the worker thread runs
+
+ void SetASyncMode( bool onoff );
+
+
+ bool IsActive( void )const
+ {
+ return m_pD3DDevice != NULL;
+ }
+
+ void D3DeviceWrapper(void)
+ {
+ m_pD3DDevice = 0;
+#if SHADERAPI_USE_SMP
+ m_pASyncThreadHandle = 0;
+#endif
+#if SHADERAPI_BUFFER_D3DCALLS
+ m_bBufferingD3DCalls = false;
+#endif
+ }
+
+ void SetDevicePtr(IDirect3DDevice9 *pD3DDev )
+ {
+ m_pD3DDevice = pD3DDev;
+ }
+
+ void SetSupportsTessellation( bool bSupportsTessellation )
+ {
+ m_bSupportsTessellation = bSupportsTessellation;
+ }
+
+ void ShutDownDevice(void)
+ {
+ if ( ASyncMode() )
+ {
+ // sync w/ thread
+ }
+ m_pD3DDevice = 0;
+ }
+
+ void FORCEINLINE SetDepthStencilSurface( IDirect3DSurface9 *new_stencil )
+ {
+ if ( ASyncMode() )
+ Push( PBCMD_SET_DEPTH_STENCIL_SURFACE, new_stencil );
+ else
+ DO_D3D( SetDepthStencilSurface( new_stencil ) );
+ }
+
+ HRESULT CreateCubeTexture(
+ UINT EdgeLength,
+ UINT Levels,
+ DWORD Usage,
+ D3DFORMAT Format,
+ D3DPOOL Pool,
+ IDirect3DCubeTexture9 ** ppCubeTexture,
+ HANDLE* pSharedHandle,
+ char *debugLabel = NULL // <-- OK to not pass this arg, only passed through on DX_TO_GL_ABSTRACTION
+ )
+ {
+ Synchronize();
+ return m_pD3DDevice->CreateCubeTexture( EdgeLength, Levels, Usage, Format, Pool,
+ ppCubeTexture, pSharedHandle
+ #if defined( DX_TO_GL_ABSTRACTION )
+ ,debugLabel
+ #endif
+ );
+ }
+
+ HRESULT CreateVolumeTexture(
+ UINT Width,
+ UINT Height,
+ UINT Depth,
+ UINT Levels,
+ DWORD Usage,
+ D3DFORMAT Format,
+ D3DPOOL Pool,
+ IDirect3DVolumeTexture9** ppVolumeTexture,
+ HANDLE* pSharedHandle,
+ char *debugLabel = NULL // <-- OK to not pass this arg, only passed through on DX_TO_GL_ABSTRACTION
+ )
+ {
+ Synchronize();
+ return m_pD3DDevice->CreateVolumeTexture( Width, Height, Depth, Levels,
+ Usage, Format, Pool, ppVolumeTexture,
+ pSharedHandle
+ #if defined( DX_TO_GL_ABSTRACTION )
+ ,debugLabel
+ #endif
+ );
+ }
+
+ HRESULT CreateOffscreenPlainSurface( UINT Width,
+ UINT Height,
+ D3DFORMAT Format,
+ D3DPOOL Pool,
+ IDirect3DSurface9** ppSurface,
+ HANDLE* pSharedHandle)
+ {
+ Synchronize();
+ return m_pD3DDevice->CreateOffscreenPlainSurface( Width, Height, Format, Pool,
+ ppSurface, pSharedHandle);
+ }
+
+ HRESULT CreateTexture(
+ UINT Width,
+ UINT Height,
+ UINT Levels,
+ DWORD Usage,
+ D3DFORMAT Format,
+ D3DPOOL Pool,
+ IDirect3DTexture9** ppTexture,
+ HANDLE* pSharedHandle,
+ char *debugLabel = NULL // <-- OK to not pass this arg, only passed through on DX_TO_GL_ABSTRACTION
+ )
+ {
+ Synchronize();
+ return m_pD3DDevice->CreateTexture( Width, Height, Levels, Usage,
+ Format, Pool, ppTexture, pSharedHandle
+ #if defined( DX_TO_GL_ABSTRACTION )
+ ,debugLabel
+ #endif
+ );
+ }
+
+ HRESULT GetRenderTargetData(
+ IDirect3DSurface9* pRenderTarget,
+ IDirect3DSurface9* pDestSurface
+ )
+ {
+ Synchronize();
+ return m_pD3DDevice->GetRenderTargetData( pRenderTarget, pDestSurface );
+ }
+
+
+ void GetDeviceCaps( D3DCAPS9 * pCaps )
+ {
+ Synchronize();
+ m_pD3DDevice->GetDeviceCaps( pCaps );
+ }
+
+ LPCSTR GetPixelShaderProfile( void )
+ {
+ Synchronize();
+ return D3DXGetPixelShaderProfile( m_pD3DDevice );
+ }
+
+ HRESULT TestCooperativeLevel( void )
+ {
+ // hack! We are going to assume that calling this immediately when in buffered mode isn't going to cause problems.
+#if !SHADERAPI_BUFFER_D3DCALLS
+ Synchronize();
+#endif
+ return m_pD3DDevice->TestCooperativeLevel();
+ }
+
+ HRESULT GetFrontBufferData( UINT iSwapChain, IDirect3DSurface9 * pDestSurface )
+ {
+ Synchronize();
+ return m_pD3DDevice->GetFrontBufferData( iSwapChain, pDestSurface );
+ }
+
+ void SetGammaRamp( int swapchain, int flags, D3DGAMMARAMP const *pRamp)
+ {
+ Synchronize();
+ m_pD3DDevice->SetGammaRamp( swapchain, flags, pRamp);
+ }
+
+ HRESULT GetTexture( DWORD Stage, IDirect3DBaseTexture9 ** ppTexture )
+ {
+ Synchronize();
+ return m_pD3DDevice->GetTexture( Stage, ppTexture );
+ }
+
+ HRESULT GetFVF( DWORD * pFVF )
+ {
+ Synchronize();
+ return m_pD3DDevice->GetFVF( pFVF );
+ }
+
+ HRESULT GetDepthStencilSurface(
+ IDirect3DSurface9 ** ppZStencilSurface
+ )
+ {
+ Synchronize();
+ return m_pD3DDevice->GetDepthStencilSurface( ppZStencilSurface );
+ }
+
+ FORCEINLINE void SetClipPlane( int idx, float const * pplane)
+ {
+ RECORD_COMMAND( DX8_SET_CLIP_PLANE, 5 );
+ RECORD_INT( idx );
+ RECORD_FLOAT( pplane[0] );
+ RECORD_FLOAT( pplane[1] );
+ RECORD_FLOAT( pplane[2] );
+ RECORD_FLOAT( pplane[3] );
+#if SHADERAPI_USE_SMP
+ if ( ASyncMode() )
+ {
+ AllocatePushBufferSpace( 6 );
+ m_pOutputPtr[0]=PBCMD_SETCLIPPLANE;
+ m_pOutputPtr[1]=idx;
+ memcpy(m_pOutputPtr+2,pplane, 4*sizeof(float) );
+ m_pOutputPtr += 6;
+ }
+ else
+#endif
+ DO_D3D( SetClipPlane( idx, pplane ) );
+ }
+
+ FORCEINLINE void SetVertexDeclaration( IDirect3DVertexDeclaration9 *decl )
+ {
+ RECORD_COMMAND( DX8_SET_VERTEX_DECLARATION, 1 );
+ RECORD_INT( ( int ) decl );
+
+#if SHADERAPI_USE_SMP
+ if ( ASyncMode() )
+ {
+ Push( PBCMD_SET_VERTEXDECLARATION, decl );
+ }
+ else
+#endif
+ DO_D3D( SetVertexDeclaration( decl ) );
+ }
+
+ FORCEINLINE void SetViewport( D3DVIEWPORT9 const *vp )
+ {
+ RECORD_COMMAND( DX8_SET_VIEWPORT, 1 );
+ RECORD_STRUCT( vp, sizeof( *vp ));
+
+#if SHADERAPI_USE_SMP
+ if ( ASyncMode() )
+ PushStruct( PBCMD_SETVIEWPORT, vp );
+ else
+#endif
+ DO_D3D( SetViewport( vp ) );
+ }
+
+ HRESULT GetRenderTarget(
+ DWORD RenderTargetIndex,
+ IDirect3DSurface9 ** ppRenderTarget)
+ {
+#if SHADERAPI_BUFFER_D3DCALLS
+ if ( ASyncMode() )
+ {
+ Assert( RenderTargetIndex >= 0 && RenderTargetIndex < SHADERAPI_BUFFER_MAXRENDERTARGETS );
+ *ppRenderTarget = m_StoredRenderTargets[RenderTargetIndex];
+ return D3D_OK;
+ }
+#endif
+ Synchronize();
+ return m_pD3DDevice->GetRenderTarget( RenderTargetIndex, ppRenderTarget );
+ }
+
+ HRESULT CreateQuery( D3DQUERYTYPE Type, IDirect3DQuery9** ppQuery )
+ {
+ Synchronize();
+ return m_pD3DDevice->CreateQuery( Type, ppQuery );
+ }
+
+ HRESULT CreateRenderTarget(
+ UINT Width,
+ UINT Height,
+ D3DFORMAT Format,
+ D3DMULTISAMPLE_TYPE MultiSample,
+ DWORD MultisampleQuality,
+ BOOL Lockable,
+ IDirect3DSurface9** ppSurface,
+ HANDLE* pSharedHandle
+ )
+ {
+ Synchronize();
+ return m_pD3DDevice->CreateRenderTarget( Width, Height, Format, MultiSample,
+ MultisampleQuality, Lockable, ppSurface,
+ pSharedHandle);
+ }
+
+ HRESULT CreateDepthStencilSurface(
+ UINT Width,
+ UINT Height,
+ D3DFORMAT Format,
+ D3DMULTISAMPLE_TYPE MultiSample,
+ DWORD MultisampleQuality,
+ BOOL Discard,
+ IDirect3DSurface9** ppSurface,
+ HANDLE* pSharedHandle
+ )
+ {
+ Synchronize();
+ return m_pD3DDevice->CreateDepthStencilSurface( Width, Height, Format, MultiSample,
+ MultisampleQuality, Discard, ppSurface,
+ pSharedHandle );
+ }
+
+
+ FORCEINLINE void SetRenderTarget( int idx, IDirect3DSurface9 *new_rt )
+ {
+ if (ASyncMode())
+ {
+ Push( PBCMD_SET_RENDER_TARGET, idx, new_rt );
+#if SHADERAPI_BUFFER_D3DCALLS
+ m_StoredRenderTargets[idx] = new_rt;
+#endif
+ }
+ else
+ {
+ // NOTE: If the debug runtime breaks here on the shadow depth render target that is normal. dx9 doesn't directly support shadow
+ // depth texturing so we are forced to initialize this texture without the render target flagr
+ DO_D3D( SetRenderTarget( idx, new_rt) );
+ }
+ }
+
+ FORCEINLINE void LightEnable( int lidx, bool onoff )
+ {
+ RECORD_COMMAND( DX8_LIGHT_ENABLE, 2 );
+ RECORD_INT( lidx );
+ RECORD_INT( onoff );
+
+ Synchronize();
+ DO_D3D( LightEnable( lidx, onoff ) );
+ }
+
+ FORCEINLINE void SetRenderState( D3DRENDERSTATETYPE state, DWORD val )
+ {
+// Assert( state >= 0 && state < MAX_NUM_RENDERSTATES );
+ RECORD_RENDER_STATE( state, val );
+ if (ASyncMode())
+ {
+ Push( PBCMD_SET_RENDERSTATE, state, val );
+ }
+ else
+ DO_D3D( SetRenderState( state, val ) );
+ }
+
+ FORCEINLINE void SetRenderStateInline( D3DRENDERSTATETYPE state, DWORD val )
+ {
+ // Assert( state >= 0 && state < MAX_NUM_RENDERSTATES );
+ RECORD_RENDER_STATE( state, val );
+ if (ASyncMode())
+ {
+ SetRenderState( state, val );
+ }
+ else
+ {
+#ifdef DX_TO_GL_ABSTRACTION
+ DO_D3D( SetRenderStateInline( state, val ) );
+#else
+ DO_D3D( SetRenderState( state, val ) );
+#endif
+ }
+ }
+
+ FORCEINLINE void SetScissorRect( const RECT *pScissorRect )
+ {
+ RECORD_COMMAND( DX8_SET_SCISSOR_RECT, 1 );
+ RECORD_STRUCT( pScissorRect, 4 * sizeof(LONG) );
+#if SHADERAPI_USE_SMP
+ if ( ASyncMode() )
+ {
+ AllocatePushBufferSpace( 5 );
+ m_pOutputPtr[0] = PBCMD_SET_SCISSOR_RECT;
+ memcpy( m_pOutputPtr + 1, pScissorRect, sizeof( *pScissorRect ) );
+ }
+ else
+#endif
+ DO_D3D( SetScissorRect( pScissorRect ) );
+ }
+
+ FORCEINLINE void SetVertexShaderConstantF( UINT StartRegister, CONST float * pConstantData,
+ UINT Vector4fCount)
+ {
+ RECORD_COMMAND( DX8_SET_VERTEX_SHADER_CONSTANT, 3 );
+ RECORD_INT( StartRegister );
+ RECORD_INT( Vector4fCount );
+ RECORD_STRUCT( pConstantData, Vector4fCount * 4 * sizeof(float) );
+#if SHADERAPI_USE_SMP
+ if ( ASyncMode() )
+ {
+ AllocatePushBufferSpace(3+4*Vector4fCount);
+ m_pOutputPtr[0]=PBCMD_SET_VERTEX_SHADER_CONSTANT;
+ m_pOutputPtr[1]=StartRegister;
+ m_pOutputPtr[2]=Vector4fCount;
+ memcpy(m_pOutputPtr+3,pConstantData,sizeof(float)*4*Vector4fCount);
+ m_pOutputPtr+=3+4*Vector4fCount;
+ }
+ else
+#endif
+ DO_D3D( SetVertexShaderConstantF( StartRegister, pConstantData, Vector4fCount ) );
+ }
+
+ FORCEINLINE void SetVertexShaderConstantB( UINT StartRegister, CONST int * pConstantData,
+ UINT BoolCount)
+ {
+ RECORD_COMMAND( DX8_SET_VERTEX_SHADER_CONSTANT, 3 );
+ RECORD_INT( StartRegister );
+ RECORD_INT( BoolCount );
+ RECORD_STRUCT( pConstantData, BoolCount * sizeof(int) );
+#if SHADERAPI_USE_SMP
+ if ( ASyncMode() )
+ {
+ AllocatePushBufferSpace(3+BoolCount);
+ m_pOutputPtr[0]=PBCMD_SET_BOOLEAN_VERTEX_SHADER_CONSTANT;
+ m_pOutputPtr[1]=StartRegister;
+ m_pOutputPtr[2]=BoolCount;
+ memcpy(m_pOutputPtr+3,pConstantData,sizeof(int)*BoolCount);
+ m_pOutputPtr+=3+BoolCount;
+ }
+ else
+#endif
+ DO_D3D( SetVertexShaderConstantB( StartRegister, pConstantData, BoolCount ) );
+ }
+
+ FORCEINLINE void SetVertexShaderConstantI( UINT StartRegister, CONST int * pConstantData,
+ UINT Vector4IntCount)
+ {
+ RECORD_COMMAND( DX8_SET_VERTEX_SHADER_CONSTANT, 3 );
+ RECORD_INT( StartRegister );
+ RECORD_INT( Vector4IntCount );
+ RECORD_STRUCT( pConstantData, Vector4IntCount * 4 * sizeof(int) );
+#if SHADERAPI_USE_SMP
+ if ( ASyncMode() )
+ {
+ AllocatePushBufferSpace(3+4*Vector4IntCount);
+ m_pOutputPtr[0]=PBCMD_SET_INTEGER_VERTEX_SHADER_CONSTANT;
+ m_pOutputPtr[1]=StartRegister;
+ m_pOutputPtr[2]=Vector4IntCount;
+ memcpy(m_pOutputPtr+3,pConstantData,sizeof(int)*4*Vector4IntCount);
+ m_pOutputPtr+=3+4*Vector4IntCount;
+ }
+ else
+#endif
+ DO_D3D( SetVertexShaderConstantI( StartRegister, pConstantData, Vector4IntCount ) );
+ }
+
+ FORCEINLINE void SetPixelShaderConstantF( UINT StartRegister, CONST float * pConstantData,
+ UINT Vector4fCount)
+ {
+ RECORD_COMMAND( DX8_SET_PIXEL_SHADER_CONSTANT, 3 );
+ RECORD_INT( StartRegister );
+ RECORD_INT( Vector4fCount );
+ RECORD_STRUCT( pConstantData, Vector4fCount * 4 * sizeof(float) );
+#if SHADERAPI_USE_SMP
+ if ( ASyncMode() )
+ {
+ AllocatePushBufferSpace(3+4*Vector4fCount);
+ m_pOutputPtr[0]=PBCMD_SET_PIXEL_SHADER_CONSTANT;
+ m_pOutputPtr[1]=StartRegister;
+ m_pOutputPtr[2]=Vector4fCount;
+ memcpy(m_pOutputPtr+3,pConstantData,sizeof(float)*4*Vector4fCount);
+ m_pOutputPtr+=3+4*Vector4fCount;
+ }
+ else
+#endif
+ DO_D3D( SetPixelShaderConstantF( StartRegister, pConstantData, Vector4fCount ) );
+ }
+
+ FORCEINLINE void SetPixelShaderConstantB( UINT StartRegister, CONST int * pConstantData,
+ UINT BoolCount)
+ {
+ RECORD_COMMAND( DX8_SET_PIXEL_SHADER_CONSTANT, 3 );
+ RECORD_INT( StartRegister );
+ RECORD_INT( BoolCount );
+ RECORD_STRUCT( pConstantData, BoolCount * sizeof(int) );
+#if SHADERAPI_USE_SMP
+ if ( ASyncMode() )
+ {
+ AllocatePushBufferSpace(3+BoolCount);
+ m_pOutputPtr[0]=PBCMD_SET_BOOLEAN_PIXEL_SHADER_CONSTANT;
+ m_pOutputPtr[1]=StartRegister;
+ m_pOutputPtr[2]=BoolCount;
+ memcpy(m_pOutputPtr+3,pConstantData,sizeof(int)*BoolCount);
+ m_pOutputPtr+=3+BoolCount;
+ }
+ else
+#endif
+ DO_D3D( SetPixelShaderConstantB( StartRegister, pConstantData, BoolCount ) );
+ }
+
+ FORCEINLINE void SetPixelShaderConstantI( UINT StartRegister, CONST int * pConstantData,
+ UINT Vector4IntCount)
+ {
+ RECORD_COMMAND( DX8_SET_PIXEL_SHADER_CONSTANT, 3 );
+ RECORD_INT( StartRegister );
+ RECORD_INT( Vector4IntCount );
+ RECORD_STRUCT( pConstantData, Vector4IntCount * 4 * sizeof(int) );
+#if SHADERAPI_USE_SMP
+ if ( ASyncMode() )
+ {
+ AllocatePushBufferSpace(3+4*Vector4IntCount);
+ m_pOutputPtr[0]=PBCMD_SET_INTEGER_PIXEL_SHADER_CONSTANT;
+ m_pOutputPtr[1]=StartRegister;
+ m_pOutputPtr[2]=Vector4IntCount;
+ memcpy(m_pOutputPtr+3,pConstantData,sizeof(int)*4*Vector4IntCount);
+ m_pOutputPtr+=3+4*Vector4IntCount;
+ }
+ else
+#endif
+ DO_D3D( SetPixelShaderConstantI( StartRegister, pConstantData, Vector4IntCount ) );
+ }
+
+ HRESULT StretchRect( IDirect3DSurface9 * pSourceSurface,
+ CONST RECT * pSourceRect,
+ IDirect3DSurface9 * pDestSurface,
+ CONST RECT * pDestRect,
+ D3DTEXTUREFILTERTYPE Filter )
+ {
+#if SHADERAPI_USE_SMP
+ if ( ASyncMode() )
+ {
+ AllocatePushBufferSpace(1+1+1+N_DWORDS( RECT )+1+1+N_DWORDS( RECT ) + 1);
+ *(m_pOutputPtr++)=PBCMD_STRETCHRECT;
+ *(m_pOutputPtr++)=(int) pSourceSurface;
+ *(m_pOutputPtr++)=(pSourceRect != NULL);
+ if (pSourceRect)
+ {
+ memcpy(m_pOutputPtr,pSourceRect,sizeof(RECT));
+ }
+ m_pOutputPtr+=N_DWORDS(RECT);
+ *(m_pOutputPtr++)=(int) pDestSurface;
+ *(m_pOutputPtr++)=(pDestRect != NULL);
+ if (pDestRect)
+ memcpy(m_pOutputPtr,pDestRect,sizeof(RECT));
+ m_pOutputPtr+=N_DWORDS(RECT);
+ *(m_pOutputPtr++)=Filter;
+ return S_OK; // !bug!
+ }
+ else
+#endif
+ return m_pD3DDevice->
+ StretchRect( pSourceSurface, pSourceRect, pDestSurface, pDestRect, Filter );
+ }
+
+
+ FORCEINLINE void BeginScene(void)
+ {
+ RECORD_COMMAND( DX8_BEGIN_SCENE, 0 );
+ if ( ASyncMode() )
+ Push( PBCMD_BEGIN_SCENE );
+ else
+ DO_D3D( BeginScene() );
+ }
+
+ FORCEINLINE void EndScene(void)
+ {
+ RECORD_COMMAND( DX8_END_SCENE, 0 );
+ if ( ASyncMode() )
+ Push( PBCMD_END_SCENE );
+ else
+ DO_D3D( EndScene() );
+ }
+
+ FORCEINLINE HRESULT Lock( IDirect3DVertexBuffer9* vb, size_t offset, size_t size, void **ptr, DWORD flags )
+ {
+ Assert( size ); // lock size of 0 = unknown entire size of buffer = bad
+ Synchronize();
+
+ HRESULT hr = vb->Lock(offset, size, ptr, flags);
+ switch (hr)
+ {
+ case D3DERR_INVALIDCALL:
+ Warning( "D3DERR_INVALIDCALL - Vertex Buffer Lock Failed in %s on line %d(offset %d, size %d, flags 0x%x)\n", V_UnqualifiedFileName(__FILE__), __LINE__, offset, size, flags );
+ break;
+ case D3DERR_DRIVERINTERNALERROR:
+ Warning( "D3DERR_DRIVERINTERNALERROR - Vertex Buffer Lock Failed in %s on line %d (offset %d, size %d, flags 0x%x)\n", V_UnqualifiedFileName(__FILE__), __LINE__, offset, size, flags );
+ break;
+ case D3DERR_OUTOFVIDEOMEMORY:
+ Warning( "D3DERR_OUTOFVIDEOMEMORY - Vertex Buffer Lock Failed in %s on line %d (offset %d, size %d, flags 0x%x)\n", V_UnqualifiedFileName(__FILE__), __LINE__, offset, size, flags );
+ break;
+ }
+
+ return hr;
+ }
+
+
+ FORCEINLINE HRESULT Lock( IDirect3DVertexBuffer9* vb, size_t offset, size_t size, void **ptr,
+ DWORD flags,
+ LockedBufferContext *lb)
+ {
+
+ HRESULT hr = D3D_OK;
+
+ // asynchronous write-only dynamic vb lock
+ if ( ASyncMode() )
+ {
+ AsynchronousLock( vb, offset, size, ptr, flags, lb );
+ }
+ else
+ {
+ hr = vb->Lock(offset, size, ptr, flags);
+ switch (hr)
+ {
+ case D3DERR_INVALIDCALL:
+ Warning( "D3DERR_INVALIDCALL - Vertex Buffer Lock Failed in %s on line %d(offset %d, size %d, flags 0x%x)\n", V_UnqualifiedFileName(__FILE__), __LINE__, offset, size, flags );
+ break;
+ case D3DERR_DRIVERINTERNALERROR:
+ Warning( "D3DERR_DRIVERINTERNALERROR - Vertex Buffer Lock Failed in %s on line %d (offset %d, size %d, flags 0x%x)\n", V_UnqualifiedFileName(__FILE__), __LINE__, offset, size, flags );
+ break;
+ case D3DERR_OUTOFVIDEOMEMORY:
+ Warning( "D3DERR_OUTOFVIDEOMEMORY - Vertex Buffer Lock Failed in %s on line %d (offset %d, size %d, flags 0x%x)\n", V_UnqualifiedFileName(__FILE__), __LINE__, offset, size, flags );
+ break;
+ }
+ }
+
+ return hr;
+ }
+
+ FORCEINLINE HRESULT Lock( IDirect3DIndexBuffer9* ib, size_t offset, size_t size, void **ptr, DWORD flags)
+ {
+ HRESULT hr = D3D_OK;
+
+ Synchronize();
+
+ hr = ib->Lock(offset, size, ptr, flags);
+ switch (hr)
+ {
+ case D3DERR_INVALIDCALL:
+ Warning( "D3DERR_INVALIDCALL - Index Buffer Lock Failed in %s on line %d(offset %d, size %d, flags 0x%x)\n", V_UnqualifiedFileName(__FILE__), __LINE__, offset, size, flags );
+ break;
+ case D3DERR_DRIVERINTERNALERROR:
+ Warning( "D3DERR_DRIVERINTERNALERROR - Index Buffer Lock Failed in %s on line %d (offset %d, size %d, flags 0x%x)\n", V_UnqualifiedFileName(__FILE__), __LINE__, offset, size, flags );
+ break;
+ case D3DERR_OUTOFVIDEOMEMORY:
+ Warning( "D3DERR_OUTOFVIDEOMEMORY - Index Buffer Lock Failed in %s on line %d (offset %d, size %d, flags 0x%x)\n", V_UnqualifiedFileName(__FILE__), __LINE__, offset, size, flags );
+ break;
+ }
+
+ return hr;
+ }
+
+ // asycnhronous lock of index buffer
+ FORCEINLINE HRESULT Lock( IDirect3DIndexBuffer9* ib, size_t offset, size_t size, void **ptr, DWORD flags,
+ LockedBufferContext * lb)
+ {
+ HRESULT hr = D3D_OK;
+
+ if ( ASyncMode() )
+ AsynchronousLock( ib, offset, size, ptr, flags, lb );
+ else
+ {
+ hr = ib->Lock(offset, size, ptr, flags);
+ switch (hr)
+ {
+ case D3DERR_INVALIDCALL:
+ Warning( "D3DERR_INVALIDCALL - Index Buffer Lock Failed in %s on line %d(offset %d, size %d, flags 0x%x)\n", V_UnqualifiedFileName(__FILE__), __LINE__, offset, size, flags );
+ break;
+ case D3DERR_DRIVERINTERNALERROR:
+ Warning( "D3DERR_DRIVERINTERNALERROR - Index Buffer Lock Failed in %s on line %d (offset %d, size %d, flags 0x%x)\n", V_UnqualifiedFileName(__FILE__), __LINE__, offset, size, flags );
+ break;
+ case D3DERR_OUTOFVIDEOMEMORY:
+ Warning( "D3DERR_OUTOFVIDEOMEMORY - Index Buffer Lock Failed in %s on line %d (offset %d, size %d, flags 0x%x)\n", V_UnqualifiedFileName(__FILE__), __LINE__, offset, size, flags );
+ break;
+ }
+ }
+
+ return hr;
+ }
+
+#ifndef DX_TO_GL_ABSTRACTION
+ FORCEINLINE HRESULT UpdateSurface( IDirect3DSurface9* pSourceSurface, CONST RECT* pSourceRect, IDirect3DSurface9* pDestSurface, CONST POINT* pDestPoint )
+ {
+ return m_pD3DDevice->UpdateSurface( pSourceSurface, pSourceRect, pDestSurface, pDestPoint );
+ }
+#endif
+
+ void Release( IDirect3DIndexBuffer9* ib )
+ {
+ Synchronize();
+ ib->Release();
+ }
+
+ void Release( IDirect3DVertexBuffer9* vb )
+ {
+ Synchronize();
+ vb->Release();
+ }
+
+ FORCEINLINE void Unlock( IDirect3DVertexBuffer9* vb )
+ {
+ // needed for d3d on pc only
+ if ( ASyncMode() )
+ Push(PBCMD_UNLOCK_VB, vb);
+ else
+ {
+ HRESULT hr = vb->Unlock( );
+
+ if ( FAILED(hr) )
+ {
+ Warning( "Vertex Buffer Unlock Failed in %s on line %d\n", V_UnqualifiedFileName(__FILE__), __LINE__ );
+ }
+ }
+ }
+
+ FORCEINLINE void Unlock( IDirect3DVertexBuffer9* vb, LockedBufferContext *lb, size_t unlock_size)
+ {
+ // needed for d3d on pc only
+#if SHADERAPI_USE_SMP
+ if ( ASyncMode() )
+ {
+ AllocatePushBufferSpace( 1+N_DWORDS_IN_PTR+N_DWORDS( LockedBufferContext )+1 );
+ *(m_pOutputPtr++)=PBCMD_ASYNC_UNLOCK_VB;
+ *((IDirect3DVertexBuffer9* *) m_pOutputPtr)=vb;
+ m_pOutputPtr+=N_DWORDS_IN_PTR;
+ *((LockedBufferContext *) m_pOutputPtr)=*lb;
+ m_pOutputPtr+=N_DWORDS( LockedBufferContext );
+ *(m_pOutputPtr++)=unlock_size;
+ }
+ else
+#endif
+ {
+ HRESULT hr = vb->Unlock();
+
+ if ( FAILED(hr) )
+ {
+ Warning( "Vertex Buffer Unlock Failed in %s on line %d\n", V_UnqualifiedFileName(__FILE__), __LINE__ );
+ }
+ }
+ }
+
+ FORCEINLINE void Unlock( IDirect3DIndexBuffer9* ib )
+ {
+ // needed for d3d on pc only
+ if ( ASyncMode() )
+ Push(PBCMD_UNLOCK_IB, ib);
+ else
+ {
+ HRESULT hr = ib->Unlock();
+
+ if ( FAILED(hr) )
+ {
+ Warning( "Index Buffer Unlock Failed in %s on line %d\n", V_UnqualifiedFileName(__FILE__), __LINE__ );
+ }
+ }
+ }
+
+ FORCEINLINE void Unlock( IDirect3DIndexBuffer9* ib, LockedBufferContext *lb, size_t unlock_size)
+ {
+ // needed for d3d on pc only
+#if SHADERAPI_USE_SMP
+ if ( ASyncMode() )
+ {
+ AllocatePushBufferSpace( 1+N_DWORDS_IN_PTR+N_DWORDS( LockedBufferContext )+1 );
+ *(m_pOutputPtr++)=PBCMD_ASYNC_UNLOCK_IB;
+ *((IDirect3DIndexBuffer9* *) m_pOutputPtr)=ib;
+ m_pOutputPtr+=N_DWORDS_IN_PTR;
+ *((LockedBufferContext *) m_pOutputPtr)=*lb;
+ m_pOutputPtr+=N_DWORDS( LockedBufferContext );
+ *(m_pOutputPtr++)=unlock_size;
+ }
+ else
+#endif
+ {
+ HRESULT hr = ib->Unlock( );
+
+ if ( FAILED(hr) )
+ {
+ Warning( "Index Buffer Unlock Failed in %s on line %d\n", V_UnqualifiedFileName(__FILE__), __LINE__ );
+ }
+ }
+ }
+
+ void ShowCursor( bool onoff)
+ {
+ Synchronize();
+ DO_D3D( ShowCursor(onoff) );
+ }
+
+ FORCEINLINE void Clear( int count, D3DRECT const *pRects, int Flags, D3DCOLOR color, float Z, int stencil)
+ {
+#if SHADERAPI_USE_SMP
+ if ( ASyncMode() )
+ {
+ int n_rects_words = count * N_DWORDS( D3DRECT );
+ AllocatePushBufferSpace( 2 + n_rects_words + 4 );
+ *(m_pOutputPtr++) = PBCMD_CLEAR;
+ *(m_pOutputPtr++) = count;
+ if ( count )
+ {
+ memcpy( m_pOutputPtr, pRects, count * sizeof( D3DRECT ) );
+ m_pOutputPtr += n_rects_words;
+ }
+ *(m_pOutputPtr++) = Flags;
+ *( (D3DCOLOR *) m_pOutputPtr ) = color;
+ m_pOutputPtr++;
+ *( (float *) m_pOutputPtr ) = Z;
+ m_pOutputPtr++;
+ *(m_pOutputPtr++) = stencil;
+ }
+ else
+#endif
+ DO_D3D( Clear(count, pRects, Flags, color, Z, stencil) );
+ }
+
+ HRESULT Reset( D3DPRESENT_PARAMETERS *parms)
+ {
+ RECORD_COMMAND( DX8_RESET, 1 );
+ RECORD_STRUCT( parms, sizeof(*parms) );
+ Synchronize();
+ return m_pD3DDevice->Reset( parms );
+ }
+
+ void Release( void )
+ {
+ Synchronize();
+ DO_D3D( Release() );
+ }
+
+ FORCEINLINE void SetTexture(int stage, IDirect3DBaseTexture9 *txtr)
+ {
+ RECORD_COMMAND( DX8_SET_TEXTURE, 3 );
+ RECORD_INT( stage );
+ RECORD_INT( -1 );
+ RECORD_INT( -1 );
+ if (ASyncMode())
+ {
+ Push( PBCMD_SET_TEXTURE, stage, txtr );
+ }
+ else
+ DO_D3D( SetTexture( stage, txtr) );
+ }
+ void SetTransform( D3DTRANSFORMSTATETYPE mtrx_id, D3DXMATRIX const *mt)
+ {
+ RECORD_COMMAND( DX8_SET_TRANSFORM, 2 );
+ RECORD_INT( mtrx_id );
+ RECORD_STRUCT( mt, sizeof(D3DXMATRIX) );
+ Synchronize();
+ DO_D3D( SetTransform( mtrx_id, mt) );
+ }
+
+ FORCEINLINE void SetSamplerState( int stage, D3DSAMPLERSTATETYPE state, DWORD val)
+ {
+ RECORD_SAMPLER_STATE( stage, state, val );
+ if ( ASyncMode() )
+ Push( PBCMD_SET_SAMPLER_STATE, stage, state, val );
+ else
+ DO_D3D( SetSamplerState( stage, state, val) );
+ }
+
+ void SetFVF( int fvf)
+ {
+ Synchronize();
+ DO_D3D( SetFVF( fvf) );
+ }
+
+ FORCEINLINE void SetTextureStageState( int stage, D3DTEXTURESTAGESTATETYPE state, DWORD val )
+ {
+ RECORD_TEXTURE_STAGE_STATE( stage, state, val );
+ Synchronize();
+ DO_D3D( SetTextureStageState( stage, state, val) );
+ }
+
+ FORCEINLINE void DrawPrimitive(
+ D3DPRIMITIVETYPE PrimitiveType,
+ UINT StartVertex,
+ UINT PrimitiveCount
+ )
+ {
+ RECORD_COMMAND( DX8_DRAW_PRIMITIVE, 3 );
+ RECORD_INT( PrimitiveType );
+ RECORD_INT( StartVertex );
+ RECORD_INT( PrimitiveCount );
+ if ( ASyncMode() )
+ {
+ Push( PBCMD_DRAWPRIM, PrimitiveType, StartVertex, PrimitiveCount );
+ SubmitIfNotBusy();
+ }
+ else
+ DO_D3D( DrawPrimitive( PrimitiveType, StartVertex, PrimitiveCount ) );
+
+ }
+
+ HRESULT CreateVertexDeclaration(
+ CONST D3DVERTEXELEMENT9* pVertexElements,
+ IDirect3DVertexDeclaration9** ppDecl
+ )
+ {
+ Synchronize();
+ return m_pD3DDevice->CreateVertexDeclaration( pVertexElements, ppDecl );
+ }
+
+
+ HRESULT ValidateDevice( DWORD * pNumPasses )
+ {
+ Synchronize();
+ return m_pD3DDevice->ValidateDevice( pNumPasses );
+ }
+
+
+
+ HRESULT CreateVertexShader(
+ CONST DWORD * pFunction,
+ IDirect3DVertexShader9** ppShader,
+ const char *pShaderName,
+ char *debugLabel = NULL
+ )
+ {
+ Synchronize();
+ #ifdef DX_TO_GL_ABSTRACTION
+ return m_pD3DDevice->CreateVertexShader( pFunction, ppShader, pShaderName, debugLabel );
+ #else
+ return m_pD3DDevice->CreateVertexShader( pFunction, ppShader );
+ #endif
+ }
+
+ HRESULT CreatePixelShader(
+ CONST DWORD * pFunction,
+ IDirect3DPixelShader9** ppShader,
+ const char *pShaderName,
+ char *debugLabel = NULL
+ )
+ {
+ Synchronize();
+ #ifdef DX_TO_GL_ABSTRACTION
+ return m_pD3DDevice->CreatePixelShader( pFunction, ppShader, pShaderName, debugLabel );
+ #else
+ return m_pD3DDevice->CreatePixelShader( pFunction, ppShader );
+ #endif
+ }
+
+
+ FORCEINLINE void SetIndices(
+ IDirect3DIndexBuffer9 * pIndexData
+ )
+ {
+ if ( ASyncMode() )
+ Push( PBCMD_SET_INDICES, pIndexData );
+ else
+ DO_D3D( SetIndices( pIndexData ) );
+ }
+
+ FORCEINLINE void SetStreamSource(
+ UINT StreamNumber,
+ IDirect3DVertexBuffer9 * pStreamData,
+ UINT OffsetInBytes,
+ UINT Stride
+ )
+ {
+ if ( ASyncMode() )
+ Push( PBCMD_SET_STREAM_SOURCE, StreamNumber, pStreamData, OffsetInBytes, Stride );
+ else
+ DO_D3D( SetStreamSource( StreamNumber, pStreamData, OffsetInBytes, Stride ) );
+ }
+
+
+ HRESULT CreateVertexBuffer(
+ UINT Length,
+ DWORD Usage,
+ DWORD FVF,
+ D3DPOOL Pool,
+ IDirect3DVertexBuffer9** ppVertexBuffer,
+ HANDLE* pSharedHandle
+ )
+ {
+ Synchronize();
+ return m_pD3DDevice->CreateVertexBuffer( Length, Usage, FVF,
+ Pool, ppVertexBuffer, pSharedHandle );
+ }
+
+ HRESULT CreateIndexBuffer(
+ UINT Length,
+ DWORD Usage,
+ D3DFORMAT Format,
+ D3DPOOL Pool,
+ IDirect3DIndexBuffer9** ppIndexBuffer,
+ HANDLE* pSharedHandle
+ )
+ {
+ Synchronize();
+ return m_pD3DDevice->CreateIndexBuffer( Length, Usage, Format, Pool, ppIndexBuffer,
+ pSharedHandle );
+ }
+
+
+ FORCEINLINE void DrawIndexedPrimitive(
+ D3DPRIMITIVETYPE Type,
+ INT BaseVertexIndex,
+ UINT MinIndex,
+ UINT NumVertices,
+ UINT StartIndex,
+ UINT PrimitiveCount )
+ {
+ RECORD_COMMAND( DX8_DRAW_INDEXED_PRIMITIVE, 6 );
+ RECORD_INT( Type );
+ RECORD_INT( BaseVertexIndex );
+ RECORD_INT( MinIndex );
+ RECORD_INT( NumVertices );
+ RECORD_INT( StartIndex );
+ RECORD_INT( PrimitiveCount );
+ if ( ASyncMode() )
+ {
+ Push(PBCMD_DRAWINDEXEDPRIM,
+ Type, BaseVertexIndex, MinIndex, NumVertices, StartIndex, PrimitiveCount );
+// SubmitIfNotBusy();
+ }
+ else
+ {
+ DO_D3D( DrawIndexedPrimitive( Type, BaseVertexIndex, MinIndex, NumVertices, StartIndex, PrimitiveCount ) );
+ }
+ }
+
+#ifndef DX_TO_GL_ABSTRACTION
+ FORCEINLINE void DrawTessellatedIndexedPrimitive( INT BaseVertexIndex, UINT MinIndex, UINT NumVertices,
+ UINT StartIndex, UINT PrimitiveCount )
+ {
+ // Setup our stream-source frequencies
+ DO_D3D( SetStreamSourceFreq( 0, D3DSTREAMSOURCE_INDEXEDDATA | PrimitiveCount ) );
+ DO_D3D( SetStreamSourceFreq( VertexStreamSpec_t::STREAM_MORPH, D3DSTREAMSOURCE_INSTANCEDATA | 1ul ) );
+ DO_D3D( SetStreamSourceFreq( VertexStreamSpec_t::STREAM_SUBDQUADS, D3DSTREAMSOURCE_INSTANCEDATA | 1ul ) );
+
+ int nIndicesPerPatch = ( ( ( m_nCurrentTessLevel + 1 ) * 2 + 2 ) * m_nCurrentTessLevel ) - 2;
+ int nVerticesPerPatch = m_nCurrentTessLevel + 1;
+ nVerticesPerPatch *= nVerticesPerPatch;
+ int nPrimitiveCount = nIndicesPerPatch - 2;
+ DO_D3D( DrawIndexedPrimitive( D3DPT_TRIANGLESTRIP, 0, 0, nVerticesPerPatch, 0, nPrimitiveCount ) );
+
+ // Disable instancing
+ DO_D3D( SetStreamSourceFreq( 0, 1ul ) );
+ DO_D3D( SetStreamSourceFreq( VertexStreamSpec_t::STREAM_MORPH, 1ul ) );
+ DO_D3D( SetStreamSourceFreq( VertexStreamSpec_t::STREAM_SUBDQUADS, 1ul ) );
+ }
+
+ FORCEINLINE void DrawTessellatedPrimitive( UINT StartVertex, UINT PrimitiveCount )
+ {
+
+ // Setup our stream-source frequencies
+ DO_D3D( SetStreamSourceFreq( 0, D3DSTREAMSOURCE_INDEXEDDATA | PrimitiveCount ) );
+ DO_D3D( SetStreamSourceFreq( VertexStreamSpec_t::STREAM_MORPH, D3DSTREAMSOURCE_INSTANCEDATA | 1ul ) );
+ DO_D3D( SetStreamSourceFreq( VertexStreamSpec_t::STREAM_SUBDQUADS, D3DSTREAMSOURCE_INSTANCEDATA | 1ul ) );
+
+ int nIndicesPerPatch = ( ( ( m_nCurrentTessLevel + 1 ) * 2 + 2 ) * m_nCurrentTessLevel ) - 2;
+ int nVerticesPerPatch = m_nCurrentTessLevel + 1;
+ nVerticesPerPatch *= nVerticesPerPatch;
+ int nPrimitiveCount = nIndicesPerPatch - 2;
+ DO_D3D( DrawIndexedPrimitive( D3DPT_TRIANGLESTRIP, 0, 0, nVerticesPerPatch, 0, nPrimitiveCount ) );
+
+ // Disable instancing
+ DO_D3D( SetStreamSourceFreq( 0, 1ul ) );
+ DO_D3D( SetStreamSourceFreq( VertexStreamSpec_t::STREAM_MORPH, 1ul ) );
+ DO_D3D( SetStreamSourceFreq( VertexStreamSpec_t::STREAM_SUBDQUADS, 1ul ) );
+ }
+
+ FORCEINLINE void SetTessellationLevel( float level )
+ {
+ // Track our current tessellation level
+ m_nCurrentTessLevel = (int)ceil( level );
+ }
+#endif
+
+ void SetMaterial( D3DMATERIAL9 const *mat)
+ {
+ RECORD_COMMAND( DX8_SET_MATERIAL, 1 );
+ RECORD_STRUCT( &mat, sizeof(mat) );
+ Synchronize();
+ DO_D3D( SetMaterial( mat ) );
+ }
+
+ FORCEINLINE void SetPixelShader( IDirect3DPixelShader9 *pShader )
+ {
+ RECORD_COMMAND( DX8_SET_PIXEL_SHADER, 1 );
+ RECORD_INT( ( int ) pShader );
+ if ( ASyncMode() )
+ Push( PBCMD_SET_PIXEL_SHADER, pShader );
+ else
+ DO_D3D( SetPixelShader( pShader ) );
+ }
+
+ FORCEINLINE void SetVertexShader( IDirect3DVertexShader9 *pShader )
+ {
+ if ( ASyncMode() )
+ Push( PBCMD_SET_VERTEX_SHADER, pShader );
+ else
+ DO_D3D( SetVertexShader( pShader ) );
+ }
+
+#ifdef DX_TO_GL_ABSTRACTION
+ FORCEINLINE HRESULT LinkShaderPair( IDirect3DVertexShader9* vs, IDirect3DPixelShader9* ps )
+ {
+ Assert ( !ASyncMode() );
+ return DO_D3D( LinkShaderPair( vs, ps ) );
+ }
+
+ HRESULT QueryShaderPair( int index, GLMShaderPairInfo *infoOut )
+ {
+ Assert ( !ASyncMode() );
+ return DO_D3D( QueryShaderPair( index, infoOut ) );
+ }
+
+ void SetMaxUsedVertexShaderConstantsHint( uint nMaxReg )
+ {
+ Assert( !ASyncMode() );
+ DO_D3D( SetMaxUsedVertexShaderConstantsHint( nMaxReg ) );
+ }
+
+#endif
+
+ void EvictManagedResources( void )
+ {
+ if (m_pD3DDevice) // people call this before creating the device
+ {
+ Synchronize();
+ DO_D3D( EvictManagedResources() );
+ }
+ }
+
+ void SetLight( int i, D3DLIGHT9 const *l)
+ {
+ RECORD_COMMAND( DX8_SET_LIGHT, 2 );
+ RECORD_INT( i );
+ RECORD_STRUCT( l, sizeof(*l) );
+
+ Synchronize();
+ DO_D3D( SetLight(i, l) );
+ }
+
+ void DrawIndexedPrimitiveUP( D3DPRIMITIVETYPE PrimitiveType,
+ UINT MinVertexIndex,
+ UINT NumVertices,
+ UINT PrimitiveCount,
+ CONST void * pIndexData,
+ D3DFORMAT IndexDataFormat,
+ CONST void* pVertexStreamZeroData,
+ UINT VertexStreamZeroStride )
+ {
+ Synchronize();
+ DO_D3D( DrawIndexedPrimitiveUP( PrimitiveType, MinVertexIndex, NumVertices, PrimitiveCount,
+ pIndexData, IndexDataFormat, pVertexStreamZeroData,
+ VertexStreamZeroStride ) );
+ }
+
+ HRESULT Present(
+ CONST RECT * pSourceRect,
+ CONST RECT * pDestRect,
+ VD3DHWND hDestWindowOverride,
+ CONST RGNDATA * pDirtyRegion)
+ {
+ RECORD_COMMAND( DX8_PRESENT, 0 );
+#if SHADERAPI_USE_SMP
+ if ( ASyncMode() )
+ {
+ // need to deal with ret code here
+ AllocatePushBufferSpace(1+1+
+ N_DWORDS( RECT )+1+N_DWORDS( RECT )+1+1+N_DWORDS( RGNDATA ));
+ *(m_pOutputPtr++)=PBCMD_PRESENT;
+ *(m_pOutputPtr++)=( pSourceRect != NULL );
+ if (pSourceRect)
+ memcpy(m_pOutputPtr, pSourceRect, sizeof( RECT ) );
+ m_pOutputPtr+=N_DWORDS( RECT );
+ *(m_pOutputPtr++)=( pDestRect != NULL );
+ if (pDestRect)
+ memcpy(m_pOutputPtr, pDestRect, sizeof( RECT ) );
+ m_pOutputPtr+=N_DWORDS( RECT );
+ *(m_pOutputPtr++)=(uint32) hDestWindowOverride;
+ *(m_pOutputPtr++)=( pDirtyRegion != NULL );
+ if (pDirtyRegion)
+ memcpy(m_pOutputPtr, pDirtyRegion, sizeof( RGNDATA ));
+ m_pOutputPtr+=N_DWORDS( RGNDATA );
+ return S_OK; // not good - caller wants to here about lost devices
+ }
+ else
+#endif
+ return m_pD3DDevice->Present( pSourceRect, pDestRect,
+ hDestWindowOverride, pDirtyRegion );
+ }
+
+
+#if defined( DX_TO_GL_ABSTRACTION )
+
+ void AcquireThreadOwnership( )
+ {
+ m_pD3DDevice->AcquireThreadOwnership();
+ }
+
+ void ReleaseThreadOwnership( )
+ {
+ m_pD3DDevice->ReleaseThreadOwnership();
+ }
+
+#endif
+
+};
+
+#endif // D3DASYNC_H
+
+#endif // #if D3D_ASYNC_SUPPORTED
diff --git a/materialsystem/shaderapidx9/dx9hook.h b/materialsystem/shaderapidx9/dx9hook.h
new file mode 100644
index 0000000..a117f3e
--- /dev/null
+++ b/materialsystem/shaderapidx9/dx9hook.h
@@ -0,0 +1,1289 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+/*
+TODO: add option to null out drawprim calls.
+
+Also maybe hook the PIX_ENABLE stuff to Telemetry
+
+ In imaterialsystem.h:
+ #define PIX_ENABLE 1 // set this to 1 and build engine/studiorender to enable pix events in the engine
+
+ And in shaderapidx8.h:
+ #define PIX_ENABLE 1 // set this to 1 and build engine/studiorender to enable pix events in the engine
+
+Might be interesting to make it so dx9hook.h paid attention to the PIX_ENABLE names
+ and allowed you to filter drawprim calls based on those?
+*/
+
+#ifndef _DX9HOOK_H_
+#define _DX9HOOK_H_
+
+#if D3D_BATCH_PERF_ANALYSIS
+ #include "../../thirdparty/miniz/miniz.c"
+ #include "../../thirdparty/miniz/simple_bitmap.h"
+
+ extern ConVar d3d_batch_vis, d3d_batch_vis_abs_scale, d3d_batch_vis_y_scale, d3d_present_vis_abs_scale;
+ extern uint64 g_nTotalD3DCalls, g_nTotalD3DCycles;
+
+ class CD3DCallTimer
+ {
+ public:
+ inline CD3DCallTimer() { g_nTotalD3DCalls++; g_nTotalD3DCycles -= tmFastTime(); }
+ inline ~CD3DCallTimer() { g_nTotalD3DCycles += tmFastTime(); }
+ };
+
+ #define D3D_BATCH_PERF(...) __VA_ARGS__
+#else
+ #define D3D_BATCH_PERF(...)
+#endif
+
+#if D3D_BATCH_PERF_ANALYSIS
+ #define XXX \
+ tmZone( TELEMETRY_LEVEL3, TMZF_NONE, "D3D9: %s", __FUNCTION__ ); \
+ CD3DCallTimer scopedCallTimer;
+#else
+ #define XXX \
+ if( ThreadInMainThread() ) \
+ { \
+ tmMessage( TELEMETRY_LEVEL0, TMMF_ICON_NOTE | TMMF_SEVERITY_WARNING, "(source/d3d)%s", __FUNCTION__ ); \
+ tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "%s", __FUNCTION__ ); \
+ }
+#endif
+
+// Hooks for routines which return values.
+#define _DOCALL0( _member ) ( m_Data.pHWObj->_member )()
+#define _DOCALL( _member, ... ) ( m_Data.pHWObj->_member )( __VA_ARGS__ )
+// And hooks for routines which return squatola.
+#define _DOCALL0_NORET( _member ) ( m_Data.pHWObj->_member )()
+#define _DOCALL_NORET( _member, ... ) ( m_Data.pHWObj->_member )( __VA_ARGS__)
+
+#define DEF_HOOKCLASSES( X ) \
+ template<> class CDx9HookBase< struct I ## X > \
+ { \
+ public: \
+ typedef I ## X _D3DINTERFACE; \
+ typedef class C ## X ## Hook _HOOKCLASS; \
+ \
+ public: \
+ CDx9HookBase() { memset( &m_Data, 0, sizeof( m_Data ) ); } \
+ virtual ~CDx9HookBase() {} \
+ \
+ public: \
+ struct DATA \
+ { \
+ class CDirect3DDevice9Hook *pDevice; \
+ _D3DINTERFACE *pHWObj; \
+ }; \
+ \
+ DATA m_Data; \
+ }
+
+template < class T > class CDx9HookBase;
+DEF_HOOKCLASSES( Direct3DVertexDeclaration9 );
+DEF_HOOKCLASSES( Direct3DPixelShader9 );
+DEF_HOOKCLASSES( Direct3DVertexShader9 );
+DEF_HOOKCLASSES( Direct3DVertexBuffer9 );
+DEF_HOOKCLASSES( Direct3DIndexBuffer9 );
+DEF_HOOKCLASSES( Direct3DQuery9 );
+DEF_HOOKCLASSES( Direct3DStateBlock9 );
+DEF_HOOKCLASSES( Direct3DSurface9 );
+DEF_HOOKCLASSES( Direct3DBaseTexture9 );
+DEF_HOOKCLASSES( Direct3DTexture9 );
+DEF_HOOKCLASSES( Direct3DCubeTexture9 );
+DEF_HOOKCLASSES( Direct3DVolume9 );
+DEF_HOOKCLASSES( Direct3DVolumeTexture9 );
+DEF_HOOKCLASSES( Direct3DSwapChain9 );
+DEF_HOOKCLASSES( Direct3D9 );
+DEF_HOOKCLASSES( Direct3DDevice9 );
+
+template < class _D3DINTERFACE > HRESULT AllocOverride( HRESULT *hr, class CDirect3DDevice9Hook *pDevice, _D3DINTERFACE **ppHWObj )
+{
+ if( SUCCEEDED(*hr) && ppHWObj && *ppHWObj )
+ {
+ CDx9HookBase< _D3DINTERFACE >::_HOOKCLASS *pClass = new CDx9HookBase< _D3DINTERFACE >::_HOOKCLASS;
+
+ if(!pClass)
+ {
+ ( *ppHWObj )->Release();
+ *hr = E_OUTOFMEMORY;
+ return NULL;
+ }
+ pClass->m_Data.pDevice = pDevice;
+ pClass->m_Data.pHWObj = *ppHWObj;
+ *ppHWObj = pClass;
+ return *hr;
+ }
+
+ return *hr;
+}
+
+template <class _D3DINTERFACE> _D3DINTERFACE *GetHWPtr( _D3DINTERFACE *pD3DInterface )
+{
+ if( pD3DInterface )
+ {
+ CDx9HookBase< _D3DINTERFACE >::_HOOKCLASS *pClass = ( CDx9HookBase< _D3DINTERFACE >::_HOOKCLASS * )pD3DInterface;
+ return pClass->m_Data.pHWObj;
+ }
+ return NULL;
+}
+
+template <class _D3DINTERFACE> CDirect3DDevice9Hook *GetHookDevice( _D3DINTERFACE *pD3DInterface )
+{
+ if( pD3DInterface )
+ {
+ CDx9HookBase< _D3DINTERFACE >::_HOOKCLASS *pClass = ( CDx9HookBase< _D3DINTERFACE >::_HOOKCLASS * )pD3DInterface;
+ return pClass->m_Data.pDevice;
+ }
+ return NULL;
+}
+
+//$ TODO: if(riid == IID_IDirect3DDevice9Ex, IID_IDirect3DDevice9, etc.
+#define IMPL_QUERYINTERFACE() \
+ STDMETHOD(QueryInterface)(THIS_ REFIID riid, void** ppvObj) \
+ { \
+ __debugbreak(); \
+ XXX; return _DOCALL(QueryInterface, riid, ppvObj); \
+ }
+
+#define IMPL_IUNKOWN() \
+ IMPL_QUERYINTERFACE(); \
+ STDMETHOD_(ULONG,AddRef)(THIS) \
+ { XXX; return _DOCALL0(AddRef); } \
+ STDMETHOD_(ULONG,Release)(THIS) \
+ { \
+ XXX; \
+ ULONG retval = _DOCALL0(Release); \
+ if(retval == 0) \
+ delete this; \
+ return retval; \
+ }
+
+#define IMPL_GETDEVICE() \
+ STDMETHOD(GetDevice)(THIS_ IDirect3DDevice9** ppDevice) \
+ { \
+ XXX; \
+ HRESULT hr = _DOCALL( GetDevice, ppDevice ); \
+ return AllocOverride( &hr, m_Data.pDevice, ppDevice ); \
+ }
+
+#define IMPL_SETPRIVATEDATA() \
+ STDMETHOD(SetPrivateData)(THIS_ REFGUID refguid,CONST void* pData,DWORD SizeOfData,DWORD Flags) \
+ { XXX; return _DOCALL(SetPrivateData, refguid, pData, SizeOfData, Flags); }
+
+#define IMPL_GETPRIVATEDATA() \
+ STDMETHOD(GetPrivateData)(THIS_ REFGUID refguid,void* pData,DWORD* pSizeOfData) \
+ { XXX; return _DOCALL(GetPrivateData, refguid, pData, pSizeOfData); }
+
+#define IMPL_FREEPRIVATEDATA() \
+ STDMETHOD(FreePrivateData)(THIS_ REFGUID refguid) \
+ { XXX; return _DOCALL(FreePrivateData, refguid); }
+
+#define IMPL_IDIRECT3DRESOURCE9() \
+ IMPL_GETDEVICE(); \
+ IMPL_SETPRIVATEDATA(); \
+ IMPL_GETPRIVATEDATA(); \
+ IMPL_FREEPRIVATEDATA(); \
+ STDMETHOD_(DWORD, SetPriority)(THIS_ DWORD PriorityNew) \
+ { XXX; return _DOCALL(SetPriority, PriorityNew); } \
+ STDMETHOD_(DWORD, GetPriority)(THIS) \
+ { XXX; return _DOCALL0(GetPriority); } \
+ STDMETHOD_(void, PreLoad)(THIS) \
+ { XXX; _DOCALL0_NORET(PreLoad); } \
+ STDMETHOD_(D3DRESOURCETYPE, GetType)(THIS) \
+ { XXX; return _DOCALL0(GetType); }
+
+class CDirect3DSwapChain9Hook : public CDx9HookBase<IDirect3DSwapChain9>, public IDirect3DSwapChain9
+{
+public:
+ /*** IUnknown methods ***/
+ IMPL_IUNKOWN();
+
+ /*** IDirect3DSwapChain9 methods ***/
+ STDMETHOD(Present)(THIS_ CONST RECT* pSourceRect,CONST RECT* pDestRect,HWND hDestWindowOverride,CONST RGNDATA* pDirtyRegion,DWORD dwFlags)
+ { XXX; return _DOCALL(Present, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags); }
+
+ STDMETHOD(GetFrontBufferData)(THIS_ IDirect3DSurface9* pDestSurface)
+ {
+ XXX; return _DOCALL(GetFrontBufferData, GetHWPtr(pDestSurface));
+ }
+ STDMETHOD(GetBackBuffer)(THIS_ UINT iBackBuffer,D3DBACKBUFFER_TYPE Type,IDirect3DSurface9** ppBackBuffer)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(GetBackBuffer, iBackBuffer, Type, ppBackBuffer);
+ return AllocOverride( &hr, m_Data.pDevice, ppBackBuffer );
+ }
+
+ STDMETHOD(GetRasterStatus)(THIS_ D3DRASTER_STATUS* pRasterStatus)
+ { XXX; return _DOCALL(GetRasterStatus, pRasterStatus); }
+ STDMETHOD(GetDisplayMode)(THIS_ D3DDISPLAYMODE* pMode)
+ { XXX; return _DOCALL(GetDisplayMode, pMode); }
+
+ IMPL_GETDEVICE();
+
+ STDMETHOD(GetPresentParameters)(THIS_ D3DPRESENT_PARAMETERS* pPresentationParameters)
+ { XXX; return _DOCALL(GetPresentParameters, pPresentationParameters); }
+};
+
+class CDirect3DVertexDeclaration9Hook : public CDx9HookBase<IDirect3DVertexDeclaration9>, public IDirect3DVertexDeclaration9
+{
+public:
+ /*** IUnknown methods ***/
+ IMPL_IUNKOWN();
+
+ // IDirect3DVertexDeclaration9 methods
+ IMPL_GETDEVICE();
+
+ STDMETHOD(GetDeclaration)(THIS_ D3DVERTEXELEMENT9 *pVertElem, UINT* pNumElements)
+ { XXX; return _DOCALL(GetDeclaration, pVertElem, pNumElements); }
+};
+
+class CDirect3DPixelShader9Hook : public CDx9HookBase<IDirect3DPixelShader9>, public IDirect3DPixelShader9
+{
+public:
+ /*** IUnknown methods ***/
+ IMPL_IUNKOWN();
+
+ // IDirect3DPixelShader9 methods
+ IMPL_GETDEVICE();
+
+ STDMETHOD(GetFunction)(THIS_ void *pData,UINT* pSizeOfData)
+ { XXX; return _DOCALL(GetFunction, pData, pSizeOfData); }
+};
+
+class CDirect3DVertexShader9Hook : public CDx9HookBase<IDirect3DVertexShader9>, public IDirect3DVertexShader9
+{
+public:
+ /*** IUnknown methods ***/
+ IMPL_IUNKOWN();
+
+ // IDirect3DVertexDeclaration9 methods
+ IMPL_GETDEVICE();
+
+ STDMETHOD(GetFunction)(THIS_ void *pData,UINT* pSizeOfData)
+ { XXX; return _DOCALL(GetFunction, pData, pSizeOfData); }
+};
+
+class CDirect3DVertexBuffer9Hook : public CDx9HookBase<IDirect3DVertexBuffer9>, public IDirect3DVertexBuffer9
+{
+public:
+ /*** IUnknown methods ***/
+ IMPL_IUNKOWN();
+
+ // IDirect3DResource9 methods
+ IMPL_IDIRECT3DRESOURCE9();
+
+ // IDirect3DVertexBuffer9
+ STDMETHOD(Lock)(THIS_ UINT OffsetToLock,UINT SizeToLock,void** ppbData,DWORD Flags)
+ { XXX; return _DOCALL(Lock, OffsetToLock, SizeToLock, ppbData, Flags); }
+ STDMETHOD(Unlock)(THIS)
+ { XXX; return _DOCALL0(Unlock); }
+
+ STDMETHOD(GetDesc)(THIS_ D3DVERTEXBUFFER_DESC *pDesc)
+ { XXX; return _DOCALL(GetDesc, pDesc); }
+};
+
+class CDirect3DIndexBuffer9Hook : public CDx9HookBase<IDirect3DIndexBuffer9>, public IDirect3DIndexBuffer9
+{
+public:
+ /*** IUnknown methods ***/
+ IMPL_IUNKOWN();
+
+ // IDirect3DResource9 methods
+ IMPL_IDIRECT3DRESOURCE9();
+
+ // IDirect3DIndexBuffer9
+ STDMETHOD(Lock)(THIS_ UINT OffsetToLock,UINT SizeToLock,void** ppbData,DWORD Flags)
+ { XXX; return _DOCALL(Lock, OffsetToLock, SizeToLock, ppbData, Flags); }
+ STDMETHOD(Unlock)(THIS)
+ { XXX; return _DOCALL0(Unlock); }
+
+ STDMETHOD(GetDesc)(THIS_ D3DINDEXBUFFER_DESC *pDesc)
+ { XXX; return _DOCALL(GetDesc, pDesc); }
+};
+
+class CDirect3DQuery9Hook : public CDx9HookBase<IDirect3DQuery9>, public IDirect3DQuery9
+{
+public:
+ /*** IUnknown methods ***/
+ IMPL_IUNKOWN();
+
+ /*** IDirect3DQuery9 methods ***/
+ IMPL_GETDEVICE();
+
+ // IDirect3DQuery9
+ STDMETHOD_(D3DQUERYTYPE, GetType)(THIS)
+ { XXX; return _DOCALL0(GetType); }
+ STDMETHOD_(DWORD, GetDataSize)(THIS)
+ { XXX; return _DOCALL0(GetDataSize); }
+ STDMETHOD(Issue)(THIS_ DWORD dwIssueFlags)
+ { XXX; return _DOCALL(Issue, dwIssueFlags); }
+ STDMETHOD(GetData)(THIS_ void* pData,DWORD dwSize,DWORD dwGetDataFlags)
+ { XXX; return _DOCALL(GetData, pData, dwSize, dwGetDataFlags); }
+};
+
+class CDirect3DStateBlock9Hook : public CDx9HookBase<IDirect3DStateBlock9>, public IDirect3DStateBlock9
+{
+public:
+ CDirect3DStateBlock9Hook() {}
+ virtual ~CDirect3DStateBlock9Hook() {}
+
+ /*** IUnknown methods ***/
+ IMPL_IUNKOWN();
+
+ // IDirect3DStateBlock9 methods
+ IMPL_GETDEVICE();
+
+ STDMETHOD(Capture)(THIS)
+ { XXX; return _DOCALL0(Capture); }
+ STDMETHOD(Apply)(THIS)
+ { XXX; return _DOCALL0(Apply); }
+};
+
+class CDirect3DSurface9Hook : public CDx9HookBase<IDirect3DSurface9>, public IDirect3DSurface9
+{
+public:
+ /*** IUnknown methods ***/
+ IMPL_IUNKOWN();
+
+ // IDirect3DResource9 methods
+ IMPL_IDIRECT3DRESOURCE9();
+
+ STDMETHOD(GetContainer)(THIS_ REFIID riid,void** ppContainer)
+ {
+ //$ TODO: do the call, check riid, and wrap the returned ppContainer
+ __debugbreak();
+ XXX; return _DOCALL(GetContainer, riid, ppContainer);
+ }
+ STDMETHOD(GetDesc)(THIS_ D3DSURFACE_DESC *pDesc)
+ { XXX; return _DOCALL(GetDesc, pDesc); }
+
+ STDMETHOD(LockRect)(THIS_ D3DLOCKED_RECT* pLockedRect,CONST RECT* pRect,DWORD Flags)
+ { XXX; return _DOCALL(LockRect, pLockedRect, pRect, Flags); }
+ STDMETHOD(UnlockRect)(THIS)
+ { XXX; return _DOCALL0(UnlockRect); }
+
+ STDMETHOD(GetDC)(THIS_ HDC *phdc)
+ { XXX; return _DOCALL(GetDC, phdc); }
+ STDMETHOD(ReleaseDC)(THIS_ HDC hdc)
+ { XXX; return _DOCALL(ReleaseDC, hdc); }
+};
+
+class CDirect3DBaseTexture9Hook : public CDx9HookBase<IDirect3DBaseTexture9>, public IDirect3DBaseTexture9
+{
+public:
+ /*** IUnknown methods ***/
+ IMPL_IUNKOWN();
+
+ /*** IDirect3DBaseTexture9 methods ***/
+ IMPL_IDIRECT3DRESOURCE9();
+
+ STDMETHOD_(DWORD, SetLOD)(THIS_ DWORD LODNew)
+ { XXX; return _DOCALL(SetLOD, LODNew); }
+ STDMETHOD_(DWORD, GetLOD)(THIS)
+ { XXX; return _DOCALL0(GetLOD); }
+ STDMETHOD_(DWORD, GetLevelCount)(THIS)
+ { XXX; return _DOCALL0(GetLevelCount); }
+ STDMETHOD(SetAutoGenFilterType)(THIS_ D3DTEXTUREFILTERTYPE FilterType)
+ { XXX; return _DOCALL(SetAutoGenFilterType, FilterType); }
+ STDMETHOD_(D3DTEXTUREFILTERTYPE, GetAutoGenFilterType)(THIS)
+ { XXX; return _DOCALL0(GetAutoGenFilterType); }
+ STDMETHOD_(void, GenerateMipSubLevels)(THIS)
+ { XXX; return _DOCALL0(GenerateMipSubLevels); }
+};
+
+class CDirect3DTexture9Hook : public CDx9HookBase<IDirect3DTexture9>, public IDirect3DTexture9
+{
+public:
+ /*** IUnknown methods ***/
+ IMPL_IUNKOWN();
+
+ /*** IDirect3DBaseTexture9 methods ***/
+ IMPL_IDIRECT3DRESOURCE9();
+
+ STDMETHOD_(DWORD, SetLOD)(THIS_ DWORD LODNew)
+ { XXX; return _DOCALL(SetLOD, LODNew); }
+ STDMETHOD_(DWORD, GetLOD)(THIS)
+ { XXX; return _DOCALL0(GetLOD); }
+ STDMETHOD_(DWORD, GetLevelCount)(THIS)
+ { XXX; return _DOCALL0(GetLevelCount); }
+ STDMETHOD(SetAutoGenFilterType)(THIS_ D3DTEXTUREFILTERTYPE FilterType)
+ { XXX; return _DOCALL(SetAutoGenFilterType, FilterType); }
+ STDMETHOD_(D3DTEXTUREFILTERTYPE, GetAutoGenFilterType)(THIS)
+ { XXX; return _DOCALL0(GetAutoGenFilterType); }
+
+ STDMETHOD_(void, GenerateMipSubLevels)(THIS)
+ { XXX; return _DOCALL0(GenerateMipSubLevels); }
+
+ STDMETHOD(GetLevelDesc)(THIS_ UINT Level,D3DSURFACE_DESC *pDesc)
+ { XXX; return _DOCALL(GetLevelDesc, Level, pDesc); }
+
+ STDMETHOD(GetSurfaceLevel)(THIS_ UINT Level,IDirect3DSurface9** ppSurfaceLevel)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(GetSurfaceLevel, Level, ppSurfaceLevel);
+ return AllocOverride( &hr, m_Data.pDevice, ppSurfaceLevel );
+ }
+ STDMETHOD(LockRect)(THIS_ UINT Level,D3DLOCKED_RECT* pLockedRect,CONST RECT* pRect,DWORD Flags)
+ { XXX; return _DOCALL(LockRect, Level, pLockedRect, pRect, Flags); }
+ STDMETHOD(UnlockRect)(THIS_ UINT Level)
+ { XXX; return _DOCALL(UnlockRect, Level); }
+
+ STDMETHOD(AddDirtyRect)(THIS_ CONST RECT* pDirtyRect)
+ { XXX; return _DOCALL(AddDirtyRect, pDirtyRect); }
+};
+
+class CDirect3DCubeTexture9Hook : public CDx9HookBase<IDirect3DCubeTexture9>, public IDirect3DCubeTexture9
+{
+public:
+ /*** IUnknown methods ***/
+ IMPL_IUNKOWN();
+
+ /*** IDirect3DBaseTexture9 methods ***/
+ IMPL_IDIRECT3DRESOURCE9();
+
+ STDMETHOD_(DWORD, SetLOD)(THIS_ DWORD LODNew)
+ { XXX; return _DOCALL(SetLOD, LODNew); }
+ STDMETHOD_(DWORD, GetLOD)(THIS)
+ { XXX; return _DOCALL0(GetLOD); }
+ STDMETHOD_(DWORD, GetLevelCount)(THIS)
+ { XXX; return _DOCALL0(GetLevelCount); }
+ STDMETHOD(SetAutoGenFilterType)(THIS_ D3DTEXTUREFILTERTYPE FilterType)
+ { XXX; return _DOCALL(SetAutoGenFilterType, FilterType); }
+ STDMETHOD_(D3DTEXTUREFILTERTYPE, GetAutoGenFilterType)(THIS)
+ { XXX; return _DOCALL0(GetAutoGenFilterType); }
+
+ STDMETHOD_(void, GenerateMipSubLevels)(THIS)
+ { XXX; return _DOCALL0(GenerateMipSubLevels); }
+
+ STDMETHOD(GetLevelDesc)(THIS_ UINT Level,D3DSURFACE_DESC *pDesc)
+ { XXX; return _DOCALL(GetLevelDesc, Level, pDesc); }
+
+ STDMETHOD(GetCubeMapSurface)(THIS_ D3DCUBEMAP_FACES FaceType,UINT Level,IDirect3DSurface9** ppCubeMapSurface)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(GetCubeMapSurface, FaceType, Level, ppCubeMapSurface);
+ return AllocOverride(&hr, m_Data.pDevice, ppCubeMapSurface);
+ }
+ STDMETHOD(LockRect)(THIS_ D3DCUBEMAP_FACES FaceType,UINT Level,D3DLOCKED_RECT* pLockedRect,CONST RECT* pRect,DWORD Flags)
+ { XXX; return _DOCALL(LockRect, FaceType, Level, pLockedRect, pRect, Flags); }
+ STDMETHOD(UnlockRect)(THIS_ D3DCUBEMAP_FACES FaceType,UINT Level)
+ { XXX; return _DOCALL(UnlockRect, FaceType, Level); }
+
+ STDMETHOD(AddDirtyRect)(THIS_ D3DCUBEMAP_FACES FaceType,CONST RECT* pDirtyRect)
+ { XXX; return _DOCALL(AddDirtyRect, FaceType, pDirtyRect); }
+};
+
+class CDirect3DVolume9Hook : public CDx9HookBase<IDirect3DVolume9>, public IDirect3DVolume9
+{
+public:
+ /*** IUnknown methods ***/
+ IMPL_IUNKOWN();
+
+ /*** IDirect3DVolume9 methods ***/
+ IMPL_GETDEVICE();
+
+ IMPL_SETPRIVATEDATA();
+ IMPL_GETPRIVATEDATA();
+ IMPL_FREEPRIVATEDATA()
+
+ STDMETHOD(GetContainer)(THIS_ REFIID riid,void** ppContainer)
+ {
+ //$ TODO: do the call, check riid, and wrap the returned ppContainer
+ __debugbreak();
+ XXX; return _DOCALL(GetContainer, riid, ppContainer);
+ }
+
+ STDMETHOD(GetDesc)(THIS_ D3DVOLUME_DESC *pDesc)
+ { XXX; return _DOCALL(GetDesc, pDesc); }
+
+ STDMETHOD(LockBox)(THIS_ D3DLOCKED_BOX * pLockedVolume,CONST D3DBOX* pBox,DWORD Flags)
+ { XXX; return _DOCALL(LockBox, pLockedVolume, pBox, Flags); }
+ STDMETHOD(UnlockBox)(THIS)
+ { XXX; return _DOCALL0(UnlockBox); }
+};
+
+class CDirect3DVolumeTexture9Hook : public CDx9HookBase<IDirect3DVolumeTexture9>, public IDirect3DVolumeTexture9
+{
+public:
+ /*** IUnknown methods ***/
+ IMPL_IUNKOWN();
+
+ /*** IDirect3DBaseTexture9 methods ***/
+ IMPL_IDIRECT3DRESOURCE9();
+
+ STDMETHOD_(DWORD, SetLOD)(THIS_ DWORD LODNew)
+ { XXX; return _DOCALL(SetLOD, LODNew); }
+ STDMETHOD_(DWORD, GetLOD)(THIS)
+ { XXX; return _DOCALL0(GetLOD); }
+ STDMETHOD_(DWORD, GetLevelCount)(THIS)
+ { XXX; return _DOCALL0(GetLevelCount); }
+ STDMETHOD(SetAutoGenFilterType)(THIS_ D3DTEXTUREFILTERTYPE FilterType)
+ { XXX; return _DOCALL(SetAutoGenFilterType, FilterType); }
+ STDMETHOD_(D3DTEXTUREFILTERTYPE, GetAutoGenFilterType)(THIS)
+ { XXX; return _DOCALL0(GetAutoGenFilterType); }
+
+ STDMETHOD_(void, GenerateMipSubLevels)(THIS)
+ { XXX; return _DOCALL0(GenerateMipSubLevels); }
+
+ STDMETHOD(GetLevelDesc)(THIS_ UINT Level,D3DVOLUME_DESC *pDesc)
+ { XXX; return _DOCALL(GetLevelDesc, Level, pDesc); }
+
+ STDMETHOD(GetVolumeLevel)(THIS_ UINT Level,IDirect3DVolume9** ppVolumeLevel)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(GetVolumeLevel, Level, ppVolumeLevel);
+ return AllocOverride( &hr, m_Data.pDevice, ppVolumeLevel );
+ }
+ STDMETHOD(LockBox)(THIS_ UINT Level,D3DLOCKED_BOX* pLockedVolume,CONST D3DBOX* pBox,DWORD Flags)
+ { XXX; return _DOCALL(LockBox, Level, pLockedVolume, pBox, Flags); }
+ STDMETHOD(UnlockBox)(THIS_ UINT Level)
+ { XXX; return _DOCALL(UnlockBox, Level); }
+
+ STDMETHOD(AddDirtyBox)(THIS_ CONST D3DBOX* pDirtyBox)
+ { XXX; return _DOCALL(AddDirtyBox, pDirtyBox); }
+};
+
+class CDirect3DDevice9Hook : public CDx9HookBase<IDirect3DDevice9>, public IDirect3DDevice9
+{
+public:
+ /*** IUnknown methods ***/
+ IMPL_IUNKOWN();
+
+ CDirect3DDevice9Hook() : CDx9HookBase<IDirect3DDevice9>(), IDirect3DDevice9()
+ {
+ D3D_BATCH_PERF( g_nTotalD3DCycles = 0; g_nTotalD3DCalls = 0; m_batch_state.Clear(); m_nTotalDraws = 0; m_nTotalPrims = 0; m_nTotalD3DCalls = 0; m_flTotalD3DTime = 0; m_nOverallDraws = 0; m_nOverallPrims = 0; m_nOverallD3DCalls = 0; m_flOverallD3DTime = 0; m_nTotalFrames = 0; m_pPrevRenderTarget0 = NULL; )
+ }
+
+ // IDirect3DDevice9 methods
+ STDMETHOD(TestCooperativeLevel)(THIS)
+ { XXX; return _DOCALL0(TestCooperativeLevel); }
+ STDMETHOD_(UINT, GetAvailableTextureMem)(THIS)
+ { XXX; return _DOCALL0(GetAvailableTextureMem); }
+ STDMETHOD(EvictManagedResources)(THIS)
+ { XXX; return _DOCALL0(EvictManagedResources); }
+ STDMETHOD(GetDirect3D)(THIS_ IDirect3D9** ppD3D9)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(GetDirect3D, ppD3D9);
+ return AllocOverride(&hr, this, ppD3D9);
+ }
+ STDMETHOD(GetDeviceCaps)(THIS_ D3DCAPS9* pCaps)
+ { XXX; return _DOCALL(GetDeviceCaps, pCaps); }
+ STDMETHOD(GetDisplayMode)(THIS_ UINT iSwapChain,D3DDISPLAYMODE* pMode)
+ { XXX; return _DOCALL(GetDisplayMode, iSwapChain, pMode); }
+ STDMETHOD(GetCreationParameters)(THIS_ D3DDEVICE_CREATION_PARAMETERS *pParameters)
+ { XXX; return _DOCALL(GetCreationParameters, pParameters); }
+ STDMETHOD(SetCursorProperties)(THIS_ UINT XHotSpot,UINT YHotSpot,IDirect3DSurface9* pCursorBitmap)
+ { XXX; return _DOCALL(SetCursorProperties, XHotSpot, YHotSpot, GetHWPtr(pCursorBitmap)); }
+ STDMETHOD_(void, SetCursorPosition)(THIS_ int X,int Y,DWORD Flags)
+ { XXX; _DOCALL_NORET(SetCursorPosition, X, Y, Flags); }
+ STDMETHOD_(BOOL, ShowCursor)(THIS_ BOOL bShow)
+ { XXX; return _DOCALL(ShowCursor, bShow); }
+ STDMETHOD(CreateAdditionalSwapChain)(THIS_ D3DPRESENT_PARAMETERS* pPresentationParameters,IDirect3DSwapChain9** ppSwapChain)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(CreateAdditionalSwapChain, pPresentationParameters, ppSwapChain);
+ return AllocOverride(&hr, this, ppSwapChain);
+ }
+ STDMETHOD(GetSwapChain)(THIS_ UINT iSwapChain,IDirect3DSwapChain9** ppSwapChain)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(GetSwapChain, iSwapChain, ppSwapChain);
+ return AllocOverride(&hr, this, ppSwapChain);
+ }
+ STDMETHOD_(UINT, GetNumberOfSwapChains)(THIS)
+ { XXX; return _DOCALL0(GetNumberOfSwapChains); }
+ STDMETHOD(Reset)(THIS_ D3DPRESENT_PARAMETERS* pPresentationParameters)
+ { XXX; return _DOCALL( Reset, pPresentationParameters ); }
+ STDMETHOD(Present)(THIS_ CONST RECT* pSourceRect,CONST RECT* pDestRect,HWND hDestWindowOverride,CONST RGNDATA* pDirtyRegion)
+ {
+ HRESULT hres;
+
+#if D3D_BATCH_PERF_ANALYSIS
+ uint64 nStartCycles = g_nTotalD3DCycles;
+
+ CFastTimer tm;
+ tm.Start();
+
+ g_nTotalD3DCalls++;
+#endif
+
+ {
+ XXX;
+ hres = _DOCALL(Present, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion);
+ }
+
+#if D3D_BATCH_PERF_ANALYSIS
+ const uint nFrameIndex = m_nTotalFrames;
+ m_nTotalFrames++;
+
+ if (nFrameIndex >= 5)
+ {
+ double flPresentTime = tm.GetDurationInProgress().GetMillisecondsF();
+ uint64 nEndCycles = g_nTotalD3DCycles;
+
+ double flTotalPresentTime = ( nEndCycles - nStartCycles ) * s_rdtsc_to_ms;
+
+ m_nTotalD3DCalls += g_nTotalD3DCalls;
+ m_flTotalD3DTime += g_nTotalD3DCycles * s_rdtsc_to_ms;
+
+ static int bPrevBatchVis = -1;
+
+ if ((bPrevBatchVis == 1) && m_batch_vis_bitmap.is_valid())
+ {
+ m_nOverallDraws += m_nTotalDraws;
+ m_nOverallPrims += m_nTotalPrims;
+ m_nOverallD3DCalls += m_nTotalD3DCalls;
+ m_flOverallD3DTime += m_flTotalD3DTime;
+
+ m_batch_vis_bitmap.fill_box(0, m_nBatchVisY, (uint)(.5f + flPresentTime / d3d_present_vis_abs_scale.GetFloat() * m_batch_vis_bitmap.width()), 10, 255, 16, 128);
+ m_batch_vis_bitmap.additive_fill_box(0, m_nBatchVisY, (uint)(.5f + flTotalPresentTime / d3d_present_vis_abs_scale.GetFloat() * m_batch_vis_bitmap.width()), 10, 0, 255, 128);
+ m_nBatchVisY += 10;
+
+ uint y = MAX( 600, m_nBatchVisY + 20 ), l = 0;
+ m_batch_vis_bitmap.draw_formatted_text(0, y+8*(l++), 1, 255, 255, 255, "Frame: %u, Batches: %u, Prims: %u", nFrameIndex, m_nTotalDraws, m_nTotalPrims );
+ m_batch_vis_bitmap.draw_formatted_text(0, y+8*(l++), 1, 255, 255, 255, "Frame: D3D Calls: %u, D3D Time: %3.3fms", m_nTotalD3DCalls, m_flTotalD3DTime);
+ l++;
+ m_batch_vis_bitmap.draw_formatted_text(0, y+8*(l++), 1, 255, 255, 255, "Overall: Batches: %u, Prims: %u", m_nOverallDraws, m_nOverallPrims );
+ m_batch_vis_bitmap.draw_formatted_text(0, y+8*(l++), 1, 255, 255, 255, "Overall: D3D Calls: %u D3D Time: %4.3fms", m_nOverallD3DCalls, m_flOverallD3DTime );
+
+ size_t png_size = 0;
+ void *pPNG_data = tdefl_write_image_to_png_file_in_memory(m_batch_vis_bitmap.get_ptr(), m_batch_vis_bitmap.width(), m_batch_vis_bitmap.height(), 3, &png_size, true);
+ if (pPNG_data)
+ {
+ char filename[256];
+ V_snprintf(filename, sizeof(filename), "left4dead2/batchvis_%u_%u.png", m_nBatchVisFileIdx, m_nBatchVisFrameIndex);
+ FILE* pFile = fopen(filename, "wb");
+ if (pFile)
+ {
+ fwrite(pPNG_data, png_size, 1, pFile);
+ fclose(pFile);
+ }
+ free(pPNG_data);
+ }
+ m_nBatchVisFrameIndex++;
+ m_nBatchVisY = 0;
+ m_batch_vis_bitmap.cls();
+ }
+
+ if (bPrevBatchVis != (int)d3d_batch_vis.GetBool())
+ {
+ bPrevBatchVis = d3d_batch_vis.GetBool();
+ if (!bPrevBatchVis)
+ {
+ m_batch_vis_bitmap.clear();
+ }
+ else
+ {
+ m_batch_vis_bitmap.init(768, 1024);
+ }
+ m_nBatchVisY = 0;
+ m_nBatchVisFrameIndex = 0;
+ m_nBatchVisFileIdx = (uint)time(NULL); //rand();
+
+ m_nOverallDraws = 0;
+ m_nOverallPrims = 0;
+ m_nOverallD3DCalls = 0;
+ m_flOverallD3DTime = 0;
+ }
+ }
+
+ m_nTotalD3DCalls = 0;
+ m_nTotalPrims = 0;
+ m_flTotalD3DTime = 0;
+ g_nTotalD3DCycles = 0;
+ g_nTotalD3DCalls = 0;
+ m_nTotalDraws = 0;
+#else
+ if ( d3d_batch_vis.GetBool() )
+ {
+ d3d_batch_vis.SetValue( false );
+
+ ConMsg( "Must define D3D_BATCH_PERF_ANALYSIS to use this feature" );
+ }
+#endif
+
+ return hres;
+ }
+
+ STDMETHOD(GetBackBuffer)(THIS_ UINT iSwapChain,UINT iBackBuffer,D3DBACKBUFFER_TYPE Type,IDirect3DSurface9** ppBackBuffer)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(GetBackBuffer, iSwapChain, iBackBuffer, Type, ppBackBuffer);
+ return AllocOverride(&hr, this, ppBackBuffer);
+ }
+ STDMETHOD(GetRasterStatus)(THIS_ UINT iSwapChain,D3DRASTER_STATUS* pRasterStatus)
+ { XXX; return _DOCALL(GetRasterStatus, iSwapChain, pRasterStatus); }
+ STDMETHOD(SetDialogBoxMode)(THIS_ BOOL bEnableDialogs)
+ { XXX; return _DOCALL(SetDialogBoxMode, bEnableDialogs); }
+ STDMETHOD_(void, SetGammaRamp)(THIS_ UINT iSwapChain,DWORD Flags,CONST D3DGAMMARAMP* pRamp)
+ { XXX; _DOCALL_NORET(SetGammaRamp, iSwapChain, Flags, pRamp); }
+ STDMETHOD_(void, GetGammaRamp)(THIS_ UINT iSwapChain,D3DGAMMARAMP* pRamp)
+ { XXX; _DOCALL_NORET(GetGammaRamp, iSwapChain, pRamp); }
+ STDMETHOD(CreateTexture)(THIS_ UINT Width,UINT Height,UINT Levels,DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,IDirect3DTexture9** ppTexture,HANDLE* pSharedHandle)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(CreateTexture, Width, Height, Levels, Usage, Format, Pool, ppTexture, pSharedHandle);
+ return AllocOverride(&hr, this, ppTexture);
+ }
+ STDMETHOD(CreateVolumeTexture)(THIS_ UINT Width,UINT Height,UINT Depth,UINT Levels,DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,IDirect3DVolumeTexture9** ppVolumeTexture,HANDLE* pSharedHandle)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(CreateVolumeTexture, Width, Height, Depth, Levels, Usage, Format, Pool, ppVolumeTexture, pSharedHandle);
+ return AllocOverride(&hr, this, ppVolumeTexture);
+ }
+ STDMETHOD(CreateCubeTexture)(THIS_ UINT EdgeLength,UINT Levels,DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,IDirect3DCubeTexture9** ppCubeTexture,HANDLE* pSharedHandle)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(CreateCubeTexture, EdgeLength, Levels, Usage, Format, Pool, ppCubeTexture, pSharedHandle);
+ return AllocOverride(&hr, this, ppCubeTexture);
+ }
+ STDMETHOD(CreateVertexBuffer)(THIS_ UINT Length,DWORD Usage,DWORD FVF,D3DPOOL Pool,IDirect3DVertexBuffer9** ppVertexBuffer,HANDLE* pSharedHandle)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(CreateVertexBuffer, Length, Usage, FVF, Pool, ppVertexBuffer, pSharedHandle);
+ return AllocOverride(&hr, this, ppVertexBuffer);
+ }
+ STDMETHOD(CreateIndexBuffer)(THIS_ UINT Length,DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,IDirect3DIndexBuffer9** ppIndexBuffer,HANDLE* pSharedHandle)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(CreateIndexBuffer, Length, Usage, Format, Pool, ppIndexBuffer, pSharedHandle);
+ return AllocOverride(&hr, this, ppIndexBuffer);
+ }
+ STDMETHOD(CreateRenderTarget)(THIS_ UINT Width,UINT Height,D3DFORMAT Format,D3DMULTISAMPLE_TYPE MultiSample,DWORD MultiSampleQuality,BOOL Lockable,IDirect3DSurface9** ppSurface,HANDLE* pSharedHandle)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(CreateRenderTarget, Width, Height, Format, MultiSample, MultiSampleQuality, Lockable, ppSurface, pSharedHandle);
+ return AllocOverride(&hr, this, ppSurface);
+ }
+ STDMETHOD(CreateDepthStencilSurface)(THIS_ UINT Width,UINT Height,D3DFORMAT Format,D3DMULTISAMPLE_TYPE MultiSample,DWORD MultiSampleQuality,BOOL Discard,IDirect3DSurface9** ppSurface,HANDLE* pSharedHandle)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(CreateDepthStencilSurface, Width, Height, Format, MultiSample, MultiSampleQuality, Discard, ppSurface, pSharedHandle);
+ return AllocOverride(&hr, this, ppSurface);
+ }
+ STDMETHOD(UpdateSurface)(THIS_ IDirect3DSurface9* pSourceSurface,CONST RECT* pSourceRect,IDirect3DSurface9* pDestinationSurface,CONST POINT* pDestPoint)
+ { XXX; return _DOCALL(UpdateSurface, GetHWPtr(pSourceSurface), pSourceRect, GetHWPtr(pDestinationSurface), pDestPoint); }
+ STDMETHOD(UpdateTexture)(THIS_ IDirect3DBaseTexture9* pSourceTexture,IDirect3DBaseTexture9* pDestinationTexture)
+ { XXX; return _DOCALL(UpdateTexture, GetHWPtr(pSourceTexture), GetHWPtr(pDestinationTexture)); }
+ STDMETHOD(GetRenderTargetData)(THIS_ IDirect3DSurface9* pRenderTarget,IDirect3DSurface9* pDestSurface)
+ { XXX; return _DOCALL(GetRenderTargetData, GetHWPtr(pRenderTarget), GetHWPtr(pDestSurface)); }
+ STDMETHOD(GetFrontBufferData)(THIS_ UINT iSwapChain,IDirect3DSurface9* pDestSurface)
+ { XXX; return _DOCALL(GetFrontBufferData, iSwapChain, GetHWPtr(pDestSurface)); }
+ STDMETHOD(StretchRect)(THIS_ IDirect3DSurface9* pSourceSurface,CONST RECT* pSourceRect,IDirect3DSurface9* pDestSurface,CONST RECT* pDestRect,D3DTEXTUREFILTERTYPE Filter)
+ { XXX; return _DOCALL(StretchRect, GetHWPtr(pSourceSurface), pSourceRect, GetHWPtr(pDestSurface), pDestRect, Filter); }
+ STDMETHOD(ColorFill)(THIS_ IDirect3DSurface9* pSurface,CONST RECT* pRect,D3DCOLOR color)
+ { XXX; return _DOCALL(ColorFill, GetHWPtr(pSurface), pRect, color); }
+ STDMETHOD(CreateOffscreenPlainSurface)(THIS_ UINT Width,UINT Height,D3DFORMAT Format,D3DPOOL Pool,IDirect3DSurface9** ppSurface,HANDLE* pSharedHandle)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(CreateOffscreenPlainSurface, Width, Height, Format, Pool, ppSurface, pSharedHandle);
+ return AllocOverride(&hr, this, ppSurface);
+ }
+
+ STDMETHOD(SetRenderTarget)(THIS_ DWORD RenderTargetIndex,IDirect3DSurface9* pRenderTarget)
+ {
+ HRESULT hres;
+ {
+ XXX;
+ hres = _DOCALL(SetRenderTarget, RenderTargetIndex, GetHWPtr(pRenderTarget));
+ }
+#if D3D_BATCH_PERF_ANALYSIS
+ if ( m_batch_vis_bitmap.is_valid() && !RenderTargetIndex )
+ {
+ if ( pRenderTarget != m_pPrevRenderTarget0 )
+ {
+ m_batch_vis_bitmap.fill_box(0, m_nBatchVisY, m_batch_vis_bitmap.width(), 1, 30, 20, 20);
+ m_nBatchVisY += 1;
+ }
+ }
+ if ( !RenderTargetIndex )
+ {
+ m_pPrevRenderTarget0 = pRenderTarget;
+ }
+#endif
+ return hres;
+ }
+
+ STDMETHOD(GetRenderTarget)(THIS_ DWORD RenderTargetIndex,IDirect3DSurface9** ppRenderTarget)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(GetRenderTarget, RenderTargetIndex, ppRenderTarget);
+ return AllocOverride(&hr, this, ppRenderTarget);
+ }
+ STDMETHOD(SetDepthStencilSurface)(THIS_ IDirect3DSurface9* pNewZStencil)
+ { XXX; return _DOCALL(SetDepthStencilSurface, GetHWPtr(pNewZStencil)); }
+ STDMETHOD(GetDepthStencilSurface)(THIS_ IDirect3DSurface9** ppZStencilSurface)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(GetDepthStencilSurface, ppZStencilSurface);
+ return AllocOverride(&hr, this, ppZStencilSurface);
+ }
+ STDMETHOD(BeginScene)(THIS)
+ { XXX; return _DOCALL0(BeginScene); }
+ STDMETHOD(EndScene)(THIS)
+ { XXX; return _DOCALL0(EndScene); }
+ STDMETHOD(Clear)(THIS_ DWORD Count,CONST D3DRECT* pRects,DWORD Flags,D3DCOLOR Color,float Z,DWORD Stencil)
+ { XXX; return _DOCALL(Clear, Count, pRects, Flags, Color, Z, Stencil); }
+ STDMETHOD(SetTransform)(THIS_ D3DTRANSFORMSTATETYPE State,CONST D3DMATRIX* pMatrix)
+ { XXX; return _DOCALL(SetTransform, State, pMatrix); }
+ STDMETHOD(GetTransform)(THIS_ D3DTRANSFORMSTATETYPE State,D3DMATRIX* pMatrix)
+ { XXX; return _DOCALL(GetTransform, State, pMatrix); }
+ STDMETHOD(MultiplyTransform)(THIS_ D3DTRANSFORMSTATETYPE State,CONST D3DMATRIX *pMatrix)
+ { XXX; return _DOCALL(MultiplyTransform, State, pMatrix); }
+ STDMETHOD(SetViewport)(THIS_ CONST D3DVIEWPORT9* pViewport)
+ { XXX; return _DOCALL(SetViewport, pViewport); }
+ STDMETHOD(GetViewport)(THIS_ D3DVIEWPORT9* pViewport)
+ { XXX; return _DOCALL(GetViewport, pViewport); }
+ STDMETHOD(SetMaterial)(THIS_ CONST D3DMATERIAL9* pMaterial)
+ { XXX; return _DOCALL(SetMaterial, pMaterial); }
+ STDMETHOD(GetMaterial)(THIS_ D3DMATERIAL9* pMaterial)
+ { XXX; return _DOCALL(GetMaterial, pMaterial); }
+ STDMETHOD(SetLight)(THIS_ DWORD Index,CONST D3DLIGHT9* pLight)
+ { XXX; return _DOCALL(SetLight, Index, pLight); }
+ STDMETHOD(GetLight)(THIS_ DWORD Index,D3DLIGHT9* pLight)
+ { XXX; return _DOCALL(GetLight, Index, pLight); }
+ STDMETHOD(LightEnable)(THIS_ DWORD Index,BOOL Enable)
+ { XXX; return _DOCALL(LightEnable, Index, Enable); }
+ STDMETHOD(GetLightEnable)(THIS_ DWORD Index,BOOL* pEnable)
+ { XXX; return _DOCALL(GetLightEnable, Index, pEnable); }
+ STDMETHOD(SetClipPlane)(THIS_ DWORD Index,CONST float* pPlane)
+ { XXX; return _DOCALL(SetClipPlane, Index, pPlane);}
+ STDMETHOD(GetClipPlane)(THIS_ DWORD Index,float* pPlane)
+ { XXX; return _DOCALL(GetClipPlane, Index, pPlane); }
+ STDMETHOD(SetRenderState)(THIS_ D3DRENDERSTATETYPE State,DWORD Value)
+ { XXX; return _DOCALL(SetRenderState, State, Value); }
+ STDMETHOD(GetRenderState)(THIS_ D3DRENDERSTATETYPE State,DWORD* pValue)
+ { XXX; return _DOCALL(GetRenderState, State, pValue); }
+ STDMETHOD(CreateStateBlock)(THIS_ D3DSTATEBLOCKTYPE Type,IDirect3DStateBlock9** ppSB)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(CreateStateBlock, Type, ppSB);
+ return AllocOverride(&hr, this, ppSB);
+ }
+ STDMETHOD(BeginStateBlock)(THIS)
+ { XXX; return _DOCALL0(BeginStateBlock); }
+ STDMETHOD(EndStateBlock)(THIS_ IDirect3DStateBlock9** ppSB)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(EndStateBlock, ppSB);
+ return AllocOverride(&hr, this, ppSB);
+ }
+ STDMETHOD(SetClipStatus)(THIS_ CONST D3DCLIPSTATUS9* pClipStatus)
+ { XXX; return _DOCALL(SetClipStatus, pClipStatus);}
+ STDMETHOD(GetClipStatus)(THIS_ D3DCLIPSTATUS9* pClipStatus)
+ { XXX; return _DOCALL(GetClipStatus, pClipStatus);}
+ STDMETHOD(GetTexture)(THIS_ DWORD Stage,IDirect3DBaseTexture9** ppTexture)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(GetTexture, Stage, ppTexture);
+ return AllocOverride(&hr, this, ppTexture);
+ }
+
+ STDMETHOD(SetTexture)(THIS_ DWORD Stage,IDirect3DBaseTexture9* pTexture)
+ {
+ HRESULT hres;
+ {
+ XXX;
+ hres = _DOCALL(SetTexture, Stage, GetHWPtr(pTexture));
+ }
+ D3D_BATCH_PERF( m_batch_state.m_nNumSamplersChanged++; )
+ return hres;
+ }
+
+ STDMETHOD(GetTextureStageState)(THIS_ DWORD Stage,D3DTEXTURESTAGESTATETYPE Type,DWORD* pValue)
+ { XXX; return _DOCALL(GetTextureStageState, Stage, Type, pValue); }
+ STDMETHOD(SetTextureStageState)(THIS_ DWORD Stage,D3DTEXTURESTAGESTATETYPE Type,DWORD Value)
+ { XXX; return _DOCALL(SetTextureStageState, Stage, Type, Value); }
+ STDMETHOD(GetSamplerState)(THIS_ DWORD Sampler,D3DSAMPLERSTATETYPE Type,DWORD* pValue)
+ { XXX; return _DOCALL(GetSamplerState, Sampler, Type, pValue); }
+ STDMETHOD(SetSamplerState)(THIS_ DWORD Sampler,D3DSAMPLERSTATETYPE Type,DWORD Value)
+ {
+ HRESULT hres;
+ {
+ XXX;
+ hres = _DOCALL(SetSamplerState, Sampler, Type, Value);
+ }
+ D3D_BATCH_PERF( m_batch_state.m_nNumSamplerStatesChanged++; )
+ return hres;
+ }
+
+ STDMETHOD(ValidateDevice)(THIS_ DWORD* pNumPasses)
+ { XXX; return _DOCALL(ValidateDevice, pNumPasses); }
+ STDMETHOD(SetPaletteEntries)(THIS_ UINT PaletteNumber,CONST PALETTEENTRY* pEntries)
+ { XXX; return _DOCALL(SetPaletteEntries, PaletteNumber, pEntries); }
+ STDMETHOD(GetPaletteEntries)(THIS_ UINT PaletteNumber,PALETTEENTRY* pEntries)
+ { XXX; return _DOCALL(GetPaletteEntries, PaletteNumber, pEntries); }
+ STDMETHOD(SetCurrentTexturePalette)(THIS_ UINT PaletteNumber)
+ { XXX; return _DOCALL(SetCurrentTexturePalette, PaletteNumber);}
+ STDMETHOD(GetCurrentTexturePalette)(THIS_ UINT *PaletteNumber)
+ { XXX; return _DOCALL(GetCurrentTexturePalette, PaletteNumber); }
+ STDMETHOD(SetScissorRect)(THIS_ CONST RECT* pRect)
+ { XXX; return _DOCALL(SetScissorRect, pRect); }
+ STDMETHOD(GetScissorRect)(THIS_ RECT* pRect)
+ { XXX; return _DOCALL(GetScissorRect, pRect); }
+ STDMETHOD(SetSoftwareVertexProcessing)(THIS_ BOOL bSoftware)
+ { XXX; return _DOCALL(SetSoftwareVertexProcessing, bSoftware); }
+ STDMETHOD_(BOOL, GetSoftwareVertexProcessing)(THIS)
+ { XXX; return _DOCALL0(GetSoftwareVertexProcessing); }
+ STDMETHOD(SetNPatchMode)(THIS_ float nSegments)
+ { XXX; return _DOCALL(SetNPatchMode, nSegments); }
+ STDMETHOD_(float, GetNPatchMode)(THIS)
+ { XXX; return _DOCALL0(GetNPatchMode);}
+ STDMETHOD(DrawPrimitive)(THIS_ D3DPRIMITIVETYPE PrimitiveType,UINT StartVertex,UINT PrimitiveCount)
+ { XXX; m_nTotalDraws++; m_nTotalPrims += PrimitiveCount; return _DOCALL(DrawPrimitive, PrimitiveType, StartVertex, PrimitiveCount); }
+ STDMETHOD(DrawIndexedPrimitive)(THIS_ D3DPRIMITIVETYPE PrimitiveType,INT BaseVertexIndex,UINT MinVertexIndex,UINT NumVertices,UINT startIndex,UINT primCount)
+ {
+ m_nTotalDraws++;
+ m_nTotalPrims += primCount;
+
+#if D3D_BATCH_PERF_ANALYSIS
+ CFastTimer tm;
+ if ( m_batch_vis_bitmap.is_valid() )
+ {
+ tm.Start();
+ }
+#endif
+
+ HRESULT hres;
+ {
+ XXX;
+ hres = _DOCALL(DrawIndexedPrimitive, PrimitiveType, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
+ }
+
+#if D3D_BATCH_PERF_ANALYSIS
+ if ( m_batch_vis_bitmap.is_valid() )
+ {
+ double t = tm.GetDurationInProgress().GetMillisecondsF();
+
+ uint h = 1;
+ if ( d3d_batch_vis_y_scale.GetFloat() > 0.0f)
+ {
+ h = ceil( t / d3d_batch_vis_y_scale.GetFloat() );
+ h = MAX(h, 1);
+ }
+
+ m_batch_vis_bitmap.fill_box(0, m_nBatchVisY, (uint)(.5f + t / d3d_batch_vis_abs_scale.GetFloat() * m_batch_vis_bitmap.width()), h, 64, 64, 64);
+
+ if ( s_rdtsc_to_ms == 0.0f )
+ {
+ TmU64 t0 = tmFastTime();
+ double d0 = Plat_FloatTime();
+
+ ThreadSleep( 1 );
+
+ TmU64 t1 = tmFastTime();
+ double d1 = Plat_FloatTime();
+
+ s_rdtsc_to_ms = ( 1000.0f * ( d1 - d0 ) ) / ( t1 - t0 );
+ }
+
+ double flTotalD3DCallMS = g_nTotalD3DCycles * s_rdtsc_to_ms;
+
+ m_batch_vis_bitmap.additive_fill_box(0, m_nBatchVisY, (uint)(.5f + flTotalD3DCallMS / d3d_batch_vis_abs_scale.GetFloat() * m_batch_vis_bitmap.width()), h, 96, 96, 128);
+
+ if (m_batch_state.m_bVertexShaderChanged) m_batch_vis_bitmap.additive_fill_box(0, m_nBatchVisY, 8, h, 0, 0, 64);
+ if (m_batch_state.m_bPixelShaderChanged) m_batch_vis_bitmap.additive_fill_box(32, m_nBatchVisY, 8, h, 64, 0, 64);
+
+ int lm = 80;
+ m_batch_vis_bitmap.fill_box(lm+0+0, m_nBatchVisY, m_batch_state.m_nNumVSConstants, h, 64, 255, 255);
+ m_batch_vis_bitmap.fill_box(lm+64+256+0, m_nBatchVisY, m_batch_state.m_nNumPSConstants, h, 64, 64, 255);
+
+ m_batch_vis_bitmap.fill_box(lm+64+256+32, m_nBatchVisY, m_batch_state.m_nNumSamplersChanged, h, 255, 255, 255);
+ m_batch_vis_bitmap.fill_box(lm+64+256+32+16, m_nBatchVisY, m_batch_state.m_nNumSamplerStatesChanged, h, 92, 128, 255);
+
+ if ( m_batch_state.m_bStreamSourceChanged) m_batch_vis_bitmap.fill_box(lm+64+256+32+16+64, m_nBatchVisY, 16, h, 128, 128, 128);
+ if ( m_batch_state.m_bIndicesChanged ) m_batch_vis_bitmap.fill_box(lm+64+256+32+16+64+16, m_nBatchVisY, 16, h, 128, 128, 255);
+
+ m_nBatchVisY += h;
+
+ m_nTotalD3DCalls += g_nTotalD3DCalls;
+ m_flTotalD3DTime += flTotalD3DCallMS;
+
+ g_nTotalD3DCycles = 0;
+ g_nTotalD3DCalls = 0;
+
+ m_batch_state.Clear();
+ }
+#endif
+
+ return hres;
+ }
+
+ STDMETHOD(DrawPrimitiveUP)(THIS_ D3DPRIMITIVETYPE PrimitiveType,UINT PrimitiveCount,CONST void* pVertexStreamZeroData,UINT VertexStreamZeroStride)
+ { XXX; m_nTotalDraws++; m_nTotalPrims += PrimitiveCount; return _DOCALL(DrawPrimitiveUP, PrimitiveType, PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride); }
+ STDMETHOD(DrawIndexedPrimitiveUP)(THIS_ D3DPRIMITIVETYPE PrimitiveType,UINT MinVertexIndex,UINT NumVertices,UINT PrimitiveCount,CONST void* pIndexData,D3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,UINT VertexStreamZeroStride)
+ { XXX; m_nTotalDraws++; m_nTotalPrims += PrimitiveCount; return _DOCALL(DrawIndexedPrimitiveUP, PrimitiveType, MinVertexIndex, NumVertices, PrimitiveCount, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride); }
+ STDMETHOD(ProcessVertices)(THIS_ UINT SrcStartIndex,UINT DestIndex,UINT VertexCount,IDirect3DVertexBuffer9* pDestBuffer,IDirect3DVertexDeclaration9* pVertexDecl,DWORD Flags)
+ { XXX; return _DOCALL(ProcessVertices, SrcStartIndex, DestIndex, VertexCount, GetHWPtr(pDestBuffer), GetHWPtr(pVertexDecl), Flags); }
+ STDMETHOD(CreateVertexDeclaration)(THIS_ CONST D3DVERTEXELEMENT9* pVertexElements,IDirect3DVertexDeclaration9** ppDecl)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(CreateVertexDeclaration, pVertexElements, ppDecl);
+ return AllocOverride(&hr, this, ppDecl);
+ }
+ STDMETHOD(SetVertexDeclaration)(THIS_ IDirect3DVertexDeclaration9* pDecl)
+ { XXX; return _DOCALL(SetVertexDeclaration, GetHWPtr(pDecl)); }
+ STDMETHOD(GetVertexDeclaration)(THIS_ IDirect3DVertexDeclaration9** ppDecl)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(GetVertexDeclaration, ppDecl);
+ return AllocOverride(&hr, this, ppDecl);
+ }
+ STDMETHOD(SetFVF)(THIS_ DWORD FVF)
+ { XXX; return _DOCALL(SetFVF, FVF); }
+ STDMETHOD(GetFVF)(THIS_ DWORD* pFVF)
+ { XXX; return _DOCALL(GetFVF, pFVF); }
+ STDMETHOD(CreateVertexShader)(THIS_ CONST DWORD* pFunction,IDirect3DVertexShader9** ppShader)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(CreateVertexShader, pFunction, ppShader);
+ return AllocOverride(&hr, this, ppShader);
+ }
+
+ STDMETHOD(SetVertexShader)(THIS_ IDirect3DVertexShader9* pShader)
+ {
+ HRESULT hres;
+ {
+ XXX;
+ hres = _DOCALL(SetVertexShader, GetHWPtr(pShader));
+ }
+ D3D_BATCH_PERF( m_batch_state.m_bVertexShaderChanged = true; )
+ return hres;
+ }
+
+ STDMETHOD(GetVertexShader)(THIS_ IDirect3DVertexShader9** ppShader)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(GetVertexShader, ppShader);
+ return AllocOverride(&hr, this, ppShader);
+ }
+
+ STDMETHOD(SetVertexShaderConstantF)(THIS_ UINT StartRegister,CONST float* pConstantData,UINT Vector4fCount)
+ {
+ HRESULT hres;
+ {
+ XXX;
+ hres = _DOCALL(SetVertexShaderConstantF, StartRegister, pConstantData, Vector4fCount);
+ }
+ D3D_BATCH_PERF( m_batch_state.m_nNumVSConstants += Vector4fCount; )
+ return hres;
+ }
+
+ STDMETHOD(GetVertexShaderConstantF)(THIS_ UINT StartRegister,float* pConstantData,UINT Vector4fCount)
+ { XXX; return _DOCALL(GetVertexShaderConstantF, StartRegister, pConstantData, Vector4fCount);}
+ STDMETHOD(SetVertexShaderConstantI)(THIS_ UINT StartRegister,CONST int* pConstantData,UINT Vector4iCount)
+ { XXX; return _DOCALL(SetVertexShaderConstantI, StartRegister, pConstantData, Vector4iCount); }
+ STDMETHOD(GetVertexShaderConstantI)(THIS_ UINT StartRegister,int* pConstantData,UINT Vector4iCount)
+ { XXX; return _DOCALL(GetVertexShaderConstantI, StartRegister, pConstantData, Vector4iCount); }
+ STDMETHOD(SetVertexShaderConstantB)(THIS_ UINT StartRegister,CONST BOOL* pConstantData,UINT BoolCount)
+ { XXX; return _DOCALL(SetVertexShaderConstantB, StartRegister, pConstantData, BoolCount); }
+ STDMETHOD(GetVertexShaderConstantB)(THIS_ UINT StartRegister,BOOL* pConstantData,UINT BoolCount)
+ { XXX; return _DOCALL(GetVertexShaderConstantB, StartRegister, pConstantData, BoolCount); }
+
+ STDMETHOD(SetStreamSource)(THIS_ UINT StreamNumber,IDirect3DVertexBuffer9* pStreamData,UINT OffsetInBytes,UINT Stride)
+
+ {
+ HRESULT hres;
+ {
+ XXX;
+ hres = _DOCALL(SetStreamSource, StreamNumber, GetHWPtr(pStreamData), OffsetInBytes, Stride);
+ }
+
+ D3D_BATCH_PERF( m_batch_state.m_bStreamSourceChanged = true; )
+
+ return hres;
+ }
+
+ STDMETHOD(GetStreamSource)(THIS_ UINT StreamNumber,IDirect3DVertexBuffer9** ppStreamData,UINT* OffsetInBytes,UINT* pStride)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(GetStreamSource, StreamNumber, ppStreamData, OffsetInBytes, pStride);
+ return AllocOverride(&hr, this, ppStreamData);
+ }
+ STDMETHOD(SetStreamSourceFreq)(THIS_ UINT StreamNumber,UINT Divider)
+ { XXX; return _DOCALL(SetStreamSourceFreq, StreamNumber, Divider); }
+
+ STDMETHOD(GetStreamSourceFreq)(THIS_ UINT StreamNumber,UINT* Divider)
+ { XXX; return _DOCALL(GetStreamSourceFreq, StreamNumber, Divider); }
+
+ STDMETHOD(SetIndices)(THIS_ IDirect3DIndexBuffer9* pIndexData)
+ {
+ HRESULT hres;
+
+ {
+ XXX;
+ hres = _DOCALL(SetIndices, GetHWPtr(pIndexData));
+ }
+
+ D3D_BATCH_PERF( m_batch_state.m_bIndicesChanged = true; )
+
+ return hres;
+ }
+
+ STDMETHOD(GetIndices)(THIS_ IDirect3DIndexBuffer9** ppIndexData)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(GetIndices, ppIndexData);
+ return AllocOverride(&hr, this, ppIndexData);
+ }
+ STDMETHOD(CreatePixelShader)(THIS_ CONST DWORD* pFunction,IDirect3DPixelShader9** ppShader)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(CreatePixelShader, pFunction, ppShader);
+ return AllocOverride(&hr, this, ppShader);
+ }
+
+ STDMETHOD(SetPixelShader)(THIS_ IDirect3DPixelShader9* pShader)
+ {
+ HRESULT hres;
+ {
+ XXX;
+ hres = _DOCALL(SetPixelShader, GetHWPtr(pShader));
+ }
+ D3D_BATCH_PERF( m_batch_state.m_bPixelShaderChanged = true; )
+ return hres;
+ }
+
+ STDMETHOD(GetPixelShader)(THIS_ IDirect3DPixelShader9** ppShader)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(GetPixelShader, ppShader);
+ return AllocOverride(&hr, this, ppShader);
+ }
+
+ STDMETHOD(SetPixelShaderConstantF)(THIS_ UINT StartRegister,CONST float* pConstantData,UINT Vector4fCount)
+ {
+ HRESULT hres;
+ {
+ XXX;
+ hres = _DOCALL(SetPixelShaderConstantF, StartRegister, pConstantData, Vector4fCount);
+ }
+ D3D_BATCH_PERF( m_batch_state.m_nNumPSConstants += Vector4fCount; )
+ return hres;
+ }
+
+ STDMETHOD(GetPixelShaderConstantF)(THIS_ UINT StartRegister,float* pConstantData,UINT Vector4fCount)
+ { XXX; return _DOCALL(GetPixelShaderConstantF, StartRegister, pConstantData, Vector4fCount); }
+ STDMETHOD(SetPixelShaderConstantI)(THIS_ UINT StartRegister,CONST int* pConstantData,UINT Vector4iCount)
+ { XXX; return _DOCALL(SetPixelShaderConstantI, StartRegister, pConstantData, Vector4iCount); }
+ STDMETHOD(GetPixelShaderConstantI)(THIS_ UINT StartRegister,int* pConstantData,UINT Vector4iCount)
+ { XXX; return _DOCALL(GetPixelShaderConstantI, StartRegister, pConstantData, Vector4iCount); }
+ STDMETHOD(SetPixelShaderConstantB)(THIS_ UINT StartRegister,CONST BOOL* pConstantData,UINT BoolCount)
+ { XXX; return _DOCALL(SetPixelShaderConstantB, StartRegister, pConstantData, BoolCount); }
+ STDMETHOD(GetPixelShaderConstantB)(THIS_ UINT StartRegister,BOOL* pConstantData,UINT BoolCount)
+ { XXX; return _DOCALL(GetPixelShaderConstantB, StartRegister, pConstantData, BoolCount); }
+ STDMETHOD(DrawRectPatch)(THIS_ UINT Handle,CONST float* pNumSegs,CONST D3DRECTPATCH_INFO* pRectPatchInfo)
+ { XXX; return _DOCALL(DrawRectPatch, Handle, pNumSegs, pRectPatchInfo);}
+ STDMETHOD(DrawTriPatch)(THIS_ UINT Handle,CONST float* pNumSegs,CONST D3DTRIPATCH_INFO* pTriPatchInfo)
+ { XXX; return _DOCALL(DrawTriPatch, Handle, pNumSegs, pTriPatchInfo); }
+ STDMETHOD(DeletePatch)(THIS_ UINT Handle)
+ { XXX; return _DOCALL(DeletePatch, Handle);}
+ STDMETHOD(CreateQuery)(THIS_ D3DQUERYTYPE Type,IDirect3DQuery9** ppQuery)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(CreateQuery, Type, ppQuery);
+ return AllocOverride(&hr, this, ppQuery);
+ }
+
+private:
+
+#if D3D_BATCH_PERF_ANALYSIS
+ IDirect3DSurface9* m_pPrevRenderTarget0;
+ simple_bitmap m_batch_vis_bitmap;
+ uint m_nBatchVisY;
+ uint m_nBatchVisFrameIndex, m_nBatchVisFileIdx;
+
+ struct BatchState_t
+ {
+ void Clear() { memset(this, 0, sizeof(*this)); }
+
+ bool m_bStreamSourceChanged;
+ bool m_bIndicesChanged;
+ bool m_bPixelShaderChanged;
+ bool m_bVertexShaderChanged;
+ uint m_nNumPSConstants;
+ uint m_nNumVSConstants;
+ uint m_nNumSamplersChanged;
+ uint m_nNumSamplerStatesChanged;
+ };
+
+ BatchState_t m_batch_state;
+
+ uint m_nTotalFrames;
+
+ uint m_nTotalDraws;
+ uint m_nTotalPrims;
+ uint m_nTotalD3DCalls;
+ double m_flTotalD3DTime;
+
+ uint m_nOverallDraws;
+ uint m_nOverallPrims;
+ uint m_nOverallD3DCalls;
+ double m_flOverallD3DTime;
+#endif
+};
+
+class CDirect3D9Hook : public CDx9HookBase<IDirect3D9>, public IDirect3D9
+{
+public:
+ /*** IUnknown methods ***/
+ IMPL_IUNKOWN();
+
+ // IDirect3D9 methods
+ STDMETHOD(RegisterSoftwareDevice)(THIS_ void* pInitializeFunction)
+ { XXX; return _DOCALL(RegisterSoftwareDevice, pInitializeFunction); }
+ STDMETHOD_(UINT, GetAdapterCount)(THIS)
+ { XXX; return _DOCALL0(GetAdapterCount); }
+ STDMETHOD(GetAdapterIdentifier)(THIS_ UINT Adapter,DWORD Flags,D3DADAPTER_IDENTIFIER9* pIdentifier)
+ { XXX; return _DOCALL(GetAdapterIdentifier, Adapter, Flags, pIdentifier);}
+ STDMETHOD_(UINT, GetAdapterModeCount)(THIS_ UINT Adapter,D3DFORMAT Format)
+ { XXX; return _DOCALL(GetAdapterModeCount, Adapter, Format);}
+ STDMETHOD(EnumAdapterModes)(THIS_ UINT Adapter,D3DFORMAT Format,UINT Mode,D3DDISPLAYMODE* pMode)
+ { XXX; return _DOCALL(EnumAdapterModes, Adapter, Format, Mode, pMode); }
+ STDMETHOD(GetAdapterDisplayMode)(THIS_ UINT Adapter,D3DDISPLAYMODE* pMode)
+ { XXX; return _DOCALL(GetAdapterDisplayMode, Adapter, pMode); }
+ STDMETHOD(CheckDeviceType)(THIS_ UINT iAdapter,D3DDEVTYPE DevType,D3DFORMAT DisplayFormat,D3DFORMAT BackBufferFormat,BOOL bWindowed)
+ { XXX; return _DOCALL(CheckDeviceType, iAdapter, DevType, DisplayFormat, BackBufferFormat, bWindowed); }
+ STDMETHOD(CheckDeviceFormat)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,DWORD Usage,D3DRESOURCETYPE RType,D3DFORMAT CheckFormat)
+ { XXX; return _DOCALL(CheckDeviceFormat, Adapter, DeviceType, AdapterFormat, Usage, RType, CheckFormat); }
+ STDMETHOD(CheckDeviceMultiSampleType)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT SurfaceFormat,BOOL Windowed,D3DMULTISAMPLE_TYPE MultiSampleType,DWORD* pQualityLevels)
+ { XXX; return _DOCALL(CheckDeviceMultiSampleType, Adapter, DeviceType, SurfaceFormat, Windowed, MultiSampleType, pQualityLevels); }
+ STDMETHOD(CheckDepthStencilMatch)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,D3DFORMAT RenderTargetFormat,D3DFORMAT DepthStencilFormat)
+ { XXX; return _DOCALL(CheckDepthStencilMatch, Adapter, DeviceType, AdapterFormat, RenderTargetFormat, DepthStencilFormat); }
+ STDMETHOD(CheckDeviceFormatConversion)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT SourceFormat,D3DFORMAT TargetFormat)
+ { XXX; return _DOCALL(CheckDeviceFormatConversion, Adapter, DeviceType, SourceFormat, TargetFormat); }
+ STDMETHOD(GetDeviceCaps)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DCAPS9* pCaps)
+ { XXX; return _DOCALL(GetDeviceCaps, Adapter, DeviceType, pCaps); }
+ STDMETHOD_(HMONITOR, GetAdapterMonitor)(THIS_ UINT Adapter)
+ { XXX; return _DOCALL(GetAdapterMonitor, Adapter); }
+ STDMETHOD(CreateDevice)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,HWND hFocusWindow,DWORD BehaviorFlags,D3DPRESENT_PARAMETERS* pPresentationParameters,IDirect3DDevice9** ppReturnedDeviceInterface)
+ {
+ XXX;
+ HRESULT hr = _DOCALL(CreateDevice, Adapter, DeviceType, hFocusWindow, BehaviorFlags, pPresentationParameters, ppReturnedDeviceInterface);
+
+ if( SUCCEEDED( hr ) && ppReturnedDeviceInterface && *ppReturnedDeviceInterface )
+ {
+ CDirect3DDevice9Hook *pDevice = new CDirect3DDevice9Hook;
+ if(!pDevice)
+ {
+ ( *ppReturnedDeviceInterface )->Release();
+ hr = E_OUTOFMEMORY;
+ return NULL;
+ }
+ pDevice->m_Data.pDevice = pDevice;
+ pDevice->m_Data.pHWObj = *ppReturnedDeviceInterface;
+ *ppReturnedDeviceInterface = pDevice;
+ }
+ return hr;
+ }
+};
+
+inline IDirect3D9 *Direct3DCreate9Hook( UINT SDKVersion )
+{
+ HRESULT hr = S_OK;
+ IDirect3D9 *pD3D = Direct3DCreate9( D3D_SDK_VERSION );
+ AllocOverride( &hr, NULL, &pD3D );
+ return pD3D;
+}
+
+#endif // _DX9HOOK_H_
diff --git a/materialsystem/shaderapidx9/dynamicib.h b/materialsystem/shaderapidx9/dynamicib.h
new file mode 100644
index 0000000..304c7ef
--- /dev/null
+++ b/materialsystem/shaderapidx9/dynamicib.h
@@ -0,0 +1,1056 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//===========================================================================//
+
+#ifndef DYNAMICIB_H
+#define DYNAMICIB_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "locald3dtypes.h"
+#include "recording.h"
+#include "shaderapidx8_global.h"
+#include "shaderapidx8.h"
+#include "shaderapi/ishaderutil.h"
+#include "materialsystem/ivballoctracker.h"
+#include "tier1/memstack.h"
+#include "gpubufferallocator.h"
+
+/////////////////////////////
+// D. Sim Dietrich Jr.
+/////////////////////////////
+
+#ifdef _WIN32
+#pragma warning (disable:4189)
+#endif
+
+#include "locald3dtypes.h"
+#include "tier1/strtools.h"
+#include "tier1/utlqueue.h"
+#include "tier0/memdbgon.h"
+
+// Helper function to unbind an index buffer
+void Unbind( IDirect3DIndexBuffer9 *pIndexBuffer );
+
+#define X360_INDEX_BUFFER_SIZE_MULTIPLIER 4.0 //minimum of 1, only affects dynamic buffers
+//#define X360_BLOCK_ON_IB_FLUSH //uncomment to block until all data is consumed when a flush is requested. Otherwise we only block when absolutely necessary
+
+#define SPEW_INDEX_BUFFER_STALLS //uncomment to allow buffer stall spewing.
+
+class CIndexBuffer
+{
+public:
+ CIndexBuffer( IDirect3DDevice9 *pD3D, int count, bool bSoftwareVertexProcessing, bool dynamic = false );
+
+#ifdef _X360
+ CIndexBuffer();
+ void Init( IDirect3DDevice9 *pD3D, uint16 *pIndexMemory, int count );
+#endif
+
+ int AddRef() { return ++m_nReferenceCount; }
+ int Release()
+ {
+ int retVal = --m_nReferenceCount;
+ if ( retVal == 0 )
+ delete this;
+ return retVal;
+ }
+
+ LPDIRECT3DINDEXBUFFER GetInterface() const
+ {
+ // If this buffer still exists, then Late Creation didn't happen. Best case: we'll render the wrong image. Worst case: Crash.
+ Assert( !m_pSysmemBuffer );
+ return m_pIB;
+ }
+
+ // Use at beginning of frame to force a flush of VB contents on first draw
+ void FlushAtFrameStart() { m_bFlush = true; }
+
+ // lock, unlock
+ unsigned short *Lock( bool bReadOnly, int numIndices, int &startIndex, int startPosition = -1 );
+ void Unlock( int numIndices );
+ void HandleLateCreation( );
+
+ // Index position
+ int IndexPosition() const { return m_Position; }
+
+ // Index size
+ int IndexSize() const { return sizeof(unsigned short); }
+
+ // Index count
+ int IndexCount() const { return m_IndexCount; }
+
+#if _X360
+ // For some IBs, memory allocation is managed by CGPUBufferAllocator, via ShaderAPI
+ const GPUBufferHandle_t *GetBufferAllocationHandle( void );
+ void SetBufferAllocationHandle( const GPUBufferHandle_t &bufferAllocationHandle );
+ bool IsPooled( void ) { return m_GPUBufferHandle.IsValid(); }
+ // Expose the data pointer for read-only CPU access to the data
+ // (double-indirection supports relocation of the data by CGPUBufferAllocator)
+ const byte **GetBufferDataPointerAddress( void );
+#endif // _X360
+ // Do we have enough room without discarding?
+ bool HasEnoughRoom( int numIndices ) const;
+
+ bool IsDynamic() const { return m_bDynamic; }
+ bool IsExternal() const { return m_bExternalMemory; }
+
+ // Block until there's a free portion of the buffer of this size, m_Position will be updated to point at where this section starts
+ void BlockUntilUnused( int nAllocationSize );
+
+#ifdef CHECK_INDICES
+ void UpdateShadowIndices( unsigned short *pData )
+ {
+ Assert( m_LockedStartIndex + m_LockedNumIndices <= m_NumIndices );
+ memcpy( m_pShadowIndices + m_LockedStartIndex, pData, m_LockedNumIndices * IndexSize() );
+ }
+
+ unsigned short GetShadowIndex( int i )
+ {
+ Assert( i >= 0 && i < (int)m_NumIndices );
+ return m_pShadowIndices[i];
+ }
+#endif
+
+ // UID
+ unsigned int UID() const
+ {
+#ifdef RECORDING
+ return m_UID;
+#else
+ return 0;
+#endif
+ }
+
+ void HandlePerFrameTextureStats( int frame )
+ {
+#ifdef VPROF_ENABLED
+ if ( m_Frame != frame && !m_bDynamic )
+ {
+ m_Frame = frame;
+ VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_frame_" TEXTURE_GROUP_STATIC_INDEX_BUFFER,
+ COUNTER_GROUP_TEXTURE_PER_FRAME, IndexCount() * IndexSize() );
+ }
+#endif
+ }
+
+ static int BufferCount()
+ {
+#ifdef _DEBUG
+ return s_BufferCount;
+#else
+ return 0;
+#endif
+ }
+
+ inline int AllocationSize() const;
+
+ inline int AllocationCount() const;
+
+ // Marks a fence indicating when this buffer was used
+ void MarkUsedInRendering()
+ {
+#ifdef _X360
+ if ( m_bDynamic && m_pIB )
+ {
+ Assert( m_AllocationRing.Count() > 0 );
+ m_AllocationRing[m_AllocationRing.Tail()].m_Fence = Dx9Device()->GetCurrentFence();
+ }
+#endif
+ }
+
+private :
+ void Create( IDirect3DDevice9 *pD3D );
+ inline void ReallyUnlock( int unlockBytes )
+ {
+ #if DX_TO_GL_ABSTRACTION
+ // Knowing how much data was actually written is critical for performance under OpenGL.
+ m_pIB->UnlockActualSize( unlockBytes );
+ #else
+ unlockBytes; // Unused here
+ m_pIB->Unlock();
+ #endif
+ }
+
+ enum LOCK_FLAGS
+ {
+ LOCKFLAGS_FLUSH = D3DLOCK_NOSYSLOCK | D3DLOCK_DISCARD,
+#if !defined( _X360 )
+ LOCKFLAGS_APPEND = D3DLOCK_NOSYSLOCK | D3DLOCK_NOOVERWRITE
+#else
+ // X360BUG: forcing all locks to gpu flush, otherwise bizarre mesh corruption on decals
+ // Currently iterating with microsoft 360 support to track source of gpu corruption
+ LOCKFLAGS_APPEND = D3DLOCK_NOSYSLOCK
+#endif
+ };
+
+ LPDIRECT3DINDEXBUFFER m_pIB;
+#ifdef _X360
+
+ struct DynamicBufferAllocation_t
+ {
+ DWORD m_Fence; //track whether this memory is safe to use again.
+ int m_iStartOffset;
+ int m_iEndOffset;
+ unsigned int m_iZPassIdx; // The zpass during which this allocation was made
+ };
+
+ int m_iNextBlockingPosition; // m_iNextBlockingPosition >= m_Position where another allocation is still in use.
+ unsigned char *m_pAllocatedMemory;
+ int m_iAllocationCount; //The total number of indices the buffer we allocated can hold. Usually greater than the number of indices asked for
+ IDirect3DIndexBuffer9 m_D3DIndexBuffer; //Only need one shared D3D header for our usage patterns.
+ CUtlLinkedList<DynamicBufferAllocation_t> m_AllocationRing; //tracks what chunks of our memory are potentially still in use by D3D
+
+ GPUBufferHandle_t m_GPUBufferHandle; // Handle to a memory allocation within a shared physical memory pool (see CGPUBufferAllocator)
+#endif
+
+ int m_IndexCount;
+ int m_Position;
+ byte *m_pSysmemBuffer;
+ int m_nSysmemBufferStartBytes;
+ unsigned char m_bLocked : 1;
+ unsigned char m_bFlush : 1;
+ unsigned char m_bDynamic : 1;
+ unsigned char m_bExternalMemory : 1;
+ unsigned char m_bSoftwareVertexProcessing : 1;
+ unsigned char m_bLateCreateShouldDiscard : 1;
+
+#ifdef VPROF_ENABLED
+ int m_Frame;
+#endif
+
+ CInterlockedInt m_nReferenceCount;
+
+#ifdef _DEBUG
+ static int s_BufferCount;
+#endif
+
+#ifdef RECORDING
+ unsigned int m_UID;
+#endif
+
+#if !defined( _X360 )
+ //LockedBufferContext m_LockData;
+#endif
+
+protected:
+#ifdef CHECK_INDICES
+ unsigned short *m_pShadowIndices;
+ unsigned int m_NumIndices;
+#endif
+
+ unsigned int m_LockedStartIndex;
+ unsigned int m_LockedNumIndices;
+
+private:
+ // Must use reference counting functions above
+ ~CIndexBuffer();
+};
+
+#if defined( _X360 )
+#include "utlmap.h"
+MEMALLOC_DECLARE_EXTERNAL_TRACKING( XMem_CIndexBuffer );
+#endif
+
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+
+inline CIndexBuffer::CIndexBuffer( IDirect3DDevice9 *pD3D, int count,
+ bool bSoftwareVertexProcessing, bool dynamic ) :
+ m_pIB(0),
+ m_Position(0),
+ m_bFlush(true),
+ m_bLocked(false),
+ m_bExternalMemory(false),
+ m_bDynamic(dynamic),
+ m_bSoftwareVertexProcessing( bSoftwareVertexProcessing ),
+ m_bLateCreateShouldDiscard( false )
+#ifdef _X360
+ ,m_pAllocatedMemory(NULL)
+ ,m_iNextBlockingPosition(0)
+ ,m_iAllocationCount(0)
+#endif
+#ifdef VPROF_ENABLED
+ ,m_Frame( -1 )
+#endif
+ , m_nReferenceCount( 0 )
+{
+ // For write-combining, ensure we always have locked memory aligned to 4-byte boundaries
+ count = ALIGN_VALUE( count, 2 );
+ m_IndexCount = count;
+
+ MEM_ALLOC_CREDIT_( m_bDynamic ? ( "D3D: " TEXTURE_GROUP_DYNAMIC_INDEX_BUFFER ) : ( "D3D: " TEXTURE_GROUP_STATIC_INDEX_BUFFER ) );
+
+#ifdef CHECK_INDICES
+ m_pShadowIndices = NULL;
+#endif
+
+#ifdef RECORDING
+ // assign a UID
+ static unsigned int uid = 0;
+ m_UID = uid++;
+#endif
+
+#ifdef _DEBUG
+ ++s_BufferCount;
+#endif
+
+#ifdef CHECK_INDICES
+ m_pShadowIndices = new unsigned short[ m_IndexCount ];
+ m_NumIndices = m_IndexCount;
+#endif
+
+
+ if ( g_pShaderUtil->GetThreadMode() != MATERIAL_SINGLE_THREADED || !ThreadInMainThread() )
+ {
+ m_pSysmemBuffer = ( byte * )malloc( count * IndexSize() );
+ m_nSysmemBufferStartBytes = 0;
+ }
+ else
+ {
+ m_pSysmemBuffer = NULL;
+ Create( pD3D );
+ }
+
+#else // _X360
+ int nBufferSize = (count * IndexSize());
+ if ( m_bDynamic )
+ {
+ m_iAllocationCount = count * X360_INDEX_BUFFER_SIZE_MULTIPLIER;
+ Assert( m_iAllocationCount >= count );
+ m_iAllocationCount = ALIGN_VALUE( m_iAllocationCount, 2 );
+ m_pAllocatedMemory = (unsigned char*)XPhysicalAlloc( m_iAllocationCount * IndexSize(), MAXULONG_PTR, 0, PAGE_READWRITE | MEM_LARGE_PAGES | PAGE_WRITECOMBINE );
+ }
+ else if ( MeshMgr()->AllocatePooledIB( this, nBufferSize, TEXTURE_GROUP_STATIC_INDEX_BUFFER ) )
+ {
+ // Successfully allocated in a shared ShaderAPI memory pool (SetBufferAllocationHandle will have been called to set the pointer and stream offset)
+ m_iAllocationCount = count;
+ Assert( m_pAllocatedMemory );
+ }
+ else
+ {
+ // Fall back to allocating a standalone IB
+ // NOTE: write-combining (PAGE_WRITECOMBINE) is deliberately not used, since it slows down CPU access to the data (decals+defragmentation)
+ m_iAllocationCount = count;
+ m_pAllocatedMemory = (unsigned char*)XPhysicalAlloc( nBufferSize, MAXULONG_PTR, 0, PAGE_READWRITE );
+ }
+
+ if ( m_pAllocatedMemory && !IsPooled() )
+ {
+ MemAlloc_RegisterExternalAllocation( XMem_CIndexBuffer, m_pAllocatedMemory, XPhysicalSize( m_pAllocatedMemory ) );
+ if ( !m_bDynamic )
+ {
+ // Track non-pooled physallocs, to help tune CGPUBufferAllocator usage
+ g_SizeIndividualIBPhysAllocs += XPhysicalSize( m_pAllocatedMemory );
+ g_NumIndividualIBPhysAllocs++;
+ }
+ }
+
+ m_iNextBlockingPosition = m_iAllocationCount;
+#endif // _X360
+
+
+#ifdef VPROF_ENABLED
+ if ( !m_bDynamic )
+ {
+ VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_global_" TEXTURE_GROUP_STATIC_INDEX_BUFFER,
+ COUNTER_GROUP_TEXTURE_GLOBAL, IndexCount() * IndexSize() );
+ }
+ else if ( IsX360() )
+ {
+ VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_global_" TEXTURE_GROUP_DYNAMIC_INDEX_BUFFER,
+ COUNTER_GROUP_TEXTURE_GLOBAL, IndexCount() * IndexSize() );
+ }
+#endif
+}
+
+
+void CIndexBuffer::Create( IDirect3DDevice9 *pD3D )
+{
+ D3DINDEXBUFFER_DESC desc;
+ memset( &desc, 0x00, sizeof( desc ) );
+ desc.Format = D3DFMT_INDEX16;
+ desc.Size = sizeof(unsigned short) * m_IndexCount;
+ desc.Type = D3DRTYPE_INDEXBUFFER;
+ desc.Pool = D3DPOOL_DEFAULT;
+ desc.Usage = D3DUSAGE_WRITEONLY;
+ if ( m_bDynamic )
+ {
+ desc.Usage |= D3DUSAGE_DYNAMIC;
+ }
+ if ( m_bSoftwareVertexProcessing )
+ {
+ desc.Usage |= D3DUSAGE_SOFTWAREPROCESSING;
+ }
+
+ RECORD_COMMAND( DX8_CREATE_INDEX_BUFFER, 6 );
+ RECORD_INT( m_UID );
+ RECORD_INT( m_IndexCount * IndexSize() );
+ RECORD_INT( desc.Usage );
+ RECORD_INT( desc.Format );
+ RECORD_INT( desc.Pool );
+ RECORD_INT( m_bDynamic );
+
+#if !defined( _X360 )
+ HRESULT hr = pD3D->CreateIndexBuffer(
+ m_IndexCount * IndexSize(),
+ desc.Usage,
+ desc.Format,
+ desc.Pool,
+ &m_pIB,
+ NULL );
+ if ( hr != D3D_OK )
+ {
+ Warning( "CreateIndexBuffer failed!\n" );
+ }
+
+ if ( ( hr == D3DERR_OUTOFVIDEOMEMORY ) || ( hr == E_OUTOFMEMORY ) )
+ {
+ // Don't have the memory for this. Try flushing all managed resources
+ // out of vid mem and try again.
+ // FIXME: need to record this
+ pD3D->EvictManagedResources();
+ hr = pD3D->CreateIndexBuffer( m_IndexCount * IndexSize(),
+ desc.Usage, desc.Format, desc.Pool, &m_pIB, NULL );
+ }
+
+ Assert( m_pIB );
+ Assert( hr == D3D_OK );
+
+#ifdef MEASURE_DRIVER_ALLOCATIONS
+ int nMemUsed = 1024;
+ VPROF_INCREMENT_GROUP_COUNTER( "ib count", COUNTER_GROUP_NO_RESET, 1 );
+ VPROF_INCREMENT_GROUP_COUNTER( "ib driver mem", COUNTER_GROUP_NO_RESET, nMemUsed );
+ VPROF_INCREMENT_GROUP_COUNTER( "total driver mem", COUNTER_GROUP_NO_RESET, nMemUsed );
+#endif
+
+#if defined( _DEBUG )
+ if ( IsPC() && m_pIB && !m_pSysmemBuffer )
+ {
+ D3DINDEXBUFFER_DESC aDesc;
+ m_pIB->GetDesc( &aDesc );
+ Assert( memcmp( &aDesc, &desc, sizeof( desc ) ) == 0 );
+ }
+#endif
+}
+
+
+#ifdef _X360
+void *AllocateTempBuffer( size_t nSizeInBytes );
+
+inline CIndexBuffer::CIndexBuffer() :
+ m_pIB(0),
+ m_Position(0),
+ m_bFlush(false),
+ m_bLocked(false),
+ m_bExternalMemory( true ),
+ m_bDynamic( false )
+#ifdef VPROF_ENABLED
+ ,m_Frame( -1 )
+#endif
+{
+ m_IndexCount = 0;
+
+#ifdef CHECK_INDICES
+ m_pShadowIndices = NULL;
+#endif
+
+ m_iAllocationCount = 0;
+ m_pAllocatedMemory = NULL;
+ m_iNextBlockingPosition = 0;
+}
+
+#include "tier0/memdbgoff.h"
+
+inline void CIndexBuffer::Init( IDirect3DDevice9 *pD3D, uint16 *pIndexMemory, int count )
+{
+ m_IndexCount = count;
+ m_Position = count;
+
+ m_iAllocationCount = count;
+ m_pAllocatedMemory = (uint8*)pIndexMemory;
+ m_iNextBlockingPosition = m_iAllocationCount;
+
+ int nBufferSize = count * sizeof(uint16);
+ m_pIB = new( AllocateTempBuffer( sizeof( IDirect3DIndexBuffer9 ) ) ) IDirect3DIndexBuffer9;
+ XGSetIndexBufferHeader( nBufferSize, 0, D3DFMT_INDEX16, 0, 0, m_pIB );
+ XGOffsetResourceAddress( m_pIB, pIndexMemory );
+}
+
+#include "tier0/memdbgon.h"
+
+#endif // _X360
+
+inline CIndexBuffer::~CIndexBuffer()
+{
+#ifdef _DEBUG
+ if ( !m_bExternalMemory )
+ {
+ --s_BufferCount;
+ }
+#endif
+
+ Unlock(0);
+
+#ifdef CHECK_INDICES
+ if ( m_pShadowIndices )
+ {
+ delete [] m_pShadowIndices;
+ m_pShadowIndices = NULL;
+ }
+#endif
+
+ if ( m_pSysmemBuffer )
+ {
+ free( m_pSysmemBuffer );
+ m_pSysmemBuffer = NULL;
+ }
+
+#ifdef MEASURE_DRIVER_ALLOCATIONS
+ if ( !m_bExternalMemory )
+ {
+ int nMemUsed = 1024;
+ VPROF_INCREMENT_GROUP_COUNTER( "ib count", COUNTER_GROUP_NO_RESET, -1 );
+ VPROF_INCREMENT_GROUP_COUNTER( "ib driver mem", COUNTER_GROUP_NO_RESET, -nMemUsed );
+ VPROF_INCREMENT_GROUP_COUNTER( "total driver mem", COUNTER_GROUP_NO_RESET, -nMemUsed );
+ }
+#endif
+
+#if !defined( _X360 )
+ if ( m_pIB )
+ {
+ RECORD_COMMAND( DX8_DESTROY_INDEX_BUFFER, 1 );
+ RECORD_INT( m_UID );
+
+ m_pIB->Release();
+ }
+#else
+ if ( m_pIB && m_pIB->IsSet( Dx9Device() ) )
+ {
+ Unbind( m_pIB );
+ }
+
+ if ( m_pAllocatedMemory && !m_bExternalMemory )
+ {
+ if ( IsPooled() )
+ {
+ MeshMgr()->DeallocatePooledIB( this );
+ }
+ else
+ {
+ MemAlloc_RegisterExternalDeallocation( XMem_CIndexBuffer, m_pAllocatedMemory, XPhysicalSize( m_pAllocatedMemory ) );
+ if ( !m_bDynamic )
+ {
+ // Track non-pooled physallocs, to help tune CGPUBufferAllocator usage
+ g_SizeIndividualIBPhysAllocs -= XPhysicalSize( m_pAllocatedMemory );
+ g_NumIndividualIBPhysAllocs--;
+ }
+ XPhysicalFree( m_pAllocatedMemory );
+ }
+ }
+
+ m_pAllocatedMemory = NULL;
+ m_pIB = NULL;
+#endif
+
+#ifdef VPROF_ENABLED
+ if ( !m_bExternalMemory )
+ {
+ if ( !m_bDynamic )
+ {
+ VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_global_" TEXTURE_GROUP_STATIC_INDEX_BUFFER,
+ COUNTER_GROUP_TEXTURE_GLOBAL, - IndexCount() * IndexSize() );
+ }
+ else if ( IsX360() )
+ {
+ VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_global_" TEXTURE_GROUP_DYNAMIC_INDEX_BUFFER,
+ COUNTER_GROUP_TEXTURE_GLOBAL, - IndexCount() * IndexSize() );
+ }
+ }
+#endif
+}
+
+#ifdef _X360
+//-----------------------------------------------------------------------------
+// Get memory allocation data
+//-----------------------------------------------------------------------------
+inline const GPUBufferHandle_t *CIndexBuffer::GetBufferAllocationHandle( void )
+{
+ Assert( IsPooled() );
+ return ( IsPooled() ? &m_GPUBufferHandle : NULL );
+}
+
+//-----------------------------------------------------------------------------
+// Update memory allocation data
+//-----------------------------------------------------------------------------
+inline void CIndexBuffer::SetBufferAllocationHandle( const GPUBufferHandle_t &bufferAllocationHandle )
+{
+ // This IB's memory has been reallocated or freed, update our cached pointer and the D3D header
+ // NOTE: this should never be called while any rendering is in flight!
+ Assert( ( m_pAllocatedMemory == NULL ) || IsPooled() );
+ if ( ( m_pAllocatedMemory == NULL ) || IsPooled() )
+ {
+ m_GPUBufferHandle = bufferAllocationHandle;
+ m_pAllocatedMemory = m_GPUBufferHandle.pMemory;
+ if ( m_pIB )
+ {
+ int nBufferSize = m_IndexCount * IndexSize();
+ XGSetIndexBufferHeader( nBufferSize, 0, D3DFMT_INDEX16, 0, 0, m_pIB );
+ XGOffsetResourceAddress( m_pIB, m_pAllocatedMemory );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Expose the data pointer for read-only CPU access to the data
+//-----------------------------------------------------------------------------
+inline const byte **CIndexBuffer::GetBufferDataPointerAddress( void )
+{
+ if ( m_bDynamic /* FIXME: || m_bExternalMemory */ )
+ return NULL;
+ return (const byte **)&m_pAllocatedMemory;
+}
+#endif // _X360
+
+//-----------------------------------------------------------------------------
+// Do we have enough room without discarding?
+//-----------------------------------------------------------------------------
+inline bool CIndexBuffer::HasEnoughRoom( int numIndices ) const
+{
+#if !defined( _X360 )
+ return ( numIndices + m_Position ) <= m_IndexCount;
+#else
+ return numIndices <= m_IndexCount; //the ring buffer will free room as needed
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Block until this part of the index buffer is free
+//-----------------------------------------------------------------------------
+inline void CIndexBuffer::BlockUntilUnused( int nAllocationSize )
+{
+ Assert( nAllocationSize <= m_IndexCount );
+
+#ifdef _X360
+ Assert( (m_AllocationRing.Count() != 0) || ((m_Position == 0) && (m_iNextBlockingPosition == m_iAllocationCount)) );
+
+ if ( (m_iNextBlockingPosition - m_Position) >= nAllocationSize )
+ return;
+
+ Assert( (m_AllocationRing[m_AllocationRing.Head()].m_iStartOffset == 0) || ((m_iNextBlockingPosition == m_AllocationRing[m_AllocationRing.Head()].m_iStartOffset) && (m_Position <= m_iNextBlockingPosition)) );
+
+ int iMinBlockPosition = m_Position + nAllocationSize;
+ if( iMinBlockPosition > m_iAllocationCount )
+ {
+ //Allocation requires us to wrap
+ iMinBlockPosition = nAllocationSize;
+ m_Position = 0;
+
+ //modify the last allocation so that it uses up the whole tail end of the buffer. Makes other code simpler
+ Assert( m_AllocationRing.Count() != 0 );
+ m_AllocationRing[m_AllocationRing.Tail()].m_iEndOffset = m_iAllocationCount;
+
+ //treat all allocations between the current position and the tail end of the ring as freed since they will be before we unblock
+ while( m_AllocationRing.Count() )
+ {
+ unsigned int head = m_AllocationRing.Head();
+ if( m_AllocationRing[head].m_iStartOffset == 0 )
+ break;
+
+ m_AllocationRing.Remove( head );
+ }
+ }
+
+ //now we go through the allocations until we find the last fence we care about. Treat everything up until that fence as freed.
+ DWORD FinalFence = 0;
+ unsigned int iFinalAllocationZPassIdx = 0;
+ while( m_AllocationRing.Count() )
+ {
+ unsigned int head = m_AllocationRing.Head();
+
+ if( m_AllocationRing[head].m_iEndOffset >= iMinBlockPosition )
+ {
+ //When this frees, we'll finally have enough space for the allocation
+ FinalFence = m_AllocationRing[head].m_Fence;
+ iFinalAllocationZPassIdx = m_AllocationRing[head].m_iZPassIdx;
+ m_iNextBlockingPosition = m_AllocationRing[head].m_iEndOffset;
+ m_AllocationRing.Remove( head );
+ break;
+ }
+ m_AllocationRing.Remove( head );
+ }
+ Assert( FinalFence != 0 );
+
+ if( Dx9Device()->IsFencePending( FinalFence ) )
+ {
+#ifdef SPEW_INDEX_BUFFER_STALLS
+ float st = Plat_FloatTime();
+#endif
+
+ if ( ( Dx9Device()->GetDeviceState() & D3DDEVICESTATE_ZPASS_BRACKET ) &&
+ ( iFinalAllocationZPassIdx == ShaderAPI()->Get360ZPassCounter() ) )
+ {
+ // We're about to overrun our IB ringbuffer in a single Z prepass. To avoid rendering corruption, close out the
+ // Z prepass and continue. This will reduce early-Z rejection efficiency and could cause a momentary framerate drop,
+ // but it's better than rendering corruption.
+ Warning( "Dynamic IB ring buffer overrun in Z Prepass. Tell Thorsten.\n" );
+
+ ShaderAPI()->End360ZPass();
+ }
+
+ Dx9Device()->BlockOnFence( FinalFence );
+
+#ifdef SPEW_INDEX_BUFFER_STALLS
+ float dt = Plat_FloatTime() - st;
+ Warning( "Blocked locking dynamic index buffer for %f ms!\n", 1000.0 * dt );
+#endif
+ }
+
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// lock, unlock
+//-----------------------------------------------------------------------------
+inline unsigned short* CIndexBuffer::Lock( bool bReadOnly, int numIndices, int& startIndex, int startPosition )
+{
+ Assert( !m_bLocked );
+
+#if defined( _X360 )
+ if ( m_pIB && m_pIB->IsSet( Dx9Device() ) )
+ {
+ Unbind( m_pIB );
+ }
+#endif
+
+ unsigned short* pLockedData = NULL;
+
+ // For write-combining, ensure we always have locked memory aligned to 4-byte boundaries
+ if( m_bDynamic )
+ numIndices = ALIGN_VALUE( numIndices, 2 );
+
+ // Ensure there is enough space in the IB for this data
+ if ( numIndices > m_IndexCount )
+ {
+ Error( "too many indices for index buffer. . tell a programmer (%d>%d)\n", ( int )numIndices, ( int )m_IndexCount );
+ Assert( false );
+ return 0;
+ }
+
+ if ( !IsX360() && !m_pIB && !m_pSysmemBuffer )
+ return 0;
+
+ DWORD dwFlags;
+
+ if ( m_bDynamic )
+ {
+ // startPosition now can be != -1, when calling in here with a static (staging) buffer.
+#if !defined( _X360 )
+ dwFlags = LOCKFLAGS_APPEND;
+
+ // If either user forced us to flush,
+ // or there is not enough space for the vertex data,
+ // then flush the buffer contents
+ // xbox must not append at position 0 because nooverwrite cannot be guaranteed
+
+ if ( !m_Position || m_bFlush || !HasEnoughRoom(numIndices) )
+ {
+ if ( m_pSysmemBuffer || !g_pShaderUtil->IsRenderThreadSafe() )
+ m_bLateCreateShouldDiscard = true;
+
+ m_bFlush = false;
+ m_Position = 0;
+
+ dwFlags = LOCKFLAGS_FLUSH;
+ }
+#else
+ if ( m_bFlush )
+ {
+# if ( defined( X360_BLOCK_ON_IB_FLUSH ) )
+ {
+ if( m_AllocationRing.Count() )
+ {
+ DWORD FinalFence = m_AllocationRing[m_AllocationRing.Tail()].m_Fence;
+
+ m_AllocationRing.RemoveAll();
+ m_Position = 0;
+ m_iNextBlockingPosition = m_iAllocationCount;
+
+# if ( defined( SPEW_VERTEX_BUFFER_STALLS ) )
+ if( Dx9Device()->IsFencePending( FinalFence ) )
+ {
+ float st = Plat_FloatTime();
+# endif
+ Dx9Device()->BlockOnFence( FinalFence );
+# if ( defined ( SPEW_VERTEX_BUFFER_STALLS ) )
+ float dt = Plat_FloatTime() - st;
+ Warning( "Blocked FLUSHING dynamic index buffer for %f ms!\n", 1000.0 * dt );
+ }
+# endif
+ }
+ }
+# endif
+ m_bFlush = false;
+ }
+#endif
+ }
+ else
+ {
+ dwFlags = D3DLOCK_NOSYSLOCK;
+ }
+
+ if ( bReadOnly )
+ {
+ dwFlags |= D3DLOCK_READONLY;
+ }
+
+ int position = m_Position;
+ if( startPosition >= 0 )
+ {
+ position = startPosition;
+ }
+
+ RECORD_COMMAND( DX8_LOCK_INDEX_BUFFER, 4 );
+ RECORD_INT( m_UID );
+ RECORD_INT( position * IndexSize() );
+ RECORD_INT( numIndices * IndexSize() );
+ RECORD_INT( dwFlags );
+
+ m_LockedStartIndex = position;
+ m_LockedNumIndices = numIndices;
+
+ HRESULT hr = D3D_OK;
+
+#if !defined( _X360 )
+ // If the caller isn't in the thread that owns the render lock, need to return a system memory pointer--cannot talk to GL from
+ // the non-current thread.
+ if ( !m_pSysmemBuffer && !g_pShaderUtil->IsRenderThreadSafe() )
+ {
+ m_pSysmemBuffer = ( byte * )malloc( m_IndexCount * IndexSize() );
+ m_nSysmemBufferStartBytes = position * IndexSize();
+ }
+
+ if ( m_pSysmemBuffer != NULL )
+ {
+ // Ensure that we're never moving backwards in a buffer--this code would need to be rewritten if so.
+ // We theorize this can happen if you hit the end of a buffer and then wrap before drawing--but
+ // this would probably break in other places as well.
+ Assert( position * IndexSize() >= m_nSysmemBufferStartBytes );
+ pLockedData = ( unsigned short * )( m_pSysmemBuffer + ( position * IndexSize() ) );
+ }
+ else
+ {
+ hr = m_pIB->Lock( position * IndexSize(), numIndices * IndexSize(),
+ reinterpret_cast< void** >( &pLockedData ), dwFlags );
+ }
+#else
+ if ( m_bDynamic )
+ {
+ // Block until earlier parts of the buffer are free
+ BlockUntilUnused( numIndices );
+ position = m_Position;
+ m_pIB = NULL;
+ Assert( (m_Position + numIndices) <= m_iAllocationCount );
+ }
+ else
+ {
+ //static, block until last lock finished?
+ m_Position = position;
+ }
+ pLockedData = (unsigned short *)(m_pAllocatedMemory + (position * IndexSize()));
+
+#endif
+
+ switch ( hr )
+ {
+ case D3DERR_INVALIDCALL:
+ Msg( "D3DERR_INVALIDCALL - Index Buffer Lock Failed in %s on line %d(offset %d, size %d, flags 0x%x)\n", V_UnqualifiedFileName(__FILE__), __LINE__, position * IndexSize(), numIndices * IndexSize(), dwFlags );
+ break;
+ case D3DERR_DRIVERINTERNALERROR:
+ Msg( "D3DERR_DRIVERINTERNALERROR - Index Buffer Lock Failed in %s on line %d (offset %d, size %d, flags 0x%x)\n", V_UnqualifiedFileName(__FILE__), __LINE__, position * IndexSize(), numIndices * IndexSize(), dwFlags );
+ break;
+ case D3DERR_OUTOFVIDEOMEMORY:
+ Msg( "D3DERR_OUTOFVIDEOMEMORY - Index Buffer Lock Failed in %s on line %d (offset %d, size %d, flags 0x%x)\n", V_UnqualifiedFileName(__FILE__), __LINE__, position * IndexSize(), numIndices * IndexSize(), dwFlags );
+ break;
+ }
+
+ Assert( pLockedData != NULL );
+
+ if ( !IsX360() )
+ {
+ startIndex = position;
+ }
+ else
+ {
+ startIndex = 0;
+ }
+
+ Assert( m_bLocked == false );
+ m_bLocked = true;
+ return pLockedData;
+}
+
+inline void CIndexBuffer::Unlock( int numIndices )
+{
+#if defined( _X360 )
+ Assert( (m_Position + numIndices) <= m_iAllocationCount );
+#else
+ Assert( (m_Position + numIndices) <= m_IndexCount );
+#endif
+
+ if ( !m_bLocked )
+ return;
+
+ // For write-combining, ensure we always have locked memory aligned to 4-byte boundaries
+// if( m_bDynamic )
+// numIndices = ALIGN_VALUE( numIndices, 2 );
+
+ if ( !IsX360() && !m_pIB && !m_pSysmemBuffer )
+ return;
+
+ RECORD_COMMAND( DX8_UNLOCK_INDEX_BUFFER, 1 );
+ RECORD_INT( m_UID );
+
+#if !defined( _X360 )
+ if ( m_pSysmemBuffer )
+ {
+ }
+ else
+ {
+#if DX_TO_GL_ABSTRACTION
+ // Knowing how much data was actually written is critical for performance under OpenGL.
+ // Important notes: numIndices indicates how much we could move the current position. For dynamic buffer, it should indicate the # of actually written indices, for static buffers it's typically 0.
+ // If it's a dynamic buffer (where we actually care about perf), assume the caller isn't lying about numIndices, otherwise just assume they wrote the entire thing.
+ // If you modify this code, be sure to test on both AMD and NVidia drivers!
+ Assert( numIndices <= (int)m_LockedNumIndices );
+ int unlockBytes = ( m_bDynamic ? numIndices : m_LockedNumIndices ) * IndexSize();
+#else
+ int unlockBytes = 0;
+#endif
+ ReallyUnlock( unlockBytes );
+ }
+#else
+ if ( m_bDynamic )
+ {
+ Assert( (m_Position == 0) || (m_AllocationRing[m_AllocationRing.Tail()].m_iEndOffset == m_Position) );
+
+ DynamicBufferAllocation_t LockData;
+ LockData.m_Fence = Dx9Device()->GetCurrentFence(); //This isn't the correct fence, but it's all we have access to for now and it'll provide marginal safety if something goes really wrong.
+ LockData.m_iStartOffset = m_Position;
+ LockData.m_iEndOffset = LockData.m_iStartOffset + numIndices;
+ LockData.m_iZPassIdx = ( Dx9Device()->GetDeviceState() & D3DDEVICESTATE_ZPASS_BRACKET ) ? ShaderAPI()->Get360ZPassCounter() : 0;
+ Assert( (LockData.m_iStartOffset == 0) || (LockData.m_iStartOffset == m_AllocationRing[m_AllocationRing.Tail()].m_iEndOffset) );
+ m_AllocationRing.AddToTail( LockData );
+
+ void* pLockedData = m_pAllocatedMemory + (LockData.m_iStartOffset * IndexSize());
+
+ //Always re-use the same index buffer header based on the assumption that D3D copies it off in the draw calls.
+ m_pIB = &m_D3DIndexBuffer;
+ XGSetIndexBufferHeader( numIndices * IndexSize(), 0, D3DFMT_INDEX16, 0, 0, m_pIB );
+ XGOffsetResourceAddress( m_pIB, pLockedData );
+
+ // Invalidate the GPU caches for this memory.
+ // FIXME: Should dynamic allocations be 4k aligned?
+ Dx9Device()->InvalidateGpuCache( pLockedData, numIndices * IndexSize(), 0 );
+ }
+ else
+ {
+ if ( !m_pIB )
+ {
+ int nBufferSize = m_IndexCount * IndexSize();
+ XGSetIndexBufferHeader( nBufferSize, 0, D3DFMT_INDEX16, 0, 0, &m_D3DIndexBuffer );
+ XGOffsetResourceAddress( &m_D3DIndexBuffer, m_pAllocatedMemory );
+ m_pIB = &m_D3DIndexBuffer;
+ }
+
+ // Invalidate the GPU caches for this memory.
+ Dx9Device()->InvalidateGpuCache( m_pAllocatedMemory, m_IndexCount * IndexSize(), 0 );
+ }
+#endif
+
+ m_Position += numIndices;
+ m_bLocked = false;
+
+ m_LockedStartIndex = 0;
+ m_LockedNumIndices = 0;
+}
+
+
+inline void CIndexBuffer::HandleLateCreation( )
+{
+ if ( !m_pSysmemBuffer )
+ {
+ return;
+ }
+
+ if( !m_pIB )
+ {
+ bool bPrior = g_VBAllocTracker->TrackMeshAllocations( "HandleLateCreation" );
+ Create( Dx9Device() );
+ if ( !bPrior )
+ {
+ g_VBAllocTracker->TrackMeshAllocations( NULL );
+ }
+ }
+
+ void* pWritePtr = NULL;
+ const int dataToWriteBytes = ( m_Position * IndexSize() ) - m_nSysmemBufferStartBytes;
+ DWORD dwFlags = D3DLOCK_NOSYSLOCK;
+ if ( m_bDynamic )
+ dwFlags |= ( m_bLateCreateShouldDiscard ? D3DLOCK_DISCARD : D3DLOCK_NOOVERWRITE );
+
+ // Always clear this.
+ m_bLateCreateShouldDiscard = false;
+
+ // Don't use the Lock function, it does a bunch of stuff we don't want.
+ HRESULT hr = m_pIB->Lock( m_nSysmemBufferStartBytes,
+ dataToWriteBytes,
+ &pWritePtr,
+ dwFlags);
+
+ // If this fails we're about to crash. Consider skipping the update and leaving
+ // m_pSysmemBuffer around to try again later. (For example in case of device loss)
+ Assert( SUCCEEDED( hr ) ); hr;
+ memcpy( pWritePtr, m_pSysmemBuffer + m_nSysmemBufferStartBytes, dataToWriteBytes );
+ ReallyUnlock( dataToWriteBytes );
+
+ free( m_pSysmemBuffer );
+ m_pSysmemBuffer = NULL;
+}
+
+
+// Returns the allocated size
+inline int CIndexBuffer::AllocationSize() const
+{
+#ifdef _X360
+ return m_iAllocationCount * IndexSize();
+#else
+ return m_IndexCount * IndexSize();
+#endif
+}
+
+inline int CIndexBuffer::AllocationCount() const
+{
+#ifdef _X360
+ return m_iAllocationCount;
+#else
+ return m_IndexCount;
+#endif
+}
+
+#ifdef _WIN32
+#pragma warning (default:4189)
+#endif
+
+#include "tier0/memdbgoff.h"
+
+#endif // DYNAMICIB_H
+
diff --git a/materialsystem/shaderapidx9/dynamicvb.h b/materialsystem/shaderapidx9/dynamicvb.h
new file mode 100644
index 0000000..5eeee8f
--- /dev/null
+++ b/materialsystem/shaderapidx9/dynamicvb.h
@@ -0,0 +1,1098 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#ifndef DYNAMICVB_H
+#define DYNAMICVB_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "locald3dtypes.h"
+#include "recording.h"
+#include "shaderapidx8_global.h"
+#include "shaderapidx8.h"
+#include "imeshdx8.h"
+#include "materialsystem/ivballoctracker.h"
+#include "gpubufferallocator.h"
+#include "tier1/utllinkedlist.h"
+#include "tier0/dbg.h"
+#include "tier1/memstack.h"
+
+/////////////////////////////
+// D. Sim Dietrich Jr.
+//////////////////////
+
+
+// Helper function to unbind an vertex buffer
+void Unbind( IDirect3DVertexBuffer9 *pVertexBuffer );
+
+#define X360_VERTEX_BUFFER_SIZE_MULTIPLIER 2.0 //minimum of 1, only affects dynamic buffers
+//#define X360_BLOCK_ON_VB_FLUSH //uncomment to block until all data is consumed when a flush is requested. Otherwise we only block when absolutely necessary
+
+//#define SPEW_VERTEX_BUFFER_STALLS //uncomment to allow buffer stall spewing.
+
+
+class CVertexBuffer
+{
+public:
+ CVertexBuffer( IDirect3DDevice9 * pD3D, VertexFormat_t fmt, DWORD theFVF, int vertexSize,
+ int theVertexCount, const char *pTextureBudgetName, bool bSoftwareVertexProcessing, bool dynamic = false );
+
+#ifdef _X360
+ CVertexBuffer();
+ void Init( IDirect3DDevice9 * pD3D, VertexFormat_t fmt, DWORD theFVF, uint8 *pVertexData, int vertexSize, int theVertexCount );
+#endif
+
+ ~CVertexBuffer();
+
+ LPDIRECT3DVERTEXBUFFER GetInterface() const
+ {
+ // If this buffer still exists, then Late Creation didn't happen. Best case: we'll render the wrong image. Worst case: Crash.
+ Assert( !m_pSysmemBuffer );
+ return m_pVB;
+ }
+
+ // Use at beginning of frame to force a flush of VB contents on first draw
+ void FlushAtFrameStart() { m_bFlush = true; }
+
+ // lock, unlock
+ unsigned char* Lock( int numVerts, int& baseVertexIndex );
+ unsigned char* Modify( bool bReadOnly, int firstVertex, int numVerts );
+ void Unlock( int numVerts );
+
+ void HandleLateCreation( );
+
+ // Vertex size
+ int VertexSize() const { return m_VertexSize; }
+
+ // Vertex count
+ int VertexCount() const { return m_VertexCount; }
+#ifdef _X360
+ // For some VBs, memory allocation is managed by CGPUBufferAllocator, via ShaderAPI
+ const GPUBufferHandle_t *GetBufferAllocationHandle( void );
+ void SetBufferAllocationHandle( const GPUBufferHandle_t &bufferAllocationHandle );
+ bool IsPooled( void ) { creturn m_GPUBufferHandle.IsValid(); }
+ // Expose the data pointer for read-only CPU access to the data
+ // (double-indirection supports relocation of the data by CGPUBufferAllocator)
+ const byte **GetBufferDataPointerAddress( void );
+#endif // _X360
+
+ static int BufferCount()
+ {
+#ifdef _DEBUG
+ return s_BufferCount;
+#else
+ return 0;
+#endif
+ }
+
+ // UID
+ unsigned int UID() const
+ {
+#ifdef RECORDING
+ return m_UID;
+#else
+ return 0;
+#endif
+ }
+
+ void HandlePerFrameTextureStats( int frame )
+ {
+#ifdef VPROF_ENABLED
+ if ( m_Frame != frame && !m_bDynamic )
+ {
+ m_Frame = frame;
+ m_pFrameCounter += m_nBufferSize;
+ }
+#endif
+ }
+
+ // Do we have enough room without discarding?
+ bool HasEnoughRoom( int numVertices ) const;
+
+ // Is this dynamic?
+ bool IsDynamic() const { return m_bDynamic; }
+ bool IsExternal() const { return m_bExternalMemory; }
+
+ // Block until this part of the vertex buffer is free
+ void BlockUntilUnused( int nBufferSize );
+
+ // used to alter the characteristics after creation
+ // allows one dynamic vb to be shared for multiple formats
+ void ChangeConfiguration( int vertexSize, int totalSize )
+ {
+ Assert( m_bDynamic && !m_bLocked && vertexSize );
+ m_VertexSize = vertexSize;
+ m_VertexCount = m_nBufferSize / vertexSize;
+ }
+
+ // Compute the next offset for the next lock
+ int NextLockOffset( ) const;
+
+ // Returns the allocated size
+ int AllocationSize() const;
+
+ // Returns the number of vertices we have enough room for
+ int NumVerticesUntilFlush() const
+ {
+#if defined( _X360 )
+ if( m_AllocationRing.Count() )
+ {
+ //Cycle through the ring buffer and see what memory is free now
+ int iNode = m_AllocationRing.Head();
+ while( m_AllocationRing.IsValidIndex( iNode ) )
+ {
+ if( Dx9Device()->IsFencePending( m_AllocationRing[iNode].m_Fence ) )
+ break;
+
+ iNode = m_AllocationRing.Next( iNode );
+ }
+
+ if( m_AllocationRing.IsValidIndex( iNode ) )
+ {
+ int iEndFreeOffset = m_AllocationRing[iNode].m_iEndOffset;
+ if( iEndFreeOffset < m_Position )
+ {
+ //Wrapped. Making the arbitrary decision that the return value for this function *should* handle the singe giant allocation case which requires contiguous memory
+ if( iEndFreeOffset > (m_iNextBlockingPosition - m_Position) )
+ return iEndFreeOffset / m_VertexSize;
+ else
+ return (m_iNextBlockingPosition - m_Position) / m_VertexSize;
+ }
+ }
+ else
+ {
+ //we didn't block on any fence
+ return m_VertexCount;
+ }
+ }
+
+ return m_VertexCount;
+#else
+ return (m_nBufferSize - NextLockOffset()) / m_VertexSize;
+#endif
+ }
+
+ // Marks a fence indicating when this buffer was used
+ void MarkUsedInRendering()
+ {
+#ifdef _X360
+ if ( m_bDynamic && m_pVB )
+ {
+ Assert( m_AllocationRing.Count() > 0 );
+ m_AllocationRing[m_AllocationRing.Tail()].m_Fence = Dx9Device()->GetCurrentFence();
+ }
+#endif
+ }
+
+private:
+ void Create( IDirect3DDevice9 *pD3D );
+ inline void ReallyUnlock( int unlockBytes )
+ {
+ #if DX_TO_GL_ABSTRACTION
+ // Knowing how much data was actually written is critical for performance under OpenGL.
+ m_pVB->UnlockActualSize( unlockBytes );
+ #else
+ unlockBytes; // Unused here
+ m_pVB->Unlock();
+ #endif
+ }
+
+ enum LOCK_FLAGS
+ {
+ LOCKFLAGS_FLUSH = D3DLOCK_NOSYSLOCK | D3DLOCK_DISCARD,
+#if !defined( _X360 )
+ LOCKFLAGS_APPEND = D3DLOCK_NOSYSLOCK | D3DLOCK_NOOVERWRITE
+#else
+ // X360BUG: forcing all locks to gpu flush, otherwise bizarre mesh corruption on decals
+ // Currently iterating with microsoft 360 support to track source of gpu corruption
+ LOCKFLAGS_APPEND = D3DLOCK_NOSYSLOCK
+#endif
+ };
+
+ LPDIRECT3DVERTEXBUFFER m_pVB;
+
+#ifdef _X360
+ struct DynamicBufferAllocation_t
+ {
+ DWORD m_Fence; //track whether this memory is safe to use again.
+ int m_iStartOffset;
+ int m_iEndOffset;
+ unsigned int m_iZPassIdx; // The zpass during which this allocation was made
+ };
+
+ int m_iNextBlockingPosition; // m_iNextBlockingPosition >= m_Position where another allocation is still in use.
+ unsigned char *m_pAllocatedMemory;
+ int m_iAllocationSize; //Total size of the ring buffer, usually more than what was asked for
+ IDirect3DVertexBuffer9 m_D3DVertexBuffer; //Only need one shared D3D header for our usage patterns.
+ CUtlLinkedList<DynamicBufferAllocation_t> m_AllocationRing; //tracks what chunks of our memory are potentially still in use by D3D
+
+ GPUBufferHandle_t m_GPUBufferHandle; // Handle to a memory allocation within a shared physical memory pool (see CGPUBufferAllocator)
+#endif
+
+ VertexFormat_t m_VertexBufferFormat; // yes, Vertex, only used for allocation tracking
+ int m_nBufferSize;
+ int m_Position;
+ int m_VertexCount;
+ int m_VertexSize;
+ DWORD m_TheFVF;
+ byte *m_pSysmemBuffer;
+ int m_nSysmemBufferStartBytes;
+
+ uint m_nLockCount;
+ unsigned char m_bDynamic : 1;
+ unsigned char m_bLocked : 1;
+ unsigned char m_bFlush : 1;
+ unsigned char m_bExternalMemory : 1;
+ unsigned char m_bSoftwareVertexProcessing : 1;
+ unsigned char m_bLateCreateShouldDiscard : 1;
+
+#ifdef VPROF_ENABLED
+ int m_Frame;
+ int *m_pFrameCounter;
+ int *m_pGlobalCounter;
+#endif
+
+#ifdef _DEBUG
+ static int s_BufferCount;
+#endif
+
+#ifdef RECORDING
+ unsigned int m_UID;
+#endif
+};
+
+#if defined( _X360 )
+#include "utlmap.h"
+MEMALLOC_DECLARE_EXTERNAL_TRACKING( XMem_CVertexBuffer );
+#endif
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+inline CVertexBuffer::CVertexBuffer(IDirect3DDevice9 * pD3D, VertexFormat_t fmt, DWORD theFVF,
+ int vertexSize, int vertexCount, const char *pTextureBudgetName,
+ bool bSoftwareVertexProcessing, bool dynamic ) :
+ m_pVB(0),
+ m_Position(0),
+ m_VertexSize(vertexSize),
+ m_VertexCount(vertexCount),
+ m_bFlush(true),
+ m_bLocked(false),
+ m_bExternalMemory( false ),
+ m_nBufferSize(vertexSize * vertexCount),
+ m_TheFVF( theFVF ),
+ m_bSoftwareVertexProcessing( bSoftwareVertexProcessing ),
+ m_bDynamic(dynamic),
+ m_VertexBufferFormat( fmt ),
+ m_bLateCreateShouldDiscard( false )
+#ifdef _X360
+ ,m_pAllocatedMemory(NULL)
+ ,m_iNextBlockingPosition(0)
+ ,m_iAllocationSize(0)
+#endif
+#ifdef VPROF_ENABLED
+ ,m_Frame( -1 )
+#endif
+{
+ MEM_ALLOC_CREDIT_( pTextureBudgetName );
+
+#ifdef RECORDING
+ // assign a UID
+ static unsigned int uid = 0;
+ m_UID = uid++;
+#endif
+
+#ifdef _DEBUG
+ ++s_BufferCount;
+#endif
+
+#ifdef VPROF_ENABLED
+ if ( !m_bDynamic )
+ {
+ char name[256];
+ V_strcpy_safe( name, "TexGroup_global_" );
+ V_strcat_safe( name, pTextureBudgetName, sizeof(name) );
+ m_pGlobalCounter = g_VProfCurrentProfile.FindOrCreateCounter( name, COUNTER_GROUP_TEXTURE_GLOBAL );
+
+ V_strcpy_safe( name, "TexGroup_frame_" );
+ V_strcat_safe( name, pTextureBudgetName, sizeof(name) );
+ m_pFrameCounter = g_VProfCurrentProfile.FindOrCreateCounter( name, COUNTER_GROUP_TEXTURE_PER_FRAME );
+ }
+ else
+ {
+ m_pGlobalCounter = g_VProfCurrentProfile.FindOrCreateCounter( "TexGroup_global_" TEXTURE_GROUP_DYNAMIC_VERTEX_BUFFER, COUNTER_GROUP_TEXTURE_GLOBAL );
+ }
+#endif
+
+ if ( !g_pShaderUtil->IsRenderThreadSafe() )
+ {
+ m_pSysmemBuffer = ( byte * )MemAlloc_AllocAligned( m_nBufferSize, 16 );
+ m_nSysmemBufferStartBytes = 0;
+ }
+ else
+ {
+ m_pSysmemBuffer = NULL;
+ Create( pD3D );
+ }
+
+#ifdef VPROF_ENABLED
+ if ( IsX360() || !m_bDynamic )
+ {
+ Assert( m_pGlobalCounter );
+ *m_pGlobalCounter += m_nBufferSize;
+ }
+#endif
+}
+
+
+void CVertexBuffer::Create( IDirect3DDevice9 *pD3D )
+{
+ D3DVERTEXBUFFER_DESC desc;
+ memset( &desc, 0x00, sizeof( desc ) );
+ desc.Format = D3DFMT_VERTEXDATA;
+ desc.Size = m_nBufferSize;
+ desc.Type = D3DRTYPE_VERTEXBUFFER;
+ desc.Pool = m_bDynamic ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED;
+ desc.FVF = m_TheFVF;
+
+#if defined(IS_WINDOWS_PC) && defined(SHADERAPIDX9)
+ extern bool g_ShaderDeviceUsingD3D9Ex;
+ if ( g_ShaderDeviceUsingD3D9Ex )
+ {
+ desc.Pool = D3DPOOL_DEFAULT;
+ }
+#endif
+
+ desc.Usage = D3DUSAGE_WRITEONLY;
+ if ( m_bDynamic )
+ {
+ desc.Usage |= D3DUSAGE_DYNAMIC;
+ // Dynamic meshes should never be compressed (slows down writing to them)
+ Assert( CompressionType( m_TheFVF ) == VERTEX_COMPRESSION_NONE );
+ }
+ if ( m_bSoftwareVertexProcessing )
+ {
+ desc.Usage |= D3DUSAGE_SOFTWAREPROCESSING;
+ }
+
+#if !defined( _X360 )
+ RECORD_COMMAND( DX8_CREATE_VERTEX_BUFFER, 6 );
+ RECORD_INT( m_UID );
+ RECORD_INT( m_nBufferSize );
+ RECORD_INT( desc.Usage );
+ RECORD_INT( desc.FVF );
+ RECORD_INT( desc.Pool );
+ RECORD_INT( m_bDynamic );
+
+ HRESULT hr = pD3D->CreateVertexBuffer( m_nBufferSize, desc.Usage, desc.FVF, desc.Pool, &m_pVB, NULL );
+
+ if ( hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY )
+ {
+ // Don't have the memory for this. Try flushing all managed resources
+ // out of vid mem and try again.
+ // FIXME: need to record this
+ pD3D->EvictManagedResources();
+ pD3D->CreateVertexBuffer( m_nBufferSize, desc.Usage, desc.FVF, desc.Pool, &m_pVB, NULL );
+ }
+
+#ifdef _DEBUG
+ if ( hr != D3D_OK )
+ {
+ switch ( hr )
+ {
+ case D3DERR_INVALIDCALL:
+ Assert( !"D3DERR_INVALIDCALL" );
+ break;
+ case D3DERR_OUTOFVIDEOMEMORY:
+ Assert( !"D3DERR_OUTOFVIDEOMEMORY" );
+ break;
+ case E_OUTOFMEMORY:
+ Assert( !"E_OUTOFMEMORY" );
+ break;
+ default:
+ Assert( 0 );
+ break;
+ }
+ }
+#endif
+
+ Assert( m_pVB );
+#else
+ // _X360
+ if ( m_bDynamic )
+ {
+ m_iAllocationSize = m_nBufferSize * X360_VERTEX_BUFFER_SIZE_MULTIPLIER;
+ Assert( m_iAllocationSize >= m_nBufferSize );
+ m_pAllocatedMemory = (unsigned char*)XPhysicalAlloc( m_iAllocationSize, MAXULONG_PTR, 0, PAGE_READWRITE | MEM_LARGE_PAGES | PAGE_WRITECOMBINE );
+ }
+ else if ( MeshMgr()->AllocatePooledVB( this, m_nBufferSize, pTextureBudgetName ) )
+ {
+ // Successfully allocated in a shared ShaderAPI memory pool (SetBufferAllocationHandle will have been called to set the pointer and stream offset)
+ m_iAllocationSize = m_nBufferSize;
+ Assert( m_pAllocatedMemory );
+ }
+ else
+ {
+ // Fall back to allocating a standalone VB
+ // NOTE: write-combining (PAGE_WRITECOMBINE) is deliberately not used, since it slows down CPU access to the data (decals+defragmentation)
+ m_iAllocationSize = m_nBufferSize;
+ m_pAllocatedMemory = (unsigned char*)XPhysicalAlloc( m_iAllocationSize, MAXULONG_PTR, 0, PAGE_READWRITE );
+ }
+
+ if ( m_pAllocatedMemory && !IsPooled() )
+ {
+ MemAlloc_RegisterExternalAllocation( XMem_CVertexBuffer, m_pAllocatedMemory, XPhysicalSize( m_pAllocatedMemory ) );
+ if ( !m_bDynamic )
+ {
+ // Track non-pooled physallocs, to help tune CGPUBufferAllocator usage
+ g_SizeIndividualVBPhysAllocs += XPhysicalSize( m_pAllocatedMemory );
+ g_NumIndividualVBPhysAllocs++;
+ }
+ }
+
+ m_iNextBlockingPosition = m_iAllocationSize;
+#endif
+
+#ifdef MEASURE_DRIVER_ALLOCATIONS
+ int nMemUsed = 1024;
+ VPROF_INCREMENT_GROUP_COUNTER( "vb count", COUNTER_GROUP_NO_RESET, 1 );
+ VPROF_INCREMENT_GROUP_COUNTER( "vb driver mem", COUNTER_GROUP_NO_RESET, nMemUsed );
+ VPROF_INCREMENT_GROUP_COUNTER( "total driver mem", COUNTER_GROUP_NO_RESET, nMemUsed );
+#endif
+
+ // Track VB allocations
+#if !defined( _X360 )
+ g_VBAllocTracker->CountVB( m_pVB, m_bDynamic, m_nBufferSize, m_VertexSize, m_VertexBufferFormat );
+#else
+ g_VBAllocTracker->CountVB( this, m_bDynamic, m_iAllocationSize, m_VertexSize, m_VertexBufferFormat );
+#endif
+}
+
+
+#ifdef _X360
+void *AllocateTempBuffer( size_t nSizeInBytes );
+
+//-----------------------------------------------------------------------------
+// This variant is for when we already have the data in physical memory
+//-----------------------------------------------------------------------------
+inline CVertexBuffer::CVertexBuffer( ) :
+ m_pVB( 0 ),
+ m_Position( 0 ),
+ m_VertexSize( 0 ),
+ m_VertexCount( 0 ),
+ m_bFlush( false ),
+ m_bLocked( false ),
+ m_bExternalMemory( true ),
+ m_nBufferSize( 0 ),
+ m_bDynamic( false )
+#ifdef VPROF_ENABLED
+ ,m_Frame( -1 )
+#endif
+{
+ m_iAllocationSize = 0;
+ m_pAllocatedMemory = 0;
+ m_iNextBlockingPosition = 0;
+}
+
+#include "tier0/memdbgoff.h"
+
+inline void CVertexBuffer::Init( IDirect3DDevice9 *pD3D, VertexFormat_t fmt, DWORD theFVF, uint8 *pVertexData, int vertexSize, int vertexCount )
+{
+ m_nBufferSize = vertexSize * vertexCount;
+ m_Position = m_Position;
+ m_VertexSize = vertexSize;
+ m_VertexCount = vertexCount;
+ m_iAllocationSize = m_nBufferSize;
+ m_pAllocatedMemory = pVertexData;
+ m_iNextBlockingPosition = m_iAllocationSize;
+
+ m_pVB = new( AllocateTempBuffer( sizeof( IDirect3DVertexBuffer9 ) ) ) IDirect3DVertexBuffer9;
+ XGSetVertexBufferHeader( m_nBufferSize, 0, 0, 0, m_pVB );
+ XGOffsetResourceAddress( m_pVB, pVertexData );
+}
+
+#include "tier0/memdbgon.h"
+
+#endif // _X360
+
+inline CVertexBuffer::~CVertexBuffer()
+{
+ // Track VB allocations (even if pooled)
+#if !defined( _X360 )
+ if ( m_pVB != NULL )
+ {
+ g_VBAllocTracker->UnCountVB( m_pVB );
+ }
+#else
+ if ( m_pVB && m_pVB->IsSet( Dx9Device() ) )
+ {
+ Unbind( m_pVB );
+ }
+
+ if ( !m_bExternalMemory )
+ {
+ g_VBAllocTracker->UnCountVB( this );
+ }
+#endif
+
+ if ( !m_bExternalMemory )
+ {
+#ifdef MEASURE_DRIVER_ALLOCATIONS
+ int nMemUsed = 1024;
+ VPROF_INCREMENT_GROUP_COUNTER( "vb count", COUNTER_GROUP_NO_RESET, -1 );
+ VPROF_INCREMENT_GROUP_COUNTER( "vb driver mem", COUNTER_GROUP_NO_RESET, -nMemUsed );
+ VPROF_INCREMENT_GROUP_COUNTER( "total driver mem", COUNTER_GROUP_NO_RESET, -nMemUsed );
+#endif
+
+#ifdef VPROF_ENABLED
+ if ( IsX360() || !m_bDynamic )
+ {
+ Assert( m_pGlobalCounter );
+ *m_pGlobalCounter -= m_nBufferSize;
+ }
+#endif
+
+#ifdef _DEBUG
+ --s_BufferCount;
+#endif
+ }
+
+ Unlock( 0 );
+
+ if ( m_pSysmemBuffer )
+ {
+ MemAlloc_FreeAligned( m_pSysmemBuffer );
+ m_pSysmemBuffer = NULL;
+ }
+
+#if !defined( _X360 )
+ if ( m_pVB )
+ {
+ RECORD_COMMAND( DX8_DESTROY_VERTEX_BUFFER, 1 );
+ RECORD_INT( m_UID );
+
+ m_pVB->Release();
+ }
+#else
+ if ( m_pAllocatedMemory && !m_bExternalMemory )
+ {
+ if ( IsPooled() )
+ {
+ MeshMgr()->DeallocatePooledVB( this );
+ }
+ else
+ {
+ MemAlloc_RegisterExternalDeallocation( XMem_CVertexBuffer, m_pAllocatedMemory, XPhysicalSize( m_pAllocatedMemory ) );
+ if ( !m_bDynamic )
+ {
+ // Track non-pooled physallocs, to help tune CGPUBufferAllocator usage
+ g_SizeIndividualVBPhysAllocs -= XPhysicalSize( m_pAllocatedMemory );
+ g_NumIndividualVBPhysAllocs--;
+ }
+ XPhysicalFree( m_pAllocatedMemory );
+ }
+ }
+
+ m_pAllocatedMemory = NULL;
+ m_pVB = NULL;
+#endif // _X360
+}
+#ifdef _X360
+//-----------------------------------------------------------------------------
+// Get memory allocation data
+//-----------------------------------------------------------------------------
+inline const GPUBufferHandle_t *CVertexBuffer::GetBufferAllocationHandle( void )
+{
+ Assert( IsPooled() );
+ return ( IsPooled() ? &m_GPUBufferHandle : NULL );
+}
+
+//-----------------------------------------------------------------------------
+// Update memory allocation data
+//-----------------------------------------------------------------------------
+inline void CVertexBuffer::SetBufferAllocationHandle( const GPUBufferHandle_t &bufferAllocationHandle )
+{
+ // This VB's memory has been reallocated or freed, update our cached pointer and the D3D header
+ // NOTE: this should never be called while any rendering is in flight!
+ Assert( ( m_pAllocatedMemory == NULL ) || IsPooled() );
+ if ( ( m_pAllocatedMemory == NULL ) || IsPooled() )
+ {
+ m_GPUBufferHandle = bufferAllocationHandle;
+ m_pAllocatedMemory = m_GPUBufferHandle.pMemory;
+ if ( m_pVB )
+ {
+ XGSetVertexBufferHeader( m_nBufferSize, 0, D3DPOOL_DEFAULT, 0, m_pVB );
+ XGOffsetResourceAddress( m_pVB, m_pAllocatedMemory );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Expose the data pointer for read-only CPU access to the data
+//-----------------------------------------------------------------------------
+inline const byte **CVertexBuffer::GetBufferDataPointerAddress( void )
+{
+ if ( m_bDynamic /* FIXME: || m_bExternalMemory*/ )
+ return NULL;
+ return (const byte **)&m_pAllocatedMemory;
+}
+#endif // _X360
+
+//-----------------------------------------------------------------------------
+// Compute the next offset for the next lock
+//-----------------------------------------------------------------------------
+inline int CVertexBuffer::NextLockOffset( ) const
+{
+#if !defined( _X360 )
+ int nNextOffset = ( m_Position + m_VertexSize - 1 ) / m_VertexSize;
+ nNextOffset *= m_VertexSize;
+ return nNextOffset;
+#else
+ return m_Position; //position is already aligned properly on unlocks for 360.
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Do we have enough room without discarding?
+//-----------------------------------------------------------------------------
+inline bool CVertexBuffer::HasEnoughRoom( int numVertices ) const
+{
+#if defined( _X360 )
+ return numVertices <= m_VertexCount; //the ring buffer will free room as needed
+#else
+ return (NextLockOffset() + (numVertices * m_VertexSize)) <= m_nBufferSize;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Block until this part of the index buffer is free
+//-----------------------------------------------------------------------------
+inline void CVertexBuffer::BlockUntilUnused( int nBufferSize )
+{
+ Assert( nBufferSize <= m_nBufferSize );
+
+#ifdef _X360
+ int nLockOffset = NextLockOffset();
+ Assert( (m_AllocationRing.Count() != 0) || ((m_Position == 0) && (m_iNextBlockingPosition == m_iAllocationSize)) );
+
+ if ( (m_iNextBlockingPosition - nLockOffset) >= nBufferSize )
+ return;
+
+ Assert( (m_AllocationRing[m_AllocationRing.Head()].m_iStartOffset == 0) || ((m_iNextBlockingPosition == m_AllocationRing[m_AllocationRing.Head()].m_iStartOffset) && (m_Position <= m_iNextBlockingPosition)) );
+
+ int iMinBlockPosition = nLockOffset + nBufferSize;
+ if( iMinBlockPosition > m_iAllocationSize )
+ {
+ //Allocation requires us to wrap
+ iMinBlockPosition = nBufferSize;
+ m_Position = 0;
+
+ //modify the last allocation so that it uses up the whole tail end of the buffer. Makes other code simpler
+ Assert( m_AllocationRing.Count() != 0 );
+ m_AllocationRing[m_AllocationRing.Tail()].m_iEndOffset = m_iAllocationSize;
+
+ //treat all allocations between the current position and the tail end of the ring as freed since they will be before we unblock
+ while( m_AllocationRing.Count() )
+ {
+ unsigned int head = m_AllocationRing.Head();
+ if( m_AllocationRing[head].m_iStartOffset == 0 )
+ break;
+
+ m_AllocationRing.Remove( head );
+ }
+ }
+
+ //now we go through the allocations until we find the last fence we care about. Treat everything up until that fence as freed.
+ DWORD FinalFence = 0;
+ unsigned int iFinalAllocationZPassIdx = 0;
+ while( m_AllocationRing.Count() )
+ {
+ unsigned int head = m_AllocationRing.Head();
+
+ if( m_AllocationRing[head].m_iEndOffset >= iMinBlockPosition )
+ {
+ //When this frees, we'll finally have enough space for the allocation
+ FinalFence = m_AllocationRing[head].m_Fence;
+ iFinalAllocationZPassIdx = m_AllocationRing[head].m_iZPassIdx;
+ m_iNextBlockingPosition = m_AllocationRing[head].m_iEndOffset;
+ m_AllocationRing.Remove( head );
+ break;
+ }
+ m_AllocationRing.Remove( head );
+ }
+ Assert( FinalFence != 0 );
+
+ if( Dx9Device()->IsFencePending( FinalFence ) )
+ {
+#ifdef SPEW_VERTEX_BUFFER_STALLS
+ float st = Plat_FloatTime();
+#endif
+
+ if ( ( Dx9Device()->GetDeviceState() & D3DDEVICESTATE_ZPASS_BRACKET ) &&
+ ( iFinalAllocationZPassIdx == ShaderAPI()->Get360ZPassCounter() ) )
+ {
+ // We're about to overrun our VB ringbuffer in a single Z prepass. To avoid rendering corruption, close out the
+ // Z prepass and continue. This will reduce early-Z rejection efficiency and could cause a momentary framerate drop,
+ // but it's better than rendering corruption.
+ Warning( "Dynamic VB ring buffer overrun in Z Prepass. Tell Thorsten.\n" );
+
+ ShaderAPI()->End360ZPass();
+ }
+
+ Dx9Device()->BlockOnFence( FinalFence );
+
+#ifdef SPEW_VERTEX_BUFFER_STALLS
+ float dt = Plat_FloatTime() - st;
+ Warning( "Blocked locking dynamic vertex buffer for %f ms!\n", 1000.0 * dt );
+#endif
+ }
+
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// lock, unlock
+//-----------------------------------------------------------------------------
+inline unsigned char* CVertexBuffer::Lock( int numVerts, int& baseVertexIndex )
+{
+#if defined( _X360 )
+ if ( m_pVB && m_pVB->IsSet( Dx9Device() ) )
+ {
+ Unbind( m_pVB );
+ }
+#endif
+
+ m_nLockCount = numVerts;
+
+ unsigned char* pLockedData = 0;
+ baseVertexIndex = 0;
+ int nBufferSize = numVerts * m_VertexSize;
+
+ Assert( IsPC() || ( IsX360() && !m_bLocked ) );
+
+ // Ensure there is enough space in the VB for this data
+ if ( numVerts > m_VertexCount )
+ {
+ Assert( 0 );
+ return 0;
+ }
+
+ if ( !IsX360() && !m_pVB && !m_pSysmemBuffer )
+ return 0;
+
+ DWORD dwFlags;
+ if ( m_bDynamic )
+ {
+ dwFlags = LOCKFLAGS_APPEND;
+
+#if !defined( _X360 )
+ // If either the user forced us to flush,
+ // or there is not enough space for the vertex data,
+ // then flush the buffer contents
+ if ( !m_Position || m_bFlush || !HasEnoughRoom(numVerts) )
+ {
+ if ( m_pSysmemBuffer || !g_pShaderUtil->IsRenderThreadSafe() )
+ m_bLateCreateShouldDiscard = true;
+ m_bFlush = false;
+ m_Position = 0;
+
+ dwFlags = LOCKFLAGS_FLUSH;
+ }
+#else
+ if( m_bFlush )
+ {
+# if ( defined( X360_BLOCK_ON_VB_FLUSH ) )
+ {
+ if( m_AllocationRing.Count() )
+ {
+ DWORD FinalFence = m_AllocationRing[m_AllocationRing.Tail()].m_Fence;
+
+ m_AllocationRing.RemoveAll();
+ m_Position = 0;
+ m_iNextBlockingPosition = m_iAllocationSize;
+
+# if ( defined( SPEW_VERTEX_BUFFER_STALLS ) )
+ if( Dx9Device()->IsFencePending( FinalFence ) )
+ {
+ float st = Plat_FloatTime();
+# endif
+ Dx9Device()->BlockOnFence( FinalFence );
+# if ( defined ( SPEW_VERTEX_BUFFER_STALLS ) )
+ float dt = Plat_FloatTime() - st;
+ Warning( "Blocked FLUSHING dynamic vertex buffer for %f ms!\n", 1000.0 * dt );
+ }
+# endif
+ }
+ }
+# endif
+ m_bFlush = false;
+ }
+#endif
+ }
+ else
+ {
+ // Since we are a static VB, always lock the beginning of the buffer.
+ dwFlags = D3DLOCK_NOSYSLOCK;
+ m_Position = 0;
+ }
+
+ if ( IsX360() && m_bDynamic )
+ {
+ // Block until we have enough room in the buffer, this affects the result of NextLockOffset() in wrap conditions.
+ BlockUntilUnused( nBufferSize );
+ m_pVB = NULL;
+ }
+
+ int nLockOffset = NextLockOffset( );
+ RECORD_COMMAND( DX8_LOCK_VERTEX_BUFFER, 4 );
+ RECORD_INT( m_UID );
+ RECORD_INT( nLockOffset );
+ RECORD_INT( nBufferSize );
+ RECORD_INT( dwFlags );
+
+#if !defined( _X360 )
+ // If the caller isn't in the thread that owns the render lock, need to return a system memory pointer--cannot talk to GL from
+ // the non-current thread.
+ if ( !m_pSysmemBuffer && !g_pShaderUtil->IsRenderThreadSafe() )
+ {
+ m_pSysmemBuffer = ( byte * )MemAlloc_AllocAligned( m_nBufferSize, 16 );
+ m_nSysmemBufferStartBytes = nLockOffset;
+ Assert( ( m_nSysmemBufferStartBytes % m_VertexSize ) == 0 );
+ }
+
+ if ( m_pSysmemBuffer != NULL )
+ {
+ // Ensure that we're never moving backwards in a buffer--this code would need to be rewritten if so.
+ // We theorize this can happen if you hit the end of a buffer and then wrap before drawing--but
+ // this would probably break in other places as well.
+ Assert( nLockOffset >= m_nSysmemBufferStartBytes );
+ pLockedData = m_pSysmemBuffer + nLockOffset;
+ }
+ else
+ {
+ m_pVB->Lock( nLockOffset,
+ nBufferSize,
+ reinterpret_cast< void** >( &pLockedData ),
+ dwFlags );
+ }
+#else
+ pLockedData = m_pAllocatedMemory + nLockOffset;
+#endif
+
+ Assert( pLockedData != 0 );
+ m_bLocked = true;
+ if ( !IsX360() )
+ {
+ baseVertexIndex = nLockOffset / m_VertexSize;
+ }
+ else
+ {
+ baseVertexIndex = 0;
+ }
+ return pLockedData;
+}
+
+inline unsigned char* CVertexBuffer::Modify( bool bReadOnly, int firstVertex, int numVerts )
+{
+ unsigned char* pLockedData = 0;
+
+ // D3D still returns a pointer when you call lock with 0 verts, so just in
+ // case it's actually doing something, don't even try to lock the buffer with 0 verts.
+ if ( numVerts == 0 )
+ return NULL;
+
+ m_nLockCount = numVerts;
+
+ // If this hits, m_pSysmemBuffer logic needs to be added to this code.
+ Assert( g_pShaderUtil->IsRenderThreadSafe() );
+ Assert( !m_pSysmemBuffer ); // if this hits, then we need to add code to handle it
+
+ Assert( m_pVB && !m_bDynamic );
+
+ if ( firstVertex + numVerts > m_VertexCount )
+ {
+ Assert( 0 );
+ return NULL;
+ }
+
+ DWORD dwFlags = D3DLOCK_NOSYSLOCK;
+ if ( bReadOnly )
+ {
+ dwFlags |= D3DLOCK_READONLY;
+ }
+
+ RECORD_COMMAND( DX8_LOCK_VERTEX_BUFFER, 4 );
+ RECORD_INT( m_UID );
+ RECORD_INT( firstVertex * m_VertexSize );
+ RECORD_INT( numVerts * m_VertexSize );
+ RECORD_INT( dwFlags );
+
+ // mmw: for forcing all dynamic... LOCKFLAGS_FLUSH );
+#if !defined( _X360 )
+ m_pVB->Lock(
+ firstVertex * m_VertexSize,
+ numVerts * m_VertexSize,
+ reinterpret_cast< void** >( &pLockedData ),
+ dwFlags );
+#else
+ if ( m_pVB->IsSet( Dx9Device() ) )
+ {
+ Unbind( m_pVB );
+ }
+ pLockedData = m_pAllocatedMemory + (firstVertex * m_VertexSize);
+#endif
+
+ m_Position = firstVertex * m_VertexSize;
+ Assert( pLockedData != 0 );
+ m_bLocked = true;
+
+ return pLockedData;
+}
+
+inline void CVertexBuffer::Unlock( int numVerts )
+{
+ if ( !m_bLocked )
+ return;
+
+ if ( !IsX360() && !m_pVB && !m_pSysmemBuffer )
+ return;
+
+ int nLockOffset = NextLockOffset();
+ int nBufferSize = numVerts * m_VertexSize;
+
+ RECORD_COMMAND( DX8_UNLOCK_VERTEX_BUFFER, 1 );
+ RECORD_INT( m_UID );
+
+#if !defined( _X360 )
+ if ( m_pSysmemBuffer != NULL )
+ {
+ }
+ else
+ {
+ #if DX_TO_GL_ABSTRACTION
+ Assert( numVerts <= (int)m_nLockCount );
+ int unlockBytes = ( m_bDynamic ? nBufferSize : ( m_nLockCount * m_VertexSize ) );
+ #else
+ int unlockBytes = 0;
+ #endif
+
+ ReallyUnlock( unlockBytes );
+ }
+ m_Position = nLockOffset + nBufferSize;
+#else
+ if ( m_bDynamic )
+ {
+ if ( numVerts > 0 )
+ {
+ DynamicBufferAllocation_t LockData;
+ LockData.m_Fence = Dx9Device()->GetCurrentFence(); //This isn't the correct fence, but it's all we have access to for now and it'll provide marginal safety if something goes really wrong.
+ LockData.m_iStartOffset = nLockOffset;
+ LockData.m_iEndOffset = LockData.m_iStartOffset + nBufferSize;
+ LockData.m_iZPassIdx = ( Dx9Device()->GetDeviceState() & D3DDEVICESTATE_ZPASS_BRACKET ) ? ShaderAPI()->Get360ZPassCounter() : 0;
+
+ // Round dynamic locks to 4k boundaries for GPU cache reasons
+ LockData.m_iEndOffset = ALIGN_VALUE( LockData.m_iEndOffset, 4096 );
+ if( LockData.m_iEndOffset > m_iAllocationSize )
+ LockData.m_iEndOffset = m_iAllocationSize;
+
+ m_AllocationRing.AddToTail( LockData );
+ m_Position = LockData.m_iEndOffset;
+
+ void* pLockedData = m_pAllocatedMemory + LockData.m_iStartOffset;
+
+ //Always re-use the same vertex buffer header based on the assumption that D3D copies it off in the draw calls.
+ m_pVB = &m_D3DVertexBuffer;
+ XGSetVertexBufferHeader( nBufferSize, 0, D3DPOOL_DEFAULT, 0, m_pVB );
+ XGOffsetResourceAddress( m_pVB, pLockedData );
+
+ // Invalidate the GPU caches for this memory.
+ Dx9Device()->InvalidateGpuCache( pLockedData, nBufferSize, 0 );
+ }
+ }
+ else
+ {
+ if ( !m_pVB )
+ {
+ m_pVB = &m_D3DVertexBuffer;
+ XGSetVertexBufferHeader( m_nBufferSize, 0, D3DPOOL_DEFAULT, 0, m_pVB );
+ XGOffsetResourceAddress( m_pVB, m_pAllocatedMemory );
+ }
+ m_Position = nLockOffset + nBufferSize;
+
+ // Invalidate the GPU caches for this memory.
+ Dx9Device()->InvalidateGpuCache( m_pAllocatedMemory, m_nBufferSize, 0 );
+ }
+#endif
+
+ m_bLocked = false;
+}
+
+
+inline void CVertexBuffer::HandleLateCreation( )
+{
+ if ( !m_pSysmemBuffer )
+ {
+ return;
+ }
+
+ if( !m_pVB )
+ {
+ bool bPrior = g_VBAllocTracker->TrackMeshAllocations( "HandleLateCreation" );
+ Create( Dx9Device() );
+ if ( !bPrior )
+ {
+ g_VBAllocTracker->TrackMeshAllocations( NULL );
+ }
+ }
+
+ void* pWritePtr = NULL;
+ const int dataToWriteBytes = m_bDynamic ? ( m_Position - m_nSysmemBufferStartBytes ) : ( m_nLockCount * m_VertexSize );
+ DWORD dwFlags = D3DLOCK_NOSYSLOCK;
+ if ( m_bDynamic )
+ {
+ dwFlags |= ( m_bLateCreateShouldDiscard ? D3DLOCK_DISCARD : D3DLOCK_NOOVERWRITE );
+ }
+
+ // Always clear this.
+ m_bLateCreateShouldDiscard = false;
+
+ // Don't use the Lock function, it does a bunch of stuff we don't want.
+ HRESULT hr = m_pVB->Lock( m_nSysmemBufferStartBytes,
+ dataToWriteBytes,
+ &pWritePtr,
+ dwFlags);
+
+ // If this fails we're about to crash. Consider skipping the update and leaving
+ // m_pSysmemBuffer around to try again later. (For example in case of device loss)
+ Assert( SUCCEEDED( hr ) ); hr;
+ memcpy( pWritePtr, m_pSysmemBuffer + m_nSysmemBufferStartBytes, dataToWriteBytes );
+ ReallyUnlock( dataToWriteBytes );
+
+ MemAlloc_FreeAligned( m_pSysmemBuffer );
+ m_pSysmemBuffer = NULL;
+}
+
+
+// Returns the allocated size
+inline int CVertexBuffer::AllocationSize() const
+{
+#ifdef _X360
+ return m_iAllocationSize;
+#else
+ return m_VertexCount * m_VertexSize;
+#endif
+}
+
+
+#endif // DYNAMICVB_H
+
diff --git a/materialsystem/shaderapidx9/gpubufferallocator.cpp b/materialsystem/shaderapidx9/gpubufferallocator.cpp
new file mode 100644
index 0000000..e86a009
--- /dev/null
+++ b/materialsystem/shaderapidx9/gpubufferallocator.cpp
@@ -0,0 +1,480 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: See gpubufferallocator.h
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#include "gpubufferallocator.h"
+#include "dynamicvb.h"
+#include "dynamicib.h"
+
+// NOTE: This has to be the last file included!
+#include "tier0/memdbgon.h"
+
+#if defined( _X360 )
+
+
+
+//-----------------------------------------------------------------------------
+// globals
+//-----------------------------------------------------------------------------
+
+#include "utlmap.h"
+MEMALLOC_DEFINE_EXTERNAL_TRACKING( XMem_CGPUBufferPool );
+
+// Track non-pooled VB/IB physical allocations (used by CGPUBufferAllocator::SpewStats)
+CInterlockedInt g_NumIndividualVBPhysAllocs = 0;
+CInterlockedInt g_SizeIndividualVBPhysAllocs = 0;
+CInterlockedInt g_NumIndividualIBPhysAllocs = 0;
+CInterlockedInt g_SizeIndividualIBPhysAllocs = 0;
+
+
+
+//=============================================================================
+//=============================================================================
+// CGPUBufferAllocator
+//=============================================================================
+//=============================================================================
+
+CGPUBufferAllocator::CGPUBufferAllocator( void )
+ : m_nBufferPools( 0 ),
+ m_bEnabled( true )
+{
+ memset( &( m_BufferPools[ 0 ] ), 0, sizeof( m_BufferPools ) );
+
+ m_bEnabled = USE_GPU_BUFFER_ALLOCATOR && !CommandLine()->FindParm( "-no_gpu_buffer_allocator" );
+ if ( m_bEnabled )
+ {
+ // Start with one pool (the size should be the lowest-common-denominator for all maps)
+ AllocatePool( INITIAL_POOL_SIZE );
+ }
+}
+
+CGPUBufferAllocator::~CGPUBufferAllocator( void )
+{
+ for ( int i = 0; i < m_nBufferPools; i++ )
+ {
+ delete m_BufferPools[ i ];
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Allocate a new memory pool
+//-----------------------------------------------------------------------------
+bool CGPUBufferAllocator::AllocatePool( int nPoolSize )
+{
+ if ( m_nBufferPools == MAX_POOLS )
+ return false;
+
+ m_BufferPools[ m_nBufferPools ] = new CGPUBufferPool( nPoolSize );
+ if ( m_BufferPools[ m_nBufferPools ]->m_pMemory == NULL )
+ {
+ // Physical alloc failed! Continue without crashing, we *might* get away with it...
+ ExecuteOnce( DebuggerBreakIfDebugging() );
+ ExecuteNTimes( 15, Warning( "CGPUBufferAllocator::AllocatePool - physical allocation failed! Physical fragmentation is in bad shape... falling back to non-pooled VB/IB allocations. Brace for a crash :o/\n" ) );
+ delete m_BufferPools[ m_nBufferPools ];
+ m_BufferPools[ m_nBufferPools ] = NULL;
+ return false;
+ }
+ m_nBufferPools++;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Make a new GPUBufferHandle_t to represent a given buffer allocation
+//-----------------------------------------------------------------------------
+inline GPUBufferHandle_t CGPUBufferAllocator::MakeGPUBufferHandle( int nPoolNum, int nPoolEntry )
+{
+ GPUBufferHandle_t newHandle;
+ newHandle.nPoolNum = nPoolNum;
+ newHandle.nPoolEntry = nPoolEntry;
+ newHandle.pMemory = m_BufferPools[ nPoolNum ]->m_pMemory + m_BufferPools[ nPoolNum ]->m_PoolEntries[ nPoolEntry ].nOffset;
+ return newHandle;
+}
+
+//-----------------------------------------------------------------------------
+// Try to allocate a block of the given size from one of our pools
+//-----------------------------------------------------------------------------
+bool CGPUBufferAllocator::AllocateBuffer( GPUBufferHandle_t *pHandle, int nBufferSize, void *pObject, bool bIsVertexBuffer )
+{
+ if ( m_bEnabled && ( nBufferSize <= MAX_BUFFER_SIZE ) )
+ {
+ // Try to allocate at the end of one of our pools
+ for ( int nPool = 0; nPool < m_nBufferPools; nPool++ )
+ {
+ int nPoolEntry = m_BufferPools[ nPool ]->Allocate( nBufferSize, bIsVertexBuffer, pObject );
+ if ( nPoolEntry >= 0 )
+ {
+ // Tada.
+ *pHandle = MakeGPUBufferHandle( nPool, nPoolEntry );
+ return true;
+ }
+ if ( nPool == ( m_nBufferPools - 1 ) )
+ {
+ // Allocate a new pool (in which this buffer should DEFINITELY fit!)
+ COMPILE_TIME_ASSERT( ADDITIONAL_POOL_SIZE >= MAX_BUFFER_SIZE );
+ AllocatePool( ADDITIONAL_POOL_SIZE );
+ }
+ }
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Clear the given allocation from our pools (NOTE: the memory cannot be reused until Defrag() is called)
+//-----------------------------------------------------------------------------
+void CGPUBufferAllocator::DeallocateBuffer( const GPUBufferHandle_t *pHandle )
+{
+ Assert( pHandle );
+ if ( pHandle )
+ {
+ Assert( ( pHandle->nPoolNum >= 0 ) && ( pHandle->nPoolNum < m_nBufferPools ) );
+ if ( ( pHandle->nPoolNum >= 0 ) && ( pHandle->nPoolNum < m_nBufferPools ) )
+ {
+ m_BufferPools[ pHandle->nPoolNum ]->Deallocate( pHandle );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// If appropriate, allocate this VB's memory from one of our pools
+//-----------------------------------------------------------------------------
+bool CGPUBufferAllocator::AllocateVertexBuffer( CVertexBuffer *pVertexBuffer, int nBufferSize )
+{
+ AUTO_LOCK( m_mutex );
+
+ bool bIsVertexBuffer = true;
+ GPUBufferHandle_t handle;
+ if ( AllocateBuffer( &handle, nBufferSize, (void *)pVertexBuffer, bIsVertexBuffer ) )
+ {
+ // Success - give the VB the handle to this allocation
+ pVertexBuffer->SetBufferAllocationHandle( handle );
+ return true;
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Deallocate this VB's memory from our pools
+//-----------------------------------------------------------------------------
+void CGPUBufferAllocator::DeallocateVertexBuffer( CVertexBuffer *pVertexBuffer )
+{
+ AUTO_LOCK( m_mutex );
+
+ // Remove the allocation from the pool and clear the VB's handle
+ DeallocateBuffer( pVertexBuffer->GetBufferAllocationHandle() );
+ pVertexBuffer->SetBufferAllocationHandle( GPUBufferHandle_t() );
+}
+
+//-----------------------------------------------------------------------------
+// If appropriate, allocate this IB's memory from one of our pools
+//-----------------------------------------------------------------------------
+bool CGPUBufferAllocator::AllocateIndexBuffer( CIndexBuffer *pIndexBuffer, int nBufferSize )
+{
+ AUTO_LOCK( m_mutex );
+
+ bool bIsNOTVertexBuffer = false;
+ GPUBufferHandle_t handle;
+ if ( AllocateBuffer( &handle, nBufferSize, (void *)pIndexBuffer, bIsNOTVertexBuffer ) )
+ {
+ // Success - give the IB the handle to this allocation
+ pIndexBuffer->SetBufferAllocationHandle( handle );
+ return true;
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Deallocate this IB's memory from our pools
+//-----------------------------------------------------------------------------
+void CGPUBufferAllocator::DeallocateIndexBuffer( CIndexBuffer *pIndexBuffer )
+{
+ AUTO_LOCK( m_mutex );
+
+ // Remove the allocation from the pool and clear the IB's handle
+ DeallocateBuffer( pIndexBuffer->GetBufferAllocationHandle() );
+ pIndexBuffer->SetBufferAllocationHandle( GPUBufferHandle_t() );
+}
+
+//-----------------------------------------------------------------------------
+// Move a buffer from one location to another (could be movement within the same pool)
+//-----------------------------------------------------------------------------
+void CGPUBufferAllocator::MoveBufferMemory( int nDstPool, int *pnDstEntry, int *pnDstOffset, CGPUBufferPool &srcPool, GPUBufferPoolEntry_t &srcEntry )
+{
+ // Move the data
+ CGPUBufferPool &dstPool = *m_BufferPools[ nDstPool ];
+ byte *pDest = dstPool.m_pMemory + *pnDstOffset;
+ byte *pSource = srcPool.m_pMemory + srcEntry.nOffset;
+ if ( pDest != pSource )
+ V_memmove( pDest, pSource, srcEntry.nSize );
+
+ // Update the destination pool's allocation entry (NOTE: this could be srcEntry, so srcEntry.nOffset would change)
+ dstPool.m_PoolEntries[ *pnDstEntry ] = srcEntry;
+ dstPool.m_PoolEntries[ *pnDstEntry ].nOffset = *pnDstOffset;
+
+ // Tell the VB/IB about the updated allocation
+ GPUBufferHandle_t newHandle = MakeGPUBufferHandle( nDstPool, *pnDstEntry );
+ if ( srcEntry.bIsVertexBuffer )
+ srcEntry.pVertexBuffer->SetBufferAllocationHandle( newHandle );
+ else
+ srcEntry.pIndexBuffer->SetBufferAllocationHandle( newHandle );
+
+ // Move the write address past this entry and increment the pool high water mark
+ *pnDstOffset += srcEntry.nSize;
+ *pnDstEntry += 1;
+ dstPool.m_nBytesUsed += srcEntry.nSize;
+}
+
+//-----------------------------------------------------------------------------
+// Reclaim space freed by destroyed buffers and compact our pools ready for new allocations
+//-----------------------------------------------------------------------------
+void CGPUBufferAllocator::Compact( void )
+{
+ // NOTE: this must only be called during map transitions, no rendering must be in flight and everything must be single-threaded!
+ AUTO_LOCK( m_mutex );
+
+ // SpewStats(); // pre-compact state
+
+ CFastTimer timer;
+ timer.Start();
+
+ // Shuffle all pools to get rid of the empty space occupied by freed buffers.
+ // We just walk the pools and entries in order, moving each buffer down within the same pool,
+ // or to the end of a previous pool (if, after compaction, it now has free space).
+ // Each pool should end up with contiguous, usable free space (may be zero bytes) at the end.
+ int nDstPool = 0, nDstEntry = 0, nDstOffset = 0;
+ for ( int nSrcPool = 0; nSrcPool < m_nBufferPools; nSrcPool++ )
+ {
+ CGPUBufferPool &srcPool = *m_BufferPools[ nSrcPool ];
+ srcPool.m_nBytesUsed = 0; // Re-fill each pool from scratch
+ int nEntriesRemainingInPool = 0;
+ for ( int nSrcEntry = 0; nSrcEntry < srcPool.m_PoolEntries.Count(); nSrcEntry++ )
+ {
+ GPUBufferPoolEntry_t &srcEntry = srcPool.m_PoolEntries[ nSrcEntry ];
+ if ( srcEntry.pVertexBuffer )
+ {
+ // First, try to move the buffer into one of the previous (already-compacted) pools
+ bool bDone = false;
+ while ( nDstPool < nSrcPool )
+ {
+ CGPUBufferPool &dstPool = *m_BufferPools[ nDstPool ];
+ if ( ( nDstOffset + srcEntry.nSize ) <= dstPool.m_nSize )
+ {
+ // Add this buffer to the end of dstPool
+ Assert( nDstEntry == dstPool.m_PoolEntries.Count() );
+ dstPool.m_PoolEntries.AddToTail();
+ MoveBufferMemory( nDstPool, &nDstEntry, &nDstOffset, srcPool, srcEntry );
+ bDone = true;
+ break;
+ }
+ else
+ {
+ // This pool is full, start writing into the next one
+ nDstPool++;
+ nDstEntry = 0;
+ nDstOffset = 0;
+ }
+ }
+
+ // If that fails, just shuffle the entry down within srcPool
+ if ( !bDone )
+ {
+ Assert( nSrcPool == nDstPool );
+ MoveBufferMemory( nDstPool, &nDstEntry, &nDstOffset, srcPool, srcEntry );
+ nEntriesRemainingInPool++;
+ }
+ }
+ }
+
+ // Discard unused entries from the end of the pool (freed buffers, or buffers moved to other pools)
+ srcPool.m_PoolEntries.SetCountNonDestructively( nEntriesRemainingInPool );
+ }
+
+ // Now free empty pools (keep the first (very large) one around, since fragmentation makes freeing+reallocing it a big risk)
+ int nBytesFreed = 0;
+ for ( int nPool = ( m_nBufferPools - 1 ); nPool > 0; nPool-- )
+ {
+ if ( m_BufferPools[ nPool ]->m_PoolEntries.Count() )
+ break;
+
+ nBytesFreed += m_BufferPools[ nPool ]->m_nSize;
+ Assert( m_BufferPools[ nPool ]->m_nBytesUsed == 0 );
+ delete m_BufferPools[ nPool ];
+ m_nBufferPools--;
+ }
+
+ if ( m_nBufferPools > 1 )
+ {
+ // The above compaction algorithm could waste space due to large allocs causing nDstPool to increment before that pool
+ // is actually full. With our current usage pattern (total in-use memory is less than INITIAL_POOL_SIZE, whenever Compact
+ // is called), that doesn't matter. If that changes (i.e. the below warning fires), then the fix would be:
+ // - for each pool, sort its entries by size (largest first) and try to allocate them on the end of prior (already-compacted) pools
+ // - pack whatever remains in the pool down, and proceed to the next pool
+ ExecuteOnce( Warning( "CGPUBufferAllocator::Compact may be wasting memory due to changed usage patterns (see code for suggested fix)." ) );
+ }
+
+#ifdef _X360
+ // Invalidate the GPU caches for all pooled memory, since stuff has moved around
+ for ( int nPool = 0; nPool < m_nBufferPools; nPool++ )
+ {
+ Dx9Device()->InvalidateGpuCache( m_BufferPools[ nPool ]->m_pMemory, m_BufferPools[ nPool ]->m_nSize, 0 );
+ }
+#endif
+
+ timer.End();
+ float compactTime = (float)timer.GetDuration().GetSeconds();
+ Msg( "CGPUBufferAllocator::Compact took %.2f seconds, and freed %.1fkb\n", compactTime, ( nBytesFreed / 1024.0f ) );
+
+ // SpewStats(); // post-compact state
+}
+
+//-----------------------------------------------------------------------------
+// Spew statistics about pool usage, so we can tune our constant values
+//-----------------------------------------------------------------------------
+void CGPUBufferAllocator::SpewStats( bool bBrief )
+{
+ AUTO_LOCK( m_mutex );
+
+ int nMemAllocated = 0;
+ int nMemUsed = 0;
+ int nOldMemWasted = 0;
+ int nVBsInPools = 0;
+ int nIBsInPools = 0;
+ int nFreedBuffers = 0;
+ int nFreedBufferMem = 0;
+ for ( int i = 0; i < m_nBufferPools; i++ )
+ {
+ CGPUBufferPool *pool = m_BufferPools[ i ];
+ nMemAllocated += pool->m_nSize;
+ nMemUsed += pool->m_nBytesUsed;
+ for ( int j = 0; j < pool->m_PoolEntries.Count(); j++ )
+ {
+ GPUBufferPoolEntry_t &poolEntry = pool->m_PoolEntries[ j ];
+ if ( poolEntry.pVertexBuffer )
+ {
+ // Figure out how much memory we WOULD have allocated for this buffer, if we'd allocated it individually:
+ nOldMemWasted += ALIGN_VALUE( poolEntry.nSize, 4096 ) - poolEntry.nSize;
+ if ( poolEntry.bIsVertexBuffer ) nVBsInPools++;
+ if ( !poolEntry.bIsVertexBuffer ) nIBsInPools++;
+ }
+ else
+ {
+ nFreedBuffers++;
+ nFreedBufferMem += poolEntry.nSize;
+ }
+ }
+ }
+
+ // NOTE: 'unused' memory doesn't count memory used by freed buffers, which should be zero during gameplay. The purpose is
+ // to measure wastage at the END of a pool, to help determine ideal values for ADDITIONAL_POOL_SIZE and MAX_BUFFER_SIZE.
+ int nMemUnused = nMemAllocated - nMemUsed;
+
+ const float KB = 1024.0f, MB = KB*KB;
+ if ( bBrief )
+ {
+ ConMsg( "[GPUBUFLOG] Pools:%2d | Size:%5.1fMB | Unused:%5.1fMB | Freed:%5.1fMB | Unpooled:%5.1fMB\n",
+ m_nBufferPools, nMemAllocated / MB, nMemUnused / MB, nFreedBufferMem / MB, ( g_SizeIndividualVBPhysAllocs + g_SizeIndividualIBPhysAllocs ) / MB );
+ }
+ else
+ {
+ Msg( "\nGPU Buffer Allocator stats:\n" );
+ Msg( " -- %5d -- Num Pools allocated\n", m_nBufferPools );
+ Msg( " -- %7.1fMB -- Memory allocated to pools\n", nMemAllocated / MB );
+ Msg( " -- %7.1fkb -- Unused memory at tail-end of pools\n", nMemUnused / KB );
+ Msg( " -- %7.1fkb -- Memory saved by allocating buffers from pools\n", nOldMemWasted / KB );
+ Msg( " -- %5d -- Number of VBs allocated from pools\n", nVBsInPools );
+ Msg( " -- %5d -- Number of IBs allocated from pools\n", nIBsInPools );
+ Msg( " -- %5d -- Number of freed buffers in pools (should be zero during gameplay)\n", nFreedBuffers );
+ Msg( " -- %7.1fkb -- Memory used by freed buffers in pools\n", nFreedBufferMem / KB );
+ Msg( " -- %7.1fkb -- Mem allocated for NON-pooled VBs (%d VBs)\n", g_SizeIndividualVBPhysAllocs / KB, g_NumIndividualVBPhysAllocs );
+ Msg( " -- %7.1fkb -- Mem allocated for NON-pooled IBs (%d IBs)\n", g_SizeIndividualIBPhysAllocs / KB, g_NumIndividualVBPhysAllocs );
+ Msg( "\n" );
+ }
+}
+
+
+//=============================================================================
+//=============================================================================
+// CGPUBufferPool
+//=============================================================================
+//=============================================================================
+
+CGPUBufferPool::CGPUBufferPool( int nSize )
+ : m_PoolEntries( POOL_ENTRIES_GROW_SIZE, POOL_ENTRIES_INIT_SIZE ),
+ m_nSize( 0 ),
+ m_nBytesUsed( 0 )
+{
+ // NOTE: write-combining (PAGE_WRITECOMBINE) is deliberately not used, since it slows down 'Compact' hugely (and doesn't noticeably benefit load times)
+ m_pMemory = (byte*)XPhysicalAlloc( nSize, MAXULONG_PTR, 0, PAGE_READWRITE );
+ if ( m_pMemory )
+ {
+ MemAlloc_RegisterExternalAllocation( XMem_CGPUBufferPool, m_pMemory, XPhysicalSize( m_pMemory ) );
+ m_nSize = nSize;
+ }
+}
+
+CGPUBufferPool::~CGPUBufferPool( void )
+{
+ for ( int i = 0; i < m_PoolEntries.Count(); i++ )
+ {
+ if ( m_PoolEntries[ i ].pVertexBuffer )
+ {
+ // Buffers should be cleaned up before the CGPUBufferAllocator is shut down!
+ Assert( 0 );
+ Warning( "ERROR: Un-freed %s in CGPUBufferPool on shut down! (%6.1fKB\n",
+ ( m_PoolEntries[ i ].bIsVertexBuffer ? "VB" : "IB" ), ( m_PoolEntries[ i ].nSize / 1024.0f ) );
+ break;
+ }
+ }
+
+ if ( m_pMemory )
+ {
+ MemAlloc_RegisterExternalDeallocation( XMem_CGPUBufferPool, m_pMemory, XPhysicalSize( m_pMemory ) );
+ XPhysicalFree( m_pMemory );
+ m_pMemory = 0;
+ }
+
+ m_nSize = m_nBytesUsed = 0;
+}
+
+//-----------------------------------------------------------------------------
+// Attempt to allocate a buffer of the given size in this pool
+//-----------------------------------------------------------------------------
+int CGPUBufferPool::Allocate( int nBufferSize, bool bIsVertexBuffer, void *pObject )
+{
+ // Align the buffer size
+ nBufferSize = ALIGN_VALUE( nBufferSize, POOL_ENTRY_ALIGNMENT );
+
+ // Check available space
+ if ( ( m_nBytesUsed + nBufferSize ) > m_nSize )
+ return -1;
+
+ int nPoolEntry = m_PoolEntries.AddToTail();
+ GPUBufferPoolEntry_t &poolEntry = m_PoolEntries[ nPoolEntry ];
+ poolEntry.nOffset = m_nBytesUsed;
+ poolEntry.nSize = nBufferSize;
+ poolEntry.bIsVertexBuffer = bIsVertexBuffer;
+ poolEntry.pVertexBuffer = (CVertexBuffer *)pObject;
+
+ // Update 'used space' high watermark
+ m_nBytesUsed += nBufferSize;
+
+ return nPoolEntry;
+}
+
+//-----------------------------------------------------------------------------
+// Deallocate the given entry from this pool
+//-----------------------------------------------------------------------------
+void CGPUBufferPool::Deallocate( const GPUBufferHandle_t *pHandle )
+{
+ Assert( m_PoolEntries.IsValidIndex( pHandle->nPoolEntry ) );
+ if ( m_PoolEntries.IsValidIndex( pHandle->nPoolEntry ) )
+ {
+ Assert( m_PoolEntries[ pHandle->nPoolEntry ].pVertexBuffer );
+ m_PoolEntries[ pHandle->nPoolEntry ].pVertexBuffer = NULL;
+ }
+}
+
+#endif // _X360
diff --git a/materialsystem/shaderapidx9/gpubufferallocator.h b/materialsystem/shaderapidx9/gpubufferallocator.h
new file mode 100644
index 0000000..cffd96d
--- /dev/null
+++ b/materialsystem/shaderapidx9/gpubufferallocator.h
@@ -0,0 +1,146 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: CGPUBufferAllocator manages allocation of VBs/IBs from shared memory pools.
+// Avoids 4KB physical alloc alignment overhead per VB/IB.
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+
+#ifndef GPUBUFFERALLOCATOR_H
+#define GPUBUFFERALLOCATOR_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#ifdef _X360
+
+#include "tier1/utlvector.h"
+#include "tier1/convar.h"
+
+class CVertexBuffer;
+class CIndexBuffer;
+
+
+// Only active on X360 atm
+#define USE_GPU_BUFFER_ALLOCATOR ( IsX360() )
+
+
+//-----------------------------------------------------------------------------
+// A handle to a buffer pool allocation, held by the allocated VB/IB
+//-----------------------------------------------------------------------------
+struct GPUBufferHandle_t
+{
+ GPUBufferHandle_t( void ) : nPoolNum( -1 ), pMemory( NULL ), nPoolEntry( -1 ) {}
+ bool IsValid( void ) { return ( pMemory != NULL ); }
+ byte * pMemory; // Physical address of the allocation
+ int nPoolNum; // Identifies the pool
+ int nPoolEntry; // Identifies this allocation within the pool
+};
+
+//-----------------------------------------------------------------------------
+// Describes an entry in a CGPUBufferPool
+//-----------------------------------------------------------------------------
+struct GPUBufferPoolEntry_t
+{
+ int nOffset;
+ int nSize;
+ bool bIsVertexBuffer;
+ union
+ {
+ // These are set to NULL by CGPUBufferPool::Free() (called when the VB/IB is destroyed)
+ CVertexBuffer *pVertexBuffer;
+ CIndexBuffer *pIndexBuffer;
+ };
+};
+
+//-----------------------------------------------------------------------------
+// A single memory block out of which individual VBs/IBs are allocated
+//-----------------------------------------------------------------------------
+class CGPUBufferPool
+{
+public:
+ CGPUBufferPool( int nSize );
+ virtual ~CGPUBufferPool( void );
+
+ // Returns the index (-1 on failure) of a new allocation in the pool, for a buffer of the given size.
+ int Allocate( int nSize, bool bIsVertexBuffer, void *pObject );
+ // Frees a given entry (just marks it as freed, the memory will not be reused by Allocate() until CGPUBufferAllocator::Defrag() is called )
+ void Deallocate( const GPUBufferHandle_t *pHandle );
+
+private:
+ // NOTE: these values are specialized for X360 and should be #ifdef'd for other target platforms
+ static const int POOL_ENTRIES_INIT_SIZE = 256;
+ static const int POOL_ENTRIES_GROW_SIZE = 256;
+ static const int POOL_ENTRY_ALIGNMENT = 4; // 4-byte alignment required for VB/IB data on XBox360
+
+ byte * m_pMemory; // Pointer to the (physical) address of the pool's memory
+ int m_nSize; // Total size of the pool
+ int m_nBytesUsed; // High watermark of used memory in the pool
+ CUtlVector<GPUBufferPoolEntry_t>m_PoolEntries; // Memory-order array of items allocated in the pool
+
+ // CGPUBufferAllocator is a friend so that CGPUBufferAllocator::Defrag() can shuffle allocations around
+ friend class CGPUBufferAllocator;
+};
+
+//-----------------------------------------------------------------------------
+// Manages a set of memory blocks out of which individual VBs/IBs are allocated
+//-----------------------------------------------------------------------------
+class CGPUBufferAllocator
+{
+public:
+ CGPUBufferAllocator( void );
+ virtual ~CGPUBufferAllocator( void );
+
+ // (De)Allocates memory for a vertex/index buffer:
+ bool AllocateVertexBuffer( CVertexBuffer *pVertexBuffer, int nBufferSize );
+ bool AllocateIndexBuffer( CIndexBuffer *pIndexBuffer, int nBufferSize );
+ void DeallocateVertexBuffer( CVertexBuffer *pVertexBuffer );
+ void DeallocateIndexBuffer( CIndexBuffer *pIndexBuffer );
+
+ // Compact memory to account for freed buffers
+ // NOTE: this must only be called during map transitions, no rendering must be in flight and everything must be single-threaded!
+ void Compact();
+
+ // Spew statistics about pooled buffer allocations
+ void SpewStats( bool bBrief = false );
+
+
+private:
+ // NOTE: these values are specialized for X360 and should be #ifdef'd for other target platforms
+ static const int INITIAL_POOL_SIZE = 57*1024*1024 + 256*1024;
+ static const int ADDITIONAL_POOL_SIZE = 2*1024*1024;
+ static const int MAX_POOLS = 8;
+ static const int MAX_BUFFER_SIZE = ADDITIONAL_POOL_SIZE; // 256*1024;
+
+
+ // Allocate a new CGPUBufferPool
+ bool AllocatePool( int nPoolSize );
+ // Allocate/deallocate a buffer (type-agnostic)
+ bool AllocateBuffer( GPUBufferHandle_t *pHandle, int nBufferSize, void *pObject, bool bIsVertexBuffer );
+ void DeallocateBuffer( const GPUBufferHandle_t *pHandle );
+ // Make a handle for a given allocation
+ GPUBufferHandle_t MakeGPUBufferHandle( int nPoolNum, int nPoolEntry );
+ // Helper for Compact
+ void MoveBufferMemory( int nDstPool, int *pnDstEntry, int *pnDstOffset, CGPUBufferPool &srcPool, GPUBufferPoolEntry_t &srcEntry );
+
+
+ CGPUBufferPool *m_BufferPools[ MAX_POOLS ];
+ int m_nBufferPools;
+ bool m_bEnabled;
+
+ CThreadFastMutex m_mutex;
+};
+
+
+// Track non-pooled physallocs, to help tune CGPUBufferAllocator usage:
+extern CInterlockedInt g_NumIndividualIBPhysAllocs;
+extern CInterlockedInt g_SizeIndividualIBPhysAllocs;
+extern CInterlockedInt g_NumIndividualVBPhysAllocs;
+extern CInterlockedInt g_SizeIndividualVBPhysAllocs;
+
+#endif // _X360
+
+#endif // GPUBUFFERALLOCATOR_H
diff --git a/materialsystem/shaderapidx9/hardwareconfig.cpp b/materialsystem/shaderapidx9/hardwareconfig.cpp
new file mode 100644
index 0000000..133be43
--- /dev/null
+++ b/materialsystem/shaderapidx9/hardwareconfig.cpp
@@ -0,0 +1,1311 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#include "togl/rendermechanism.h"
+#include "hardwareconfig.h"
+#include "shaderapi/ishaderutil.h"
+#include "shaderapi_global.h"
+#include "materialsystem/materialsystem_config.h"
+#include "tier1/convar.h"
+#include "shaderdevicebase.h"
+#include "tier0/icommandline.h"
+
+
+//-----------------------------------------------------------------------------
+//
+// Hardware Config!
+//
+//-----------------------------------------------------------------------------
+static CHardwareConfig s_HardwareConfig;
+CHardwareConfig *g_pHardwareConfig = &s_HardwareConfig;
+
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CHardwareConfig, IMaterialSystemHardwareConfig,
+ MATERIALSYSTEM_HARDWARECONFIG_INTERFACE_VERSION, s_HardwareConfig )
+
+template<typename T>
+static void ccs_create_convar_from_hwconfig( const T& val, const char *pName )
+{
+ int nValue = static_cast<int>( val );
+
+ ConVar *pConVar = g_pCVar->FindVar( pName );
+ if ( pConVar )
+ {
+ pConVar->SetValue( nValue );
+ }
+ else
+ {
+ // Don't care if this leaks - this is only used for development
+ pConVar = new ConVar( pName, "" );
+ }
+ if ( !nValue )
+ pConVar->SetValue( "0" );
+ else
+ pConVar->SetValue( nValue );
+}
+
+static void ccs_create_convar_from_hwconfig( const char *pVal, const char *pName )
+{
+ ConVar *pConVar = g_pCVar->FindVar( pName );
+ if ( pConVar )
+ {
+ pConVar->SetValue( pVal );
+ }
+ else
+ {
+ // Don't care if this leaks - this is only used for development
+ pConVar = new ConVar( pName, "" );
+ }
+ pConVar->SetValue( pVal );
+}
+
+CON_COMMAND_F( ccs_create_convars_from_hwconfig, "Create convars from the current hardware config, useful for diffing purposes", FCVAR_CHEAT )
+{
+ if ( !g_pHardwareConfig )
+ return;
+
+ const HardwareCaps_t &caps = g_pHardwareConfig->CapsForEdit();
+
+#define HWCFG( Name ) ccs_create_convar_from_hwconfig( caps.Name, #Name )
+ HWCFG( m_NumTextureStages );
+ HWCFG( m_nMaxAnisotropy );
+ HWCFG( m_MaxTextureWidth );
+ HWCFG( m_MaxTextureHeight );
+ HWCFG( m_MaxTextureDepth );
+ HWCFG( m_MaxTextureAspectRatio );
+ HWCFG( m_MaxPrimitiveCount );
+ HWCFG( m_NumPixelShaderConstants );
+ HWCFG( m_NumBooleanPixelShaderConstants );
+ HWCFG( m_NumIntegerPixelShaderConstants );
+ HWCFG( m_NumVertexShaderConstants );
+ HWCFG( m_NumBooleanVertexShaderConstants );
+ HWCFG( m_NumIntegerVertexShaderConstants );
+ HWCFG( m_TextureMemorySize );
+ HWCFG( m_MaxNumLights );
+ HWCFG( m_MaxBlendMatrices );
+ HWCFG( m_MaxBlendMatrixIndices );
+ HWCFG( m_MaxVertexShaderBlendMatrices );
+ HWCFG( m_MaxUserClipPlanes );
+ HWCFG( m_HDRType );
+ HWCFG( m_pShaderDLL );
+ HWCFG( m_ShadowDepthTextureFormat );
+ HWCFG( m_NullTextureFormat );
+ HWCFG( m_nVertexTextureCount );
+ HWCFG( m_nMaxVertexTextureDimension );
+ HWCFG( m_AlphaToCoverageState );
+ HWCFG( m_AlphaToCoverageEnableValue );
+ HWCFG( m_AlphaToCoverageDisableValue );
+ HWCFG( m_nMaxViewports );
+ HWCFG( m_flMinGammaControlPoint );
+ HWCFG( m_flMaxGammaControlPoint );
+ HWCFG( m_nGammaControlPointCount );
+ HWCFG( m_MaxVertexShader30InstructionSlots );
+ HWCFG( m_MaxPixelShader30InstructionSlots );
+ HWCFG( m_MaxSimultaneousRenderTargets );
+ HWCFG( m_bDeviceOk );
+ HWCFG( m_HasSetDeviceGammaRamp );
+ HWCFG( m_SupportsVertexShaders );
+ HWCFG( m_SupportsVertexShaders_2_0 );
+ HWCFG( m_SupportsPixelShaders );
+ HWCFG( m_SupportsPixelShaders_1_4 );
+ HWCFG( m_SupportsPixelShaders_2_0 );
+ HWCFG( m_SupportsPixelShaders_2_b );
+ HWCFG( m_SupportsShaderModel_3_0 );
+ HWCFG( m_bSupportsAnisotropicFiltering );
+ HWCFG( m_bSupportsMagAnisotropicFiltering );
+ HWCFG( m_bSupportsVertexTextures );
+ HWCFG( m_ZBiasAndSlopeScaledDepthBiasSupported );
+ HWCFG( m_SupportsMipmapping );
+ HWCFG( m_SupportsOverbright );
+ HWCFG( m_SupportsCubeMaps );
+ HWCFG( m_SupportsHardwareLighting );
+ HWCFG( m_SupportsMipmappedCubemaps );
+ HWCFG( m_SupportsNonPow2Textures );
+ HWCFG( m_PreferDynamicTextures );
+ HWCFG( m_HasProjectedBumpEnv );
+ HWCFG( m_SupportsSRGB );
+ HWCFG( m_bSupportsSpheremapping );
+ HWCFG( m_UseFastClipping );
+ HWCFG( m_bNeedsATICentroidHack );
+ HWCFG( m_bDisableShaderOptimizations );
+ HWCFG( m_bColorOnSecondStream );
+ HWCFG( m_bSupportsStreamOffset );
+ HWCFG( m_bFogColorSpecifiedInLinearSpace );
+ HWCFG( m_bFogColorAlwaysLinearSpace );
+ HWCFG( m_bSupportsAlphaToCoverage );
+ HWCFG( m_bSupportsShadowDepthTextures );
+ HWCFG( m_bSupportsFetch4 );
+ HWCFG( m_bSoftwareVertexProcessing );
+ HWCFG( m_bScissorSupported );
+ HWCFG( m_bSupportsFloat32RenderTargets );
+ HWCFG( m_bSupportsBorderColor );
+ HWCFG( m_bDX10Card );
+ HWCFG( m_bDX10Blending );
+ HWCFG( m_bSupportsStaticControlFlow );
+ HWCFG( m_FakeSRGBWrite );
+ HWCFG( m_CanDoSRGBReadFromRTs );
+ HWCFG( m_bSupportsGLMixedSizeTargets );
+ HWCFG( m_bCanStretchRectFromTextures );
+
+ HWCFG( m_MaxHDRType );
+#undef HWCFG
+}
+
+CHardwareConfig::CHardwareConfig()
+{
+ memset( &m_Caps, 0, sizeof( HardwareCaps_t ) );
+ memset( &m_ActualCaps, 0, sizeof( HardwareCaps_t ) );
+ memset( &m_UnOverriddenCaps, 0, sizeof( HardwareCaps_t ) );
+
+#ifdef POSIX
+ GLMPRINTF((" CHardwareConfig::CHardwareConfig setting m_bHDREnabled to false on %8x", this ));
+#endif
+
+ m_bHDREnabled = false;
+
+ // FIXME: This is kind of a hack to deal with DX8 worldcraft startup.
+ // We can at least have this much texture
+ m_Caps.m_MaxTextureWidth = m_Caps.m_MaxTextureHeight = m_Caps.m_MaxTextureDepth = 256;
+}
+
+
+//-----------------------------------------------------------------------------
+
+bool CHardwareConfig::GetHDREnabled( void ) const
+{
+// printf("\n CHardwareConfig::GetHDREnabled returning m_bHDREnabled value of %s on %8x", m_bHDREnabled?"true":"false", this );
+ return m_bHDREnabled;
+}
+
+void CHardwareConfig::SetHDREnabled( bool bEnable )
+{
+// printf("\n CHardwareConfig::SetHDREnabled setting m_bHDREnabled to value of %s on %8x", bEnable?"true":"false", this );
+ m_bHDREnabled = bEnable;
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the recommended configuration associated with a particular dx level
+//-----------------------------------------------------------------------------
+void CHardwareConfig::ForceCapsToDXLevel( HardwareCaps_t *pCaps, int nDxLevel, const HardwareCaps_t &actualCaps )
+{
+ if ( !IsPC() || nDxLevel >= 100 )
+ return;
+
+ pCaps->m_nDXSupportLevel = nDxLevel;
+ switch( nDxLevel )
+ {
+ case 60:
+ // NOTE: Prior to dx9, numsamplers = num texture stages
+ pCaps->m_NumTextureStages = min( 2, actualCaps.m_NumTextureStages );
+ pCaps->m_NumSamplers = pCaps->m_NumTextureStages;
+ pCaps->m_SupportsVertexShaders = false;
+ pCaps->m_SupportsVertexShaders_2_0 = false;
+ pCaps->m_SupportsPixelShaders = false;
+ pCaps->m_SupportsPixelShaders_1_4 = false;
+ pCaps->m_SupportsPixelShaders_2_0 = false;
+ pCaps->m_SupportsPixelShaders_2_b = false;
+ pCaps->m_SupportsShaderModel_3_0 = false;
+ pCaps->m_bSupportsStaticControlFlow = false;
+ pCaps->m_SupportsCompressedTextures = COMPRESSED_TEXTURES_OFF;
+ pCaps->m_SupportsCompressedVertices = VERTEX_COMPRESSION_NONE;
+ pCaps->m_bSupportsAnisotropicFiltering = false;
+ pCaps->m_bSupportsMagAnisotropicFiltering = false;
+ pCaps->m_nMaxAnisotropy = 1;
+ pCaps->m_MaxTextureWidth = max( 256, pCaps->m_MaxTextureWidth );
+ pCaps->m_MaxTextureHeight = max( 256, pCaps->m_MaxTextureHeight );
+ pCaps->m_MaxTextureDepth = max( 256, pCaps->m_MaxTextureDepth );
+ // m_MaxTextureAspectRatio;
+ // int m_MaxPrimitiveCount;
+ pCaps->m_ZBiasAndSlopeScaledDepthBiasSupported = false;
+ // pCaps->m_SupportsMipmapping =
+ // bool m_SupportsOverbright;
+ pCaps->m_SupportsCubeMaps = false;
+ pCaps->m_NumPixelShaderConstants = 0;
+ pCaps->m_NumBooleanPixelShaderConstants = 0;
+ pCaps->m_NumIntegerPixelShaderConstants = 0;
+ pCaps->m_NumVertexShaderConstants = 0;
+ pCaps->m_NumBooleanVertexShaderConstants = 0;
+ pCaps->m_NumIntegerVertexShaderConstants = 0;
+ pCaps->m_NumBooleanPixelShaderConstants = 0;
+ pCaps->m_NumIntegerPixelShaderConstants = 0;
+ pCaps->m_TextureMemorySize = 32 * 1024 * 1024;
+ pCaps->m_MaxNumLights = 0;
+ pCaps->m_SupportsHardwareLighting = 0;
+ pCaps->m_MaxBlendMatrices = 0;
+ pCaps->m_MaxBlendMatrixIndices = 0;
+ pCaps->m_MaxVertexShaderBlendMatrices = 0;
+ pCaps->m_SupportsMipmappedCubemaps = false;
+ pCaps->m_SupportsNonPow2Textures = false;
+ // pCaps->m_DXSupportLevel = 60;
+ pCaps->m_PreferDynamicTextures = false;
+ pCaps->m_HasProjectedBumpEnv = false;
+ pCaps->m_MaxUserClipPlanes = 0;
+ pCaps->m_SupportsSRGB = false;
+ pCaps->m_FakeSRGBWrite = false;
+ pCaps->m_CanDoSRGBReadFromRTs = true;
+ pCaps->m_bSupportsGLMixedSizeTargets = false;
+ pCaps->m_HDRType = HDR_TYPE_NONE;
+ // pCaps->m_bSupportsSpheremapping = true;
+ pCaps->m_UseFastClipping = true;
+ pCaps->m_bNeedsATICentroidHack = false;
+ pCaps->m_bColorOnSecondStream = false;
+ pCaps->m_bSupportsStreamOffset = false;
+ pCaps->m_bFogColorSpecifiedInLinearSpace = false;
+ pCaps->m_bFogColorAlwaysLinearSpace = false;
+ pCaps->m_bSupportsAlphaToCoverage = false;
+ pCaps->m_bSupportsShadowDepthTextures = false;
+ pCaps->m_bSupportsFetch4 = false;
+ pCaps->m_bSupportsBorderColor = false;
+ // m_bSoftwareVertexProcessing
+ pCaps->m_nVertexTextureCount = 0;
+ pCaps->m_nMaxVertexTextureDimension = 0;
+ pCaps->m_bSupportsVertexTextures = false;
+ pCaps->m_nMaxViewports = 1;
+ // m_bScissorSupported
+ pCaps->m_bSupportsFloat32RenderTargets = false;
+ // ImageFormat m_ShadowDepthTextureFormat;
+ // ImageFormat m_NullTextureFormat;
+ // m_AlphaToCoverageState;
+ // m_AlphaToCoverageEnableValue;
+ // m_AlphaToCoverageDisableValue;
+ // m_flMinGammaControlPoint
+ // m_flMaxGammaControlPoint
+ // m_nGammaControlPointCount
+ pCaps->m_MaxVertexShader30InstructionSlots = 0;
+ pCaps->m_MaxPixelShader30InstructionSlots = 0;
+ pCaps->m_bCanStretchRectFromTextures = false;
+ break;
+
+ case 70:
+ // NOTE: Prior to dx9, numsamplers = num texture stages
+ pCaps->m_NumTextureStages = min( 2, actualCaps.m_NumTextureStages );
+ pCaps->m_NumSamplers = pCaps->m_NumTextureStages;
+ pCaps->m_SupportsVertexShaders = false;
+ pCaps->m_SupportsVertexShaders_2_0 = false;
+ pCaps->m_SupportsPixelShaders = false;
+ pCaps->m_SupportsPixelShaders_1_4 = false;
+ pCaps->m_SupportsPixelShaders_2_0 = false;
+ pCaps->m_SupportsPixelShaders_2_b = false;
+ pCaps->m_SupportsShaderModel_3_0 = false;
+ pCaps->m_bSupportsStaticControlFlow = false;
+ // pCaps->m_SupportsCompressedTextures = true;
+ pCaps->m_SupportsCompressedVertices = VERTEX_COMPRESSION_NONE;
+ pCaps->m_bSupportsAnisotropicFiltering = false;
+ pCaps->m_bSupportsMagAnisotropicFiltering = false;
+ pCaps->m_nMaxAnisotropy = 1;
+ // pCaps->m_MaxTextureWidth = max( 256, pCaps->m_MaxTextureWidth );
+ // pCaps->m_MaxTextureHeight = max( 256, pCaps->m_MaxTextureHeight );
+// pCaps->m_MaxTextureDepth = max( 256, pCaps->m_MaxTextureDepth );
+ // m_MaxTextureAspectRatio;
+ // int m_MaxPrimitiveCount;
+ pCaps->m_ZBiasAndSlopeScaledDepthBiasSupported = false;
+ // pCaps->m_SupportsMipmapping =
+ // bool m_SupportsOverbright;
+ // pCaps->m_SupportsCubeMaps = false;
+ pCaps->m_NumPixelShaderConstants = 0;
+ pCaps->m_NumBooleanPixelShaderConstants = 0;
+ pCaps->m_NumIntegerPixelShaderConstants = 0;
+ pCaps->m_NumBooleanPixelShaderConstants = 0;
+ pCaps->m_NumIntegerPixelShaderConstants = 0;
+ pCaps->m_NumVertexShaderConstants = 0;
+ pCaps->m_NumBooleanVertexShaderConstants = 0;
+ pCaps->m_NumIntegerVertexShaderConstants = 0;
+ pCaps->m_TextureMemorySize = 32 * 1024 * 1024;
+ pCaps->m_MaxNumLights = 2;
+ pCaps->m_SupportsHardwareLighting = 1;
+ pCaps->m_MaxBlendMatrices = 0;
+ pCaps->m_MaxBlendMatrixIndices = 0;
+ pCaps->m_MaxVertexShaderBlendMatrices = 0;
+ pCaps->m_SupportsMipmappedCubemaps = false;
+ pCaps->m_SupportsNonPow2Textures = false;
+ pCaps->m_nDXSupportLevel = 70;
+ pCaps->m_PreferDynamicTextures = false;
+ pCaps->m_HasProjectedBumpEnv = false;
+ pCaps->m_MaxUserClipPlanes = 0;
+ pCaps->m_SupportsSRGB = false;
+ pCaps->m_FakeSRGBWrite = false;
+ pCaps->m_CanDoSRGBReadFromRTs = true;
+ pCaps->m_bSupportsGLMixedSizeTargets = false;
+ pCaps->m_HDRType = HDR_TYPE_NONE;
+ // pCaps->m_bSupportsSpheremapping = true;
+ pCaps->m_UseFastClipping = true;
+ pCaps->m_bNeedsATICentroidHack = false;
+ // pCaps->m_bColorOnSecondStream = false; // dont' force this!
+ pCaps->m_bSupportsStreamOffset = false;
+ pCaps->m_bFogColorSpecifiedInLinearSpace = false;
+ pCaps->m_bFogColorAlwaysLinearSpace = false;
+ pCaps->m_bSupportsAlphaToCoverage = false;
+ pCaps->m_bSupportsShadowDepthTextures = false;
+ pCaps->m_bSupportsFetch4 = false;
+ pCaps->m_bSupportsBorderColor = false;
+ // m_bSoftwareVertexProcessing
+ pCaps->m_nVertexTextureCount = 0;
+ pCaps->m_nMaxVertexTextureDimension = 0;
+ pCaps->m_bSupportsVertexTextures = false;
+ pCaps->m_nMaxViewports = 1;
+ // m_bScissorSupported
+ pCaps->m_bSupportsFloat32RenderTargets = false;
+ pCaps->m_bDX10Card = false;
+ pCaps->m_bDX10Blending = false;
+ pCaps->m_bCanStretchRectFromTextures = false;
+ break;
+
+ case 80:
+ // NOTE: Prior to dx9, numsamplers = num texture stages
+ // We clamp num texture stages to 2, though, since we never use
+ // fixed-function shaders with more than 2 texture stages
+ pCaps->m_NumTextureStages = min( 2, actualCaps.m_NumTextureStages );
+ pCaps->m_NumSamplers = min( 4, actualCaps.m_NumTextureStages );
+ // pCaps->m_SupportsVertexShaders = true;
+ pCaps->m_SupportsVertexShaders_2_0 = false;
+ // pCaps->m_SupportsPixelShaders = false;
+ pCaps->m_SupportsPixelShaders_1_4 = false;
+ pCaps->m_SupportsPixelShaders_2_0 = false;
+ pCaps->m_SupportsPixelShaders_2_b = false;
+ pCaps->m_SupportsShaderModel_3_0 = false;
+ pCaps->m_bSupportsStaticControlFlow = false;
+ // pCaps->m_SupportsCompressedTextures = true;
+ pCaps->m_SupportsCompressedVertices = VERTEX_COMPRESSION_NONE;
+ // pCaps->m_bSupportsAnisotropicFiltering = false;
+ // pCaps->m_bSupportsMagAnisotropicFiltering = false;
+ // pCaps->m_nMaxAnisotropy = 1;
+ // pCaps->m_MaxTextureWidth = max( 256, pCaps->m_MaxTextureWidth );
+ // pCaps->m_MaxTextureHeight = max( 256, pCaps->m_MaxTextureHeight );
+ // pCaps->m_MaxTextureDepth = max( 256, pCaps->m_MaxTextureDepth );
+ // m_MaxTextureAspectRatio;
+ // int m_MaxPrimitiveCount;
+ // pCaps->m_ZBiasAndSlopeScaledDepthBiasSupported = false;
+ // pCaps->m_SupportsMipmapping =
+ // bool m_SupportsOverbright;
+ // pCaps->m_SupportsCubeMaps = false;
+ pCaps->m_NumPixelShaderConstants = 8;
+ pCaps->m_NumVertexShaderConstants = min( 96, pCaps->m_NumVertexShaderConstants );
+ pCaps->m_NumBooleanVertexShaderConstants = 0;
+ pCaps->m_NumIntegerVertexShaderConstants = 0;
+ pCaps->m_NumBooleanPixelShaderConstants = 0;
+ pCaps->m_NumIntegerPixelShaderConstants = 0;
+ // pCaps->m_TextureMemorySize = 32 * 1024 * 1024;
+ // pCaps->m_MaxNumLights = 0;
+ // pCaps->m_SupportsHardwareLighting = 0;
+ // pCaps->m_MaxBlendMatrices = 0;
+ // pCaps->m_MaxBlendMatrixIndices = 0;
+ pCaps->m_MaxVertexShaderBlendMatrices = min( 16, pCaps->m_MaxVertexShaderBlendMatrices );
+ // pCaps->m_SupportsMipmappedCubemaps = false;
+ // pCaps->m_SupportsNonPow2Textures = false;
+ pCaps->m_nDXSupportLevel = 80;
+ // pCaps->m_PreferDynamicTextures = false;
+ // pCaps->m_HasProjectedBumpEnv = false;
+ // pCaps->m_MaxUserClipPlanes = 0;
+ pCaps->m_bSupportsGLMixedSizeTargets = false;
+ pCaps->m_HDRType = HDR_TYPE_NONE;
+ // pCaps->m_bSupportsSpheremapping = true;
+ // pCaps->m_UseFastClipping = true;
+ // pCaps->m_bNeedsATICentroidHack = false;
+ // pCaps->m_bColorOnSecondStream = false;
+ pCaps->m_bSupportsStreamOffset = false;
+ pCaps->m_bFogColorSpecifiedInLinearSpace = false;
+ pCaps->m_bFogColorAlwaysLinearSpace = false;
+ pCaps->m_bSupportsAlphaToCoverage = false;
+ pCaps->m_bSupportsShadowDepthTextures = false;
+ pCaps->m_bSupportsFetch4 = false;
+ // m_bSoftwareVertexProcessing
+ pCaps->m_nVertexTextureCount = 0;
+ pCaps->m_nMaxVertexTextureDimension = 0;
+ pCaps->m_bSupportsVertexTextures = false;
+ pCaps->m_MaxNumLights = 2;
+ pCaps->m_nMaxViewports = 1;
+ // m_bScissorSupported
+ pCaps->m_SupportsSRGB = false;
+ pCaps->m_FakeSRGBWrite = false;
+ pCaps->m_CanDoSRGBReadFromRTs = true;
+ pCaps->m_bSupportsGLMixedSizeTargets = false;
+ pCaps->m_bSupportsFetch4 = false;
+ pCaps->m_bSupportsBorderColor = false;
+ pCaps->m_bSupportsFloat32RenderTargets = false;
+ // ImageFormat m_ShadowDepthTextureFormat;
+ // ImageFormat m_NullTextureFormat;
+ // m_AlphaToCoverageState;
+ // m_AlphaToCoverageEnableValue;
+ // m_AlphaToCoverageDisableValue;
+ // m_flMinGammaControlPoint
+ // m_flMaxGammaControlPoint
+ // m_nGammaControlPointCount
+ pCaps->m_MaxVertexShader30InstructionSlots = 0;
+ pCaps->m_MaxPixelShader30InstructionSlots = 0;
+ pCaps->m_bDX10Card = false;
+ pCaps->m_bDX10Blending = false;
+ pCaps->m_bCanStretchRectFromTextures = false;
+ break;
+
+ case 81:
+ // NOTE: Prior to dx9, numsamplers = num texture stages
+ // We clamp num texture stages to 2, though, since we never use
+ // fixed-function shaders with more than 2 texture stages
+ pCaps->m_NumTextureStages = min( 2, actualCaps.m_NumTextureStages );
+ pCaps->m_NumSamplers = min( 6, actualCaps.m_NumTextureStages );
+ // pCaps->m_SupportsVertexShaders = true;
+ pCaps->m_SupportsVertexShaders_2_0 = false;
+ // pCaps->m_SupportsPixelShaders = false;
+ pCaps->m_SupportsPixelShaders_1_4 = true;
+ pCaps->m_SupportsPixelShaders_2_0 = false;
+ pCaps->m_SupportsPixelShaders_2_b = false;
+ pCaps->m_SupportsShaderModel_3_0 = false;
+ pCaps->m_bSupportsStaticControlFlow = false;
+ // pCaps->m_SupportsCompressedTextures = true;
+ pCaps->m_SupportsCompressedVertices = VERTEX_COMPRESSION_NONE;
+ // pCaps->m_bSupportsAnisotropicFiltering = false;
+ // pCaps->m_bSupportsMagAnisotropicFiltering = false;
+ // pCaps->m_nMaxAnisotropy = 1;
+ // pCaps->m_MaxTextureWidth = max( 256, pCaps->m_MaxTextureWidth );
+ // pCaps->m_MaxTextureHeight = max( 256, pCaps->m_MaxTextureHeight );
+ // pCaps->m_MaxTextureDepth = max( 256, pCaps->m_MaxTextureDepth );
+ // m_MaxTextureAspectRatio;
+ // int m_MaxPrimitiveCount;
+ // pCaps->m_ZBiasAndSlopeScaledDepthBiasSupported = false;
+ // pCaps->m_SupportsMipmapping =
+ // bool m_SupportsOverbright;
+ // pCaps->m_SupportsCubeMaps = false;
+ pCaps->m_NumPixelShaderConstants = 8;
+ pCaps->m_NumVertexShaderConstants = min( 96, pCaps->m_NumVertexShaderConstants );
+ pCaps->m_NumBooleanVertexShaderConstants = 0;
+ pCaps->m_NumIntegerVertexShaderConstants = 0;
+ pCaps->m_NumBooleanPixelShaderConstants = 0;
+ pCaps->m_NumIntegerPixelShaderConstants = 0;
+ // pCaps->m_TextureMemorySize = 32 * 1024 * 1024;
+ pCaps->m_MaxNumLights = 2;
+ // pCaps->m_SupportsHardwareLighting = 0;
+ // pCaps->m_MaxBlendMatrices = 0;
+ // pCaps->m_MaxBlendMatrixIndices = 0;
+ pCaps->m_MaxVertexShaderBlendMatrices = min( 16, pCaps->m_MaxVertexShaderBlendMatrices );
+ // pCaps->m_SupportsMipmappedCubemaps = false;
+ // pCaps->m_SupportsNonPow2Textures = false;
+ pCaps->m_nDXSupportLevel = 81;
+ // pCaps->m_PreferDynamicTextures = false;
+ // pCaps->m_HasProjectedBumpEnv = false;
+ // pCaps->m_MaxUserClipPlanes = 0;
+ pCaps->m_SupportsSRGB = false;
+ pCaps->m_FakeSRGBWrite = false;
+ pCaps->m_CanDoSRGBReadFromRTs = true;
+ pCaps->m_bSupportsGLMixedSizeTargets = false;
+ pCaps->m_HDRType = HDR_TYPE_NONE;
+ // pCaps->m_bSupportsSpheremapping = true;
+ // pCaps->m_UseFastClipping = true;
+ // pCaps->m_bNeedsATICentroidHack = false;
+ // pCaps->m_bColorOnSecondStream = false;
+ pCaps->m_bSupportsStreamOffset = false;
+ pCaps->m_bFogColorSpecifiedInLinearSpace = false;
+ pCaps->m_bFogColorAlwaysLinearSpace = false;
+ pCaps->m_bSupportsAlphaToCoverage = false;
+ pCaps->m_bSupportsShadowDepthTextures = false;
+ pCaps->m_bSupportsFetch4 = false;
+ pCaps->m_bSupportsBorderColor = false;
+ // m_bSoftwareVertexProcessing
+ pCaps->m_nVertexTextureCount = 0;
+ pCaps->m_nMaxVertexTextureDimension = 0;
+ pCaps->m_bSupportsVertexTextures = false;
+ pCaps->m_nMaxViewports = 1;
+ // m_bScissorSupported
+ pCaps->m_bSupportsFloat32RenderTargets = false;
+ // ImageFormat m_ShadowDepthTextureFormat;
+ // ImageFormat m_NullTextureFormat;
+ // m_AlphaToCoverageState;
+ // m_AlphaToCoverageEnableValue;
+ // m_AlphaToCoverageDisableValue;
+ // m_flMinGammaControlPoint
+ // m_flMaxGammaControlPoint
+ // m_nGammaControlPointCount
+ pCaps->m_MaxVertexShader30InstructionSlots = 0;
+ pCaps->m_MaxPixelShader30InstructionSlots = 0;
+ pCaps->m_bDX10Card = false;
+ pCaps->m_bDX10Blending = false;
+ pCaps->m_bCanStretchRectFromTextures = false;
+ break;
+
+ case 90:
+ pCaps->m_nVertexTextureCount = 0;
+ pCaps->m_nMaxVertexTextureDimension = 0;
+ pCaps->m_bSupportsVertexTextures = false;
+ pCaps->m_bSupportsStreamOffset = true;
+ pCaps->m_bSupportsGLMixedSizeTargets = true;
+
+ if ( IsOpenGL() )
+ {
+ //FIXME this is way too complicated, we should just check the caps bit from GLM
+
+ pCaps->m_bSupportsStaticControlFlow = false;
+
+ if (1) //(CommandLine()->FindParm("-glslmode"))
+ {
+ // rbarris 03Feb10: this is now hardwired because we are defaulting GLSL mode "on".
+ // so this will mean that the engine will always ask for user clip planes.
+ // this will misbehave under ARB mode, since ARB shaders won't respect that state.
+ // it's difficult to make this fluid without teaching the engine about a cap that could change during run.
+
+ pCaps->m_MaxUserClipPlanes = 2;
+ pCaps->m_UseFastClipping = false;
+ }
+ else
+ {
+ pCaps->m_MaxUserClipPlanes = 0;
+ pCaps->m_UseFastClipping = true;
+ }
+
+ pCaps->m_MaxNumLights = 2;
+ }
+ else
+ {
+ pCaps->m_bSupportsStaticControlFlow = true;
+ pCaps->m_MaxNumLights = pCaps->m_SupportsPixelShaders_2_b ? 4 : 2; // 2b gets four lights, 2.0 gets two...
+ }
+
+ pCaps->m_bSupportsBorderColor = false;
+ pCaps->m_nMaxViewports = 1;
+ pCaps->m_NumPixelShaderConstants = 32;
+ pCaps->m_nMaxVertexTextureDimension = 0;
+ pCaps->m_MaxVertexShader30InstructionSlots = 0;
+ pCaps->m_MaxPixelShader30InstructionSlots = 0;
+ pCaps->m_bCanStretchRectFromTextures = false;
+ break;
+
+ case 92:
+ pCaps->m_nVertexTextureCount = 0;
+ pCaps->m_nMaxVertexTextureDimension = 0;
+ pCaps->m_bSupportsVertexTextures = false;
+ pCaps->m_bSupportsBorderColor = false;
+
+ // 2b gets four lights, 2.0 gets two...
+ pCaps->m_SupportsShaderModel_3_0 = false;
+ if ( IsOpenGL() )
+ {
+ if ( IsOSX() )
+ {
+ pCaps->m_bSupportsStaticControlFlow = CommandLine()->CheckParm( "-glslcontrolflow" ) != NULL;
+ }
+ else
+ {
+ pCaps->m_bSupportsStaticControlFlow = !CommandLine()->CheckParm( "-noglslcontrolflow" );
+ }
+
+ pCaps->m_MaxUserClipPlanes = 2;
+ pCaps->m_UseFastClipping = false;
+ pCaps->m_MaxNumLights = pCaps->m_bSupportsStaticControlFlow ? MAX_NUM_LIGHTS : ( MAX_NUM_LIGHTS - 2 );
+ }
+ else
+ {
+ pCaps->m_MaxNumLights = MAX_NUM_LIGHTS;
+ }
+
+ pCaps->m_nMaxViewports = 1;
+ pCaps->m_NumPixelShaderConstants = 32;
+ pCaps->m_nMaxVertexTextureDimension = 0;
+ pCaps->m_bDX10Card = false;
+ pCaps->m_bDX10Blending = false;
+ pCaps->m_MaxVertexShader30InstructionSlots = 0;
+ pCaps->m_MaxPixelShader30InstructionSlots = 0;
+ pCaps->m_bCanStretchRectFromTextures = false;
+ break;
+
+ case 95:
+ pCaps->m_bSupportsStreamOffset = true;
+ pCaps->m_bSupportsStaticControlFlow = true;
+ pCaps->m_bDX10Card = false;
+ pCaps->m_bDX10Blending = false;
+ pCaps->m_MaxNumLights = MAX_NUM_LIGHTS;
+ pCaps->m_nMaxViewports = 1;
+ pCaps->m_bSupportsBorderColor = false;
+ pCaps->m_bCanStretchRectFromTextures = false;
+ break;
+
+ case 100:
+ break;
+
+ default:
+ Assert( 0 );
+ break;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets up the hardware caps given the specified DX level
+//-----------------------------------------------------------------------------
+void CHardwareConfig::SetupHardwareCaps( int nDXLevel, const HardwareCaps_t &actualCaps )
+{
+ Assert( nDXLevel != 0 );
+
+ memcpy( &m_Caps, &actualCaps, sizeof(HardwareCaps_t) );
+ memcpy( &m_UnOverriddenCaps, &actualCaps, sizeof(HardwareCaps_t) );
+
+ // Don't bother with fallbacks for DX10 or consoles
+#ifdef DX_TO_GL_ABSTRACTION
+ if ( nDXLevel >= 100 )
+#else
+ if ( !( IsPC() || IsPosix() ) || ( nDXLevel >= 100 ) )
+#endif
+ return;
+
+ // Slam the support level to what we were requested
+ m_Caps.m_nDXSupportLevel = nDXLevel;
+ if ( m_Caps.m_nDXSupportLevel != m_Caps.m_nMaxDXSupportLevel || CommandLine()->ParmValue( "-maxdxlevel", 0 ) > 0 )
+ {
+ // We're falling back to some other dx level
+ ForceCapsToDXLevel( &m_Caps, m_Caps.m_nDXSupportLevel, m_ActualCaps );
+ }
+
+ // Clamp num texture stages to 2, since it's only used for fixed function
+ m_Caps.m_NumTextureStages = min( 2, m_Caps.m_NumTextureStages );
+
+ // Read dxsupport.cfg which has config overrides for particular cards.
+ g_pShaderDeviceMgr->ReadHardwareCaps( m_Caps, m_Caps.m_nDXSupportLevel );
+
+ // This is the spot to validate read in caps versus actual caps.
+ if ( m_Caps.m_MaxUserClipPlanes > m_ActualCaps.m_MaxUserClipPlanes )
+ {
+ m_Caps.m_MaxUserClipPlanes = m_ActualCaps.m_MaxUserClipPlanes;
+ }
+ if ( m_Caps.m_MaxUserClipPlanes == 0 )
+ {
+ m_Caps.m_UseFastClipping = true;
+ }
+
+ if ( IsOpenGL() )
+ {
+ m_Caps.m_MaxNumLights = MIN( m_Caps.m_MaxNumLights, ( m_Caps.m_bSupportsStaticControlFlow && m_Caps.m_SupportsPixelShaders_2_b ) ? MAX_NUM_LIGHTS : ( MAX_NUM_LIGHTS - 2 ) );
+ m_Caps.m_bSupportsShadowDepthTextures = true;
+ }
+ else // not POSIX or emulated
+ {
+ // 2b supports more lights than just 2.0
+ if ( m_Caps.m_SupportsPixelShaders_2_b )
+ {
+ m_Caps.m_MaxNumLights = MIN( m_Caps.m_MaxNumLights, MAX_NUM_LIGHTS );
+ }
+ else
+ {
+ m_Caps.m_MaxNumLights = MIN( m_Caps.m_MaxNumLights, MAX_NUM_LIGHTS - 2 );
+ }
+ }
+
+ m_Caps.m_MaxNumLights = min( m_Caps.m_MaxNumLights, (int)MAX_NUM_LIGHTS );
+
+ memcpy( &m_UnOverriddenCaps, &m_Caps, sizeof(HardwareCaps_t) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets up the hardware caps given the specified DX level
+//-----------------------------------------------------------------------------
+void CHardwareConfig::SetupHardwareCaps( const ShaderDeviceInfo_t& mode, const HardwareCaps_t &actualCaps )
+{
+ memcpy( &m_ActualCaps, &actualCaps, sizeof(HardwareCaps_t) );
+ SetupHardwareCaps( mode.m_nDXLevel, actualCaps );
+}
+
+
+void CHardwareConfig::OverrideStreamOffsetSupport( bool bOverrideEnabled, bool bEnableSupport )
+{
+ if ( bOverrideEnabled )
+ {
+ m_Caps.m_bSupportsStreamOffset = bEnableSupport;
+ if ( !m_ActualCaps.m_bSupportsStreamOffset )
+ {
+ m_Caps.m_bSupportsStreamOffset = false;
+ }
+ }
+ else
+ {
+ // Go back to default
+ m_Caps.m_bSupportsStreamOffset = m_UnOverriddenCaps.m_bSupportsStreamOffset;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Implementation of IMaterialSystemHardwareConfig
+//-----------------------------------------------------------------------------
+bool CHardwareConfig::HasDestAlphaBuffer() const
+{
+ if ( !g_pShaderDevice )
+ return false;
+ return (g_pShaderDevice->GetBackBufferFormat() == IMAGE_FORMAT_BGRA8888);
+}
+
+bool CHardwareConfig::HasStencilBuffer() const
+{
+ return StencilBufferBits() > 0;
+}
+
+int CHardwareConfig::GetFrameBufferColorDepth() const
+{
+ if ( !g_pShaderDevice )
+ return 0;
+ return ShaderUtil()->ImageFormatInfo( g_pShaderDevice->GetBackBufferFormat() ).m_NumBytes;
+}
+
+int CHardwareConfig::GetSamplerCount() const
+{
+ return m_Caps.m_NumSamplers;
+}
+
+bool CHardwareConfig::HasSetDeviceGammaRamp() const
+{
+ return m_Caps.m_HasSetDeviceGammaRamp;
+}
+
+bool CHardwareConfig::SupportsCompressedTextures() const
+{
+ Assert( m_Caps.m_SupportsCompressedTextures != COMPRESSED_TEXTURES_NOT_INITIALIZED );
+ return m_Caps.m_SupportsCompressedTextures == COMPRESSED_TEXTURES_ON;
+}
+
+VertexCompressionType_t CHardwareConfig::SupportsCompressedVertices() const
+{
+ return m_Caps.m_SupportsCompressedVertices;
+}
+
+bool CHardwareConfig::SupportsBorderColor() const
+{
+ return m_Caps.m_bSupportsBorderColor;
+}
+
+bool CHardwareConfig::SupportsFetch4() const
+{
+ return m_Caps.m_bSupportsFetch4;
+}
+
+bool CHardwareConfig::CanStretchRectFromTextures() const
+{
+ return m_Caps.m_bCanStretchRectFromTextures;
+}
+
+bool CHardwareConfig::SupportsVertexAndPixelShaders() const
+{
+ if ( (ShaderUtil()->GetConfig().dxSupportLevel != 0) && (GetDXSupportLevel() < 80) )
+ return false;
+
+ return m_Caps.m_SupportsPixelShaders;
+}
+
+bool CHardwareConfig::SupportsPixelShaders_1_4() const
+{
+ if ( (ShaderUtil()->GetConfig().dxSupportLevel != 0) && (GetDXSupportLevel() < 81) )
+ return false;
+
+ return m_Caps.m_SupportsPixelShaders_1_4;
+}
+
+bool CHardwareConfig::SupportsPixelShaders_2_0() const
+{
+ if ( (ShaderUtil()->GetConfig().dxSupportLevel != 0) && (GetDXSupportLevel() < 90) )
+ return false;
+
+ return m_Caps.m_SupportsPixelShaders_2_0;
+}
+
+bool CHardwareConfig::SupportsPixelShaders_2_b() const
+{
+ if ((ShaderUtil()->GetConfig().dxSupportLevel != 0) &&
+ (GetDXSupportLevel() < 90))
+ return false;
+
+ return m_Caps.m_SupportsPixelShaders_2_b;
+}
+
+bool CHardwareConfig::SupportsVertexShaders_2_0() const
+{
+ if ((ShaderUtil()->GetConfig().dxSupportLevel != 0) &&
+ (GetDXSupportLevel() < 90))
+ return false;
+
+ return m_Caps.m_SupportsVertexShaders_2_0;
+}
+
+bool CHardwareConfig::SupportsStaticControlFlow() const
+{
+ return m_Caps.m_bSupportsStaticControlFlow;
+}
+
+
+bool CHardwareConfig::SupportsShaderModel_3_0() const
+{
+ if ((ShaderUtil()->GetConfig().dxSupportLevel != 0) &&
+ (GetDXSupportLevel() < 95))
+ return false;
+
+ return m_Caps.m_SupportsShaderModel_3_0;
+}
+
+// If you change these, make the corresponding change in common_ps_fxc.h
+#define NVIDIA_PCF_POISSON 0
+#define ATI_NOPCF 1
+#define ATI_NO_PCF_FETCH4 2
+
+int CHardwareConfig::GetShadowFilterMode() const
+{
+
+#ifdef DX_TO_GL_ABSTRACTION
+ if ( !m_Caps.m_bSupportsShadowDepthTextures )
+ return 0;
+#else
+ if ( !m_Caps.m_bSupportsShadowDepthTextures || !ShaderUtil()->GetConfig().ShadowDepthTexture() )
+ return 0;
+#endif
+
+ switch ( m_Caps.m_ShadowDepthTextureFormat )
+ {
+ case IMAGE_FORMAT_NV_DST16:
+ case IMAGE_FORMAT_NV_DST24:
+
+ return NVIDIA_PCF_POISSON; // NVIDIA hardware bilinear PCF
+
+ case IMAGE_FORMAT_ATI_DST16:
+ case IMAGE_FORMAT_ATI_DST24:
+
+ if ( m_Caps.m_bSupportsFetch4 )
+ return ATI_NO_PCF_FETCH4; // ATI fetch4 depth texture sampling
+
+ return ATI_NOPCF; // ATI vanilla depth texture sampling
+
+#if defined( _X360 )
+ case IMAGE_FORMAT_X360_DST16:
+ case IMAGE_FORMAT_X360_DST24:
+ case IMAGE_FORMAT_X360_DST24F:
+ return 0;
+#endif
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static ConVar r_shader_srgb( "r_shader_srgb", "0", FCVAR_ALLOWED_IN_COMPETITIVE, "-1 = use hardware caps. 0 = use hardware srgb. 1 = use shader srgb(software lookup)" ); // -1=use caps 0=off 1=on
+
+int CHardwareConfig::NeedsShaderSRGBConversion() const
+{
+ if ( IsX360() )
+ {
+ // 360 always now uses a permanent hw solution
+ return false;
+ }
+
+ int cValue = r_shader_srgb.GetInt();
+ switch( cValue )
+ {
+ case 0:
+ return false;
+
+ case 1:
+ return true;
+
+ default:
+ return m_Caps.m_bDX10Blending; // !!! change to return false after portal deport built!!!!!
+ }
+}
+
+bool CHardwareConfig::UsesSRGBCorrectBlending() const
+{
+ int cValue = r_shader_srgb.GetInt();
+ return ( cValue == 0 ) && ( ( m_Caps.m_bDX10Blending ) || IsX360() );
+}
+
+static ConVar mat_disablehwmorph( "mat_disablehwmorph", "0", FCVAR_ALLOWED_IN_COMPETITIVE, "Disables HW morphing for particular mods" );
+bool CHardwareConfig::HasFastVertexTextures() const
+{
+ static int bEnableFastVertexTextures = -1;
+ static bool bDisableHWMorph = false;
+ if ( bEnableFastVertexTextures < 0 )
+ {
+ bEnableFastVertexTextures = 1;
+ if ( CommandLine()->FindParm( "-disallowhwmorph" ) )
+ {
+ bEnableFastVertexTextures = 0;
+ }
+ bDisableHWMorph = ( mat_disablehwmorph.GetInt() != 0 );
+ }
+
+ // JasonM - turned this off for Orange Box release...
+ return false;
+
+// return m_Caps.m_bDX10Card && ( GetDXSupportLevel() >= 95 ) && ( bEnableFastVertexTextures != 0 ) && ( !bDisableHWMorph );
+}
+
+int CHardwareConfig::MaxHWMorphBatchCount() const
+{
+ return ShaderUtil()->MaxHWMorphBatchCount();
+}
+
+int CHardwareConfig::MaximumAnisotropicLevel() const
+{
+ return m_Caps.m_nMaxAnisotropy;
+}
+
+int CHardwareConfig::MaxTextureWidth() const
+{
+ return m_Caps.m_MaxTextureWidth;
+}
+
+int CHardwareConfig::MaxTextureHeight() const
+{
+ return m_Caps.m_MaxTextureHeight;
+}
+
+int CHardwareConfig::TextureMemorySize() const
+{
+ return m_Caps.m_TextureMemorySize;
+}
+
+bool CHardwareConfig::SupportsOverbright() const
+{
+ return m_Caps.m_SupportsOverbright;
+}
+
+bool CHardwareConfig::SupportsCubeMaps() const
+{
+ if ( (ShaderUtil()->GetConfig().dxSupportLevel > 0) && (GetDXSupportLevel() < 70) )
+ return false;
+
+ return m_Caps.m_SupportsCubeMaps;
+}
+
+bool CHardwareConfig::SupportsMipmappedCubemaps() const
+{
+ if ( (ShaderUtil()->GetConfig().dxSupportLevel > 0) && (GetDXSupportLevel() < 70) )
+ return false;
+
+ return m_Caps.m_SupportsMipmappedCubemaps;
+}
+
+bool CHardwareConfig::SupportsNonPow2Textures() const
+{
+ return m_Caps.m_SupportsNonPow2Textures;
+}
+
+int CHardwareConfig::GetTextureStageCount() const
+{
+ return m_Caps.m_NumTextureStages;
+}
+
+int CHardwareConfig::NumVertexShaderConstants() const
+{
+ return m_Caps.m_NumVertexShaderConstants;
+}
+
+int CHardwareConfig::NumBooleanVertexShaderConstants() const
+{
+ return m_Caps.m_NumBooleanVertexShaderConstants;
+}
+
+int CHardwareConfig::NumIntegerVertexShaderConstants() const
+{
+ return m_Caps.m_NumIntegerVertexShaderConstants;
+}
+
+int CHardwareConfig::NumPixelShaderConstants() const
+{
+ return m_Caps.m_NumPixelShaderConstants;
+}
+
+int CHardwareConfig::NumBooleanPixelShaderConstants() const
+{
+ return m_Caps.m_NumBooleanPixelShaderConstants;
+}
+
+int CHardwareConfig::NumIntegerPixelShaderConstants() const
+{
+ return m_Caps.m_NumIntegerPixelShaderConstants;
+}
+
+int CHardwareConfig::MaxNumLights() const
+{
+ return m_Caps.m_MaxNumLights;
+}
+
+bool CHardwareConfig::SupportsHardwareLighting() const
+{
+ if ( (ShaderUtil()->GetConfig().dxSupportLevel > 0) && (GetDXSupportLevel() < 70) )
+ return false;
+
+ return m_Caps.m_SupportsHardwareLighting;
+}
+
+int CHardwareConfig::MaxBlendMatrices() const
+{
+ if ( (ShaderUtil()->GetConfig().dxSupportLevel > 0) && (GetDXSupportLevel() < 70) )
+ return 1;
+
+ return m_Caps.m_MaxBlendMatrices;
+}
+
+int CHardwareConfig::MaxBlendMatrixIndices() const
+{
+ if ( (ShaderUtil()->GetConfig().dxSupportLevel > 0) && (GetDXSupportLevel() < 70) )
+ return 1;
+
+ return m_Caps.m_MaxBlendMatrixIndices;
+}
+
+int CHardwareConfig::MaxTextureAspectRatio() const
+{
+ return m_Caps.m_MaxTextureAspectRatio;
+}
+
+int CHardwareConfig::MaxVertexShaderBlendMatrices() const
+{
+ if ( (ShaderUtil()->GetConfig().dxSupportLevel > 0) && (GetDXSupportLevel() < 70) )
+ return 1;
+
+ return m_Caps.m_MaxVertexShaderBlendMatrices;
+}
+
+// Useful for testing fastclip on Windows
+extern ConVar mat_fastclip;
+
+int CHardwareConfig::MaxUserClipPlanes() const
+{
+ if ( mat_fastclip.GetBool() )
+ return 0;
+
+ return m_Caps.m_MaxUserClipPlanes;
+}
+
+bool CHardwareConfig::UseFastClipping() const
+{
+ // rbarris broke this up for easier view of outcome in debugger
+ bool fastclip = mat_fastclip.GetBool();
+
+ bool result = m_Caps.m_UseFastClipping || fastclip;
+
+ return result;
+}
+
+int CHardwareConfig::MaxTextureDepth() const
+{
+ return m_Caps.m_MaxTextureDepth;
+}
+
+int CHardwareConfig::GetDXSupportLevel() const
+{
+ if ( ShaderUtil()->GetConfig().dxSupportLevel != 0 )
+ {
+ return min( ShaderUtil()->GetConfig().dxSupportLevel, m_Caps.m_nDXSupportLevel );
+ }
+
+ return m_Caps.m_nDXSupportLevel;
+}
+
+const char *CHardwareConfig::GetShaderDLLName() const
+{
+ return ( m_Caps.m_pShaderDLL && m_Caps.m_pShaderDLL[0] ) ? m_Caps.m_pShaderDLL : "DEFAULT";
+}
+
+bool CHardwareConfig::ReadPixelsFromFrontBuffer() const
+{
+ if ( IsX360() )
+ {
+ // future proof safety, not allowing the front read path
+ return false;
+ }
+
+ // GR - in DX 9.0a can blit from MSAA back buffer
+ return false;
+}
+
+bool CHardwareConfig::PreferDynamicTextures() const
+{
+ if ( IsX360() )
+ {
+ // future proof safety, not allowing these
+ return false;
+ }
+
+ return m_Caps.m_PreferDynamicTextures;
+}
+
+bool CHardwareConfig::SupportsHDR() const
+{
+ // This is a deprecated function. . use GetHDRType instead. For shipping HL2, this always being false is correct.
+ Assert( 0 );
+ return false;
+}
+
+bool CHardwareConfig::SupportsHDRMode( HDRType_t nHDRType ) const
+{
+ switch( nHDRType )
+ {
+ case HDR_TYPE_NONE:
+ return true;
+
+ case HDR_TYPE_INTEGER:
+ return ( m_Caps.m_MaxHDRType == HDR_TYPE_INTEGER ) || ( m_Caps.m_MaxHDRType == HDR_TYPE_FLOAT );
+
+ case HDR_TYPE_FLOAT:
+ return ( m_Caps.m_MaxHDRType == HDR_TYPE_FLOAT );
+
+ }
+ return false;
+
+}
+
+bool CHardwareConfig::HasProjectedBumpEnv() const
+{
+ return m_Caps.m_HasProjectedBumpEnv;
+}
+
+bool CHardwareConfig::SupportsSpheremapping() const
+{
+ return m_Caps.m_bSupportsSpheremapping;
+}
+
+bool CHardwareConfig::NeedsAAClamp() const
+{
+ return false;
+}
+
+bool CHardwareConfig::NeedsATICentroidHack() const
+{
+ return m_Caps.m_bNeedsATICentroidHack;
+}
+
+bool CHardwareConfig::SupportsColorOnSecondStream() const
+{
+ return m_Caps.m_bColorOnSecondStream;
+}
+
+bool CHardwareConfig::SupportsStaticPlusDynamicLighting() const
+{
+ return GetDXSupportLevel() >= 80;
+}
+
+bool CHardwareConfig::PreferReducedFillrate() const
+{
+ return ShaderUtil()->GetConfig().ReduceFillrate();
+}
+
+// This is the max dx support level supported by the card
+int CHardwareConfig::GetMaxDXSupportLevel() const
+{
+ return m_ActualCaps.m_nMaxDXSupportLevel;
+}
+
+bool CHardwareConfig::SpecifiesFogColorInLinearSpace() const
+{
+ return m_Caps.m_bFogColorSpecifiedInLinearSpace;
+}
+
+bool CHardwareConfig::SupportsSRGB() const
+{
+ return m_Caps.m_SupportsSRGB;
+}
+
+bool CHardwareConfig::FakeSRGBWrite() const
+{
+ return m_Caps.m_FakeSRGBWrite;
+}
+
+bool CHardwareConfig::CanDoSRGBReadFromRTs() const
+{
+ return m_Caps.m_CanDoSRGBReadFromRTs;
+}
+
+bool CHardwareConfig::SupportsGLMixedSizeTargets() const
+{
+ return m_Caps.m_bSupportsGLMixedSizeTargets;
+}
+
+bool CHardwareConfig::IsAAEnabled() const
+{
+ return g_pShaderDevice ? g_pShaderDevice->IsAAEnabled() : false;
+// bool bAntialiasing = ( m_PresentParameters.MultiSampleType != D3DMULTISAMPLE_NONE );
+// return bAntialiasing;
+}
+
+int CHardwareConfig::GetVertexTextureCount() const
+{
+ return m_Caps.m_nVertexTextureCount;
+}
+
+int CHardwareConfig::GetMaxVertexTextureDimension() const
+{
+ return m_Caps.m_nMaxVertexTextureDimension;
+}
+
+HDRType_t CHardwareConfig::GetHDRType() const
+{
+ bool enabled = m_bHDREnabled;
+ int dxlev = GetDXSupportLevel();
+ int dxsupp = dxlev >= 90;
+ HDRType_t caps_hdr = m_Caps.m_HDRType;
+ HDRType_t result = HDR_TYPE_NONE;
+
+ //printf("\nCHardwareConfig::GetHDRType...");
+ if (enabled)
+ {
+ //printf("-> enabled...");
+ if (dxsupp)
+ {
+ //printf("-> supported...");
+ result = caps_hdr;
+ }
+ }
+
+ //printf("-> result is %d.\n", result);
+ return result;
+
+/*
+ if ( m_bHDREnabled && ( GetDXSupportLevel() >= 90 ) )
+ return m_Caps.m_HDRType;
+ return HDR_TYPE_NONE;
+*/
+}
+
+HDRType_t CHardwareConfig::GetHardwareHDRType() const
+{
+ return m_Caps.m_HDRType;
+}
+
+bool CHardwareConfig::SupportsStreamOffset() const
+{
+ return ( (GetDXSupportLevel() >= 90) && m_Caps.m_bSupportsStreamOffset );
+}
+
+int CHardwareConfig::StencilBufferBits() const
+{
+ return g_pShaderDevice ? g_pShaderDevice->StencilBufferBits() : 0;
+}
+
+int CHardwareConfig:: MaxViewports() const
+{
+ return m_Caps.m_nMaxViewports;
+}
+
+int CHardwareConfig::GetActualSamplerCount() const
+{
+ return m_ActualCaps.m_NumSamplers;
+}
+
+int CHardwareConfig::GetActualTextureStageCount() const
+{
+ return m_ActualCaps.m_NumTextureStages;
+}
+
+const char *CHardwareConfig::GetHWSpecificShaderDLLName() const
+{
+ return m_Caps.m_pShaderDLL && m_Caps.m_pShaderDLL[0] ? m_Caps.m_pShaderDLL : NULL;
+}
+
+bool CHardwareConfig::SupportsMipmapping() const
+{
+ return m_Caps.m_SupportsMipmapping;
+}
+
+bool CHardwareConfig::ActuallySupportsPixelShaders_2_b() const
+{
+ return m_ActualCaps.m_SupportsPixelShaders_2_b;
+}
diff --git a/materialsystem/shaderapidx9/hardwareconfig.h b/materialsystem/shaderapidx9/hardwareconfig.h
new file mode 100644
index 0000000..792a80e
--- /dev/null
+++ b/materialsystem/shaderapidx9/hardwareconfig.h
@@ -0,0 +1,286 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#ifndef HARDWARECONFIG_H
+#define HARDWARECONFIG_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "materialsystem/imaterialsystemhardwareconfig.h"
+#include "IHardwareConfigInternal.h"
+#include "bitmap/imageformat.h"
+#include "materialsystem/imaterialsystem.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+struct ShaderDeviceInfo_t;
+
+
+//-----------------------------------------------------------------------------
+// Vendor IDs sometimes needed for vendor-specific code
+//-----------------------------------------------------------------------------
+#define VENDORID_NVIDIA 0x10DE
+#define VENDORID_ATI 0x1002
+#define VENDORID_INTEL 0x8086
+
+//-----------------------------------------------------------------------------
+// ShaderAPI constants
+//-----------------------------------------------------------------------------
+enum
+{
+#if defined( DX_TO_GL_ABSTRACTION )
+ MAXUSERCLIPPLANES = 2,
+#else
+ MAXUSERCLIPPLANES = 6,
+#endif
+ MAX_NUM_LIGHTS = 4,
+ MAX_OUTPUTS = 3,
+};
+
+
+//-----------------------------------------------------------------------------
+// Hardware caps structures
+//-----------------------------------------------------------------------------
+enum CompressedTextureState_t
+{
+ COMPRESSED_TEXTURES_ON,
+ COMPRESSED_TEXTURES_OFF,
+ COMPRESSED_TEXTURES_NOT_INITIALIZED
+};
+
+struct HardwareCaps_t : public MaterialAdapterInfo_t
+{
+ // *****************************NOTE*********************************************
+ // If you change any members, make sure and reflect the changes in CHardwareConfig::ForceCapsToDXLevel for every dxlevel!!!!!
+ // If you change any members, make sure and reflect the changes in CHardwareConfig::ForceCapsToDXLevel for every dxlevel!!!!!
+ // If you change any members, make sure and reflect the changes in CHardwareConfig::ForceCapsToDXLevel for every dxlevel!!!!!
+ // If you change any members, make sure and reflect the changes in CHardwareConfig::ForceCapsToDXLevel for every dxlevel!!!!!
+ // If you change any members, make sure and reflect the changes in CHardwareConfig::ForceCapsToDXLevel for every dxlevel!!!!!
+ // *****************************NOTE*********************************************
+ //
+ // NOTE: Texture stages are an obsolete concept; used by fixed-function hardware
+ // Samplers are dx9+, indicating how many textures we can simultaneously bind
+ // In Dx8, samplers didn't exist and texture stages were used to indicate the
+ // number of simultaneously bound textures; we'll emulate that by slamming
+ // the number of samplers to == the number of texture stages.
+ CompressedTextureState_t m_SupportsCompressedTextures;
+ VertexCompressionType_t m_SupportsCompressedVertices;
+ int m_NumSamplers;
+ int m_NumTextureStages;
+ int m_nMaxAnisotropy;
+ int m_MaxTextureWidth;
+ int m_MaxTextureHeight;
+ int m_MaxTextureDepth;
+ int m_MaxTextureAspectRatio;
+ int m_MaxPrimitiveCount;
+ int m_NumPixelShaderConstants;
+ int m_NumBooleanPixelShaderConstants;
+ int m_NumIntegerPixelShaderConstants;
+ int m_NumVertexShaderConstants;
+ int m_NumBooleanVertexShaderConstants;
+ int m_NumIntegerVertexShaderConstants;
+ int m_TextureMemorySize;
+ int m_MaxNumLights;
+ int m_MaxBlendMatrices;
+ int m_MaxBlendMatrixIndices;
+ int m_MaxVertexShaderBlendMatrices;
+ int m_MaxUserClipPlanes;
+ HDRType_t m_HDRType;
+ char m_pShaderDLL[32];
+ ImageFormat m_ShadowDepthTextureFormat;
+ ImageFormat m_NullTextureFormat;
+ int m_nVertexTextureCount;
+ int m_nMaxVertexTextureDimension;
+ unsigned long m_AlphaToCoverageState; // State to ping to toggle Alpha To Coverage (vendor-dependent)
+ unsigned long m_AlphaToCoverageEnableValue; // Value to set above state to turn on Alpha To Coverage (vendor-dependent)
+ unsigned long m_AlphaToCoverageDisableValue; // Value to set above state to turn off Alpha To Coverage (vendor-dependent)
+ int m_nMaxViewports;
+ float m_flMinGammaControlPoint;
+ float m_flMaxGammaControlPoint;
+ int m_nGammaControlPointCount;
+ int m_MaxVertexShader30InstructionSlots;
+ int m_MaxPixelShader30InstructionSlots;
+ int m_MaxSimultaneousRenderTargets;
+
+ bool m_bDeviceOk : 1;
+ bool m_HasSetDeviceGammaRamp : 1;
+ bool m_SupportsVertexShaders : 1;
+ bool m_SupportsVertexShaders_2_0 : 1;
+ bool m_SupportsPixelShaders : 1;
+ bool m_SupportsPixelShaders_1_4 : 1;
+ bool m_SupportsPixelShaders_2_0 : 1;
+ bool m_SupportsPixelShaders_2_b : 1;
+ bool m_SupportsShaderModel_3_0 : 1;
+ bool m_bSupportsAnisotropicFiltering : 1;
+ bool m_bSupportsMagAnisotropicFiltering : 1;
+ bool m_bSupportsVertexTextures : 1;
+ bool m_ZBiasAndSlopeScaledDepthBiasSupported : 1;
+ bool m_SupportsMipmapping : 1;
+ bool m_SupportsOverbright : 1;
+ bool m_SupportsCubeMaps : 1;
+ bool m_SupportsHardwareLighting : 1;
+ bool m_SupportsMipmappedCubemaps : 1;
+ bool m_SupportsNonPow2Textures : 1;
+ bool m_PreferDynamicTextures : 1;
+ bool m_HasProjectedBumpEnv : 1;
+ bool m_SupportsSRGB : 1; // Means both read and write
+ bool m_bSupportsSpheremapping : 1;
+ bool m_UseFastClipping : 1;
+ bool m_bNeedsATICentroidHack : 1;
+ bool m_bDisableShaderOptimizations : 1;
+ bool m_bColorOnSecondStream : 1;
+ bool m_bSupportsStreamOffset : 1;
+ bool m_bFogColorSpecifiedInLinearSpace : 1;
+ bool m_bFogColorAlwaysLinearSpace : 1;
+ bool m_bSupportsAlphaToCoverage : 1;
+ bool m_bSupportsShadowDepthTextures : 1;
+ bool m_bSupportsFetch4 : 1;
+ bool m_bSoftwareVertexProcessing : 1;
+ bool m_bScissorSupported : 1;
+ bool m_bSupportsFloat32RenderTargets : 1;
+ bool m_bSupportsBorderColor : 1;
+ bool m_bDX10Card : 1; // Indicates DX10 part with performant vertex textures running DX9 path
+ bool m_bDX10Blending : 1; // Indicates DX10 part that does DX10 blending (but may not have performant vertex textures, such as Intel parts)
+ bool m_bSupportsStaticControlFlow : 1; // Useful on OpenGL, where we have a mix of support...
+ bool m_FakeSRGBWrite : 1; // Gotta do this on OpenGL. Mostly hidden, but some high level code needs to know
+ bool m_CanDoSRGBReadFromRTs : 1; // Gotta do this on OpenGL. Mostly hidden, but some high level code needs to know
+ bool m_bSupportsGLMixedSizeTargets : 1; // on OpenGL, are mixed size depth buffers supported - aka ARB_framebuffer_object
+ bool m_bCanStretchRectFromTextures : 1; // Does the device expose D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES (or is it >DX9?)
+
+ HDRType_t m_MaxHDRType;
+};
+
+
+//-----------------------------------------------------------------------------
+// Contains the hardware configuration for the current device
+//-----------------------------------------------------------------------------
+class CHardwareConfig : public IHardwareConfigInternal
+{
+public:
+ CHardwareConfig();
+
+ // Sets up the hardware caps given the specified DX level
+ void SetupHardwareCaps( const ShaderDeviceInfo_t& mode, const HardwareCaps_t &actualCaps );
+
+ // FIXME: This is for backward compat only.. don't use these
+ void SetupHardwareCaps( int nDXLevel, const HardwareCaps_t &actualCaps );
+ HardwareCaps_t& ActualCapsForEdit() { return m_ActualCaps; }
+ HardwareCaps_t& CapsForEdit() { return m_Caps; }
+
+ // Members of IMaterialSystemHardwareConfig
+ virtual bool HasDestAlphaBuffer() const;
+ virtual bool HasStencilBuffer() const;
+ virtual int GetFrameBufferColorDepth() const;
+ virtual int GetSamplerCount() const;
+ virtual bool HasSetDeviceGammaRamp() const;
+ virtual bool SupportsCompressedTextures() const;
+ virtual VertexCompressionType_t SupportsCompressedVertices() const;
+ virtual bool SupportsBorderColor() const;
+ virtual bool SupportsFetch4() const;
+ virtual bool CanStretchRectFromTextures() const;
+ virtual bool SupportsVertexAndPixelShaders() const;
+ virtual bool SupportsPixelShaders_1_4() const;
+ virtual bool SupportsPixelShaders_2_0() const;
+ virtual bool SupportsStaticControlFlow() const;
+ virtual bool SupportsVertexShaders_2_0() const;
+ virtual int MaximumAnisotropicLevel() const;
+ virtual int MaxTextureWidth() const;
+ virtual int MaxTextureHeight() const;
+ virtual int TextureMemorySize() const;
+ virtual bool SupportsOverbright() const;
+ virtual bool SupportsCubeMaps() const;
+ virtual bool SupportsMipmappedCubemaps() const;
+ virtual bool SupportsNonPow2Textures() const;
+ virtual int GetTextureStageCount() const;
+ virtual int NumVertexShaderConstants() const;
+ virtual int NumBooleanVertexShaderConstants() const;
+ virtual int NumIntegerVertexShaderConstants() const;
+ virtual int NumPixelShaderConstants() const;
+ virtual int NumBooleanPixelShaderConstants() const;
+ virtual int NumIntegerPixelShaderConstants() const;
+ virtual int MaxNumLights() const;
+ virtual bool SupportsHardwareLighting() const;
+ virtual int MaxBlendMatrices() const;
+ virtual int MaxBlendMatrixIndices() const;
+ virtual int MaxTextureAspectRatio() const;
+ virtual int MaxVertexShaderBlendMatrices() const;
+ virtual int MaxUserClipPlanes() const;
+ virtual bool UseFastClipping() const;
+ virtual int GetDXSupportLevel() const;
+ virtual const char *GetShaderDLLName() const;
+ virtual bool ReadPixelsFromFrontBuffer() const;
+ virtual bool PreferDynamicTextures() const;
+ virtual bool SupportsHDR() const;
+ virtual bool HasProjectedBumpEnv() const;
+ virtual bool SupportsSpheremapping() const;
+ virtual bool NeedsAAClamp() const;
+ virtual bool NeedsATICentroidHack() const;
+ virtual bool SupportsColorOnSecondStream() const;
+ virtual bool SupportsStaticPlusDynamicLighting() const;
+ virtual bool PreferReducedFillrate() const;
+ virtual int GetMaxDXSupportLevel() const;
+ virtual bool SpecifiesFogColorInLinearSpace() const;
+ virtual bool SupportsSRGB() const;
+ virtual bool FakeSRGBWrite() const;
+ virtual bool CanDoSRGBReadFromRTs() const;
+ virtual bool SupportsGLMixedSizeTargets() const;
+ virtual bool IsAAEnabled() const;
+ virtual int GetVertexTextureCount() const;
+ virtual int GetMaxVertexTextureDimension() const;
+ virtual int MaxTextureDepth() const;
+ virtual HDRType_t GetHDRType() const;
+ virtual HDRType_t GetHardwareHDRType() const;
+ virtual bool SupportsPixelShaders_2_b() const;
+ virtual bool SupportsShaderModel_3_0() const;
+ virtual bool SupportsStreamOffset() const;
+ virtual int StencilBufferBits() const;
+ virtual int MaxViewports() const;
+ virtual void OverrideStreamOffsetSupport( bool bOverrideEnabled, bool bEnableSupport );
+ virtual int GetShadowFilterMode() const;
+ virtual int NeedsShaderSRGBConversion() const;
+ virtual bool UsesSRGBCorrectBlending() const;
+ virtual bool HasFastVertexTextures() const;
+ virtual int MaxHWMorphBatchCount() const;
+
+ const char *GetHWSpecificShaderDLLName() const;
+ int GetActualSamplerCount() const;
+ int GetActualTextureStageCount() const;
+ bool SupportsMipmapping() const;
+ virtual bool ActuallySupportsPixelShaders_2_b() const;
+
+ virtual bool SupportsHDRMode( HDRType_t nHDRMode ) const;
+
+ const HardwareCaps_t& ActualCaps() const { return m_ActualCaps; }
+ const HardwareCaps_t& Caps() const { return m_Caps; }
+ virtual bool GetHDREnabled( void ) const;
+ virtual void SetHDREnabled( bool bEnable );
+
+protected:
+ // Gets the recommended configuration associated with a particular dx level
+ void ForceCapsToDXLevel( HardwareCaps_t *pCaps, int nDxLevel, const HardwareCaps_t &actualCaps );
+
+ // Members related to capabilities
+ HardwareCaps_t m_ActualCaps;
+ HardwareCaps_t m_Caps;
+ HardwareCaps_t m_UnOverriddenCaps;
+ bool m_bHDREnabled;
+};
+
+
+//-----------------------------------------------------------------------------
+// Singleton hardware config
+//-----------------------------------------------------------------------------
+extern CHardwareConfig *g_pHardwareConfig;
+
+
+#endif // HARDWARECONFIG_H
diff --git a/materialsystem/shaderapidx9/imeshdx8.h b/materialsystem/shaderapidx9/imeshdx8.h
new file mode 100644
index 0000000..96697a7
--- /dev/null
+++ b/materialsystem/shaderapidx9/imeshdx8.h
@@ -0,0 +1,98 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#ifndef IMESHDX8_H
+#define IMESHDX8_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "meshbase.h"
+#include "shaderapi/ishaderapi.h"
+
+
+abstract_class IMeshMgr
+{
+public:
+ // Initialize, shutdown
+ virtual void Init() = 0;
+ virtual void Shutdown() = 0;
+
+ // Task switch...
+ virtual void ReleaseBuffers() = 0;
+ virtual void RestoreBuffers() = 0;
+
+ // Releases all dynamic vertex buffers
+ virtual void DestroyVertexBuffers() = 0;
+
+ // Flushes the dynamic mesh. Should be called when state changes
+ virtual void Flush() = 0;
+
+ // Discards the dynamic vertex and index buffer
+ virtual void DiscardVertexBuffers() = 0;
+
+ // Creates, destroys static meshes
+ virtual IMesh* CreateStaticMesh( VertexFormat_t vertexFormat, const char *pTextureBudgetGroup, IMaterial *pMaterial = NULL ) = 0;
+ virtual void DestroyStaticMesh( IMesh* pMesh ) = 0;
+
+ // Gets at the dynamic mesh
+ virtual IMesh* GetDynamicMesh( IMaterial* pMaterial, VertexFormat_t vertexFormat, int nHWSkinBoneCount, bool buffered = true,
+ IMesh* pVertexOverride = 0, IMesh* pIndexOverride = 0) = 0;
+
+// ------------ New Vertex/Index Buffer interface ----------------------------
+ // Do we need support for bForceTempMesh and bSoftwareVertexShader?
+ // I don't think we use bSoftwareVertexShader anymore. .need to look into bForceTempMesh.
+ virtual IVertexBuffer *CreateVertexBuffer( ShaderBufferType_t type, VertexFormat_t fmt, int nVertexCount, const char *pBudgetGroup ) = 0;
+ virtual IIndexBuffer *CreateIndexBuffer( ShaderBufferType_t indexBufferType, MaterialIndexFormat_t fmt, int nIndexCount, const char *pBudgetGroup ) = 0;
+ virtual void DestroyVertexBuffer( IVertexBuffer * ) = 0;
+ virtual void DestroyIndexBuffer( IIndexBuffer * ) = 0;
+ // Do we need to specify the stream here in the case of locking multiple dynamic VBs on different streams?
+ virtual IVertexBuffer *GetDynamicVertexBuffer( int streamID, VertexFormat_t vertexFormat, bool bBuffered = true ) = 0;
+ virtual IIndexBuffer *GetDynamicIndexBuffer( MaterialIndexFormat_t fmt, bool bBuffered = true ) = 0;
+ virtual void BindVertexBuffer( int streamID, IVertexBuffer *pVertexBuffer, int nOffsetInBytes, int nFirstVertex, int nVertexCount, VertexFormat_t fmt, int nRepetitions = 1 ) = 0;
+ virtual void BindIndexBuffer( IIndexBuffer *pIndexBuffer, int nOffsetInBytes ) = 0;
+ virtual void Draw( MaterialPrimitiveType_t primitiveType, int nFirstIndex, int nIndexCount ) = 0;
+// ------------ End ----------------------------
+ virtual VertexFormat_t GetCurrentVertexFormat( void ) const = 0;
+ virtual void RenderPassWithVertexAndIndexBuffers( void ) = 0;
+
+ // Computes the vertex format
+ virtual VertexFormat_t ComputeVertexFormat( unsigned int flags,
+ int numTexCoords, int* pTexCoordDimensions, int numBoneWeights,
+ int userDataSize ) const = 0;
+
+ // Returns the number of buffers...
+ virtual int BufferCount() const = 0;
+
+ // Use fat vertices (for tools)
+ virtual void UseFatVertices( bool bUseFat ) = 0;
+
+ // Returns the number of vertices + indices we can render using the dynamic mesh
+ // Passing true in the second parameter will return the max # of vertices + indices
+ // we can use before a flush is provoked and may return different values
+ // if called multiple times in succession.
+ // Passing false into the second parameter will return
+ // the maximum possible vertices + indices that can be rendered in a single batch
+ virtual void GetMaxToRender( IMesh *pMesh, bool bMaxUntilFlush, int *pMaxVerts, int *pMaxIndices ) = 0;
+
+ // Returns the max number of vertices we can render for a given material
+ virtual int GetMaxVerticesToRender( IMaterial *pMaterial ) = 0;
+ virtual int GetMaxIndicesToRender( ) = 0;
+ virtual IMesh *GetFlexMesh() = 0;
+
+ virtual void ComputeVertexDescription( unsigned char* pBuffer, VertexFormat_t vertexFormat, MeshDesc_t& desc ) const = 0;
+
+ virtual IVertexBuffer *GetDynamicVertexBuffer( IMaterial *pMaterial, bool buffered = true ) = 0;
+ virtual IIndexBuffer *GetDynamicIndexBuffer( IMaterial *pMaterial, bool buffered = true ) = 0;
+
+ virtual void MarkUnusedVertexFields( unsigned int nFlags, int nTexCoordCount, bool *pUnusedTexCoords ) = 0;
+};
+
+#endif // IMESHDX8_H
diff --git a/materialsystem/shaderapidx9/inputlayoutdx10.cpp b/materialsystem/shaderapidx9/inputlayoutdx10.cpp
new file mode 100644
index 0000000..9482907
--- /dev/null
+++ b/materialsystem/shaderapidx9/inputlayoutdx10.cpp
@@ -0,0 +1,214 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#include <d3d10.h>
+#undef GetCommandLine
+
+#include "inputlayoutdx10.h"
+#include "materialsystem/imesh.h"
+#include "shaderdevicedx10.h"
+
+// NOTE: This has to be the last file included!
+#include "tier0/memdbgon.h"
+
+
+//-----------------------------------------------------------------------------
+// Standard input layouts
+//-----------------------------------------------------------------------------
+static const DXGI_FORMAT s_pSizeLookup[] =
+{
+ DXGI_FORMAT_UNKNOWN, // Should be unused...
+ DXGI_FORMAT_R32_FLOAT, // D3DDECLTYPE_FLOAT1
+ DXGI_FORMAT_R32G32_FLOAT, // D3DDECLTYPE_FLOAT2,
+ DXGI_FORMAT_R32G32B32_FLOAT, // D3DDECLTYPE_FLOAT3,
+ DXGI_FORMAT_R32G32B32A32_FLOAT, // D3DDECLTYPE_FLOAT4
+};
+
+struct FieldInfo_t
+{
+ const char *m_pSemanticString;
+ unsigned int m_nSemanticIndex;
+ uint64 m_nFormatMask;
+ int m_nFieldSize;
+};
+
+static FieldInfo_t s_pFieldInfo[] =
+{
+ { "POSITION", 0, VERTEX_POSITION, sizeof( float ) * 3 },
+ { "BLENDWEIGHT", 0, VERTEX_BONE_WEIGHT_MASK, 0 },
+ { "BLENDINDICES", 0, VERTEX_BONE_INDEX, 4 },
+ { "NORMAL", 0, VERTEX_NORMAL, sizeof( float ) * 3 },
+ { "COLOR", 0, VERTEX_COLOR, 4 },
+ { "SPECULAR", 0, VERTEX_SPECULAR, 4 },
+ { "TEXCOORD", 0, VERTEX_TEXCOORD_MASK(0), 0 },
+ { "TEXCOORD", 1, VERTEX_TEXCOORD_MASK(1), 0 },
+ { "TEXCOORD", 2, VERTEX_TEXCOORD_MASK(2), 0 },
+ { "TEXCOORD", 3, VERTEX_TEXCOORD_MASK(3), 0 },
+ { "TEXCOORD", 4, VERTEX_TEXCOORD_MASK(4), 0 },
+ { "TEXCOORD", 5, VERTEX_TEXCOORD_MASK(5), 0 },
+ { "TEXCOORD", 6, VERTEX_TEXCOORD_MASK(6), 0 },
+ { "TEXCOORD", 7, VERTEX_TEXCOORD_MASK(7), 0 },
+ { "TANGENT", 0, VERTEX_TANGENT_S, sizeof( float ) * 3 },
+ { "BINORMAL", 0, VERTEX_TANGENT_T, sizeof( float ) * 3 },
+ { "USERDATA", 0, USER_DATA_SIZE_MASK, 0 },
+ { NULL, 0, 0 },
+};
+
+static D3D10_INPUT_ELEMENT_DESC s_pVertexDesc[] =
+{
+ { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
+ { "BLENDWEIGHT", 0, DXGI_FORMAT_UNKNOWN, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
+ { "BLENDINDICES", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
+ { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
+ { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
+ { "SPECULAR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
+ { "TEXCOORD", 0, DXGI_FORMAT_UNKNOWN, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
+ { "TEXCOORD", 1, DXGI_FORMAT_UNKNOWN, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
+ { "TEXCOORD", 2, DXGI_FORMAT_UNKNOWN, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
+ { "TEXCOORD", 3, DXGI_FORMAT_UNKNOWN, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
+ { "TEXCOORD", 4, DXGI_FORMAT_UNKNOWN, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
+ { "TEXCOORD", 5, DXGI_FORMAT_UNKNOWN, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
+ { "TEXCOORD", 6, DXGI_FORMAT_UNKNOWN, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
+ { "TEXCOORD", 7, DXGI_FORMAT_UNKNOWN, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
+ { "TANGENT", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
+ { "BINORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
+ { "USERDATA", 0, DXGI_FORMAT_UNKNOWN, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
+};
+
+static D3D10_INPUT_ELEMENT_DESC s_pFallbackVertexDesc[] =
+{
+ { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 15, 0, D3D10_INPUT_PER_INSTANCE_DATA, UINT_MAX },
+ { "BLENDWEIGHT", 0, DXGI_FORMAT_R32G32_FLOAT, 15, 12, D3D10_INPUT_PER_INSTANCE_DATA, UINT_MAX },
+ { "BLENDINDICES", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 15, 20, D3D10_INPUT_PER_INSTANCE_DATA, UINT_MAX },
+ { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 15, 24, D3D10_INPUT_PER_INSTANCE_DATA, UINT_MAX },
+ { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 15, 36, D3D10_INPUT_PER_INSTANCE_DATA, UINT_MAX },
+ { "SPECULAR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 15, 40, D3D10_INPUT_PER_INSTANCE_DATA, UINT_MAX },
+ { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 15, 44, D3D10_INPUT_PER_INSTANCE_DATA, UINT_MAX },
+ { "TEXCOORD", 1, DXGI_FORMAT_R32G32_FLOAT, 15, 52, D3D10_INPUT_PER_INSTANCE_DATA, UINT_MAX },
+ { "TEXCOORD", 2, DXGI_FORMAT_R32G32_FLOAT, 15, 60, D3D10_INPUT_PER_INSTANCE_DATA, UINT_MAX },
+ { "TEXCOORD", 3, DXGI_FORMAT_R32G32_FLOAT, 15, 68, D3D10_INPUT_PER_INSTANCE_DATA, UINT_MAX },
+ { "TEXCOORD", 4, DXGI_FORMAT_R32G32_FLOAT, 15, 76, D3D10_INPUT_PER_INSTANCE_DATA, UINT_MAX },
+ { "TEXCOORD", 5, DXGI_FORMAT_R32G32_FLOAT, 15, 84, D3D10_INPUT_PER_INSTANCE_DATA, UINT_MAX },
+ { "TEXCOORD", 6, DXGI_FORMAT_R32G32_FLOAT, 15, 92, D3D10_INPUT_PER_INSTANCE_DATA, UINT_MAX },
+ { "TEXCOORD", 7, DXGI_FORMAT_R32G32_FLOAT, 15, 100, D3D10_INPUT_PER_INSTANCE_DATA, UINT_MAX },
+ { "TANGENT", 0, DXGI_FORMAT_R32G32B32_FLOAT, 15, 108, D3D10_INPUT_PER_INSTANCE_DATA, UINT_MAX },
+ { "BINORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 15, 120, D3D10_INPUT_PER_INSTANCE_DATA, UINT_MAX },
+ { "USERDATA", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 15, 132, D3D10_INPUT_PER_INSTANCE_DATA, UINT_MAX },
+};
+
+
+//-----------------------------------------------------------------------------
+// Computes the required input desc based on the vertex format
+//-----------------------------------------------------------------------------
+static void PrintInputDesc( int nCount, const D3D10_INPUT_ELEMENT_DESC *pDecl )
+{
+ for ( int i = 0; i < nCount; i++ )
+ {
+ Msg( "%s (%d): Stream: %d, Offset: %d, Instanced? %c\n",
+ pDecl[i].SemanticName,
+ pDecl[i].SemanticIndex,
+ ( int )pDecl[i].InputSlot,
+ ( int )pDecl[i].AlignedByteOffset,
+ pDecl[i].InputSlotClass == D3D10_INPUT_PER_VERTEX_DATA ? 'n' : 'y'
+ );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Checks to see if a shader requires a particular field
+//-----------------------------------------------------------------------------
+static bool CheckShaderSignatureExpectations( ID3D10ShaderReflection* pReflection, const char* pSemantic, unsigned int nSemanticIndex )
+{
+ D3D10_SHADER_DESC shaderDesc;
+ D3D10_SIGNATURE_PARAMETER_DESC paramDesc;
+
+ Assert( pSemantic );
+ Assert( pReflection );
+
+ pReflection->GetDesc( &shaderDesc );
+
+ for ( unsigned int k=0; k < shaderDesc.InputParameters; k++ )
+ {
+ pReflection->GetInputParameterDesc( k, &paramDesc );
+ if ( ( nSemanticIndex == paramDesc.SemanticIndex ) && !Q_stricmp( pSemantic, paramDesc.SemanticName ) )
+ return true;
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Computes the required input desc based on the vertex format
+//-----------------------------------------------------------------------------
+static unsigned int ComputeInputDesc( VertexFormat_t fmt, D3D10_INPUT_ELEMENT_DESC *pDecl, ID3D10ShaderReflection* pReflection )
+{
+ unsigned int nCount = 0;
+ int nOffset = 0;
+
+ // Fix up the global table so we don't need special-case code
+ int nBoneCount = NumBoneWeights( fmt );
+ s_pFieldInfo[1].m_nFieldSize = sizeof( float ) * nBoneCount;
+ s_pVertexDesc[1].Format = s_pSizeLookup[ nBoneCount ];
+
+ int nUserDataSize = UserDataSize( fmt );
+ s_pFieldInfo[16].m_nFieldSize = sizeof( float ) * nUserDataSize;
+ s_pVertexDesc[16].Format = s_pSizeLookup[ nUserDataSize ];
+
+ // NOTE: Fix s_pFieldInfo, s_pVertexDesc, s_pFallbackVertexDesc if you add more fields
+ // As well as the fallback stream (stream #15)
+ COMPILE_TIME_ASSERT( VERTEX_MAX_TEXTURE_COORDINATES == 8 );
+ for ( int i = 0; i < VERTEX_MAX_TEXTURE_COORDINATES; ++i )
+ {
+ int nTexCoordCount = TexCoordSize( i, fmt );
+ s_pFieldInfo[6+i].m_nFieldSize = sizeof( float ) * nTexCoordCount;
+ s_pVertexDesc[6+i].Format = s_pSizeLookup[ nTexCoordCount ];
+ }
+
+ // FIXME: Change this loop so CheckShaderSignatureExpectations is called once!
+ for ( int i = 0; s_pFieldInfo[i].m_pSemanticString; ++i )
+ {
+ if ( fmt & s_pFieldInfo[i].m_nFormatMask )
+ {
+ memcpy( &pDecl[nCount], &s_pVertexDesc[i], sizeof(D3D10_INPUT_ELEMENT_DESC) );
+ pDecl[nCount].AlignedByteOffset = nOffset;
+ nOffset += s_pFieldInfo[i].m_nFieldSize;
+ ++nCount;
+ }
+ else if ( CheckShaderSignatureExpectations( pReflection, s_pFieldInfo[i].m_pSemanticString, s_pFieldInfo[i].m_nSemanticIndex ) )
+ {
+ memcpy( &pDecl[nCount], &s_pFallbackVertexDesc[i], sizeof(D3D10_INPUT_ELEMENT_DESC) );
+ ++nCount;
+ }
+ }
+
+ // For debugging only...
+// PrintInputDesc( nCount, pDecl );
+
+ return nCount;
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the input layout associated with a vertex format
+//-----------------------------------------------------------------------------
+ID3D10InputLayout *CreateInputLayout( VertexFormat_t fmt, ID3D10ShaderReflection* pReflection, const void *pByteCode, size_t nByteCodeLen )
+{
+ D3D10_INPUT_ELEMENT_DESC pDecl[32];
+ unsigned int nDeclCount = ComputeInputDesc( fmt, pDecl, pReflection );
+
+ ID3D10InputLayout *pInputLayout;
+ HRESULT hr = D3D10Device()->CreateInputLayout( pDecl, nDeclCount, pByteCode, nByteCodeLen, &pInputLayout );
+ if ( FAILED( hr ) )
+ {
+ Warning( "CreateInputLayout::Unable to create input layout for format %llX!\n", fmt );
+ return NULL;
+ }
+ return pInputLayout;
+}
diff --git a/materialsystem/shaderapidx9/inputlayoutdx10.h b/materialsystem/shaderapidx9/inputlayoutdx10.h
new file mode 100644
index 0000000..b1ac116
--- /dev/null
+++ b/materialsystem/shaderapidx9/inputlayoutdx10.h
@@ -0,0 +1,35 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#ifndef INPUTLAYOUTDX10_H
+#define INPUTLAYOUTDX10_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "materialsystem/imaterial.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declaration
+//-----------------------------------------------------------------------------
+struct ID3D10InputLayout;
+struct ID3D10ShaderReflection;
+
+
+//-----------------------------------------------------------------------------
+// Gets the input layout associated with a vertex format
+// FIXME: Note that we'll need to change this from a VertexFormat_t
+//-----------------------------------------------------------------------------
+ID3D10InputLayout *CreateInputLayout( VertexFormat_t fmt,
+ ID3D10ShaderReflection* pReflection, const void *pByteCode, size_t nByteCodeLen );
+
+
+#endif // INPUTLAYOUTDX10_H
+
diff --git a/materialsystem/shaderapidx9/ivertexbufferdx8.h b/materialsystem/shaderapidx9/ivertexbufferdx8.h
new file mode 100644
index 0000000..dea00d7
--- /dev/null
+++ b/materialsystem/shaderapidx9/ivertexbufferdx8.h
@@ -0,0 +1,34 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#ifndef IVERTEXBUFFERDX8_H
+#define IVERTEXBUFFERDX8_H
+#pragma once
+
+#include "IVertexBuffer.h"
+
+abstract_class IVertexBufferDX8 : public IVertexBuffer
+{
+public:
+ // TEMPORARY!
+ virtual int Begin( int flags, int numVerts ) = 0;
+
+ // Sets up the renderstate
+ virtual void SetRenderState( int stream ) = 0;
+
+ // Gets FVF info
+ virtual void ComputeFVFInfo( int flags, int& fvf, int& size ) const = 0;
+
+ // Cleans up the vertex buffers
+ virtual void CleanUp() = 0;
+
+ // Flushes the vertex buffers
+ virtual void Flush() = 0;
+};
+
+#endif // IVERTEXBUFFERDX8_H
diff --git a/materialsystem/shaderapidx9/locald3dtypes.h b/materialsystem/shaderapidx9/locald3dtypes.h
new file mode 100644
index 0000000..ad45355
--- /dev/null
+++ b/materialsystem/shaderapidx9/locald3dtypes.h
@@ -0,0 +1,191 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//===========================================================================//
+
+#ifndef LOCALD3DTYPES_H
+#define LOCALD3DTYPES_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#if defined( DX10 ) && !defined( DX_TO_GL_ABSTRACTION )
+
+#include <d3d10.h>
+#include <d3dx10.h>
+
+struct IDirect3D10BaseTexture
+{
+ ID3D10Resource *m_pBaseTexture;
+ ID3D10ShaderResourceView *m_pSRView;
+ ID3D10RenderTargetView *m_pRTView;
+};
+
+class CDx10Types
+{
+public:
+ typedef struct IDirect3D10BaseTexture IDirect3DTexture;
+ // FIXME: What is this called now ?
+ // typedef ID3D10TextureCube IDirect3DCubeTexture;
+ typedef ID3D10Texture3D IDirect3DVolumeTexture;
+ typedef ID3D10Device IDirect3DDevice;
+ typedef D3D10_VIEWPORT D3DVIEWPORT;
+ typedef ID3D10Buffer IDirect3DIndexBuffer;
+ typedef ID3D10Buffer IDirect3DVertexBuffer;
+ typedef ID3D10VertexShader IDirect3DVertexShader;
+ typedef ID3D10PixelShader IDirect3DPixelShader;
+ typedef ID3D10ShaderResourceView IDirect3DSurface;
+ typedef ID3DX10Font ID3DXFont;
+ typedef ID3D10Query ID3DQuery;
+
+ typedef ID3D10Device *LPDIRECT3DDEVICE;
+ typedef ID3D10Buffer *LPDIRECT3DINDEXBUFFER;
+ typedef ID3D10Buffer *LPDIRECT3DVERTEXBUFFER;
+};
+
+#endif // defined( DX10 ) && !defined( DX_TO_GL_ABSTRACTION )
+
+
+#if !defined( _X360 ) && !defined( DX_TO_GL_ABSTRACTION )
+#ifdef _DEBUG
+#define D3D_DEBUG_INFO 1
+#endif
+#endif
+
+struct IDirect3DTexture9;
+struct IDirect3DBaseTexture9;
+struct IDirect3DCubeTexture9;
+struct IDirect3D9;
+struct IDirect3DDevice9;
+struct IDirect3DSurface9;
+struct IDirect3DIndexBuffer9;
+struct IDirect3DVertexBuffer9;
+struct IDirect3DVertexShader9;
+struct IDirect3DPixelShader9;
+struct IDirect3DVolumeTexture9;
+
+typedef struct _D3DLIGHT9 D3DLIGHT9;
+typedef struct _D3DADAPTER_IDENTIFIER9 D3DADAPTER_IDENTIFIER9;
+typedef struct _D3DCAPS9 D3DCAPS9;
+typedef struct _D3DVIEWPORT9 D3DVIEWPORT9;
+typedef struct _D3DMATERIAL9 D3DMATERIAL9;
+typedef IDirect3DTexture9 IDirect3DTexture;
+typedef IDirect3DBaseTexture9 IDirect3DBaseTexture;
+typedef IDirect3DCubeTexture9 IDirect3DCubeTexture;
+typedef IDirect3DVolumeTexture9 IDirect3DVolumeTexture;
+typedef IDirect3DDevice9 IDirect3DDevice;
+typedef D3DMATERIAL9 D3DMATERIAL;
+typedef D3DLIGHT9 D3DLIGHT;
+typedef IDirect3DSurface9 IDirect3DSurface;
+typedef D3DCAPS9 D3DCAPS;
+typedef IDirect3DIndexBuffer9 IDirect3DIndexBuffer;
+typedef IDirect3DVertexBuffer9 IDirect3DVertexBuffer;
+typedef IDirect3DPixelShader9 IDirect3DPixelShader;
+typedef IDirect3DDevice *LPDIRECT3DDEVICE;
+typedef IDirect3DIndexBuffer *LPDIRECT3DINDEXBUFFER;
+typedef IDirect3DVertexBuffer *LPDIRECT3DVERTEXBUFFER;
+
+class CDx9Types
+{
+public:
+ typedef IDirect3DTexture9 IDirect3DTexture;
+ typedef IDirect3DBaseTexture9 IDirect3DBaseTexture;
+ typedef IDirect3DCubeTexture9 IDirect3DCubeTexture;
+ typedef IDirect3DVolumeTexture9 IDirect3DVolumeTexture;
+ typedef IDirect3DDevice9 IDirect3DDevice;
+ typedef D3DMATERIAL9 D3DMATERIAL;
+ typedef D3DLIGHT9 D3DLIGHT;
+ typedef IDirect3DSurface9 IDirect3DSurface;
+ typedef D3DCAPS9 D3DCAPS;
+ typedef IDirect3DIndexBuffer9 IDirect3DIndexBuffer;
+ typedef IDirect3DVertexBuffer9 IDirect3DVertexBuffer;
+ typedef IDirect3DPixelShader9 IDirect3DPixelShader;
+ typedef IDirect3DDevice *LPDIRECT3DDEVICE;
+ typedef IDirect3DIndexBuffer *LPDIRECT3DINDEXBUFFER;
+ typedef IDirect3DVertexBuffer *LPDIRECT3DVERTEXBUFFER;
+};
+
+typedef void *HardwareShader_t;
+
+//-----------------------------------------------------------------------------
+// The vertex and pixel shader type
+//-----------------------------------------------------------------------------
+typedef int VertexShader_t;
+typedef int PixelShader_t;
+
+//-----------------------------------------------------------------------------
+// Bitpattern for an invalid shader
+//-----------------------------------------------------------------------------
+#define INVALID_SHADER ( 0xFFFFFFFF )
+#define INVALID_HARDWARE_SHADER ( NULL )
+
+#define D3DSAMP_NOTSUPPORTED D3DSAMP_FORCE_DWORD
+#define D3DRS_NOTSUPPORTED D3DRS_FORCE_DWORD
+
+#include "togl/rendermechanism.h"
+
+#if defined( _X360 )
+
+// not supported, keeping for port ease
+#define D3DSAMP_SRGBTEXTURE D3DSAMP_NOTSUPPORTED
+#define D3DRS_LIGHTING D3DRS_NOTSUPPORTED
+#define D3DRS_DIFFUSEMATERIALSOURCE D3DRS_NOTSUPPORTED
+#define D3DRS_SPECULARENABLE D3DRS_NOTSUPPORTED
+#define D3DRS_SHADEMODE D3DRS_NOTSUPPORTED
+#define D3DRS_LASTPIXEL D3DRS_NOTSUPPORTED
+#define D3DRS_DITHERENABLE D3DRS_NOTSUPPORTED
+#define D3DRS_FOGENABLE D3DRS_NOTSUPPORTED
+#define D3DRS_FOGCOLOR D3DRS_NOTSUPPORTED
+#define D3DRS_FOGTABLEMODE D3DRS_NOTSUPPORTED
+#define D3DRS_FOGSTART D3DRS_NOTSUPPORTED
+#define D3DRS_FOGEND D3DRS_NOTSUPPORTED
+#define D3DRS_FOGDENSITY D3DRS_NOTSUPPORTED
+#define D3DRS_RANGEFOGENABLE D3DRS_NOTSUPPORTED
+#define D3DRS_TEXTUREFACTOR D3DRS_NOTSUPPORTED
+#define D3DRS_CLIPPING D3DRS_NOTSUPPORTED
+#define D3DRS_AMBIENT D3DRS_NOTSUPPORTED
+#define D3DRS_FOGVERTEXMODE D3DRS_NOTSUPPORTED
+#define D3DRS_COLORVERTEX D3DRS_NOTSUPPORTED
+#define D3DRS_LOCALVIEWER D3DRS_NOTSUPPORTED
+#define D3DRS_NORMALIZENORMALS D3DRS_NOTSUPPORTED
+#define D3DRS_SPECULARMATERIALSOURCE D3DRS_NOTSUPPORTED
+#define D3DRS_AMBIENTMATERIALSOURCE D3DRS_NOTSUPPORTED
+#define D3DRS_EMISSIVEMATERIALSOURCE D3DRS_NOTSUPPORTED
+#define D3DRS_VERTEXBLEND D3DRS_NOTSUPPORTED
+#define D3DRS_POINTSCALEENABLE D3DRS_NOTSUPPORTED
+#define D3DRS_POINTSCALE_A D3DRS_NOTSUPPORTED
+#define D3DRS_POINTSCALE_B D3DRS_NOTSUPPORTED
+#define D3DRS_POINTSCALE_C D3DRS_NOTSUPPORTED
+#define D3DRS_PATCHEDGESTYLE D3DRS_NOTSUPPORTED
+#define D3DRS_DEBUGMONITORTOKEN D3DRS_NOTSUPPORTED
+#define D3DRS_INDEXEDVERTEXBLENDENABLE D3DRS_NOTSUPPORTED
+#define D3DRS_TWEENFACTOR D3DRS_NOTSUPPORTED
+#define D3DRS_POSITIONDEGREE D3DRS_NOTSUPPORTED
+#define D3DRS_NORMALDEGREE D3DRS_NOTSUPPORTED
+#define D3DRS_ANTIALIASEDLINEENABLE D3DRS_NOTSUPPORTED
+#define D3DRS_ADAPTIVETESS_X D3DRS_NOTSUPPORTED
+#define D3DRS_ADAPTIVETESS_Y D3DRS_NOTSUPPORTED
+#define D3DRS_ADAPTIVETESS_Z D3DRS_NOTSUPPORTED
+#define D3DRS_ADAPTIVETESS_W D3DRS_NOTSUPPORTED
+#define D3DRS_ENABLEADAPTIVETESSELLATION D3DRS_NOTSUPPORTED
+#define D3DRS_SRGBWRITEENABLE D3DRS_NOTSUPPORTED
+#define D3DLOCK_DISCARD 0
+#define D3DUSAGE_DYNAMIC 0
+#define D3DUSAGE_AUTOGENMIPMAP 0
+#define D3DDEVTYPE_REF D3DDEVTYPE_HAL
+#define D3DENUM_WHQL_LEVEL 0
+#define D3DCREATE_SOFTWARE_VERTEXPROCESSING D3DCREATE_HARDWARE_VERTEXPROCESSING
+#define D3DDMT_ENABLE 0
+
+typedef enum D3DSHADEMODE
+{
+ D3DSHADE_FLAT = 0,
+ D3DSHADE_GOURAUD = 0,
+};
+
+#endif // _X360
+
+#endif // LOCALD3DTYPES_H
diff --git a/materialsystem/shaderapidx9/meshbase.cpp b/materialsystem/shaderapidx9/meshbase.cpp
new file mode 100644
index 0000000..336f150
--- /dev/null
+++ b/materialsystem/shaderapidx9/meshbase.cpp
@@ -0,0 +1,419 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//===========================================================================//
+
+#include "meshbase.h"
+#include "shaderapi_global.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+//-----------------------------------------------------------------------------
+// Helpers with VertexDesc_t...
+//-----------------------------------------------------------------------------
+// FIXME: add compression-agnostic read-accessors (which decompress and return by value, checking desc.m_CompressionType)
+inline Vector &Position( VertexDesc_t const &desc, int vert )
+{
+ return *(Vector*)((unsigned char*)desc.m_pPosition + vert * desc.m_VertexSize_Position );
+}
+
+inline float Wrinkle( VertexDesc_t const &desc, int vert )
+{
+ return *(float*)((unsigned char*)desc.m_pWrinkle + vert * desc.m_VertexSize_Wrinkle );
+}
+
+inline float *BoneWeight( VertexDesc_t const &desc, int vert )
+{
+ Assert( desc.m_CompressionType == VERTEX_COMPRESSION_NONE );
+ return (float*)((unsigned char*)desc.m_pBoneWeight + vert * desc.m_VertexSize_BoneWeight );
+}
+
+inline unsigned char *BoneIndex( VertexDesc_t const &desc, int vert )
+{
+ return desc.m_pBoneMatrixIndex + vert * desc.m_VertexSize_BoneMatrixIndex;
+}
+
+inline Vector &Normal( VertexDesc_t const &desc, int vert )
+{
+ Assert( desc.m_CompressionType == VERTEX_COMPRESSION_NONE );
+ return *(Vector*)((unsigned char*)desc.m_pNormal + vert * desc.m_VertexSize_Normal );
+}
+
+inline unsigned char *Color( VertexDesc_t const &desc, int vert )
+{
+ return desc.m_pColor + vert * desc.m_VertexSize_Color;
+}
+
+inline Vector2D &TexCoord( VertexDesc_t const &desc, int vert, int stage )
+{
+ return *(Vector2D*)((unsigned char*)desc.m_pTexCoord[stage] + vert * desc.m_VertexSize_TexCoord[stage] );
+}
+
+inline Vector &TangentS( VertexDesc_t const &desc, int vert )
+{
+ return *(Vector*)((unsigned char*)desc.m_pTangentS + vert * desc.m_VertexSize_TangentS );
+}
+
+inline Vector &TangentT( VertexDesc_t const &desc, int vert )
+{
+ return *(Vector*)((unsigned char*)desc.m_pTangentT + vert * desc.m_VertexSize_TangentT );
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// Vertex Buffer implementations begin here
+//
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+CVertexBufferBase::CVertexBufferBase( const char *pBudgetGroupName )
+{
+ m_pBudgetGroupName = pBudgetGroupName;
+}
+
+CVertexBufferBase::~CVertexBufferBase()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Displays the vertex format
+//-----------------------------------------------------------------------------
+void CVertexBufferBase::PrintVertexFormat( VertexFormat_t vertexFormat )
+{
+ VertexCompressionType_t compression = CompressionType( vertexFormat );
+ if( vertexFormat & VERTEX_POSITION )
+ {
+ Msg( "VERTEX_POSITION|" );
+ }
+ if( vertexFormat & VERTEX_NORMAL )
+ {
+ // FIXME: genericise this stuff using VertexElement_t data tables (so funcs like 'just work' if we make compression changes)
+ if ( compression == VERTEX_COMPRESSION_ON )
+ Msg( "VERTEX_NORMAL|" );
+ else
+ Msg( "VERTEX_NORMAL[COMPRESSED]|" );
+ }
+ if( vertexFormat & VERTEX_COLOR )
+ {
+ Msg( "VERTEX_COLOR|" );
+ }
+ if( vertexFormat & VERTEX_SPECULAR )
+ {
+ Msg( "VERTEX_SPECULAR|" );
+ }
+ if( vertexFormat & VERTEX_TANGENT_S )
+ {
+ Msg( "VERTEX_TANGENT_S|" );
+ }
+ if( vertexFormat & VERTEX_TANGENT_T )
+ {
+ Msg( "VERTEX_TANGENT_T|" );
+ }
+ if( vertexFormat & VERTEX_BONE_INDEX )
+ {
+ Msg( "VERTEX_BONE_INDEX|" );
+ }
+ if( vertexFormat & VERTEX_FORMAT_VERTEX_SHADER )
+ {
+ Msg( "VERTEX_FORMAT_VERTEX_SHADER|" );
+ }
+ if( NumBoneWeights( vertexFormat ) > 0 )
+ {
+ Msg( "VERTEX_BONEWEIGHT(%d)%s|",
+ NumBoneWeights( vertexFormat ), ( compression ? "[COMPRESSED]" : "" ) );
+ }
+ if( UserDataSize( vertexFormat ) > 0 )
+ {
+ Msg( "VERTEX_USERDATA_SIZE(%d)|", UserDataSize( vertexFormat ) );
+ }
+ int i;
+ for( i = 0; i < VERTEX_MAX_TEXTURE_COORDINATES; i++ )
+ {
+ int nDim = TexCoordSize( i, vertexFormat );
+ if ( nDim == 0 )
+ continue;
+
+ Msg( "VERTEX_TEXCOORD_SIZE(%d,%d)", i, nDim );
+ }
+ Msg( "\n" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Used to construct vertex data
+//-----------------------------------------------------------------------------
+void CVertexBufferBase::ComputeVertexDescription( unsigned char *pBuffer,
+ VertexFormat_t vertexFormat, VertexDesc_t &desc )
+{
+ ComputeVertexDesc( pBuffer, vertexFormat, desc );
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the vertex format size
+//-----------------------------------------------------------------------------
+int CVertexBufferBase::VertexFormatSize( VertexFormat_t vertexFormat )
+{
+ // FIXME: We could make this much faster
+ MeshDesc_t temp;
+ ComputeVertexDescription( 0, vertexFormat, temp );
+ return temp.m_ActualVertexSize;
+}
+
+
+//-----------------------------------------------------------------------------
+// Spews the mesh data
+//-----------------------------------------------------------------------------
+void CVertexBufferBase::Spew( int nVertexCount, const VertexDesc_t &desc )
+{
+ LOCK_SHADERAPI();
+
+ char pTempBuf[1024];
+ Q_snprintf( pTempBuf, sizeof(pTempBuf), "\nVerts %d (First %d, Offset %d) :\n", nVertexCount, desc.m_nFirstVertex, desc.m_nOffset );
+ Warning( "%s", pTempBuf );
+
+ Assert( ( desc.m_NumBoneWeights == 2 ) || ( desc.m_NumBoneWeights == 0 ) );
+
+ int nLen = 0;
+ int nBoneWeightCount = desc.m_NumBoneWeights;
+ for ( int i = 0; i < nVertexCount; ++i )
+ {
+ nLen += Q_snprintf( &pTempBuf[nLen], sizeof(pTempBuf) - nLen, "[%4d] ", i + desc.m_nFirstVertex );
+ if ( desc.m_VertexSize_Position )
+ {
+ Vector &pos = Position( desc, i );
+ nLen += Q_snprintf( &pTempBuf[nLen], sizeof(pTempBuf) - nLen, "P %8.2f %8.2f %8.2f ",
+ pos[0], pos[1], pos[2]);
+ }
+
+ if ( desc.m_VertexSize_Wrinkle )
+ {
+ float flWrinkle = Wrinkle( desc, i );
+ nLen += Q_snprintf( &pTempBuf[nLen], sizeof(pTempBuf) - nLen, "Wr %8.2f ",flWrinkle );
+ }
+
+ if ( nBoneWeightCount )
+ {
+ nLen += Q_snprintf( &pTempBuf[nLen], sizeof(pTempBuf) - nLen, "BW ");
+ float* pWeight = BoneWeight( desc, i );
+ for ( int j = 0; j < nBoneWeightCount; ++j )
+ {
+ nLen += Q_snprintf( &pTempBuf[nLen], sizeof(pTempBuf) - nLen, "%1.2f ", pWeight[j] );
+ }
+ }
+ if ( desc.m_VertexSize_BoneMatrixIndex )
+ {
+ unsigned char *pIndex = BoneIndex( desc, i );
+ nLen += Q_snprintf( &pTempBuf[nLen], sizeof(pTempBuf) - nLen, "BI %d %d %d %d ", ( int )pIndex[0], ( int )pIndex[1], ( int )pIndex[2], ( int )pIndex[3] );
+ Assert( pIndex[0] >= 0 && pIndex[0] < 16 );
+ Assert( pIndex[1] >= 0 && pIndex[1] < 16 );
+ Assert( pIndex[2] >= 0 && pIndex[2] < 16 );
+ Assert( pIndex[3] >= 0 && pIndex[3] < 16 );
+ }
+
+ if ( desc.m_VertexSize_Normal )
+ {
+ Vector & normal = Normal( desc, i );
+ nLen += Q_snprintf( &pTempBuf[nLen], sizeof(pTempBuf) - nLen, "N %1.2f %1.2f %1.2f ",
+ normal[0], normal[1], normal[2]);
+ }
+
+ if ( desc.m_VertexSize_Color )
+ {
+ unsigned char* pColor = Color( desc, i );
+ nLen += Q_snprintf( &pTempBuf[nLen], sizeof(pTempBuf) - nLen, "C b %3d g %3d r %3d a %3d ",
+ pColor[0], pColor[1], pColor[2], pColor[3]);
+ }
+
+ for ( int j = 0; j < VERTEX_MAX_TEXTURE_COORDINATES; ++j )
+ {
+ if ( desc.m_VertexSize_TexCoord[j] )
+ {
+ Vector2D& texcoord = TexCoord( desc, i, j );
+ nLen += Q_snprintf( &pTempBuf[nLen], sizeof(pTempBuf) - nLen, "T%d %.2f %.2f ", j,texcoord[0], texcoord[1]);
+ }
+ }
+
+ if ( desc.m_VertexSize_TangentS )
+ {
+ Vector& tangentS = TangentS( desc, i );
+ nLen += Q_snprintf( &pTempBuf[nLen], sizeof(pTempBuf) - nLen, "S %1.2f %1.2f %1.2f ",
+ tangentS[0], tangentS[1], tangentS[2]);
+ }
+
+ if ( desc.m_VertexSize_TangentT )
+ {
+ Vector& tangentT = TangentT( desc, i );
+ nLen += Q_snprintf( &pTempBuf[nLen], sizeof(pTempBuf) - nLen, "T %1.2f %1.2f %1.2f ",
+ tangentT[0], tangentT[1], tangentT[2]);
+ }
+
+ Q_snprintf( &pTempBuf[nLen], sizeof(pTempBuf) - nLen, "\n" );
+ Warning( "%s", pTempBuf );
+ nLen = 0;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Validates vertex buffer data
+//-----------------------------------------------------------------------------
+void CVertexBufferBase::ValidateData( int nVertexCount, const VertexDesc_t &spewDesc )
+{
+ LOCK_SHADERAPI();
+#ifdef VALIDATE_DEBUG
+ int i;
+
+ // This is needed so buffering can just use this
+ VertexFormat_t fmt = m_pMaterial->GetVertexUsage();
+
+ // Set up the vertex descriptor
+ VertexDesc_t desc = spewDesc;
+
+ int numBoneWeights = NumBoneWeights( fmt );
+ for ( i = 0; i < nVertexCount; ++i )
+ {
+ if( fmt & VERTEX_POSITION )
+ {
+ D3DXVECTOR3& pos = Position( desc, i );
+ Assert( IsFinite( pos[0] ) && IsFinite( pos[1] ) && IsFinite( pos[2] ) );
+ }
+ if( fmt & VERTEX_WRINKLE )
+ {
+ float flWrinkle = Wrinkle( desc, i );
+ Assert( IsFinite( flWrinkle ) );
+ }
+ if (numBoneWeights > 0)
+ {
+ float* pWeight = BoneWeight( desc, i );
+ for (int j = 0; j < numBoneWeights; ++j)
+ {
+ Assert( pWeight[j] >= 0.0f && pWeight[j] <= 1.0f );
+ }
+ }
+ if( fmt & VERTEX_BONE_INDEX )
+ {
+ unsigned char *pIndex = BoneIndex( desc, i );
+ Assert( pIndex[0] >= 0 && pIndex[0] < 16 );
+ Assert( pIndex[1] >= 0 && pIndex[1] < 16 );
+ Assert( pIndex[2] >= 0 && pIndex[2] < 16 );
+ Assert( pIndex[3] >= 0 && pIndex[3] < 16 );
+ }
+ if( fmt & VERTEX_NORMAL )
+ {
+ D3DXVECTOR3& normal = Normal( desc, i );
+ Assert( normal[0] >= -1.05f && normal[0] <= 1.05f );
+ Assert( normal[1] >= -1.05f && normal[1] <= 1.05f );
+ Assert( normal[2] >= -1.05f && normal[2] <= 1.05f );
+ }
+
+ if (fmt & VERTEX_COLOR)
+ {
+ int* pColor = (int*)Color( desc, i );
+ Assert( *pColor != FLOAT32_NAN_BITS );
+ }
+
+ for (int j = 0; j < VERTEX_MAX_TEXTURE_COORDINATES; ++j)
+ {
+ if( TexCoordSize( j, fmt ) > 0)
+ {
+ D3DXVECTOR2& texcoord = TexCoord( desc, i, j );
+ Assert( IsFinite( texcoord[0] ) && IsFinite( texcoord[1] ) );
+ }
+ }
+
+ if (fmt & VERTEX_TANGENT_S)
+ {
+ D3DXVECTOR3& tangentS = TangentS( desc, i );
+ Assert( IsFinite( tangentS[0] ) && IsFinite( tangentS[1] ) && IsFinite( tangentS[2] ) );
+ }
+
+ if (fmt & VERTEX_TANGENT_T)
+ {
+ D3DXVECTOR3& tangentT = TangentT( desc, i );
+ Assert( IsFinite( tangentT[0] ) && IsFinite( tangentT[1] ) && IsFinite( tangentT[2] ) );
+ }
+ }
+#endif // _DEBUG
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// Index Buffer implementations begin here
+//
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+CIndexBufferBase::CIndexBufferBase( const char *pBudgetGroupName ) : m_pBudgetGroupName( pBudgetGroupName )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Spews the mesh data
+//-----------------------------------------------------------------------------
+void CIndexBufferBase::Spew( int nIndexCount, const IndexDesc_t &indexDesc )
+{
+ LOCK_SHADERAPI();
+
+ char pTempBuf[512];
+ int nLen = 0;
+ pTempBuf[0] = '\0';
+ char *pTemp = pTempBuf;
+ Q_snprintf( pTempBuf, sizeof(pTempBuf), "\nIndices: %d (First %d, Offset %d)\n", nIndexCount, indexDesc.m_nFirstIndex, indexDesc.m_nOffset );
+ Warning( "%s", pTempBuf );
+ for ( int i = 0; i < nIndexCount; ++i )
+ {
+ nLen += Q_snprintf( pTemp, sizeof(pTempBuf) - nLen - 1, "%d ", ( int )indexDesc.m_pIndices[i] );
+ pTemp = pTempBuf + nLen;
+ if ( (i & 0x0F) == 0x0F )
+ {
+ Q_snprintf( pTemp, sizeof(pTempBuf) - nLen - 1, "\n" );
+ Warning( "%s", pTempBuf );
+ pTempBuf[0] = '\0';
+ nLen = 0;
+ pTemp = pTempBuf;
+ }
+ }
+ Q_snprintf( pTemp, sizeof(pTempBuf) - nLen - 1, "\n" );
+ Warning( "%s", pTempBuf );
+}
+
+
+//-----------------------------------------------------------------------------
+// Call this in debug mode to make sure our data is good.
+//-----------------------------------------------------------------------------
+void CIndexBufferBase::ValidateData( int nIndexCount, const IndexDesc_t& desc )
+{
+ /* FIXME */
+ // NOTE: Is there anything reasonable to do here at all?
+ // Or is this a bogus method altogether?
+}
+
+
+
+//-----------------------------------------------------------------------------
+//
+// Base mesh
+//
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+CMeshBase::CMeshBase()
+{
+}
+
+CMeshBase::~CMeshBase()
+{
+}
diff --git a/materialsystem/shaderapidx9/meshbase.h b/materialsystem/shaderapidx9/meshbase.h
new file mode 100644
index 0000000..b566099
--- /dev/null
+++ b/materialsystem/shaderapidx9/meshbase.h
@@ -0,0 +1,309 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#ifndef MESHBASE_H
+#define MESHBASE_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "materialsystem/imesh.h"
+#include "materialsystem/imaterial.h"
+
+
+//-----------------------------------------------------------------------------
+// Base vertex buffer
+//-----------------------------------------------------------------------------
+abstract_class CVertexBufferBase : public IVertexBuffer
+{
+ // Methods of IVertexBuffer
+public:
+ virtual void Spew( int nVertexCount, const VertexDesc_t &desc );
+ virtual void ValidateData( int nVertexCount, const VertexDesc_t& desc );
+
+public:
+ // constructor, destructor
+ CVertexBufferBase( const char *pBudgetGroupName );
+ virtual ~CVertexBufferBase();
+
+ // Displays the vertex format
+ static void PrintVertexFormat( VertexFormat_t vertexFormat );
+
+ // Used to construct vertex data
+ static void ComputeVertexDescription( unsigned char *pBuffer, VertexFormat_t vertexFormat, VertexDesc_t &desc );
+
+ // Returns the vertex format size
+ static int VertexFormatSize( VertexFormat_t vertexFormat );
+
+protected:
+ const char *m_pBudgetGroupName;
+};
+
+
+//-----------------------------------------------------------------------------
+// Base index buffer
+//-----------------------------------------------------------------------------
+abstract_class CIndexBufferBase : public IIndexBuffer
+{
+ // Methods of IIndexBuffer
+public:
+ virtual void Spew( int nIndexCount, const IndexDesc_t &desc );
+ virtual void ValidateData( int nIndexCount, const IndexDesc_t& desc );
+
+ // Other public methods
+public:
+ // constructor, destructor
+ CIndexBufferBase( const char *pBudgetGroupName );
+ virtual ~CIndexBufferBase() {}
+
+protected:
+ const char *m_pBudgetGroupName;
+};
+
+
+//-----------------------------------------------------------------------------
+// Base mesh
+//-----------------------------------------------------------------------------
+class CMeshBase : public IMesh
+{
+ // Methods of IMesh
+public:
+
+ // Other public methods that need to be overridden
+public:
+ // Begins a pass
+ virtual void BeginPass( ) = 0;
+
+ // Draws a single pass of the mesh
+ virtual void RenderPass() = 0;
+
+ // Does it have a color mesh?
+ virtual bool HasColorMesh() const = 0;
+
+ // Am I using morph data?
+ virtual bool IsUsingMorphData() const = 0;
+
+ virtual bool HasFlexMesh() const = 0;
+
+ virtual IMesh *GetMesh() { return this; }
+
+public:
+ // constructor, destructor
+ CMeshBase();
+ virtual ~CMeshBase();
+
+};
+
+//-----------------------------------------------------------------------------
+// Utility method for VertexDesc_t (don't want to expose it in public, in imesh.h)
+//-----------------------------------------------------------------------------
+inline void ComputeVertexDesc( unsigned char * pBuffer, VertexFormat_t vertexFormat, VertexDesc_t & desc )
+{
+ int i;
+ int *pVertexSizesToSet[64];
+ int nVertexSizesToSet = 0;
+ static ALIGN32 ModelVertexDX8_t temp[4];
+ float *dummyData = (float*)&temp; // should be larger than any CMeshBuilder command can set.
+
+ // Determine which vertex compression type this format specifies (affects element sizes/decls):
+ VertexCompressionType_t compression = CompressionType( vertexFormat );
+ desc.m_CompressionType = compression;
+
+ // We use fvf instead of flags here because we may pad out the fvf
+ // vertex structure to optimize performance
+ int offset = 0;
+ // NOTE: At the moment, we assume that if you specify wrinkle, you also specify position
+ Assert( ( ( vertexFormat & VERTEX_WRINKLE ) == 0 ) || ( ( vertexFormat & VERTEX_POSITION ) != 0 ) );
+ if ( vertexFormat & VERTEX_POSITION )
+ {
+ // UNDONE: compress position+wrinkle to SHORT4N, and roll the scale into the transform matrices
+ desc.m_pPosition = reinterpret_cast<float*>(pBuffer);
+ offset += GetVertexElementSize( VERTEX_ELEMENT_POSITION, compression );
+ pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_Position;
+
+ if ( vertexFormat & VERTEX_WRINKLE )
+ {
+ desc.m_pWrinkle = reinterpret_cast<float*>( pBuffer + offset );
+ offset += GetVertexElementSize( VERTEX_ELEMENT_WRINKLE, compression );
+ pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_Wrinkle;
+ }
+ else
+ {
+ desc.m_pWrinkle = dummyData;
+ desc.m_VertexSize_Wrinkle = 0;
+ }
+ }
+ else
+ {
+ desc.m_pPosition = dummyData;
+ desc.m_VertexSize_Position = 0;
+ desc.m_pWrinkle = dummyData;
+ desc.m_VertexSize_Wrinkle = 0;
+ }
+
+ // Bone weights/matrix indices
+ desc.m_NumBoneWeights = NumBoneWeights( vertexFormat );
+
+ Assert( ( desc.m_NumBoneWeights == 2 ) || ( desc.m_NumBoneWeights == 0 ) );
+
+ // We assume that if you have any indices/weights, you have exactly two of them
+ Assert( ( ( desc.m_NumBoneWeights == 2 ) && ( ( vertexFormat & VERTEX_BONE_INDEX ) != 0 ) ) ||
+ ( ( desc.m_NumBoneWeights == 0 ) && ( ( vertexFormat & VERTEX_BONE_INDEX ) == 0 ) ) );
+
+ if ( ( vertexFormat & VERTEX_BONE_INDEX ) != 0 )
+ {
+ if ( desc.m_NumBoneWeights > 0 )
+ {
+ Assert( desc.m_NumBoneWeights == 2 );
+
+ // Always exactly two weights
+ desc.m_pBoneWeight = reinterpret_cast<float*>(pBuffer + offset);
+ offset += GetVertexElementSize( VERTEX_ELEMENT_BONEWEIGHTS2, compression );
+ pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_BoneWeight;
+ }
+ else
+ {
+ desc.m_pBoneWeight = dummyData;
+ desc.m_VertexSize_BoneWeight = 0;
+ }
+
+ desc.m_pBoneMatrixIndex = pBuffer + offset;
+ offset += GetVertexElementSize( VERTEX_ELEMENT_BONEINDEX, compression );
+ pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_BoneMatrixIndex;
+ }
+ else
+ {
+ desc.m_pBoneWeight = dummyData;
+ desc.m_VertexSize_BoneWeight = 0;
+
+ desc.m_pBoneMatrixIndex = (unsigned char*)dummyData;
+ desc.m_VertexSize_BoneMatrixIndex = 0;
+ }
+
+ if ( vertexFormat & VERTEX_NORMAL )
+ {
+ desc.m_pNormal = reinterpret_cast<float*>(pBuffer + offset);
+ // See PackNormal_[SHORT2|UBYTE4|HEND3N] in mathlib.h for the compression algorithm
+ offset += GetVertexElementSize( VERTEX_ELEMENT_NORMAL, compression );
+ pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_Normal;
+ }
+ else
+ {
+ desc.m_pNormal = dummyData;
+ desc.m_VertexSize_Normal = 0;
+ }
+
+ if ( vertexFormat & VERTEX_COLOR )
+ {
+ desc.m_pColor = pBuffer + offset;
+ offset += GetVertexElementSize( VERTEX_ELEMENT_COLOR, compression );
+ pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_Color;
+ }
+ else
+ {
+ desc.m_pColor = (unsigned char*)dummyData;
+ desc.m_VertexSize_Color = 0;
+ }
+
+ if ( vertexFormat & VERTEX_SPECULAR )
+ {
+ desc.m_pSpecular = pBuffer + offset;
+ offset += GetVertexElementSize( VERTEX_ELEMENT_SPECULAR, compression );
+ pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_Specular;
+ }
+ else
+ {
+ desc.m_pSpecular = (unsigned char*)dummyData;
+ desc.m_VertexSize_Specular = 0;
+ }
+
+ // Set up texture coordinates
+ for ( i = 0; i < VERTEX_MAX_TEXTURE_COORDINATES; ++i )
+ {
+ // FIXME: compress texcoords to SHORT2N/SHORT4N, with a scale rolled into the texture transform
+ VertexElement_t texCoordElements[4] = { VERTEX_ELEMENT_TEXCOORD1D_0, VERTEX_ELEMENT_TEXCOORD2D_0, VERTEX_ELEMENT_TEXCOORD3D_0, VERTEX_ELEMENT_TEXCOORD4D_0 };
+ int nSize = TexCoordSize( i, vertexFormat );
+ if ( nSize != 0 )
+ {
+ desc.m_pTexCoord[i] = reinterpret_cast<float*>(pBuffer + offset);
+ VertexElement_t texCoordElement = (VertexElement_t)( texCoordElements[ nSize - 1 ] + i );
+ offset += GetVertexElementSize( texCoordElement, compression );
+ pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_TexCoord[i];
+ }
+ else
+ {
+ desc.m_pTexCoord[i] = dummyData;
+ desc.m_VertexSize_TexCoord[i] = 0;
+ }
+ }
+
+ // Binormal + tangent...
+ // Note we have to put these at the end so the vertex is FVF + stuff at end
+ if ( vertexFormat & VERTEX_TANGENT_S )
+ {
+ // UNDONE: use normal compression here (use mem_dumpvballocs to see if this uses much memory)
+ desc.m_pTangentS = reinterpret_cast<float*>(pBuffer + offset);
+ offset += GetVertexElementSize( VERTEX_ELEMENT_TANGENT_S, compression );
+ pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_TangentS;
+ }
+ else
+ {
+ desc.m_pTangentS = dummyData;
+ desc.m_VertexSize_TangentS = 0;
+ }
+
+ if ( vertexFormat & VERTEX_TANGENT_T )
+ {
+ // UNDONE: use normal compression here (use mem_dumpvballocs to see if this uses much memory)
+ desc.m_pTangentT = reinterpret_cast<float*>(pBuffer + offset);
+ offset += GetVertexElementSize( VERTEX_ELEMENT_TANGENT_T, compression );
+ pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_TangentT;
+ }
+ else
+ {
+ desc.m_pTangentT = dummyData;
+ desc.m_VertexSize_TangentT = 0;
+ }
+
+ // User data..
+ int userDataSize = UserDataSize( vertexFormat );
+ if ( userDataSize > 0 )
+ {
+ desc.m_pUserData = reinterpret_cast<float*>(pBuffer + offset);
+ VertexElement_t userDataElement = (VertexElement_t)( VERTEX_ELEMENT_USERDATA1 + ( userDataSize - 1 ) );
+ // See PackNormal_[SHORT2|UBYTE4|HEND3N] in mathlib.h for the compression algorithm
+ offset += GetVertexElementSize( userDataElement, compression );
+
+ pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_UserData;
+ }
+ else
+ {
+ desc.m_pUserData = dummyData;
+ desc.m_VertexSize_UserData = 0;
+ }
+
+ // We always use vertex sizes which are half-cache aligned (16 bytes)
+ // x360 compressed vertexes are not compatible with forced alignments
+ bool bCacheAlign = ( vertexFormat & VERTEX_FORMAT_USE_EXACT_FORMAT ) == 0;
+ if ( bCacheAlign && ( offset > 16 ) && IsPC() )
+ {
+ offset = (offset + 0xF) & (~0xF);
+ }
+ desc.m_ActualVertexSize = offset;
+
+ // Now set the m_VertexSize for all the members that were actually valid.
+ Assert( nVertexSizesToSet < sizeof(pVertexSizesToSet)/sizeof(pVertexSizesToSet[0]) );
+ for ( int iElement=0; iElement < nVertexSizesToSet; iElement++ )
+ {
+ *pVertexSizesToSet[iElement] = offset;
+ }
+}
+
+#endif // MESHBASE_H
diff --git a/materialsystem/shaderapidx9/meshdx10.cpp b/materialsystem/shaderapidx9/meshdx10.cpp
new file mode 100644
index 0000000..b1a892c
--- /dev/null
+++ b/materialsystem/shaderapidx9/meshdx10.cpp
@@ -0,0 +1,775 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#include <d3d10.h>
+#undef GetCommandLine
+
+#include "meshdx10.h"
+#include "utlvector.h"
+#include "materialsystem/imaterialsystem.h"
+#include "IHardwareConfigInternal.h"
+#include "shaderapi_global.h"
+#include "shaderapi/ishaderutil.h"
+#include "shaderapi/ishaderapi.h"
+#include "shaderdevicedx10.h"
+#include "materialsystem/imesh.h"
+#include "tier0/vprof.h"
+#include "tier0/dbg.h"
+#include "materialsystem/idebugtextureinfo.h"
+#include "materialsystem/ivballoctracker.h"
+#include "tier2/tier2.h"
+
+
+//-----------------------------------------------------------------------------
+//
+// Dx10 implementation of a vertex buffer
+//
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// globals
+//-----------------------------------------------------------------------------
+#ifdef _DEBUG
+int CVertexBufferDx10::s_nBufferCount = 0;
+#endif
+
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+CVertexBufferDx10::CVertexBufferDx10( ShaderBufferType_t type, VertexFormat_t fmt, int nVertexCount, const char *pBudgetGroupName ) :
+ BaseClass( pBudgetGroupName )
+{
+ Assert( nVertexCount != 0 );
+
+ m_pVertexBuffer = NULL;
+ m_VertexFormat = fmt;
+ m_nVertexCount = ( fmt == VERTEX_FORMAT_UNKNOWN ) ? 0 : nVertexCount;
+ m_nBufferSize = ( fmt == VERTEX_FORMAT_UNKNOWN ) ? nVertexCount : nVertexCount * VertexSize();
+ m_nFirstUnwrittenOffset = 0;
+ m_bIsLocked = false;
+ m_bIsDynamic = ( type == SHADER_BUFFER_TYPE_DYNAMIC ) || ( type == SHADER_BUFFER_TYPE_DYNAMIC_TEMP );
+ m_bFlush = false;
+}
+
+CVertexBufferDx10::~CVertexBufferDx10()
+{
+ Free();
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates, destroys the vertex buffer
+//-----------------------------------------------------------------------------
+bool CVertexBufferDx10::Allocate( )
+{
+ Assert( !m_pVertexBuffer );
+
+ m_nFirstUnwrittenOffset = 0;
+
+ D3D10_BUFFER_DESC bd;
+ bd.Usage = D3D10_USAGE_DYNAMIC;
+ bd.ByteWidth = m_nBufferSize;
+ bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
+ bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
+ bd.MiscFlags = 0;
+
+ HRESULT hr = D3D10Device()->CreateBuffer( &bd, NULL, &m_pVertexBuffer );
+ bool bOk = !FAILED( hr ) && ( m_pVertexBuffer != 0 );
+
+ if ( bOk )
+ {
+ // Track VB allocations
+ g_VBAllocTracker->CountVB( m_pVertexBuffer, m_bIsDynamic, m_nBufferSize, VertexSize(), GetVertexFormat() );
+
+ if ( !m_bIsDynamic )
+ {
+ VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_global_" TEXTURE_GROUP_STATIC_INDEX_BUFFER,
+ COUNTER_GROUP_TEXTURE_GLOBAL, m_nBufferSize );
+ }
+ else
+ {
+ VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_global_" TEXTURE_GROUP_DYNAMIC_INDEX_BUFFER,
+ COUNTER_GROUP_TEXTURE_GLOBAL, m_nBufferSize );
+ // Dynamic meshes should never be compressed (slows down writing to them)
+ Assert( CompressionType( GetVertexFormat() ) == VERTEX_COMPRESSION_NONE );
+ }
+#ifdef _DEBUG
+ ++s_nBufferCount;
+#endif
+ }
+
+ return bOk;
+}
+
+void CVertexBufferDx10::Free()
+{
+ if ( m_pVertexBuffer )
+ {
+#ifdef _DEBUG
+ --s_nBufferCount;
+#endif
+
+ // Track VB allocations
+ g_VBAllocTracker->UnCountVB( m_pVertexBuffer );
+
+ m_pVertexBuffer->Release();
+ m_pVertexBuffer = NULL;
+
+ if ( !m_bIsDynamic )
+ {
+ VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_global_" TEXTURE_GROUP_STATIC_INDEX_BUFFER,
+ COUNTER_GROUP_TEXTURE_GLOBAL, - m_nBufferSize );
+ }
+ else
+ {
+ VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_global_" TEXTURE_GROUP_DYNAMIC_INDEX_BUFFER,
+ COUNTER_GROUP_TEXTURE_GLOBAL, - m_nBufferSize );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Vertex Buffer info
+//-----------------------------------------------------------------------------
+int CVertexBufferDx10::VertexCount() const
+{
+ Assert( !m_bIsDynamic );
+ return m_nVertexCount;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the buffer format (only valid for static index buffers)
+//-----------------------------------------------------------------------------
+VertexFormat_t CVertexBufferDx10::GetVertexFormat() const
+{
+ Assert( !m_bIsDynamic );
+ return m_VertexFormat;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns true if the buffer is dynamic
+//-----------------------------------------------------------------------------
+bool CVertexBufferDx10::IsDynamic() const
+{
+ return m_bIsDynamic;
+}
+
+
+//-----------------------------------------------------------------------------
+// Only used by dynamic buffers, indicates the next lock should perform a discard.
+//-----------------------------------------------------------------------------
+void CVertexBufferDx10::Flush()
+{
+ // This strange-looking line makes a flush only occur if the buffer is dynamic.
+ m_bFlush = m_bIsDynamic;
+}
+
+
+//-----------------------------------------------------------------------------
+// Casts a dynamic buffer to be a particular vertex type
+//-----------------------------------------------------------------------------
+void CVertexBufferDx10::BeginCastBuffer( VertexFormat_t format )
+{
+ Assert( format != MATERIAL_INDEX_FORMAT_UNKNOWN );
+ Assert( m_bIsDynamic && ( m_VertexFormat == 0 || m_VertexFormat == format ) );
+ if ( !m_bIsDynamic )
+ return;
+
+ m_VertexFormat = format;
+ m_nVertexCount = m_nBufferSize / VertexSize();
+}
+
+void CVertexBufferDx10::EndCastBuffer( )
+{
+ Assert( m_bIsDynamic && m_VertexFormat != 0 );
+ if ( !m_bIsDynamic )
+ return;
+ m_VertexFormat = 0;
+ m_nVertexCount = 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the number of indices that can be written into the buffer
+//-----------------------------------------------------------------------------
+int CVertexBufferDx10::GetRoomRemaining() const
+{
+ return ( m_nBufferSize - m_nFirstUnwrittenOffset ) / VertexSize();
+}
+
+
+//-----------------------------------------------------------------------------
+// Lock, unlock
+//-----------------------------------------------------------------------------
+bool CVertexBufferDx10::Lock( int nMaxVertexCount, bool bAppend, VertexDesc_t &desc )
+{
+ Assert( !m_bIsLocked && ( nMaxVertexCount != 0 ) && ( nMaxVertexCount <= m_nVertexCount ) );
+ Assert( m_VertexFormat != 0 );
+
+ // FIXME: Why do we need to sync matrices now?
+ ShaderUtil()->SyncMatrices();
+ g_ShaderMutex.Lock();
+
+ void *pLockedData = NULL;
+ HRESULT hr;
+
+ // This can happen if the buffer was locked but a type wasn't bound
+ if ( m_VertexFormat == 0 )
+ goto vertexBufferLockFailed;
+
+ // Just give the app crap buffers to fill up while we're suppressed...
+ if ( g_pShaderDevice->IsDeactivated() || ( nMaxVertexCount == 0 ) )
+ goto vertexBufferLockFailed;
+
+ // Did we ask for something too large?
+ if ( nMaxVertexCount > m_nVertexCount )
+ {
+ Warning( "Too many vertices for vertex buffer. . tell a programmer (%d>%d)\n", nMaxVertexCount, m_nVertexCount );
+ goto vertexBufferLockFailed;
+ }
+
+ // We might not have a buffer owing to alt-tab type stuff
+ if ( !m_pVertexBuffer )
+ {
+ if ( !Allocate() )
+ goto vertexBufferLockFailed;
+ }
+
+ // Check to see if we have enough memory
+ int nMemoryRequired = nMaxVertexCount * VertexSize();
+ bool bHasEnoughMemory = ( m_nFirstUnwrittenOffset + nMemoryRequired <= m_nBufferSize );
+
+ D3D10_MAP map;
+ if ( bAppend )
+ {
+ // Can't have the first lock after a flush be an appending lock
+ Assert( !m_bFlush );
+
+ // If we're appending and we don't have enough room, then puke!
+ if ( !bHasEnoughMemory || m_bFlush )
+ goto vertexBufferLockFailed;
+ map = ( m_nFirstUnwrittenOffset == 0 ) ? D3D10_MAP_WRITE_DISCARD : D3D10_MAP_WRITE_NO_OVERWRITE;
+ }
+ else
+ {
+ // If we're not appending, no overwrite unless we don't have enough room
+ // If we're a static buffer, always discard if we're not appending
+ if ( !m_bFlush && bHasEnoughMemory && m_bIsDynamic )
+ {
+ map = ( m_nFirstUnwrittenOffset == 0 ) ? D3D10_MAP_WRITE_DISCARD : D3D10_MAP_WRITE_NO_OVERWRITE;
+ }
+ else
+ {
+ map = D3D10_MAP_WRITE_DISCARD;
+ m_nFirstUnwrittenOffset = 0;
+ m_bFlush = false;
+ }
+ }
+
+ hr = m_pVertexBuffer->Map( map, 0, &pLockedData );
+ if ( FAILED( hr ) )
+ {
+ Warning( "Failed to lock vertex buffer in CVertexBufferDx10::Lock\n" );
+ goto vertexBufferLockFailed;
+ }
+
+ ComputeVertexDescription( (unsigned char*)pLockedData + m_nFirstUnwrittenOffset, m_VertexFormat, desc );
+ desc.m_nFirstVertex = 0;
+ desc.m_nOffset = m_nFirstUnwrittenOffset;
+ m_bIsLocked = true;
+ return true;
+
+vertexBufferLockFailed:
+ g_ShaderMutex.Unlock();
+
+ // Set up a bogus index descriptor
+ ComputeVertexDescription( 0, 0, desc );
+ desc.m_nFirstVertex = 0;
+ desc.m_nOffset = 0;
+ return false;
+}
+
+void CVertexBufferDx10::Unlock( int nWrittenVertexCount, VertexDesc_t &desc )
+{
+ Assert( nWrittenVertexCount <= m_nVertexCount );
+
+ // NOTE: This can happen if the lock occurs during alt-tab
+ // or if another application is initializing
+ if ( !m_bIsLocked )
+ return;
+
+ if ( m_pVertexBuffer )
+ {
+ m_pVertexBuffer->Unmap();
+ }
+
+ m_nFirstUnwrittenOffset += nWrittenVertexCount * VertexSize();
+ m_bIsLocked = false;
+ g_ShaderMutex.Unlock();
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// Dx10 implementation of an index buffer
+//
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// globals
+//-----------------------------------------------------------------------------
+
+// shove indices into this if you don't actually want indices
+static unsigned int s_nScratchIndexBuffer = 0;
+
+#ifdef _DEBUG
+int CIndexBufferDx10::s_nBufferCount = 0;
+#endif
+
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+CIndexBufferDx10::CIndexBufferDx10( ShaderBufferType_t type, MaterialIndexFormat_t fmt, int nIndexCount, const char *pBudgetGroupName ) :
+ BaseClass( pBudgetGroupName )
+{
+ Assert( nIndexCount != 0 );
+ Assert( IsDynamicBufferType( type ) || ( fmt != MATERIAL_INDEX_FORMAT_UNKNOWN ) );
+
+ m_pIndexBuffer = NULL;
+ m_IndexFormat = fmt;
+ m_nIndexCount = ( fmt == MATERIAL_INDEX_FORMAT_UNKNOWN ) ? 0 : nIndexCount;
+ m_nBufferSize = ( fmt == MATERIAL_INDEX_FORMAT_UNKNOWN ) ? nIndexCount : nIndexCount * IndexSize();
+ m_nFirstUnwrittenOffset = 0;
+ m_bIsLocked = false;
+ m_bIsDynamic = IsDynamicBufferType( type );
+ m_bFlush = false;
+
+ // NOTE: This has to happen at the end since m_IndexFormat must be valid for IndexSize() to work
+ if ( m_bIsDynamic )
+ {
+ m_IndexFormat = MATERIAL_INDEX_FORMAT_UNKNOWN;
+ m_nIndexCount = 0;
+ }
+}
+
+CIndexBufferDx10::~CIndexBufferDx10()
+{
+ Free();
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates, destroys the index buffer
+//-----------------------------------------------------------------------------
+bool CIndexBufferDx10::Allocate( )
+{
+ Assert( !m_pIndexBuffer );
+
+ m_nFirstUnwrittenOffset = 0;
+
+ D3D10_BUFFER_DESC bd;
+ bd.Usage = D3D10_USAGE_DYNAMIC;
+ bd.ByteWidth = m_nBufferSize;
+ bd.BindFlags = D3D10_BIND_INDEX_BUFFER;
+ bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
+ bd.MiscFlags = 0;
+
+ HRESULT hr = D3D10Device()->CreateBuffer( &bd, NULL, &m_pIndexBuffer );
+ bool bOk = !FAILED( hr ) && ( m_pIndexBuffer != NULL );
+
+ if ( bOk )
+ {
+ if ( !m_bIsDynamic )
+ {
+ VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_global_" TEXTURE_GROUP_STATIC_INDEX_BUFFER,
+ COUNTER_GROUP_TEXTURE_GLOBAL, m_nBufferSize );
+ }
+ else
+ {
+ VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_global_" TEXTURE_GROUP_DYNAMIC_INDEX_BUFFER,
+ COUNTER_GROUP_TEXTURE_GLOBAL, m_nBufferSize );
+ }
+#ifdef _DEBUG
+ ++s_nBufferCount;
+#endif
+ }
+
+ return bOk;
+}
+
+void CIndexBufferDx10::Free()
+{
+ if ( m_pIndexBuffer )
+ {
+#ifdef _DEBUG
+ --s_nBufferCount;
+#endif
+
+ m_pIndexBuffer->Release();
+ m_pIndexBuffer = NULL;
+
+ if ( !m_bIsDynamic )
+ {
+ VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_global_" TEXTURE_GROUP_STATIC_INDEX_BUFFER,
+ COUNTER_GROUP_TEXTURE_GLOBAL, - m_nBufferSize );
+ }
+ else
+ {
+ VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_global_" TEXTURE_GROUP_DYNAMIC_INDEX_BUFFER,
+ COUNTER_GROUP_TEXTURE_GLOBAL, - m_nBufferSize );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the buffer size (only valid for static index buffers)
+//-----------------------------------------------------------------------------
+int CIndexBufferDx10::IndexCount() const
+{
+ Assert( !m_bIsDynamic );
+ return m_nIndexCount;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the buffer format (only valid for static index buffers)
+//-----------------------------------------------------------------------------
+MaterialIndexFormat_t CIndexBufferDx10::IndexFormat() const
+{
+ Assert( !m_bIsDynamic );
+ return m_IndexFormat;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns true if the buffer is dynamic
+//-----------------------------------------------------------------------------
+bool CIndexBufferDx10::IsDynamic() const
+{
+ return m_bIsDynamic;
+}
+
+
+//-----------------------------------------------------------------------------
+// Only used by dynamic buffers, indicates the next lock should perform a discard.
+//-----------------------------------------------------------------------------
+void CIndexBufferDx10::Flush()
+{
+ // This strange-looking line makes a flush only occur if the buffer is dynamic.
+ m_bFlush = m_bIsDynamic;
+}
+
+
+//-----------------------------------------------------------------------------
+// Casts a dynamic buffer to be a particular index type
+//-----------------------------------------------------------------------------
+void CIndexBufferDx10::BeginCastBuffer( MaterialIndexFormat_t format )
+{
+ Assert( format != MATERIAL_INDEX_FORMAT_UNKNOWN );
+ Assert( m_bIsDynamic && ( m_IndexFormat == MATERIAL_INDEX_FORMAT_UNKNOWN || m_IndexFormat == format ) );
+ if ( !m_bIsDynamic )
+ return;
+
+ m_IndexFormat = format;
+ m_nIndexCount = m_nBufferSize / IndexSize();
+}
+
+void CIndexBufferDx10::EndCastBuffer( )
+{
+ Assert( m_bIsDynamic && m_IndexFormat != MATERIAL_INDEX_FORMAT_UNKNOWN );
+ if ( !m_bIsDynamic )
+ return;
+ m_IndexFormat = MATERIAL_INDEX_FORMAT_UNKNOWN;
+ m_nIndexCount = 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the number of indices that can be written into the buffer
+//-----------------------------------------------------------------------------
+int CIndexBufferDx10::GetRoomRemaining() const
+{
+ return ( m_nBufferSize - m_nFirstUnwrittenOffset ) / IndexSize();
+}
+
+
+//-----------------------------------------------------------------------------
+// Locks, unlocks the mesh
+//-----------------------------------------------------------------------------
+bool CIndexBufferDx10::Lock( int nMaxIndexCount, bool bAppend, IndexDesc_t &desc )
+{
+ Assert( !m_bIsLocked && ( nMaxIndexCount != 0 ) && ( nMaxIndexCount <= m_nIndexCount ) );
+ Assert( m_IndexFormat != MATERIAL_INDEX_FORMAT_UNKNOWN );
+
+ // FIXME: Why do we need to sync matrices now?
+ ShaderUtil()->SyncMatrices();
+ g_ShaderMutex.Lock();
+
+ void *pLockedData = NULL;
+ HRESULT hr;
+
+ // This can happen if the buffer was locked but a type wasn't bound
+ if ( m_IndexFormat == MATERIAL_INDEX_FORMAT_UNKNOWN )
+ goto indexBufferLockFailed;
+
+ // Just give the app crap buffers to fill up while we're suppressed...
+ if ( g_pShaderDevice->IsDeactivated() || ( nMaxIndexCount == 0 ) )
+ goto indexBufferLockFailed;
+
+ // Did we ask for something too large?
+ if ( nMaxIndexCount > m_nIndexCount )
+ {
+ Warning( "Too many indices for index buffer. . tell a programmer (%d>%d)\n", nMaxIndexCount, m_nIndexCount );
+ goto indexBufferLockFailed;
+ }
+
+ // We might not have a buffer owing to alt-tab type stuff
+ if ( !m_pIndexBuffer )
+ {
+ if ( !Allocate() )
+ goto indexBufferLockFailed;
+ }
+
+ // Check to see if we have enough memory
+ int nMemoryRequired = nMaxIndexCount * IndexSize();
+ bool bHasEnoughMemory = ( m_nFirstUnwrittenOffset + nMemoryRequired <= m_nBufferSize );
+
+ D3D10_MAP map;
+ if ( bAppend )
+ {
+ // Can't have the first lock after a flush be an appending lock
+ Assert( !m_bFlush );
+
+ // If we're appending and we don't have enough room, then puke!
+ if ( !bHasEnoughMemory || m_bFlush )
+ goto indexBufferLockFailed;
+ map = ( m_nFirstUnwrittenOffset == 0 ) ? D3D10_MAP_WRITE_DISCARD : D3D10_MAP_WRITE_NO_OVERWRITE;
+ }
+ else
+ {
+ // If we're not appending, no overwrite unless we don't have enough room
+ if ( !m_bFlush && bHasEnoughMemory && m_bIsDynamic )
+ {
+ map = ( m_nFirstUnwrittenOffset == 0 ) ? D3D10_MAP_WRITE_DISCARD : D3D10_MAP_WRITE_NO_OVERWRITE;
+ }
+ else
+ {
+ map = D3D10_MAP_WRITE_DISCARD;
+ m_nFirstUnwrittenOffset = 0;
+ m_bFlush = false;
+ }
+ }
+
+ hr = m_pIndexBuffer->Map( map, 0, &pLockedData );
+ if ( FAILED( hr ) )
+ {
+ Warning( "Failed to lock index buffer in CIndexBufferDx10::Lock\n" );
+ goto indexBufferLockFailed;
+ }
+
+ desc.m_pIndices = (unsigned short*)( (unsigned char*)pLockedData + m_nFirstUnwrittenOffset );
+ desc.m_nIndexSize = IndexSize() >> 1;
+ desc.m_nFirstIndex = 0;
+ desc.m_nOffset = m_nFirstUnwrittenOffset;
+ m_bIsLocked = true;
+ return true;
+
+indexBufferLockFailed:
+ g_ShaderMutex.Unlock();
+
+ // Set up a bogus index descriptor
+ desc.m_pIndices = (unsigned short*)( &s_nScratchIndexBuffer );
+ desc.m_nFirstIndex = 0;
+ desc.m_nIndexSize = 0;
+ desc.m_nOffset = 0;
+ return false;
+}
+
+void CIndexBufferDx10::Unlock( int nWrittenIndexCount, IndexDesc_t &desc )
+{
+ Assert( nWrittenIndexCount <= m_nIndexCount );
+
+ // NOTE: This can happen if the lock occurs during alt-tab
+ // or if another application is initializing
+ if ( !m_bIsLocked )
+ return;
+
+ if ( m_pIndexBuffer )
+ {
+ m_pIndexBuffer->Unmap();
+ }
+
+ m_nFirstUnwrittenOffset += nWrittenIndexCount * IndexSize();
+ m_bIsLocked = false;
+ g_ShaderMutex.Unlock();
+}
+
+
+//-----------------------------------------------------------------------------
+// Locks, unlocks an existing mesh
+//-----------------------------------------------------------------------------
+void CIndexBufferDx10::ModifyBegin( bool bReadOnly, int nFirstIndex, int nIndexCount, IndexDesc_t& desc )
+{
+ Assert( 0 );
+}
+
+void CIndexBufferDx10::ModifyEnd( IndexDesc_t& desc )
+{
+
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// The empty mesh...
+//
+//-----------------------------------------------------------------------------
+CMeshDx10::CMeshDx10()
+{
+ m_pVertexMemory = new unsigned char[VERTEX_BUFFER_SIZE];
+}
+
+CMeshDx10::~CMeshDx10()
+{
+ delete[] m_pVertexMemory;
+}
+
+void CMeshDx10::LockMesh( int numVerts, int numIndices, MeshDesc_t& desc )
+{
+ // Who cares about the data?
+ desc.m_pPosition = (float*)m_pVertexMemory;
+ desc.m_pNormal = (float*)m_pVertexMemory;
+ desc.m_pColor = m_pVertexMemory;
+ int i;
+ for ( i = 0; i < VERTEX_MAX_TEXTURE_COORDINATES; ++i)
+ desc.m_pTexCoord[i] = (float*)m_pVertexMemory;
+ desc.m_pIndices = (unsigned short*)m_pVertexMemory;
+
+ desc.m_pBoneWeight = (float*)m_pVertexMemory;
+ desc.m_pBoneMatrixIndex = (unsigned char*)m_pVertexMemory;
+ desc.m_pTangentS = (float*)m_pVertexMemory;
+ desc.m_pTangentT = (float*)m_pVertexMemory;
+ desc.m_pUserData = (float*)m_pVertexMemory;
+ desc.m_NumBoneWeights = 2;
+
+ desc.m_VertexSize_Position = 0;
+ desc.m_VertexSize_BoneWeight = 0;
+ desc.m_VertexSize_BoneMatrixIndex = 0;
+ desc.m_VertexSize_Normal = 0;
+ desc.m_VertexSize_Color = 0;
+ for( i=0; i < VERTEX_MAX_TEXTURE_COORDINATES; i++ )
+ desc.m_VertexSize_TexCoord[i] = 0;
+ desc.m_VertexSize_TangentS = 0;
+ desc.m_VertexSize_TangentT = 0;
+ desc.m_VertexSize_UserData = 0;
+ desc.m_ActualVertexSize = 0; // Size of the vertices.. Some of the m_VertexSize_ elements above
+
+ desc.m_nFirstVertex = 0;
+ desc.m_nIndexSize = 0;
+}
+
+void CMeshDx10::UnlockMesh( int numVerts, int numIndices, MeshDesc_t& desc )
+{
+}
+
+void CMeshDx10::ModifyBeginEx( bool bReadOnly, int firstVertex, int numVerts, int firstIndex, int numIndices, MeshDesc_t& desc )
+{
+ // Who cares about the data?
+ desc.m_pPosition = (float*)m_pVertexMemory;
+ desc.m_pNormal = (float*)m_pVertexMemory;
+ desc.m_pColor = m_pVertexMemory;
+ int i;
+ for ( i = 0; i < VERTEX_MAX_TEXTURE_COORDINATES; ++i)
+ desc.m_pTexCoord[i] = (float*)m_pVertexMemory;
+ desc.m_pIndices = (unsigned short*)m_pVertexMemory;
+
+ desc.m_pBoneWeight = (float*)m_pVertexMemory;
+ desc.m_pBoneMatrixIndex = (unsigned char*)m_pVertexMemory;
+ desc.m_pTangentS = (float*)m_pVertexMemory;
+ desc.m_pTangentT = (float*)m_pVertexMemory;
+ desc.m_pUserData = (float*)m_pVertexMemory;
+ desc.m_NumBoneWeights = 2;
+
+ desc.m_VertexSize_Position = 0;
+ desc.m_VertexSize_BoneWeight = 0;
+ desc.m_VertexSize_BoneMatrixIndex = 0;
+ desc.m_VertexSize_Normal = 0;
+ desc.m_VertexSize_Color = 0;
+ for( i=0; i < VERTEX_MAX_TEXTURE_COORDINATES; i++ )
+ desc.m_VertexSize_TexCoord[i] = 0;
+ desc.m_VertexSize_TangentS = 0;
+ desc.m_VertexSize_TangentT = 0;
+ desc.m_VertexSize_UserData = 0;
+ desc.m_ActualVertexSize = 0; // Size of the vertices.. Some of the m_VertexSize_ elements above
+
+ desc.m_nFirstVertex = 0;
+ desc.m_nIndexSize = 0;
+}
+
+void CMeshDx10::ModifyBegin( int firstVertex, int numVerts, int firstIndex, int numIndices, MeshDesc_t& desc )
+{
+ ModifyBeginEx( false, firstVertex, numVerts, firstIndex, numIndices, desc );
+}
+
+void CMeshDx10::ModifyEnd( MeshDesc_t& desc )
+{
+}
+
+// returns the # of vertices (static meshes only)
+int CMeshDx10::VertexCount() const
+{
+ return 0;
+}
+
+// Sets the primitive type
+void CMeshDx10::SetPrimitiveType( MaterialPrimitiveType_t type )
+{
+}
+
+// Draws the entire mesh
+void CMeshDx10::Draw( int firstIndex, int numIndices )
+{
+}
+
+void CMeshDx10::Draw(CPrimList *pPrims, int nPrims)
+{
+}
+
+// Copy verts and/or indices to a mesh builder. This only works for temp meshes!
+void CMeshDx10::CopyToMeshBuilder(
+ int iStartVert, // Which vertices to copy.
+ int nVerts,
+ int iStartIndex, // Which indices to copy.
+ int nIndices,
+ int indexOffset, // This is added to each index.
+ CMeshBuilder &builder )
+{
+}
+
+// Spews the mesh data
+void CMeshDx10::Spew( int numVerts, int numIndices, const MeshDesc_t & desc )
+{
+}
+
+void CMeshDx10::ValidateData( int numVerts, int numIndices, const MeshDesc_t & desc )
+{
+}
+
+// gets the associated material
+IMaterial* CMeshDx10::GetMaterial()
+{
+ // umm. this don't work none
+ Assert(0);
+ return 0;
+}
diff --git a/materialsystem/shaderapidx9/meshdx10.h b/materialsystem/shaderapidx9/meshdx10.h
new file mode 100644
index 0000000..2279612
--- /dev/null
+++ b/materialsystem/shaderapidx9/meshdx10.h
@@ -0,0 +1,282 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+
+#ifndef MESHDX10_H
+#define MESHDX10_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "meshbase.h"
+#include "shaderapi/ishaderdevice.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declaration
+//-----------------------------------------------------------------------------
+struct ID3D10Buffer;
+
+
+//-----------------------------------------------------------------------------
+// Dx10 implementation of a vertex buffer
+//-----------------------------------------------------------------------------
+class CVertexBufferDx10 : public CVertexBufferBase
+{
+ typedef CVertexBufferBase BaseClass;
+
+ // Methods of IVertexBuffer
+public:
+ virtual int VertexCount() const;
+ virtual VertexFormat_t GetVertexFormat() const;
+ virtual bool Lock( int nMaxVertexCount, bool bAppend, VertexDesc_t &desc );
+ virtual void Unlock( int nWrittenVertexCount, VertexDesc_t &desc );
+ virtual bool IsDynamic() const;
+ virtual void BeginCastBuffer( VertexFormat_t format );
+ virtual void EndCastBuffer( );
+ virtual int GetRoomRemaining() const;
+
+ // Other public methods
+public:
+ // constructor, destructor
+ CVertexBufferDx10( ShaderBufferType_t type, VertexFormat_t fmt, int nVertexCount, const char *pBudgetGroupName );
+ virtual ~CVertexBufferDx10();
+
+ ID3D10Buffer* GetDx10Buffer() const;
+ int VertexSize() const;
+
+ // Only used by dynamic buffers, indicates the next lock should perform a discard.
+ void Flush();
+
+protected:
+ // Creates, destroys the index buffer
+ bool Allocate( );
+ void Free();
+
+ ID3D10Buffer *m_pVertexBuffer;
+ VertexFormat_t m_VertexFormat;
+ int m_nVertexCount;
+ int m_nBufferSize;
+ int m_nFirstUnwrittenOffset;
+ bool m_bIsLocked : 1;
+ bool m_bIsDynamic : 1;
+ bool m_bFlush : 1; // Used only for dynamic buffers, indicates to discard the next time
+
+#ifdef _DEBUG
+ static int s_nBufferCount;
+#endif
+};
+
+
+//-----------------------------------------------------------------------------
+// inline methods for CVertexBufferDx10
+//-----------------------------------------------------------------------------
+inline ID3D10Buffer* CVertexBufferDx10::GetDx10Buffer() const
+{
+ return m_pVertexBuffer;
+}
+
+inline int CVertexBufferDx10::VertexSize() const
+{
+ return VertexFormatSize( m_VertexFormat );
+}
+
+
+//-----------------------------------------------------------------------------
+// Dx10 implementation of an index buffer
+//-----------------------------------------------------------------------------
+class CIndexBufferDx10 : public CIndexBufferBase
+{
+ typedef CIndexBufferBase BaseClass;
+
+ // Methods of IIndexBuffer
+public:
+ virtual int IndexCount() const;
+ virtual MaterialIndexFormat_t IndexFormat() const;
+ virtual int GetRoomRemaining() const;
+ virtual bool Lock( int nMaxIndexCount, bool bAppend, IndexDesc_t &desc );
+ virtual void Unlock( int nWrittenIndexCount, IndexDesc_t &desc );
+ virtual void ModifyBegin( bool bReadOnly, int nFirstIndex, int nIndexCount, IndexDesc_t& desc );
+ virtual void ModifyEnd( IndexDesc_t& desc );
+ virtual bool IsDynamic() const;
+ virtual void BeginCastBuffer( MaterialIndexFormat_t format );
+ virtual void EndCastBuffer( );
+
+ // Other public methods
+public:
+ // constructor, destructor
+ CIndexBufferDx10( ShaderBufferType_t type, MaterialIndexFormat_t fmt, int nIndexCount, const char *pBudgetGroupName );
+ virtual ~CIndexBufferDx10();
+
+ ID3D10Buffer* GetDx10Buffer() const;
+ MaterialIndexFormat_t GetIndexFormat() const;
+
+ // Only used by dynamic buffers, indicates the next lock should perform a discard.
+ void Flush();
+
+protected:
+ // Creates, destroys the index buffer
+ bool Allocate( );
+ void Free();
+
+ // Returns the size of the index in bytes
+ int IndexSize() const;
+
+ ID3D10Buffer *m_pIndexBuffer;
+ MaterialIndexFormat_t m_IndexFormat;
+ int m_nIndexCount;
+ int m_nBufferSize;
+ int m_nFirstUnwrittenOffset; // Used only for dynamic buffers, indicates where it's safe to write (nooverwrite)
+ bool m_bIsLocked : 1;
+ bool m_bIsDynamic : 1;
+ bool m_bFlush : 1; // Used only for dynamic buffers, indicates to discard the next time
+
+#ifdef _DEBUG
+ static int s_nBufferCount;
+#endif
+};
+
+
+//-----------------------------------------------------------------------------
+// Returns the size of the index in bytes
+//-----------------------------------------------------------------------------
+inline int CIndexBufferDx10::IndexSize() const
+{
+ switch( m_IndexFormat )
+ {
+ default:
+ case MATERIAL_INDEX_FORMAT_UNKNOWN:
+ return 0;
+ case MATERIAL_INDEX_FORMAT_16BIT:
+ return 2;
+ case MATERIAL_INDEX_FORMAT_32BIT:
+ return 4;
+ }
+}
+
+inline ID3D10Buffer* CIndexBufferDx10::GetDx10Buffer() const
+{
+ return m_pIndexBuffer;
+}
+
+inline MaterialIndexFormat_t CIndexBufferDx10::GetIndexFormat() const
+{
+ return m_IndexFormat;
+}
+
+
+//-----------------------------------------------------------------------------
+// Dx10 implementation of a mesh
+//-----------------------------------------------------------------------------
+class CMeshDx10 : public CMeshBase
+{
+public:
+ CMeshDx10();
+ virtual ~CMeshDx10();
+
+ // FIXME: Make this work! Unsupported methods of IIndexBuffer
+ virtual bool Lock( int nMaxIndexCount, bool bAppend, IndexDesc_t& desc ) { Assert(0); return false; }
+ virtual void Unlock( int nWrittenIndexCount, IndexDesc_t& desc ) { Assert(0); }
+ virtual int GetRoomRemaining() const { Assert(0); return 0; }
+ virtual void ModifyBegin( bool bReadOnly, int nFirstIndex, int nIndexCount, IndexDesc_t& desc ) { Assert(0); }
+ virtual void ModifyEnd( IndexDesc_t& desc ) { Assert(0); }
+ virtual void Spew( int nIndexCount, const IndexDesc_t & desc ) { Assert(0); }
+ virtual void ValidateData( int nIndexCount, const IndexDesc_t &desc ) { Assert(0); }
+ virtual bool Lock( int nVertexCount, bool bAppend, VertexDesc_t &desc ) { Assert(0); return false; }
+ virtual void Unlock( int nVertexCount, VertexDesc_t &desc ) { Assert(0); }
+ virtual void Spew( int nVertexCount, const VertexDesc_t &desc ) { Assert(0); }
+ virtual void ValidateData( int nVertexCount, const VertexDesc_t & desc ) { Assert(0); }
+ virtual bool IsDynamic() const { Assert(0); return false; }
+ virtual void BeginCastBuffer( MaterialIndexFormat_t format ) { Assert(0); }
+ virtual void BeginCastBuffer( VertexFormat_t format ) { Assert(0); }
+ virtual void EndCastBuffer( ) { Assert(0); }
+
+ void LockMesh( int numVerts, int numIndices, MeshDesc_t& desc );
+ void UnlockMesh( int numVerts, int numIndices, MeshDesc_t& desc );
+
+ void ModifyBeginEx( bool bReadOnly, int firstVertex, int numVerts, int firstIndex, int numIndices, MeshDesc_t& desc );
+ void ModifyBegin( int firstVertex, int numVerts, int firstIndex, int numIndices, MeshDesc_t& desc );
+ void ModifyEnd( MeshDesc_t& desc );
+
+ // returns the # of vertices (static meshes only)
+ int VertexCount() const;
+
+ virtual void BeginPass( ) {}
+ virtual void RenderPass() {}
+ virtual bool HasColorMesh() const { return false; }
+ virtual bool IsUsingMorphData() const { return false; }
+ virtual bool HasFlexMesh() const { return false; }
+
+ // Sets the primitive type
+ void SetPrimitiveType( MaterialPrimitiveType_t type );
+
+ // Draws the entire mesh
+ void Draw(int firstIndex, int numIndices);
+
+ void Draw(CPrimList *pPrims, int nPrims);
+
+ // Copy verts and/or indices to a mesh builder. This only works for temp meshes!
+ virtual void CopyToMeshBuilder(
+ int iStartVert, // Which vertices to copy.
+ int nVerts,
+ int iStartIndex, // Which indices to copy.
+ int nIndices,
+ int indexOffset, // This is added to each index.
+ CMeshBuilder &builder );
+
+ // Spews the mesh data
+ void Spew( int numVerts, int numIndices, const MeshDesc_t & desc );
+
+ void ValidateData( int numVerts, int numIndices, const MeshDesc_t & desc );
+
+ // gets the associated material
+ IMaterial* GetMaterial();
+
+ void SetColorMesh( IMesh *pColorMesh, int nVertexOffset )
+ {
+ }
+
+
+ virtual int IndexCount() const
+ {
+ return 0;
+ }
+
+ virtual MaterialIndexFormat_t IndexFormat() const
+ {
+ Assert( 0 );
+ return MATERIAL_INDEX_FORMAT_UNKNOWN;
+ }
+
+ virtual void SetFlexMesh( IMesh *pMesh, int nVertexOffset ) {}
+
+ virtual void DisableFlexMesh() {}
+
+ virtual void MarkAsDrawn() {}
+
+ virtual unsigned ComputeMemoryUsed() { return 0; }
+
+ virtual VertexFormat_t GetVertexFormat() const { return VERTEX_POSITION; }
+
+ virtual IMesh *GetMesh()
+ {
+ return this;
+ }
+
+private:
+ enum
+ {
+ VERTEX_BUFFER_SIZE = 1024 * 1024
+ };
+
+ unsigned char* m_pVertexMemory;
+};
+
+#endif // MESHDX10_H
+
diff --git a/materialsystem/shaderapidx9/meshdx8.cpp b/materialsystem/shaderapidx9/meshdx8.cpp
new file mode 100644
index 0000000..9a4af9e
--- /dev/null
+++ b/materialsystem/shaderapidx9/meshdx8.cpp
@@ -0,0 +1,5980 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//===========================================================================//
+
+#define DISABLE_PROTECTED_THINGS
+#include "locald3dtypes.h"
+#include "imeshdx8.h"
+#include "shaderapidx8_global.h"
+#include "materialsystem/IShader.h"
+#include "tier0/vprof.h"
+#include "studio.h"
+#include "tier1/fmtstr.h"
+
+#include "tier0/platform.h"
+#include "tier0/systeminformation.h"
+
+// fixme - stick this in a header file.
+#if defined( _DEBUG ) && !defined( _X360 )
+// define this if you want to range check all indices when drawing
+#define CHECK_INDICES
+#endif
+#ifdef CHECK_INDICES
+#define CHECK_INDICES_MAX_NUM_STREAMS 2
+#endif
+
+#include "dynamicib.h"
+#include "dynamicvb.h"
+#include "utlvector.h"
+#include "shaderapi/ishaderapi.h"
+#include "imaterialinternal.h"
+#include "imaterialsysteminternal.h"
+#include "shaderapidx8.h"
+#include "shaderapi/ishaderutil.h"
+#include "materialsystem/imaterialsystemhardwareconfig.h"
+#include "materialsystem/materialsystem_config.h"
+#include "materialsystem/ivballoctracker.h"
+#include "tier1/strtools.h"
+#include "convar.h"
+#include "shaderdevicedx8.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//-----------------------------------------------------------------------------
+// Uncomment this to test buffered state
+//-----------------------------------------------------------------------------
+//#define DEBUG_BUFFERED_MESHES 1
+
+#define MAX_DX8_STREAMS 16
+
+#define VERTEX_FORMAT_INVALID 0xFFFFFFFFFFFFFFFFull
+
+// this is hooked into the engines convar
+extern ConVar mat_debugalttab;
+
+//#define DRAW_SELECTION 1
+static bool g_bDrawSelection = true; // only used in DRAW_SELECTION
+static unsigned short g_nScratchIndexBuffer[6]; // large enough for a fast quad; used when device is not active
+#ifdef _DEBUG
+int CVertexBuffer::s_BufferCount = 0;
+int CIndexBuffer::s_BufferCount = 0;
+#endif
+
+//-----------------------------------------------------------------------------
+// Important enumerations
+//-----------------------------------------------------------------------------
+enum
+{
+ VERTEX_BUFFER_SIZE = 32768,
+ MAX_QUAD_INDICES = 16384,
+};
+
+
+//-----------------------------------------------------------------------------
+//
+// Code related to vertex buffers start here
+//
+//-----------------------------------------------------------------------------
+class CVertexBufferDx8 : public CVertexBufferBase
+{
+ typedef CVertexBufferBase BaseClass;
+
+ // Methods of IVertexBuffer
+public:
+ virtual int VertexCount() const;
+ virtual VertexFormat_t GetVertexFormat() const;
+ virtual bool IsDynamic() const;
+ virtual void BeginCastBuffer( VertexFormat_t format );
+ virtual void EndCastBuffer( );
+ virtual int GetRoomRemaining() const;
+ virtual bool Lock( int nVertexCount, bool bAppend, VertexDesc_t &desc );
+ virtual void Unlock( int nVertexCount, VertexDesc_t &desc );
+
+public:
+ // constructor
+ CVertexBufferDx8( ShaderBufferType_t type, VertexFormat_t fmt, int nVertexCount, const char *pBudgetGroupName );
+ virtual ~CVertexBufferDx8();
+
+ // Allocates, deallocates the index buffer
+ bool Allocate( );
+ void Free();
+
+ // Returns the vertex size
+ int VertexSize() const;
+
+ // Only used by dynamic buffers, indicates the next lock should perform a discard.
+ void Flush();
+
+ // Returns the D3D buffer
+ IDirect3DVertexBuffer9* GetDx9Buffer();
+
+ // Used to measure how much static buffer memory is touched each frame
+ void HandlePerFrameTextureStats( int nFrame );
+
+protected:
+ IDirect3DVertexBuffer9 *m_pVertexBuffer;
+ VertexFormat_t m_VertexFormat;
+ int m_nVertexCount;
+ int m_nBufferSize;
+ int m_nFirstUnwrittenOffset; // Used only for dynamic buffers, indicates where it's safe to write (nooverwrite)
+
+ // Is it locked?
+ bool m_bIsLocked : 1;
+ bool m_bIsDynamic : 1;
+ bool m_bFlush : 1; // Used only for dynamic buffers, indicates to discard the next time
+
+#ifdef VPROF_ENABLED
+ int m_nVProfFrame;
+ int *m_pFrameCounter;
+ int *m_pGlobalCounter;
+#endif
+
+#ifdef _DEBUG
+ static int s_nBufferCount;
+#endif
+};
+
+
+//-----------------------------------------------------------------------------
+//
+// Code related to index buffers start here
+//
+//-----------------------------------------------------------------------------
+class CIndexBufferDx8 : public CIndexBufferBase
+{
+ typedef CIndexBufferBase BaseClass;
+
+ // Methods of IIndexBuffer
+public:
+ virtual int IndexCount( ) const;
+ virtual MaterialIndexFormat_t IndexFormat() const;
+ virtual int GetRoomRemaining() const;
+ virtual bool Lock( int nIndexCount, bool bAppend, IndexDesc_t &desc );
+ virtual void Unlock( int nIndexCount, IndexDesc_t &desc );
+ virtual void BeginCastBuffer( MaterialIndexFormat_t format );
+ virtual void EndCastBuffer( );
+ virtual bool IsDynamic() const;
+ virtual void ModifyBegin( bool bReadOnly, int nFirstIndex, int nIndexCount, IndexDesc_t& desc ) { Assert(0); }
+ virtual void ModifyEnd( IndexDesc_t& desc ) { Assert(0); }
+
+public:
+ // constructor
+ CIndexBufferDx8( ShaderBufferType_t bufferType, MaterialIndexFormat_t fmt, int nIndexCount, const char *pBudgetGroupName );
+ virtual ~CIndexBufferDx8();
+
+ // Allocates, deallocates the index buffer
+ bool Allocate( );
+ void Free();
+
+ // Returns the index size
+ int IndexSize() const;
+
+ // Only used by dynamic buffers, indicates the next lock should perform a discard.
+ void Flush();
+
+ // Returns the D3D buffer
+ IDirect3DIndexBuffer9* GetDx9Buffer();
+
+ // Used to measure how much static buffer memory is touched each frame
+ void HandlePerFrameTextureStats( int nFrame );
+
+#ifdef CHECK_INDICES
+ unsigned short GetShadowIndex( int i ) const;
+#endif
+
+private:
+ IDirect3DIndexBuffer9 *m_pIndexBuffer;
+ MaterialIndexFormat_t m_IndexFormat;
+ int m_nIndexCount;
+ int m_nBufferSize;
+ int m_nFirstUnwrittenOffset; // Used only for dynamic buffers, indicates where it's safe to write (nooverwrite)
+
+ // Is it locked?
+ bool m_bIsLocked : 1;
+ bool m_bIsDynamic : 1;
+ bool m_bFlush : 1; // Used only for dynamic buffers, indicates to discard the next time
+
+#ifdef CHECK_INDICES
+ unsigned char *m_pShadowIndices;
+ void *m_pLockIndexBuffer;
+ int m_nLockIndexBufferSize;
+ int m_nLockIndexOffset;
+#endif
+
+#ifdef VPROF_ENABLED
+ int m_nVProfFrame;
+#endif
+
+#ifdef _DEBUG
+ static int s_nBufferCount;
+#endif
+};
+
+
+//-----------------------------------------------------------------------------
+//
+// Backward compat mesh code; will go away soon
+//
+//-----------------------------------------------------------------------------
+abstract_class CBaseMeshDX8 : public CMeshBase
+{
+public:
+ // constructor, destructor
+ CBaseMeshDX8();
+ virtual ~CBaseMeshDX8();
+
+ // FIXME: Make this work! Unsupported methods of IIndexBuffer + IVertexBuffer
+ virtual bool Lock( int nMaxIndexCount, bool bAppend, IndexDesc_t& desc ) { Assert(0); return false; }
+ virtual void Unlock( int nWrittenIndexCount, IndexDesc_t& desc ) { Assert(0); }
+ virtual void ModifyBegin( bool bReadOnly, int nFirstIndex, int nIndexCount, IndexDesc_t& desc ) { Assert(0); }
+ virtual void ModifyEnd( IndexDesc_t& desc ) { Assert(0); }
+ virtual void Spew( int nIndexCount, const IndexDesc_t & desc ) { Assert(0); }
+ virtual void ValidateData( int nIndexCount, const IndexDesc_t &desc ) { Assert(0); }
+ virtual bool Lock( int nVertexCount, bool bAppend, VertexDesc_t &desc ) { Assert(0); return false; }
+ virtual void Unlock( int nVertexCount, VertexDesc_t &desc ) { Assert(0); }
+ virtual void Spew( int nVertexCount, const VertexDesc_t &desc ) { Assert(0); }
+ virtual void ValidateData( int nVertexCount, const VertexDesc_t & desc ) { Assert(0); }
+
+ // Locks mesh for modifying
+ void ModifyBeginEx( bool bReadOnly, int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t& desc );
+ void ModifyBegin( int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t& desc );
+ void ModifyEnd( MeshDesc_t& desc );
+
+ // Sets/gets the vertex format
+ virtual void SetVertexFormat( VertexFormat_t format );
+ virtual VertexFormat_t GetVertexFormat() const;
+
+ // Sets/gets the morph format
+ virtual void SetMorphFormat( MorphFormat_t format );
+ virtual MorphFormat_t GetMorphFormat() const;
+ // Am I using morph data?
+ virtual bool IsUsingMorphData() const;
+ bool IsUsingVertexID() const
+ {
+ return ShaderAPI()->GetBoundMaterial()->IsUsingVertexID();
+ }
+
+ // Sets the material
+ virtual void SetMaterial( IMaterial* pMaterial );
+
+ // returns the # of vertices (static meshes only)
+ int VertexCount() const { return 0; }
+
+ void SetColorMesh( IMesh *pColorMesh, int nVertexOffsetInBytes )
+ {
+ Assert( 0 );
+ }
+
+ void SetFlexMesh( IMesh *pMesh, int nVertexOffsetInBytes )
+ {
+ Assert( pMesh == NULL && nVertexOffsetInBytes == 0 );
+ }
+
+ void DisableFlexMesh( )
+ {
+ Assert( 0 );
+ }
+
+ void MarkAsDrawn() {}
+
+ bool HasColorMesh( ) const { return false; }
+ bool HasFlexMesh( ) const { return false; }
+
+ // Draws the mesh
+ void DrawMesh( );
+
+ // Begins a pass
+ void BeginPass( );
+
+ // Spews the mesh data
+ virtual void Spew( int nVertexCount, int nIndexCount, const MeshDesc_t & desc );
+
+ // Call this in debug mode to make sure our data is good.
+ virtual void ValidateData( int nVertexCount, int nIndexCount, const MeshDesc_t & desc );
+
+ virtual void HandleLateCreation( ) = 0;
+
+ void Draw( CPrimList *pLists, int nLists );
+
+ // Copy verts and/or indices to a mesh builder. This only works for temp meshes!
+ virtual void CopyToMeshBuilder(
+ int iStartVert, // Which vertices to copy.
+ int nVerts,
+ int iStartIndex, // Which indices to copy.
+ int nIndices,
+ int indexOffset, // This is added to each index.
+ CMeshBuilder &builder );
+
+ // returns the primitive type
+ virtual MaterialPrimitiveType_t GetPrimitiveType() const = 0;
+
+ // Returns the number of indices in a mesh..
+ virtual int IndexCount( ) const = 0;
+
+ // FIXME: Make this work!
+ virtual MaterialIndexFormat_t IndexFormat() const { return MATERIAL_INDEX_FORMAT_16BIT; }
+
+ // NOTE: For dynamic index buffers only!
+ // Casts the memory of the dynamic index buffer to the appropriate type
+ virtual void BeginCastBuffer( MaterialIndexFormat_t format ) { Assert(0); }
+ virtual void BeginCastBuffer( VertexFormat_t format ) { Assert(0); }
+ virtual void EndCastBuffer( ) { Assert(0); }
+ virtual int GetRoomRemaining() const { Assert(0); return 0; }
+
+ // returns a static vertex buffer...
+ virtual CVertexBuffer *GetVertexBuffer() { return 0; }
+ virtual CIndexBuffer *GetIndexBuffer() { return 0; }
+
+ // Do I need to reset the vertex format?
+ virtual bool NeedsVertexFormatReset( VertexFormat_t fmt ) const;
+
+ // Do I have enough room?
+ virtual bool HasEnoughRoom( int nVertexCount, int nIndexCount ) const;
+
+ // Operation to do pre-lock
+ virtual void PreLock() {}
+
+ virtual unsigned ComputeMemoryUsed();
+
+ bool m_bMeshLocked;
+
+protected:
+ bool DebugTrace() const;
+
+ // The vertex format we're using...
+ VertexFormat_t m_VertexFormat;
+
+ // The morph format we're using
+ MorphFormat_t m_MorphFormat;
+
+#ifdef DBGFLAG_ASSERT
+ IMaterialInternal* m_pMaterial;
+ bool m_IsDrawing;
+#endif
+};
+
+//-----------------------------------------------------------------------------
+// Implementation of the mesh
+//-----------------------------------------------------------------------------
+class CMeshDX8 : public CBaseMeshDX8
+{
+public:
+ // constructor
+ CMeshDX8( const char *pTextureGroupName );
+ virtual ~CMeshDX8();
+
+ // Locks/unlocks the mesh
+ void LockMesh( int nVertexCount, int nIndexCount, MeshDesc_t& desc );
+ void UnlockMesh( int nVertexCount, int nIndexCount, MeshDesc_t& desc );
+
+ // Locks mesh for modifying
+ void ModifyBeginEx( bool bReadOnly, int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t& desc );
+ void ModifyBegin( int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t& desc );
+ void ModifyEnd( MeshDesc_t& desc );
+
+ // returns the # of vertices (static meshes only)
+ int VertexCount() const;
+
+ // returns the # of indices
+ virtual int IndexCount( ) const;
+
+ // Sets up the vertex and index buffers
+ void UseIndexBuffer( CIndexBuffer* pBuffer );
+ void UseVertexBuffer( CVertexBuffer* pBuffer );
+
+ // returns a static vertex buffer...
+ CVertexBuffer *GetVertexBuffer() { return m_pVertexBuffer; }
+ CIndexBuffer *GetIndexBuffer() { return m_pIndexBuffer; }
+
+ void SetColorMesh( IMesh *pColorMesh, int nVertexOffsetInBytes );
+ void SetFlexMesh( IMesh *pMesh, int nVertexOffsetInBytes );
+ void DisableFlexMesh();
+
+ virtual void HandleLateCreation( );
+
+ bool HasColorMesh( ) const;
+ bool HasFlexMesh( ) const;
+
+ // Draws the mesh
+ void Draw( int nFirstIndex, int nIndexCount );
+ void Draw( CPrimList *pLists, int nLists );
+ void DrawInternal( CPrimList *pLists, int nLists );
+
+ // Draws a single pass
+ void RenderPass();
+
+ // Sets the primitive type
+ void SetPrimitiveType( MaterialPrimitiveType_t type );
+ MaterialPrimitiveType_t GetPrimitiveType() const;
+
+ bool IsDynamic() const { return false; }
+
+protected:
+ // Sets the render state.
+ bool SetRenderState( int nVertexOffsetInBytes, int nFirstVertexIdx, VertexFormat_t vertexFormat = VERTEX_FORMAT_INVALID );
+
+ // Is the vertex format valid?
+ bool IsValidVertexFormat( VertexFormat_t vertexFormat = VERTEX_FORMAT_INVALID );
+
+ // Locks/ unlocks the vertex buffer
+ bool Lock( int nVertexCount, bool bAppend, VertexDesc_t &desc );
+ void Unlock( int nVertexCount, VertexDesc_t &desc );
+
+ // Locks/unlocks the index buffer
+ // Pass in nFirstIndex=-1 to lock wherever the index buffer is. Pass in a value
+ // >= 0 to specify where to lock.
+ int Lock( bool bReadOnly, int nFirstIndex, int nIndexCount, IndexDesc_t &pIndices );
+ void Unlock( int nIndexCount, IndexDesc_t &desc );
+
+ // computes how many primitives we've got
+ int NumPrimitives( int nVertexCount, int nIndexCount ) const;
+
+ // Debugging output...
+ void SpewMaterialVerts( );
+
+ // Stream source setting methods
+ void SetVertexIDStreamState( );
+ void SetColorStreamState( );
+ void SetVertexStreamState( int nVertOffsetInBytes );
+ void SetIndexStreamState( int firstVertexIdx );
+
+ void CheckIndices( CPrimList *pPrim, int numPrimitives );
+
+ // The vertex and index buffers
+ CVertexBuffer* m_pVertexBuffer;
+ CIndexBuffer* m_pIndexBuffer;
+
+ // The current color mesh (to be bound to stream 1)
+ // The vertex offset allows use of a global, shared color mesh VB
+ CMeshDX8 * m_pColorMesh;
+ int m_nColorMeshVertOffsetInBytes;
+
+ CVertexBuffer *m_pFlexVertexBuffer;
+
+ bool m_bHasFlexVerts;
+ int m_nFlexVertOffsetInBytes;
+ int m_flexVertCount;
+
+ // Primitive type
+ MaterialPrimitiveType_t m_Type;
+
+ // Primitive mode
+ D3DPRIMITIVETYPE m_Mode;
+
+ // Number of primitives
+ unsigned int m_NumIndices;
+ unsigned short m_NumVertices;
+
+ // Is it locked?
+ bool m_IsVBLocked;
+ bool m_IsIBLocked;
+
+ // Used in rendering sub-parts of the mesh
+ static CPrimList *s_pPrims;
+ static int s_nPrims;
+ static unsigned int s_FirstVertex; // Gets reset during CMeshDX8::DrawInternal
+ static unsigned int s_NumVertices;
+ int m_FirstIndex;
+
+#ifdef RECORDING
+ int m_LockVertexBufferSize;
+ void *m_LockVertexBuffer;
+#endif
+
+#if defined( RECORDING ) || defined( CHECK_INDICES )
+ void *m_LockIndexBuffer;
+ int m_LockIndexBufferSize;
+#endif
+ const char *m_pTextureGroupName;
+
+ friend class CMeshMgr; // MESHFIXME
+};
+
+
+//-----------------------------------------------------------------------------
+// A little extra stuff for the dynamic version
+//-----------------------------------------------------------------------------
+class CDynamicMeshDX8 : public CMeshDX8
+{
+public:
+ // constructor, destructor
+ CDynamicMeshDX8();
+ virtual ~CDynamicMeshDX8();
+
+ // Initializes the dynamic mesh
+ void Init( int nBufferId );
+
+ // Sets the vertex format
+ virtual void SetVertexFormat( VertexFormat_t format );
+
+ // Resets the state in case of a task switch
+ void Reset();
+
+ // Do I have enough room in the buffer?
+ bool HasEnoughRoom( int nVertexCount, int nIndexCount ) const;
+
+ // returns the # of indices
+ int IndexCount( ) const;
+
+ // Locks the mesh
+ void LockMesh( int nVertexCount, int nIndexCount, MeshDesc_t& desc );
+
+ // Unlocks the mesh
+ void UnlockMesh( int nVertexCount, int nIndexCount, MeshDesc_t& desc );
+
+ // Override vertex + index buffer
+ void OverrideVertexBuffer( CVertexBuffer *pStaticVertexBuffer );
+ void OverrideIndexBuffer( CIndexBuffer *pStaticIndexBuffer );
+
+ // Do I need to reset the vertex format?
+ bool NeedsVertexFormatReset(VertexFormat_t fmt) const;
+
+ // Draws it
+ void Draw( int nFirstIndex, int nIndexCount );
+ void MarkAsDrawn() { m_HasDrawn = true; }
+ // Simply draws what's been buffered up immediately, without state change
+ void DrawSinglePassImmediately();
+
+ // Operation to do pre-lock
+ void PreLock();
+
+ bool IsDynamic() const { return true; }
+
+private:
+ // Resets buffering state
+ void ResetVertexAndIndexCounts();
+
+ // Buffer Id
+ int m_nBufferId;
+
+ // total queued vertices
+ int m_TotalVertices;
+ int m_TotalIndices;
+
+ // the first vertex and index since the last draw
+ int m_nFirstVertex;
+ int m_FirstIndex;
+
+ // Have we drawn since the last lock?
+ bool m_HasDrawn;
+
+ // Any overrides?
+ bool m_VertexOverride;
+ bool m_IndexOverride;
+};
+
+
+//-----------------------------------------------------------------------------
+// A mesh that stores temporary vertex data in the correct format (for modification)
+//-----------------------------------------------------------------------------
+class CTempMeshDX8 : public CBaseMeshDX8
+{
+public:
+ // constructor, destructor
+ CTempMeshDX8( bool isDynamic );
+ virtual ~CTempMeshDX8();
+
+ // Sets the material
+ virtual void SetVertexFormat( VertexFormat_t format );
+
+ // Locks/unlocks the mesh
+ void LockMesh( int nVertexCount, int nIndexCount, MeshDesc_t &desc );
+ void UnlockMesh( int nVertexCount, int nIndexCount, MeshDesc_t &desc );
+
+ // Locks mesh for modifying
+ virtual void ModifyBeginEx( bool bReadOnly, int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t& desc );
+ virtual void ModifyBegin( int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t& desc );
+ virtual void ModifyEnd( MeshDesc_t& desc );
+
+ // Number of indices + vertices
+ int VertexCount() const;
+ virtual int IndexCount() const;
+ virtual bool IsDynamic() const;
+
+ // Sets the primitive type
+ void SetPrimitiveType( MaterialPrimitiveType_t type );
+ MaterialPrimitiveType_t GetPrimitiveType() const;
+
+ // Begins a pass
+ void BeginPass( );
+
+ // Draws a single pass
+ void RenderPass();
+
+ virtual void HandleLateCreation()
+ {
+ Assert( !"TBD - CTempMeshDX8::HandleLateCreation()" );
+ }
+
+ // Draws the entire beast
+ void Draw( int nFirstIndex, int nIndexCount );
+
+ virtual void CopyToMeshBuilder(
+ int iStartVert, // Which vertices to copy.
+ int nVerts,
+ int iStartIndex, // Which indices to copy.
+ int nIndices,
+ int indexOffset, // This is added to each index.
+ CMeshBuilder &builder );
+private:
+ // Selection mode
+ void TestSelection( );
+ void ClipTriangle( D3DXVECTOR3 **ppVert, float zNear, D3DXMATRIX &proj );
+
+ CDynamicMeshDX8 *GetDynamicMesh();
+
+ CUtlVector< unsigned char, CUtlMemoryAligned< unsigned char, 32 > > m_VertexData;
+ CUtlVector< unsigned short > m_IndexData;
+
+ unsigned short m_VertexSize;
+ MaterialPrimitiveType_t m_Type;
+ int m_LockedVerts;
+ int m_LockedIndices;
+ bool m_IsDynamic;
+
+ // Used in rendering sub-parts of the mesh
+ static unsigned int s_NumIndices;
+ static unsigned int s_FirstIndex;
+
+#ifdef DBGFLAG_ASSERT
+ bool m_Locked;
+ bool m_InPass;
+#endif
+};
+
+#if 0
+//-----------------------------------------------------------------------------
+// A mesh that stores temporary vertex data in the correct format (for modification)
+//-----------------------------------------------------------------------------
+class CTempIndexBufferDX8 : public CIndexBufferBase
+{
+public:
+ // constructor, destructor
+ CTempIndexBufferDX8( bool isDynamic );
+ virtual ~CTempIndexBufferDX8();
+
+ // Locks/unlocks the mesh
+ void LockIndexBuffer( int nIndexCount );
+ void UnlockMesh( int nIndexCount );
+
+ // Locks mesh for modifying
+ virtual void ModifyBeginEx( bool bReadOnly, int nFirstIndex, int nIndexCount );
+ virtual void ModifyEnd();
+
+ // Number of indices
+ virtual int IndexCount() const;
+ virtual bool IsDynamic() const;
+
+ virtual void CopyToIndexBuilder(
+ int iStartIndex, // Which indices to copy.
+ int nIndices,
+ int indexOffset, // This is added to each index.
+ CIndexBuilder &builder );
+private:
+ // Selection mode
+ void TestSelection( );
+
+ CDynamicMeshDX8 *GetDynamicMesh();
+
+ CUtlVector< unsigned short > m_IndexData;
+
+ MaterialPrimitiveType_t m_Type;
+ int m_LockedIndices;
+ bool m_IsDynamic;
+
+ // Used in rendering sub-parts of the mesh
+ static unsigned int s_NumIndices;
+ static unsigned int s_FirstIndex;
+
+#ifdef DBGFLAG_ASSERT
+ bool m_Locked;
+ bool m_InPass;
+#endif
+};
+#endif
+//-----------------------------------------------------------------------------
+// This is a version that buffers up vertex data so we can blast through it later
+//-----------------------------------------------------------------------------
+class CBufferedMeshDX8 : public CBaseMeshDX8
+{
+public:
+ // constructor, destructor
+ CBufferedMeshDX8();
+ virtual ~CBufferedMeshDX8();
+
+ // checks to see if it was rendered..
+ void ResetRendered();
+ bool WasNotRendered() const;
+
+ // Sets the mesh we're really going to draw into
+ void SetMesh( CBaseMeshDX8* pMesh );
+ const CBaseMeshDX8* GetMesh() const { return m_pMesh; }
+
+ // Spews the mesh data
+ virtual void Spew( int nVertexCount, int nIndexCount, const MeshDesc_t &spewDesc );
+
+ // Sets the vertex format
+ virtual void SetVertexFormat( VertexFormat_t format );
+ virtual VertexFormat_t GetVertexFormat() const;
+
+ // Sets the morph format
+ virtual void SetMorphFormat( MorphFormat_t format );
+
+ // Sets the material
+ void SetMaterial( IMaterial *pMaterial );
+
+ // returns the number of indices (should never be called!)
+ virtual int IndexCount() const { Assert(0); return 0; }
+ virtual MaterialIndexFormat_t IndexFormat() const { Assert(0); return MATERIAL_INDEX_FORMAT_16BIT; }
+ virtual bool IsDynamic() const { Assert(0); return true; }
+ virtual void BeginCastBuffer( MaterialIndexFormat_t format ) { Assert(0); }
+ virtual void EndCastBuffer( ) { Assert(0); }
+ virtual int GetRoomRemaining() const { Assert(0); return 0; }
+
+ // Locks the mesh
+ void LockMesh( int nVertexCount, int nIndexCount, MeshDesc_t& desc );
+ void UnlockMesh( int nVertexCount, int nIndexCount, MeshDesc_t& desc );
+
+ // Sets the primitive type
+ void SetPrimitiveType( MaterialPrimitiveType_t type );
+ MaterialPrimitiveType_t GetPrimitiveType( ) const;
+
+ void ValidateData( int nVertexCount, int nIndexCount, const MeshDesc_t & spewDesc );
+
+ virtual void HandleLateCreation( )
+ {
+ if ( m_pMesh )
+ {
+ m_pMesh->HandleLateCreation();
+ }
+ }
+
+ // Draws it
+ void Draw( int nFirstIndex, int nIndexCount );
+
+ // Renders a pass
+ void RenderPass();
+
+ // Flushes queued data
+ void Flush( );
+
+ void SetFlexMesh( IMesh *pMesh, int nVertexOffsetInBytes );
+
+private:
+ // The actual mesh we need to render....
+ CBaseMeshDX8* m_pMesh;
+
+ // The index of the last vertex (for tristrip fixup)
+ unsigned short m_LastIndex;
+
+ // Extra padding indices for tristrips
+ unsigned short m_ExtraIndices;
+
+ // Am I currently flushing?
+ bool m_IsFlushing;
+
+ // has the dynamic mesh been rendered?
+ bool m_WasRendered;
+
+ // Do I need to flush?
+ bool m_FlushNeeded;
+
+#ifdef DEBUG_BUFFERED_MESHES
+ // for debugging only
+ bool m_BufferedStateSet;
+ BufferedState_t m_BufferedState;
+#endif
+};
+
+
+//-----------------------------------------------------------------------------
+// Implementation of the mesh manager
+//-----------------------------------------------------------------------------
+class CMeshMgr : public IMeshMgr
+{
+public:
+ // constructor, destructor
+ CMeshMgr();
+ virtual ~CMeshMgr();
+
+ // Initialize, shutdown
+ void Init();
+ void Shutdown();
+
+ // Task switch...
+ void ReleaseBuffers();
+ void RestoreBuffers();
+
+ // Releases all dynamic vertex buffers
+ void DestroyVertexBuffers();
+
+ // Flushes the dynamic mesh
+ void Flush();
+
+ // Flushes the vertex buffers
+ void DiscardVertexBuffers();
+
+ // Creates, destroys static meshes
+ IMesh *CreateStaticMesh( VertexFormat_t vertexFormat, const char *pTextureBudgetGroup, IMaterial *pMaterial = NULL );
+ void DestroyStaticMesh( IMesh *pMesh );
+
+ // Gets at the dynamic mesh (spoofs it though)
+ IMesh *GetDynamicMesh( IMaterial *pMaterial, VertexFormat_t vertexFormat, int nHWSkinBoneCount, bool buffered,
+ IMesh *pVertexOverride, IMesh *pIndexOverride );
+
+// -----------------------------------------------------------
+// ------------ New Vertex/Index Buffer interface ----------------------------
+ // Do we need support for bForceTempMesh and bSoftwareVertexShader?
+ // I don't think we use bSoftwareVertexShader anymore. .need to look into bForceTempMesh.
+ IVertexBuffer *CreateVertexBuffer( ShaderBufferType_t type, VertexFormat_t fmt, int nVertexCount, const char *pBudgetGroup );
+ IIndexBuffer *CreateIndexBuffer( ShaderBufferType_t bufferType, MaterialIndexFormat_t fmt, int nIndexCount, const char *pBudgetGroup );
+ void DestroyVertexBuffer( IVertexBuffer * );
+ void DestroyIndexBuffer( IIndexBuffer * );
+ // Do we need to specify the stream here in the case of locking multiple dynamic VBs on different streams?
+ IVertexBuffer *GetDynamicVertexBuffer( int streamID, VertexFormat_t vertexFormat, bool bBuffered = true );
+ IIndexBuffer *GetDynamicIndexBuffer( MaterialIndexFormat_t fmt, bool bBuffered = true );
+ void BindVertexBuffer( int streamID, IVertexBuffer *pVertexBuffer, int nOffsetInBytes, int nFirstVertex, int nVertexCount, VertexFormat_t fmt, int nRepetitions = 1 );
+ void BindIndexBuffer( IIndexBuffer *pIndexBuffer, int nOffsetInBytes );
+ void Draw( MaterialPrimitiveType_t primitiveType, int nFirstIndex, int nIndexCount );
+// ------------ End ----------------------------
+ void RenderPassWithVertexAndIndexBuffers( void );
+
+ VertexFormat_t GetCurrentVertexFormat( void ) const { return m_CurrentVertexFormat; }
+
+ // Gets at the *actual* dynamic mesh
+ IMesh* GetActualDynamicMesh( VertexFormat_t vertexFormat );
+ IMesh *GetFlexMesh();
+
+ // Computes vertex format from a list of ingredients
+ VertexFormat_t ComputeVertexFormat( unsigned int flags,
+ int numTexCoords, int *pTexCoordDimensions, int numBoneWeights,
+ int userDataSize ) const;
+
+ // Use fat vertices (for tools)
+ virtual void UseFatVertices( bool bUseFat );
+
+ // Returns the number of vertices we can render using the dynamic mesh
+ virtual void GetMaxToRender( IMesh *pMesh, bool bMaxUntilFlush, int *pMaxVerts, int *pMaxIndices );
+ virtual int GetMaxVerticesToRender( IMaterial *pMaterial );
+ virtual int GetMaxIndicesToRender( );
+
+ // Returns a vertex buffer appropriate for the flags
+ CVertexBuffer *FindOrCreateVertexBuffer( int nDynamicBufferId, VertexFormat_t fmt );
+ CIndexBuffer *GetDynamicIndexBuffer();
+
+ // Is the mesh dynamic?
+ bool IsDynamicMesh( IMesh *pMesh ) const;
+ bool IsBufferedDynamicMesh( IMesh *pMesh ) const;
+
+ // Is the vertex buffer dynamic?
+ bool IsDynamicVertexBuffer( IVertexBuffer *pVertexBuffer ) const;
+
+ // Is the index buffer dynamic?
+ bool IsDynamicIndexBuffer( IIndexBuffer *pIndexBuffer ) const;
+
+ // Returns the vertex size
+ int VertexFormatSize( VertexFormat_t vertexFormat ) const
+ {
+ return CVertexBufferBase::VertexFormatSize( vertexFormat );
+ }
+
+ // Computes the vertex buffer pointers
+ void ComputeVertexDescription( unsigned char *pBuffer,
+ VertexFormat_t vertexFormat, MeshDesc_t &desc ) const;
+
+ // Returns the number of buffers...
+ int BufferCount() const
+ {
+#ifdef _DEBUG
+ return CVertexBuffer::BufferCount() + CIndexBuffer::BufferCount();
+#else
+ return 0;
+#endif
+ }
+
+ CVertexBuffer *GetVertexIDBuffer();
+
+ IVertexBuffer *GetDynamicVertexBuffer( IMaterial *pMaterial, bool buffered = true );
+ IIndexBuffer *GetDynamicIndexBuffer( IMaterial *pMaterial, bool buffered = true );
+ virtual void MarkUnusedVertexFields( unsigned int nFlags, int nTexCoordCount, bool *pUnusedTexCoords );
+
+ int UnusedVertexFields() const { return m_nUnusedVertexFields; }
+ int UnusedTextureCoords() const { return m_nUnusedTextureCoords; }
+
+ IDirect3DVertexBuffer9 *GetZeroVertexBuffer() const { return m_pZeroVertexBuffer; }
+
+private:
+ void SetVertexIDStreamState( );
+ void SetColorStreamState( );
+ void SetVertexStreamState( int nVertOffsetInBytes, int nVertexStride );
+ void SetIndexStreamState( int firstVertexIdx );
+ bool SetRenderState( int nVertexOffsetInBytes, int nFirstVertexIdx, VertexFormat_t vertexFormat, int nVertexStride );
+
+ struct VertexBufferLookup_t
+ {
+ CVertexBuffer* m_pBuffer;
+ int m_VertexSize;
+ };
+
+ void CopyStaticMeshIndexBufferToTempMeshIndexBuffer( CTempMeshDX8 *pDstIndexMesh, CMeshDX8 *pSrcIndexMesh );
+
+ // Cleans up the class
+ void CleanUp();
+
+ // Creates, destroys the dynamic index
+ void CreateDynamicIndexBuffer();
+ void DestroyDynamicIndexBuffer();
+
+ // Creates, destroys the vertexID buffer
+ void CreateVertexIDBuffer();
+ void DestroyVertexIDBuffer();
+ void CreateZeroVertexBuffer();
+ void DestroyZeroVertexBuffer();
+
+ // Fills a vertexID buffer
+ void FillVertexIDBuffer( CVertexBuffer *pVertexIDBuffer, int nCount );
+
+ // The dynamic index buffer
+ CIndexBuffer *m_pDynamicIndexBuffer;
+
+ // A static vertexID buffer
+ CVertexBuffer *m_pVertexIDBuffer;
+
+ // The dynamic vertex buffers
+ CUtlVector< VertexBufferLookup_t > m_DynamicVertexBuffers;
+
+ // The buffered mesh
+ CBufferedMeshDX8 m_BufferedMesh;
+
+ // The current dynamic mesh
+ CDynamicMeshDX8 m_DynamicMesh;
+ CDynamicMeshDX8 m_DynamicFlexMesh;
+
+ // The current dynamic vertex buffer
+ CVertexBufferDx8 m_DynamicVertexBuffer;
+
+ // The current dynamic index buffer
+ CIndexBufferDx8 m_DynamicIndexBuffer;
+
+ // The dynamic mesh temp version (for shaders that modify vertex data)
+ CTempMeshDX8 m_DynamicTempMesh;
+
+ // Am I buffering or not?
+ bool m_BufferedMode;
+
+ // Using fat vertices?
+ bool m_bUseFatVertices;
+
+ CVertexBufferDx8 *m_pCurrentVertexBuffer;
+ VertexFormat_t m_CurrentVertexFormat;
+ int m_pVertexBufferOffset[MAX_DX8_STREAMS];
+ int m_pCurrentVertexStride[MAX_DX8_STREAMS];
+ int m_pFirstVertex[MAX_DX8_STREAMS];
+ int m_pVertexCount[MAX_DX8_STREAMS];
+ CIndexBufferBase *m_pCurrentIndexBuffer;
+ int m_nIndexBufferOffset;
+ MaterialPrimitiveType_t m_PrimitiveType;
+ int m_nFirstIndex;
+ int m_nNumIndices;
+
+ unsigned int m_nUnusedVertexFields;
+ unsigned int m_nUnusedTextureCoords;
+
+ // 4096 byte static VB containing all-zeros
+ IDirect3DVertexBuffer9 *m_pZeroVertexBuffer;
+};
+
+//-----------------------------------------------------------------------------
+// Singleton...
+//-----------------------------------------------------------------------------
+static CMeshMgr g_MeshMgr;
+IMeshMgr* MeshMgr()
+{
+ return &g_MeshMgr;
+}
+
+//-----------------------------------------------------------------------------
+// Tracks stream state and queued data
+//-----------------------------------------------------------------------------
+static CIndexBuffer *g_pLastIndex = NULL;
+static IDirect3DIndexBuffer9 *g_pLastIndexBuffer = NULL;
+static CVertexBuffer *g_pLastVertex = NULL;
+static IDirect3DVertexBuffer9 *g_pLastVertexBuffer = NULL;
+static int g_nLastVertOffsetInBytes = 0;
+static int g_nLastVertStride = 0;
+static int g_LastVertexIdx = -1;
+static CMeshDX8 *g_pLastColorMesh = NULL;
+static int g_nLastColorMeshVertOffsetInBytes = 0;
+static bool g_bUsingVertexID = false;
+static bool g_bFlexMeshStreamSet = false;
+static VertexFormat_t g_LastVertexFormat = 0;
+
+inline void D3DSetStreamSource( unsigned int streamNumber, IDirect3DVertexBuffer9 *pStreamData,
+ unsigned int nVertexOffsetInBytes, unsigned int stride )
+{
+ Dx9Device()->SetStreamSource( streamNumber, pStreamData, nVertexOffsetInBytes, stride );
+}
+
+
+//-----------------------------------------------------------------------------
+// Tracks stream state and queued data
+//-----------------------------------------------------------------------------
+void Unbind( IDirect3DIndexBuffer9 *pIndexBuffer )
+{
+#ifdef _X360
+ IDirect3DIndexBuffer9 *pBoundBuffer;
+ Dx9Device()->GetIndices( &pBoundBuffer );
+ if ( pBoundBuffer == pIndexBuffer )
+ {
+ // xboxissue - cannot lock indexes set in a d3d device, clear possibly set indices
+ Dx9Device()->SetIndices( NULL );
+ g_pLastIndex = NULL;
+ g_pLastIndexBuffer = NULL;
+ }
+
+ if ( pBoundBuffer )
+ {
+ pBoundBuffer->Release();
+ }
+#endif
+}
+
+void Unbind( IDirect3DVertexBuffer9 *pVertexBuffer )
+{
+#ifdef _X360
+ UINT nOffset, nStride;
+ IDirect3DVertexBuffer9 *pBoundBuffer;
+ for ( int i = 0; i < MAX_DX8_STREAMS; ++i )
+ {
+ Dx9Device()->GetStreamSource( i, &pBoundBuffer, &nOffset, &nStride );
+ if ( pBoundBuffer == pVertexBuffer )
+ {
+ // xboxissue - cannot lock indexes set in a d3d device, clear possibly set indices
+ Dx9Device()->SetStreamSource( i, 0, 0, 0 );
+ switch ( i )
+ {
+ case 0:
+ g_pLastVertex = NULL;
+ g_pLastVertexBuffer = NULL;
+ break;
+
+ case 1:
+ g_pLastColorMesh = NULL;
+ g_nLastColorMeshVertOffsetInBytes = 0;
+ break;
+ }
+ }
+
+ if ( pBoundBuffer )
+ {
+ pBoundBuffer->Release();
+ }
+ }
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Helpers to count texture coordinates
+//-----------------------------------------------------------------------------
+static int NumTextureCoordinates( VertexFormat_t vertexFormat )
+{
+ int nTexCoordCount = 0;
+ for ( int i = 0; i < VERTEX_MAX_TEXTURE_COORDINATES; ++i )
+ {
+ if ( TexCoordSize( i, vertexFormat ) == 0 )
+ continue;
+ ++nTexCoordCount;
+ }
+ return nTexCoordCount;
+}
+
+
+//-----------------------------------------------------------------------------
+// Makes sure that the render state is always set next time
+//-----------------------------------------------------------------------------
+static void ResetMeshRenderState()
+{
+ SafeRelease( &g_pLastIndex );
+ g_pLastIndexBuffer = 0;
+ g_pLastVertex = 0;
+ g_nLastVertOffsetInBytes = 0;
+ g_pLastColorMesh = 0;
+ g_nLastColorMeshVertOffsetInBytes = 0;
+ g_LastVertexIdx = -1;
+ g_bUsingVertexID = false;
+ g_bFlexMeshStreamSet = false;
+ g_LastVertexFormat = 0;
+}
+
+//-----------------------------------------------------------------------------
+// Makes sure that the render state is always set next time
+//-----------------------------------------------------------------------------
+static void ResetIndexBufferRenderState()
+{
+ SafeRelease( &g_pLastIndex );
+ g_pLastIndexBuffer = 0;
+ g_LastVertexIdx = -1;
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// Index Buffer implementations begin here
+//
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// Globals
+//-----------------------------------------------------------------------------
+#ifdef _DEBUG
+int CIndexBufferDx8::s_nBufferCount = 0;
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Constructor, destructor
+//-----------------------------------------------------------------------------
+CIndexBufferDx8::CIndexBufferDx8( ShaderBufferType_t bufferType, MaterialIndexFormat_t fmt, int nIndexCount, const char *pBudgetGroupName ) :
+ BaseClass( pBudgetGroupName )
+{
+// Debugger();
+
+ Assert( nIndexCount != 0 );
+
+ // NOTE: MATERIAL_INDEX_FORMAT_UNKNOWN can't be dealt with under dx9
+ // because format is bound at buffer creation time. What we'll do
+ // is just arbitrarily choose to use a 16-bit index buffer of the same size
+ if ( fmt == MATERIAL_INDEX_FORMAT_UNKNOWN )
+ {
+ fmt = MATERIAL_INDEX_FORMAT_16BIT;
+ nIndexCount /= 2;
+ }
+
+ m_pIndexBuffer = NULL;
+ m_IndexFormat = fmt;
+ m_nBufferSize = nIndexCount * IndexSize();
+ m_nIndexCount = nIndexCount;
+ m_nFirstUnwrittenOffset = 0;
+ m_bIsLocked = false;
+ m_bIsDynamic = IsDynamicBufferType( bufferType );
+ m_bFlush = false;
+
+#ifdef CHECK_INDICES
+ m_pShadowIndices = NULL;
+#endif
+
+#ifdef VPROF_ENABLED
+ m_nVProfFrame = -1;
+#endif
+}
+
+CIndexBufferDx8::~CIndexBufferDx8()
+{
+ Free();
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the index size
+//-----------------------------------------------------------------------------
+inline int CIndexBufferDx8::IndexSize() const
+{
+ Assert( m_IndexFormat != MATERIAL_INDEX_FORMAT_UNKNOWN );
+ return ( m_IndexFormat == MATERIAL_INDEX_FORMAT_16BIT ) ? 2 : 4;
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates, destroys the index buffer
+//-----------------------------------------------------------------------------
+bool CIndexBufferDx8::Allocate()
+{
+#ifdef OSX
+ Debugger();
+#endif
+ Assert( !m_pIndexBuffer );
+ m_nFirstUnwrittenOffset = 0;
+
+ // FIXME: This doesn't really work for dynamic buffers; dynamic buffers
+ // can't have mixed-type indices in them. Bleah.
+ D3DFORMAT format = ( m_IndexFormat == MATERIAL_INDEX_FORMAT_32BIT ) ?
+ D3DFMT_INDEX32 : D3DFMT_INDEX16;
+
+ DWORD usage = D3DUSAGE_WRITEONLY;
+ if ( m_bIsDynamic )
+ {
+ usage |= D3DUSAGE_DYNAMIC;
+ }
+
+ HRESULT hr = Dx9Device()->CreateIndexBuffer(
+ m_nBufferSize, usage, format, D3DPOOL_DEFAULT, &m_pIndexBuffer, NULL );
+
+#if !defined( _X360 )
+ if ( ( hr == D3DERR_OUTOFVIDEOMEMORY ) || ( hr == E_OUTOFMEMORY ) )
+ {
+ // Don't have the memory for this. Try flushing all managed resources
+ // out of vid mem and try again.
+ // FIXME: need to record this
+ Dx9Device()->EvictManagedResources();
+ hr = Dx9Device()->CreateIndexBuffer(
+ m_nBufferSize, usage, format, D3DPOOL_DEFAULT, &m_pIndexBuffer, NULL );
+ }
+#endif // !X360
+
+ if ( FAILED(hr) || ( m_pIndexBuffer == NULL ) )
+ {
+ Warning( "CIndexBufferDx8::Allocate: CreateIndexBuffer failed!\n" );
+ return false;
+ }
+
+ if ( !m_bIsDynamic )
+ {
+ VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_global_" TEXTURE_GROUP_STATIC_INDEX_BUFFER,
+ COUNTER_GROUP_TEXTURE_GLOBAL, m_nBufferSize );
+ }
+ else
+ {
+ VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_global_" TEXTURE_GROUP_DYNAMIC_INDEX_BUFFER,
+ COUNTER_GROUP_TEXTURE_GLOBAL, m_nBufferSize );
+ }
+
+#ifdef CHECK_INDICES
+ Assert ( !m_pShadowIndices );
+ m_pShadowIndices = new unsigned char[ m_nBufferSize ];
+ memset( m_pShadowIndices, 0xFF, m_nBufferSize );
+#endif // CHECK_INDICES
+
+#ifdef _DEBUG
+ ++s_nBufferCount;
+#endif
+
+ return true;
+}
+
+void CIndexBufferDx8::Free()
+{
+// FIXME: Unlock(0);
+ if ( m_pIndexBuffer )
+ {
+#ifdef _DEBUG
+ --s_nBufferCount;
+#endif
+
+ m_pIndexBuffer->Release();
+ m_pIndexBuffer = NULL;
+
+ if ( !m_bIsDynamic )
+ {
+ VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_global_" TEXTURE_GROUP_STATIC_INDEX_BUFFER,
+ COUNTER_GROUP_TEXTURE_GLOBAL, - m_nBufferSize );
+ }
+ else
+ {
+ VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_global_" TEXTURE_GROUP_DYNAMIC_INDEX_BUFFER,
+ COUNTER_GROUP_TEXTURE_GLOBAL, - m_nBufferSize );
+ }
+ }
+
+#ifdef CHECK_INDICES
+ if ( m_pShadowIndices )
+ {
+ delete[] m_pShadowIndices;
+ m_pShadowIndices = NULL;
+ }
+#endif // CHECK_INDICES
+}
+
+
+//-----------------------------------------------------------------------------
+// Index buffer information
+//-----------------------------------------------------------------------------
+int CIndexBufferDx8::IndexCount( ) const
+{
+ Assert( !m_bIsDynamic );
+ return m_nIndexCount;
+}
+
+MaterialIndexFormat_t CIndexBufferDx8::IndexFormat() const
+{
+ Assert( !m_bIsDynamic );
+ return m_IndexFormat;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns true if the buffer is dynamic
+//-----------------------------------------------------------------------------
+bool CIndexBufferDx8::IsDynamic() const
+{
+ return m_bIsDynamic;
+}
+
+
+//-----------------------------------------------------------------------------
+// Only used by dynamic buffers, indicates the next lock should perform a discard.
+//-----------------------------------------------------------------------------
+void CIndexBufferDx8::Flush()
+{
+ // This strange-looking line makes a flush only occur if the buffer is dynamic.
+ m_bFlush = m_bIsDynamic;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the D3D buffer
+//-----------------------------------------------------------------------------
+IDirect3DIndexBuffer9* CIndexBufferDx8::GetDx9Buffer()
+{
+ return m_pIndexBuffer;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns a shadowed index, for validation
+//-----------------------------------------------------------------------------
+#ifdef CHECK_INDICES
+unsigned short CIndexBufferDx8::GetShadowIndex( int i ) const
+{
+ Assert( i >= 0 && i < m_nIndexCount );
+ Assert( m_IndexFormat == MATERIAL_INDEX_FORMAT_16BIT );
+ return *(unsigned short*)( &m_pShadowIndices[ i * IndexSize() ] );
+}
+#endif // CHECK_INDICES
+
+
+//-----------------------------------------------------------------------------
+// Used to measure how much static buffer memory is touched each frame
+//-----------------------------------------------------------------------------
+void CIndexBufferDx8::HandlePerFrameTextureStats( int nFrame )
+{
+#ifdef VPROF_ENABLED
+ if ( m_nVProfFrame != nFrame && !m_bIsDynamic )
+ {
+ m_nVProfFrame = nFrame;
+ VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_frame_" TEXTURE_GROUP_STATIC_INDEX_BUFFER,
+ COUNTER_GROUP_TEXTURE_PER_FRAME, m_nBufferSize );
+ }
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Casts a dynamic buffer to be a particular index type
+//-----------------------------------------------------------------------------
+void CIndexBufferDx8::BeginCastBuffer( MaterialIndexFormat_t format )
+{
+ // NOTE: This should have no effect under Dx9, since we can't recast index buffers.
+ Assert( format != MATERIAL_INDEX_FORMAT_UNKNOWN );
+ Assert( m_bIsDynamic && ( m_IndexFormat == format ) );
+}
+
+void CIndexBufferDx8::EndCastBuffer( )
+{
+ // NOTE: This should have no effect under Dx9, since we can't recast index buffers.
+}
+
+int CIndexBufferDx8::GetRoomRemaining() const
+{
+ return ( m_nBufferSize - m_nFirstUnwrittenOffset ) / IndexSize();
+}
+
+
+//-----------------------------------------------------------------------------
+// Locks/unlocks the index buffer
+//-----------------------------------------------------------------------------
+bool CIndexBufferDx8::Lock( int nMaxIndexCount, bool bAppend, IndexDesc_t &desc )
+{
+ Assert( !m_bIsLocked && ( nMaxIndexCount != 0 ) && ( nMaxIndexCount <= m_nIndexCount ) );
+ Assert( m_IndexFormat != MATERIAL_INDEX_FORMAT_UNKNOWN );
+
+ // FIXME: Why do we need to sync matrices now?
+ ShaderUtil()->SyncMatrices();
+ g_ShaderMutex.Lock();
+
+ VPROF( "CIndexBufferX8::Lock" );
+
+ void *pLockedData = NULL;
+ HRESULT hr;
+ int nMemoryRequired;
+ bool bHasEnoughMemory;
+ UINT nLockFlags;
+
+ // This can happen if the buffer was locked but a type wasn't bound
+ if ( m_IndexFormat == MATERIAL_INDEX_FORMAT_UNKNOWN )
+ goto indexBufferLockFailed;
+
+ // Just give the app crap buffers to fill up while we're suppressed...
+ if ( g_pShaderDeviceDx8->IsDeactivated() || ( nMaxIndexCount == 0 ) )
+ goto indexBufferLockFailed;
+
+ // Did we ask for something too large?
+ if ( nMaxIndexCount > m_nIndexCount )
+ {
+ Warning( "Too many indices for index buffer. . tell a programmer (%d>%d)\n", nMaxIndexCount, m_nIndexCount );
+ goto indexBufferLockFailed;
+ }
+
+ // We might not have a buffer owing to alt-tab type stuff
+ if ( !m_pIndexBuffer )
+ {
+ if ( !Allocate() )
+ goto indexBufferLockFailed;
+ }
+
+ // Check to see if we have enough memory
+ nMemoryRequired = nMaxIndexCount * IndexSize();
+ bHasEnoughMemory = ( m_nFirstUnwrittenOffset + nMemoryRequired <= m_nBufferSize );
+
+ nLockFlags = D3DLOCK_NOSYSLOCK;
+ if ( bAppend )
+ {
+ // Can't have the first lock after a flush be an appending lock
+ Assert( !m_bFlush );
+
+ // If we're appending and we don't have enough room, then puke!
+ if ( !bHasEnoughMemory || m_bFlush )
+ goto indexBufferLockFailed;
+ nLockFlags |= ( m_nFirstUnwrittenOffset == 0 ) ? D3DLOCK_DISCARD : D3DLOCK_NOOVERWRITE;
+ }
+ else
+ {
+ // If we're not appending, no overwrite unless we don't have enough room
+ // If we're a static buffer, always discard if we're not appending
+ if ( !m_bFlush && bHasEnoughMemory && m_bIsDynamic )
+ {
+ nLockFlags |= ( m_nFirstUnwrittenOffset == 0 ) ? D3DLOCK_DISCARD : D3DLOCK_NOOVERWRITE;
+ }
+ else
+ {
+ if ( m_bIsDynamic )
+ {
+ nLockFlags |= D3DLOCK_DISCARD;
+ }
+ m_nFirstUnwrittenOffset = 0;
+ m_bFlush = false;
+ }
+ }
+
+#if !defined( _X360 )
+ hr = m_pIndexBuffer->Lock( m_nFirstUnwrittenOffset, nMemoryRequired, &pLockedData, nLockFlags );
+#else
+ hr = m_pIndexBuffer->Lock( 0, 0, &pLockedData, nLockFlags );
+ pLockedData = ( ( unsigned char * )pLockedData + m_nFirstUnwrittenOffset );
+#endif
+
+ if ( FAILED( hr ) )
+ {
+ Warning( "Failed to lock index buffer in CIndexBufferDx8::LockIndexBuffer\n" );
+ goto indexBufferLockFailed;
+ }
+
+ desc.m_pIndices = (unsigned short*)( pLockedData );
+ desc.m_nIndexSize = IndexSize() >> 1;
+ if ( g_pHardwareConfig->SupportsStreamOffset() )
+ {
+ desc.m_nFirstIndex = 0;
+ desc.m_nOffset = m_nFirstUnwrittenOffset;
+ }
+ else
+ {
+ desc.m_nFirstIndex = m_nFirstUnwrittenOffset / IndexSize();
+ Assert( (int)( desc.m_nFirstIndex * IndexSize() ) == m_nFirstUnwrittenOffset );
+ desc.m_nOffset = 0;
+ }
+ m_bIsLocked = true;
+
+#ifdef CHECK_INDICES
+ m_nLockIndexBufferSize = nMemoryRequired;
+ m_pLockIndexBuffer = desc.m_pIndices;
+ m_nLockIndexOffset = m_nFirstUnwrittenOffset;
+#endif // CHECK_INDICES
+
+ return true;
+
+indexBufferLockFailed:
+ g_ShaderMutex.Unlock();
+
+ // Set up a bogus index descriptor
+ desc.m_pIndices = g_nScratchIndexBuffer;
+ desc.m_nIndexSize = 0;
+ desc.m_nFirstIndex = 0;
+ desc.m_nOffset = 0;
+ return false;
+}
+
+void CIndexBufferDx8::Unlock( int nWrittenIndexCount, IndexDesc_t &desc )
+{
+ Assert( nWrittenIndexCount <= m_nIndexCount );
+
+ // NOTE: This can happen if another application finishes
+ // initializing during the construction of a mesh
+ if ( !m_bIsLocked )
+ return;
+
+#ifdef CHECK_INDICES
+ memcpy( (unsigned char*)m_pShadowIndices + m_nLockIndexOffset, m_pLockIndexBuffer, nWrittenIndexCount * IndexSize() );
+#endif // CHECK_INDICES
+
+ if ( m_pIndexBuffer )
+ {
+ m_pIndexBuffer->Unlock();
+ }
+
+ m_nFirstUnwrittenOffset += nWrittenIndexCount * IndexSize();
+ m_bIsLocked = false;
+ g_ShaderMutex.Unlock();
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// Vertex Buffer implementations begin here
+//
+//-----------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------
+// globals
+//-----------------------------------------------------------------------------
+#ifdef _DEBUG
+int CVertexBufferDx8::s_nBufferCount = 0;
+#endif
+
+
+//-----------------------------------------------------------------------------
+// constructor
+//-----------------------------------------------------------------------------
+CVertexBufferDx8::CVertexBufferDx8( ShaderBufferType_t type, VertexFormat_t fmt, int nVertexCount, const char *pBudgetGroupName ) :
+ BaseClass( pBudgetGroupName )
+{
+// Debugger();
+ Assert( nVertexCount != 0 );
+
+ m_pVertexBuffer = NULL;
+ m_VertexFormat = fmt;
+ m_nVertexCount = ( fmt == VERTEX_FORMAT_UNKNOWN ) ? 0 : nVertexCount;
+ m_nBufferSize = ( fmt == VERTEX_FORMAT_UNKNOWN ) ? nVertexCount : nVertexCount * VertexSize();
+ m_nFirstUnwrittenOffset = 0;
+ m_bIsLocked = false;
+ m_bIsDynamic = ( type == SHADER_BUFFER_TYPE_DYNAMIC ) || ( type == SHADER_BUFFER_TYPE_DYNAMIC_TEMP );
+ m_bFlush = false;
+
+#ifdef VPROF_ENABLED
+ if ( !m_bIsDynamic )
+ {
+ char name[256];
+ V_strcpy_safe( name, "TexGroup_global_" );
+ V_strcat_safe( name, pBudgetGroupName, sizeof(name) );
+ m_pGlobalCounter = g_VProfCurrentProfile.FindOrCreateCounter( name, COUNTER_GROUP_TEXTURE_GLOBAL );
+
+ V_strcpy_safe( name, "TexGroup_frame_" );
+ V_strcat_safe( name, pBudgetGroupName, sizeof(name) );
+ m_pFrameCounter = g_VProfCurrentProfile.FindOrCreateCounter( name, COUNTER_GROUP_TEXTURE_PER_FRAME );
+ }
+ else
+ {
+ m_pGlobalCounter = g_VProfCurrentProfile.FindOrCreateCounter( "TexGroup_global_" TEXTURE_GROUP_DYNAMIC_VERTEX_BUFFER, COUNTER_GROUP_TEXTURE_GLOBAL );
+ m_pFrameCounter = NULL;
+ }
+ m_nVProfFrame = -1;
+#endif
+}
+
+CVertexBufferDx8::~CVertexBufferDx8()
+{
+ Free();
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the vertex size
+//-----------------------------------------------------------------------------
+inline int CVertexBufferDx8::VertexSize() const
+{
+ Assert( m_VertexFormat != VERTEX_FORMAT_UNKNOWN );
+ return VertexFormatSize( m_VertexFormat );
+}
+
+//-----------------------------------------------------------------------------
+// Creates, destroys the vertex buffer
+//-----------------------------------------------------------------------------
+bool CVertexBufferDx8::Allocate()
+{
+ Assert( !m_pVertexBuffer );
+ m_nFirstUnwrittenOffset = 0;
+
+ D3DPOOL pool = D3DPOOL_MANAGED;
+
+#if defined(IS_WINDOWS_PC) && defined(SHADERAPIDX9)
+ extern bool g_ShaderDeviceUsingD3D9Ex;
+ if ( g_ShaderDeviceUsingD3D9Ex )
+ {
+ pool = D3DPOOL_DEFAULT;
+ }
+#endif
+
+ DWORD usage = D3DUSAGE_WRITEONLY;
+ if ( m_bIsDynamic )
+ {
+ usage |= D3DUSAGE_DYNAMIC;
+ pool = D3DPOOL_DEFAULT;
+ // Dynamic meshes should never be compressed (slows down writing to them)
+ Assert( CompressionType( GetVertexFormat() ) == VERTEX_COMPRESSION_NONE );
+ }
+
+ HRESULT hr = Dx9Device()->CreateVertexBuffer(
+ m_nBufferSize, usage, 0, pool, &m_pVertexBuffer, NULL );
+
+#if !defined( _X360 )
+ if ( ( hr == D3DERR_OUTOFVIDEOMEMORY ) || ( hr == E_OUTOFMEMORY ) )
+ {
+ // Don't have the memory for this. Try flushing all managed resources
+ // out of vid mem and try again.
+ // FIXME: need to record this
+ Dx9Device()->EvictManagedResources();
+ hr = Dx9Device()->CreateVertexBuffer(
+ m_nBufferSize, usage, 0, pool, &m_pVertexBuffer, NULL );
+ }
+#endif // !X360
+
+ if ( FAILED(hr) || ( m_pVertexBuffer == NULL ) )
+ {
+ Warning( "CVertexBufferDx8::Allocate: CreateVertexBuffer failed!\n" );
+ return false;
+ }
+
+ // Track VB allocations
+ g_VBAllocTracker->CountVB( m_pVertexBuffer, m_bIsDynamic, m_nBufferSize, VertexSize(), GetVertexFormat() );
+
+#ifdef VPROF_ENABLED
+ if ( IsX360() || !m_bIsDynamic )
+ {
+ Assert( m_pGlobalCounter );
+ *m_pGlobalCounter += m_nBufferSize;
+ }
+#endif
+
+#ifdef _DEBUG
+ ++s_nBufferCount;
+#endif
+
+ return true;
+}
+
+void CVertexBufferDx8::Free()
+{
+ // FIXME: Unlock(0);
+ if ( m_pVertexBuffer )
+ {
+#ifdef _DEBUG
+ --s_nBufferCount;
+#endif
+
+ // Track VB allocations
+ g_VBAllocTracker->UnCountVB( m_pVertexBuffer );
+
+#ifdef VPROF_ENABLED
+ if ( IsX360() || !m_bIsDynamic )
+ {
+ Assert( m_pGlobalCounter );
+ *m_pGlobalCounter -= m_nBufferSize;
+ }
+#endif
+
+ m_pVertexBuffer->Release();
+ m_pVertexBuffer = NULL;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Vertex buffer information
+//-----------------------------------------------------------------------------
+int CVertexBufferDx8::VertexCount() const
+{
+ Assert( !m_bIsDynamic );
+ return m_nVertexCount;
+}
+
+VertexFormat_t CVertexBufferDx8::GetVertexFormat() const
+{
+ Assert( !m_bIsDynamic );
+ return m_VertexFormat;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns true if the buffer is dynamic
+//-----------------------------------------------------------------------------
+bool CVertexBufferDx8::IsDynamic() const
+{
+ return m_bIsDynamic;
+}
+
+
+//-----------------------------------------------------------------------------
+// Only used by dynamic buffers, indicates the next lock should perform a discard.
+//-----------------------------------------------------------------------------
+void CVertexBufferDx8::Flush()
+{
+ // This strange-looking line makes a flush only occur if the buffer is dynamic.
+ m_bFlush = m_bIsDynamic;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the D3D buffer
+//-----------------------------------------------------------------------------
+IDirect3DVertexBuffer9* CVertexBufferDx8::GetDx9Buffer()
+{
+ return m_pVertexBuffer;
+}
+
+
+//-----------------------------------------------------------------------------
+// Casts a dynamic buffer to be a particular vertex type
+//-----------------------------------------------------------------------------
+void CVertexBufferDx8::BeginCastBuffer( VertexFormat_t format )
+{
+ Assert( format != MATERIAL_INDEX_FORMAT_UNKNOWN );
+ Assert( m_bIsDynamic && ( m_VertexFormat == 0 || m_VertexFormat == format ) );
+ if ( !m_bIsDynamic )
+ return;
+
+ m_VertexFormat = format;
+ int nVertexSize = VertexSize();
+ m_nVertexCount = m_nBufferSize / nVertexSize;
+
+ // snap current position up to the next position based on expected size
+ // so append can safely guarantee nooverwrite regardless of a format growth or shrinkage
+ if ( !g_pHardwareConfig->SupportsStreamOffset() )
+ {
+ m_nFirstUnwrittenOffset = ( m_nFirstUnwrittenOffset + nVertexSize - 1 ) / nVertexSize;
+ m_nFirstUnwrittenOffset *= nVertexSize;
+ if ( m_nFirstUnwrittenOffset > m_nBufferSize )
+ {
+ m_nFirstUnwrittenOffset = m_nBufferSize;
+ }
+ }
+}
+
+void CVertexBufferDx8::EndCastBuffer( )
+{
+ Assert( m_bIsDynamic && m_VertexFormat != 0 );
+ if ( !m_bIsDynamic )
+ return;
+ m_VertexFormat = 0;
+ m_nVertexCount = 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the number of vertices we can still write into the buffer
+//-----------------------------------------------------------------------------
+int CVertexBufferDx8::GetRoomRemaining() const
+{
+ return ( m_nBufferSize - m_nFirstUnwrittenOffset ) / VertexSize();
+}
+
+
+//-----------------------------------------------------------------------------
+// Locks/unlocks the vertex buffer mesh
+//-----------------------------------------------------------------------------
+bool CVertexBufferDx8::Lock( int nMaxVertexCount, bool bAppend, VertexDesc_t &desc )
+{
+ Assert( !m_bIsLocked && ( nMaxVertexCount != 0 ) && ( nMaxVertexCount <= m_nVertexCount ) );
+ Assert( m_VertexFormat != VERTEX_FORMAT_UNKNOWN );
+
+ // FIXME: Why do we need to sync matrices now?
+ ShaderUtil()->SyncMatrices();
+ g_ShaderMutex.Lock();
+
+ VPROF( "CVertexBufferDx8::Lock" );
+
+ void *pLockedData = NULL;
+ HRESULT hr;
+ int nMemoryRequired;
+ bool bHasEnoughMemory;
+ UINT nLockFlags;
+
+ // This can happen if the buffer was locked but a type wasn't bound
+ if ( m_VertexFormat == VERTEX_FORMAT_UNKNOWN )
+ goto vertexBufferLockFailed;
+
+ // Just give the app crap buffers to fill up while we're suppressed...
+ if ( g_pShaderDeviceDx8->IsDeactivated() || ( nMaxVertexCount == 0 ) )
+ goto vertexBufferLockFailed;
+
+ // Did we ask for something too large?
+ if ( nMaxVertexCount > m_nVertexCount )
+ {
+ Warning( "Too many vertices for vertex buffer. . tell a programmer (%d>%d)\n", nMaxVertexCount, m_nVertexCount );
+ goto vertexBufferLockFailed;
+ }
+
+ // We might not have a buffer owing to alt-tab type stuff
+ if ( !m_pVertexBuffer )
+ {
+ if ( !Allocate() )
+ goto vertexBufferLockFailed;
+ }
+
+ // Check to see if we have enough memory
+ nMemoryRequired = nMaxVertexCount * VertexSize();
+ bHasEnoughMemory = ( m_nFirstUnwrittenOffset + nMemoryRequired <= m_nBufferSize );
+
+ nLockFlags = D3DLOCK_NOSYSLOCK;
+ if ( bAppend )
+ {
+ // Can't have the first lock after a flush be an appending lock
+ Assert( !m_bFlush );
+
+ // If we're appending and we don't have enough room, then puke!
+ if ( !bHasEnoughMemory || m_bFlush )
+ goto vertexBufferLockFailed;
+ nLockFlags |= ( m_nFirstUnwrittenOffset == 0 ) ? D3DLOCK_DISCARD : D3DLOCK_NOOVERWRITE;
+ }
+ else
+ {
+ // If we're not appending, no overwrite unless we don't have enough room
+ // If we're a static buffer, always discard if we're not appending
+ if ( !m_bFlush && bHasEnoughMemory && m_bIsDynamic )
+ {
+ nLockFlags |= ( m_nFirstUnwrittenOffset == 0 ) ? D3DLOCK_DISCARD : D3DLOCK_NOOVERWRITE;
+ }
+ else
+ {
+ if ( m_bIsDynamic )
+ {
+ nLockFlags |= D3DLOCK_DISCARD;
+ }
+ m_nFirstUnwrittenOffset = 0;
+ m_bFlush = false;
+ }
+ }
+
+#if !defined( _X360 )
+ hr = m_pVertexBuffer->Lock( m_nFirstUnwrittenOffset, nMemoryRequired, &pLockedData, nLockFlags );
+#else
+ hr = m_pVertexBuffer->Lock( 0, 0, &pLockedData, nLockFlags );
+ pLockedData = (unsigned char*)pLockedData + m_nFirstUnwrittenOffset;
+#endif
+
+ if ( FAILED( hr ) )
+ {
+ // Check if paged pool is in critical state ( < 5% free )
+ PAGED_POOL_INFO_t ppi;
+ if ( ( SYSCALL_SUCCESS == Plat_GetPagedPoolInfo( &ppi ) ) &&
+ ( ( ppi.numPagesFree * 20 ) < ( ppi.numPagesUsed + ppi.numPagesFree ) ) )
+ {
+ Error( "Out of OS Paged Pool Memory! For more information, please see\nhttp://support.steampowered.com/cgi-bin/steampowered.cfg/php/enduser/std_adp.php?p_faqid=150\n" );
+ }
+ else
+ {
+ Warning( "Failed to lock vertex buffer in CVertexBufferDx8::Lock\n" );
+ }
+ goto vertexBufferLockFailed;
+ }
+
+ ComputeVertexDescription( (unsigned char*)pLockedData, m_VertexFormat, desc );
+ if ( g_pHardwareConfig->SupportsStreamOffset() )
+ {
+ desc.m_nFirstVertex = 0;
+ desc.m_nOffset = m_nFirstUnwrittenOffset;
+ }
+ else
+ {
+ desc.m_nFirstVertex = m_nFirstUnwrittenOffset / VertexSize();
+ desc.m_nOffset = 0;
+ Assert( m_nFirstUnwrittenOffset == VertexSize() * desc.m_nFirstVertex );
+ }
+ m_bIsLocked = true;
+ return true;
+
+vertexBufferLockFailed:
+ ComputeVertexDescription( 0, 0, desc );
+ desc.m_nFirstVertex = 0;
+ desc.m_nOffset = 0;
+ return false;
+}
+
+
+void CVertexBufferDx8::Unlock( int nWrittenVertexCount, VertexDesc_t &desc )
+{
+ Assert( nWrittenVertexCount <= m_nVertexCount );
+
+ // NOTE: This can happen if another application finishes
+ // initializing during the construction of a mesh
+ if ( !m_bIsLocked )
+ return;
+
+ if ( m_pVertexBuffer )
+ {
+ m_pVertexBuffer->Unlock();
+ }
+
+ m_nFirstUnwrittenOffset += nWrittenVertexCount * VertexSize();
+ m_bIsLocked = false;
+ g_ShaderMutex.Unlock();
+}
+
+
+//-----------------------------------------------------------------------------
+// Used to measure how much static buffer memory is touched each frame
+//-----------------------------------------------------------------------------
+void CVertexBufferDx8::HandlePerFrameTextureStats( int nFrame )
+{
+#ifdef VPROF_ENABLED
+ if ( m_nVProfFrame != nFrame && !m_bIsDynamic )
+ {
+ m_nVProfFrame = nFrame;
+ m_pFrameCounter += m_nBufferSize;
+ }
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Helpers with meshdescs...
+//-----------------------------------------------------------------------------
+// FIXME: add compression-agnostic read-accessors (which decompress and return by value, checking desc.m_CompressionType)
+inline D3DXVECTOR3 &Position( MeshDesc_t const &desc, int vert )
+{
+ return *(D3DXVECTOR3*)((unsigned char*)desc.m_pPosition + vert * desc.m_VertexSize_Position );
+}
+
+inline float Wrinkle( MeshDesc_t const &desc, int vert )
+{
+ return *(float*)((unsigned char*)desc.m_pWrinkle + vert * desc.m_VertexSize_Wrinkle );
+}
+
+inline D3DXVECTOR3 &BoneWeight( MeshDesc_t const &desc, int vert )
+{
+ Assert( desc.m_CompressionType == VERTEX_COMPRESSION_NONE );
+ return *(D3DXVECTOR3*)((unsigned char*)desc.m_pBoneWeight + vert * desc.m_VertexSize_BoneWeight );
+}
+
+inline unsigned char *BoneIndex( MeshDesc_t const &desc, int vert )
+{
+ return desc.m_pBoneMatrixIndex + vert * desc.m_VertexSize_BoneMatrixIndex;
+}
+
+inline D3DXVECTOR3 &Normal( MeshDesc_t const &desc, int vert )
+{
+ Assert( desc.m_CompressionType == VERTEX_COMPRESSION_NONE );
+ return *(D3DXVECTOR3*)((unsigned char*)desc.m_pNormal + vert * desc.m_VertexSize_Normal );
+}
+
+inline unsigned char *Color( MeshDesc_t const &desc, int vert )
+{
+ return desc.m_pColor + vert * desc.m_VertexSize_Color;
+}
+
+inline D3DXVECTOR2 &TexCoord( MeshDesc_t const &desc, int vert, int stage )
+{
+ return *(D3DXVECTOR2*)((unsigned char*)desc.m_pTexCoord[stage] + vert * desc.m_VertexSize_TexCoord[stage] );
+}
+
+inline D3DXVECTOR3 &TangentS( MeshDesc_t const &desc, int vert )
+{
+ return *(D3DXVECTOR3*)((unsigned char*)desc.m_pTangentS + vert * desc.m_VertexSize_TangentS );
+}
+
+inline D3DXVECTOR3 &TangentT( MeshDesc_t const &desc, int vert )
+{
+ return *(D3DXVECTOR3*)((unsigned char*)desc.m_pTangentT + vert * desc.m_VertexSize_TangentT );
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// Base mesh
+//
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+
+CBaseMeshDX8::CBaseMeshDX8() : m_VertexFormat(0)
+{
+ m_bMeshLocked = false;
+#ifdef DBGFLAG_ASSERT
+ m_IsDrawing = false;
+ m_pMaterial = 0;
+#endif
+}
+
+CBaseMeshDX8::~CBaseMeshDX8()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// For debugging...
+//-----------------------------------------------------------------------------
+bool CBaseMeshDX8::DebugTrace() const
+{
+#ifdef _DEBUG
+ if (m_pMaterial)
+ return m_pMaterial->PerformDebugTrace();
+#endif
+
+ return false;
+}
+
+void CBaseMeshDX8::SetMaterial( IMaterial *pMaterial )
+{
+#ifdef DBGFLAG_ASSERT
+ m_pMaterial = static_cast<IMaterialInternal *>(pMaterial);
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets, gets the vertex format
+//-----------------------------------------------------------------------------
+void CBaseMeshDX8::SetVertexFormat( VertexFormat_t format )
+{
+ m_VertexFormat = format;
+}
+
+VertexFormat_t CBaseMeshDX8::GetVertexFormat() const
+{
+ return m_VertexFormat;
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets/gets the morph format
+//-----------------------------------------------------------------------------
+void CBaseMeshDX8::SetMorphFormat( MorphFormat_t format )
+{
+ m_MorphFormat = format;
+}
+
+MorphFormat_t CBaseMeshDX8::GetMorphFormat() const
+{
+ return m_MorphFormat;
+}
+
+
+//-----------------------------------------------------------------------------
+// Am I using morph data?
+//-----------------------------------------------------------------------------
+bool CBaseMeshDX8::IsUsingMorphData() const
+{
+ LOCK_SHADERAPI();
+ // We're not using a morph unless the bound morph is a superset of what the rendermesh needs
+ MorphFormat_t morphFormat = GetMorphFormat();
+ if ( !morphFormat )
+ return false;
+
+ return ( ( morphFormat & ShaderUtil()->GetBoundMorphFormat() ) == morphFormat );
+}
+
+//-----------------------------------------------------------------------------
+// Do I need to reset the vertex format?
+//-----------------------------------------------------------------------------
+bool CBaseMeshDX8::NeedsVertexFormatReset( VertexFormat_t fmt ) const
+{
+ return m_VertexFormat != fmt;
+}
+
+
+//-----------------------------------------------------------------------------
+// Do I have enough room?
+//-----------------------------------------------------------------------------
+bool CBaseMeshDX8::HasEnoughRoom( int nVertexCount, int nIndexCount ) const
+{
+ // by default, we do
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Estimate the memory used
+//-----------------------------------------------------------------------------
+unsigned CBaseMeshDX8::ComputeMemoryUsed()
+{
+ unsigned size = 0;
+
+ if ( GetVertexBuffer() )
+ {
+ size += GetVertexBuffer()->VertexCount() * GetVertexBuffer()->VertexSize();
+ }
+
+ if ( GetIndexBuffer() )
+ {
+ size += GetIndexBuffer()->IndexCount() * GetIndexBuffer()->IndexSize();
+ }
+
+ return size;
+}
+
+
+//-----------------------------------------------------------------------------
+// Locks mesh for modifying
+//-----------------------------------------------------------------------------
+void CBaseMeshDX8::ModifyBeginEx( bool bReadOnly, int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t& desc )
+{
+ LOCK_SHADERAPI();
+ // for the time being, disallow for most cases
+ Assert(0);
+}
+
+void CBaseMeshDX8::ModifyBegin( int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t& desc )
+{
+ LOCK_SHADERAPI();
+ // for the time being, disallow for most cases
+ Assert(0);
+}
+
+void CBaseMeshDX8::ModifyEnd( MeshDesc_t& desc )
+{
+ LOCK_SHADERAPI();
+ // for the time being, disallow for most cases
+ Assert(0);
+}
+
+
+//-----------------------------------------------------------------------------
+// Begins a pass
+//-----------------------------------------------------------------------------
+void CBaseMeshDX8::BeginPass( )
+{
+ LOCK_SHADERAPI();
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the render state and gets the drawing going
+//-----------------------------------------------------------------------------
+inline void CBaseMeshDX8::DrawMesh( )
+{
+#ifdef DBGFLAG_ASSERT
+ // Make sure we're not drawing...
+ Assert( !m_IsDrawing );
+ m_IsDrawing = true;
+#endif
+
+ // This is going to cause RenderPass to get called a bunch
+ ShaderAPI()->DrawMesh( this );
+
+#ifdef DBGFLAG_ASSERT
+ m_IsDrawing = false;
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Spews the mesh data
+//-----------------------------------------------------------------------------
+void CBaseMeshDX8::Spew( int nVertexCount, int nIndexCount, const MeshDesc_t &spewDesc )
+{
+ LOCK_SHADERAPI();
+ // This has regressed.
+ int i;
+
+
+ // FIXME: just fall back to the base class (CVertexBufferBase) version of this function!
+
+
+#ifdef _DEBUG
+ if( m_pMaterial )
+ {
+ Plat_DebugString( ( const char * )m_pMaterial->GetName() );
+ Plat_DebugString( "\n" );
+ }
+#endif // _DEBUG
+
+ // This is needed so buffering can just use this
+ VertexFormat_t fmt = m_VertexFormat;
+
+ // Set up the vertex descriptor
+ MeshDesc_t desc = spewDesc;
+
+ char tempbuf[256];
+ char* temp = tempbuf;
+ sprintf( tempbuf,"\nVerts: (Vertex Format %llx)\n", fmt);
+ Plat_DebugString(tempbuf);
+
+ CVertexBufferBase::PrintVertexFormat( fmt );
+
+ int numBoneWeights = NumBoneWeights( fmt );
+ for ( i = 0; i < nVertexCount; ++i )
+ {
+ temp += sprintf( temp, "[%4d] ", i + desc.m_nFirstVertex );
+ if( fmt & VERTEX_POSITION )
+ {
+ D3DXVECTOR3& pos = Position( desc, i );
+ temp += sprintf(temp, "P %8.2f %8.2f %8.2f ",
+ pos[0], pos[1], pos[2]);
+ }
+
+ if ( fmt & VERTEX_WRINKLE )
+ {
+ float flWrinkle = Wrinkle( desc, i );
+ temp += sprintf(temp, "Wr %8.2f ",flWrinkle );
+ }
+
+ if (numBoneWeights > 0)
+ {
+ temp += sprintf(temp, "BW ");
+ float* pWeight = BoneWeight( desc, i );
+ for (int j = 0; j < numBoneWeights; ++j)
+ {
+ temp += sprintf(temp, "%1.2f ", pWeight[j]);
+ }
+ }
+ if ( fmt & VERTEX_BONE_INDEX )
+ {
+ unsigned char *pIndex = BoneIndex( desc, i );
+ temp += sprintf( temp, "BI %d %d %d %d ", ( int )pIndex[0], ( int )pIndex[1], ( int )pIndex[2], ( int )pIndex[3] );
+ Assert( pIndex[0] < 16 );
+ Assert( pIndex[1] < 16 );
+ Assert( pIndex[2] < 16 );
+ Assert( pIndex[3] < 16 );
+ }
+
+ if ( fmt & VERTEX_NORMAL )
+ {
+ D3DXVECTOR3& normal = Normal( desc, i );
+ temp += sprintf(temp, "N %1.2f %1.2f %1.2f ",
+ normal[0], normal[1], normal[2]);
+ }
+
+ if (fmt & VERTEX_COLOR)
+ {
+ unsigned char* pColor = Color( desc, i );
+ temp += sprintf(temp, "C b %3d g %3d r %3d a %3d ",
+ pColor[0], pColor[1], pColor[2], pColor[3]);
+ }
+
+ for (int j = 0; j < VERTEX_MAX_TEXTURE_COORDINATES; ++j)
+ {
+ if( TexCoordSize( j, fmt ) > 0)
+ {
+ D3DXVECTOR2& texcoord = TexCoord( desc, i, j );
+ temp += sprintf(temp, "T%d %.2f %.2f ", j,texcoord[0], texcoord[1]);
+ }
+ }
+
+ if (fmt & VERTEX_TANGENT_S)
+ {
+ D3DXVECTOR3& tangentS = TangentS( desc, i );
+ temp += sprintf(temp, "S %1.2f %1.2f %1.2f ",
+ tangentS[0], tangentS[1], tangentS[2]);
+ }
+
+ if (fmt & VERTEX_TANGENT_T)
+ {
+ D3DXVECTOR3& tangentT = TangentT( desc, i );
+ temp += sprintf(temp, "T %1.2f %1.2f %1.2f ",
+ tangentT[0], tangentT[1], tangentT[2]);
+ }
+
+ sprintf(temp,"\n");
+ Plat_DebugString(tempbuf);
+ temp = tempbuf;
+ }
+
+ sprintf( tempbuf,"\nIndices: %d\n", nIndexCount );
+ Plat_DebugString(tempbuf);
+ for ( i = 0; i < nIndexCount; ++i )
+ {
+ temp += sprintf( temp, "%d ", ( int )desc.m_pIndices[i] );
+ if ((i & 0x0F) == 0x0F)
+ {
+ sprintf( temp, "\n" );
+ Plat_DebugString(tempbuf);
+ tempbuf[0] = '\0';
+ temp = tempbuf;
+ }
+ }
+ sprintf(temp,"\n");
+ Plat_DebugString( tempbuf );
+}
+
+void CBaseMeshDX8::ValidateData( int nVertexCount, int nIndexCount, const MeshDesc_t &spewDesc )
+{
+ LOCK_SHADERAPI();
+#ifdef VALIDATE_DEBUG
+ int i;
+
+
+ // FIXME: just fall back to the base class (CVertexBufferBase) version of this function!
+
+
+ // This is needed so buffering can just use this
+ VertexFormat_t fmt = m_pMaterial->GetVertexUsage();
+
+ // Set up the vertex descriptor
+ MeshDesc_t desc = spewDesc;
+
+ int numBoneWeights = NumBoneWeights( fmt );
+ for ( i = 0; i < nVertexCount; ++i )
+ {
+ if( fmt & VERTEX_POSITION )
+ {
+ D3DXVECTOR3& pos = Position( desc, i );
+ Assert( IsFinite( pos[0] ) && IsFinite( pos[1] ) && IsFinite( pos[2] ) );
+ }
+ if( fmt & VERTEX_WRINKLE )
+ {
+ float flWrinkle = Wrinkle( desc, i );
+ Assert( IsFinite( flWrinkle ) );
+ }
+ if (numBoneWeights > 0)
+ {
+ float* pWeight = BoneWeight( desc, i );
+ for (int j = 0; j < numBoneWeights; ++j)
+ {
+ Assert( pWeight[j] >= 0.0f && pWeight[j] <= 1.0f );
+ }
+ }
+ if( fmt & VERTEX_BONE_INDEX )
+ {
+ unsigned char *pIndex = BoneIndex( desc, i );
+ Assert( pIndex[0] >= 0 && pIndex[0] < 16 );
+ Assert( pIndex[1] >= 0 && pIndex[1] < 16 );
+ Assert( pIndex[2] >= 0 && pIndex[2] < 16 );
+ Assert( pIndex[3] >= 0 && pIndex[3] < 16 );
+ }
+ if( fmt & VERTEX_NORMAL )
+ {
+ D3DXVECTOR3& normal = Normal( desc, i );
+ Assert( normal[0] >= -1.05f && normal[0] <= 1.05f );
+ Assert( normal[1] >= -1.05f && normal[1] <= 1.05f );
+ Assert( normal[2] >= -1.05f && normal[2] <= 1.05f );
+ }
+
+ if (fmt & VERTEX_COLOR)
+ {
+ int* pColor = (int*)Color( desc, i );
+ Assert( *pColor != FLOAT32_NAN_BITS );
+ }
+
+ for (int j = 0; j < VERTEX_MAX_TEXTURE_COORDINATES; ++j)
+ {
+ if( TexCoordSize( j, fmt ) > 0)
+ {
+ D3DXVECTOR2& texcoord = TexCoord( desc, i, j );
+ Assert( IsFinite( texcoord[0] ) && IsFinite( texcoord[1] ) );
+ }
+ }
+
+ if (fmt & VERTEX_TANGENT_S)
+ {
+ D3DXVECTOR3& tangentS = TangentS( desc, i );
+ Assert( IsFinite( tangentS[0] ) && IsFinite( tangentS[1] ) && IsFinite( tangentS[2] ) );
+ }
+
+ if (fmt & VERTEX_TANGENT_T)
+ {
+ D3DXVECTOR3& tangentT = TangentT( desc, i );
+ Assert( IsFinite( tangentT[0] ) && IsFinite( tangentT[1] ) && IsFinite( tangentT[2] ) );
+ }
+ }
+#endif // _DEBUG
+}
+
+void CBaseMeshDX8::Draw( CPrimList *pLists, int nLists )
+{
+ LOCK_SHADERAPI();
+ Assert( !"CBaseMeshDX8::Draw(CPrimList, int): should never get here." );
+}
+
+
+// Copy verts and/or indices to a mesh builder. This only works for temp meshes!
+void CBaseMeshDX8::CopyToMeshBuilder(
+ int iStartVert, // Which vertices to copy.
+ int nVerts,
+ int iStartIndex, // Which indices to copy.
+ int nIndices,
+ int indexOffset, // This is added to each index.
+ CMeshBuilder &builder )
+{
+ LOCK_SHADERAPI();
+ Assert( false );
+ Warning( "CopyToMeshBuilder called on something other than a temp mesh.\n" );
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// static mesh
+//
+//-----------------------------------------------------------------------------
+
+CPrimList *CMeshDX8::s_pPrims;
+int CMeshDX8::s_nPrims;
+unsigned int CMeshDX8::s_FirstVertex;
+unsigned int CMeshDX8::s_NumVertices;
+
+
+//-----------------------------------------------------------------------------
+// Computes the mode
+//-----------------------------------------------------------------------------
+inline D3DPRIMITIVETYPE ComputeMode( MaterialPrimitiveType_t type )
+{
+ switch(type)
+ {
+#ifdef _X360
+ case MATERIAL_INSTANCED_QUADS:
+ return D3DPT_QUADLIST;
+#endif
+
+ case MATERIAL_POINTS:
+ return D3DPT_POINTLIST;
+
+ case MATERIAL_LINES:
+ return D3DPT_LINELIST;
+
+ case MATERIAL_TRIANGLES:
+ return D3DPT_TRIANGLELIST;
+
+ case MATERIAL_TRIANGLE_STRIP:
+ return D3DPT_TRIANGLESTRIP;
+
+ // Here, we expect to have the type set later. only works for static meshes
+ case MATERIAL_HETEROGENOUS:
+ return (D3DPRIMITIVETYPE)-1;
+
+ default:
+ Assert(0);
+ return (D3DPRIMITIVETYPE)-1;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// constructor
+//-----------------------------------------------------------------------------
+CMeshDX8::CMeshDX8( const char *pTextureGroupName ) : m_NumVertices(0), m_NumIndices(0), m_pVertexBuffer(0),
+ m_pColorMesh( 0 ), m_nColorMeshVertOffsetInBytes( 0 ),
+ m_pIndexBuffer(0), m_Type(MATERIAL_TRIANGLES), m_IsVBLocked(false),
+ m_IsIBLocked(false)
+{
+ m_pTextureGroupName = pTextureGroupName;
+ m_Mode = ComputeMode(m_Type);
+
+ m_bHasFlexVerts = false;
+ m_pFlexVertexBuffer = NULL;
+ m_nFlexVertOffsetInBytes = 0;
+}
+
+CMeshDX8::~CMeshDX8()
+{
+ // Don't release the vertex buffer
+ if (!g_MeshMgr.IsDynamicMesh(this))
+ {
+ if (m_pVertexBuffer)
+ {
+ delete m_pVertexBuffer;
+ }
+ if (m_pIndexBuffer)
+ {
+ SafeRelease( &m_pIndexBuffer );
+ }
+ }
+}
+
+void CMeshDX8::SetFlexMesh( IMesh *pMesh, int nVertexOffsetInBytes )
+{
+ if ( !ShaderUtil()->OnSetFlexMesh( this, pMesh, nVertexOffsetInBytes ) )
+ return;
+
+ LOCK_SHADERAPI();
+ m_nFlexVertOffsetInBytes = nVertexOffsetInBytes; // Offset into dynamic mesh (in bytes)
+
+ if ( pMesh )
+ {
+ m_flexVertCount = pMesh->VertexCount();
+ pMesh->MarkAsDrawn();
+
+ CBaseMeshDX8 *pBaseMesh = static_cast<CBaseMeshDX8 *>(pMesh);
+ m_pFlexVertexBuffer = pBaseMesh->GetVertexBuffer();
+
+ m_bHasFlexVerts = true;
+ }
+ else
+ {
+ m_flexVertCount = 0;
+ m_pFlexVertexBuffer = NULL;
+ m_bHasFlexVerts = false;
+ }
+}
+
+void CMeshDX8::DisableFlexMesh( )
+{
+ CMeshDX8::SetFlexMesh( NULL, 0 );
+}
+
+bool CMeshDX8::HasFlexMesh( ) const
+{
+ LOCK_SHADERAPI();
+ return m_bHasFlexVerts;
+}
+
+void CMeshDX8::SetColorMesh( IMesh *pColorMesh, int nVertexOffsetInBytes )
+{
+ if ( !ShaderUtil()->OnSetColorMesh( this, pColorMesh, nVertexOffsetInBytes ) )
+ return;
+
+ LOCK_SHADERAPI();
+ m_pColorMesh = ( CMeshDX8 * )pColorMesh; // dangerous conversion! garymcthack
+ m_nColorMeshVertOffsetInBytes = nVertexOffsetInBytes;
+ Assert( m_pColorMesh || ( nVertexOffsetInBytes == 0 ) );
+
+#ifdef _DEBUG
+ if ( pColorMesh )
+ {
+ int nVertexCount = VertexCount();
+ int numVertsColorMesh = m_pColorMesh->VertexCount();
+ Assert( numVertsColorMesh >= nVertexCount );
+ }
+#endif
+}
+
+
+void CMeshDX8::HandleLateCreation( )
+{
+ if ( m_pVertexBuffer )
+ {
+ m_pVertexBuffer->HandleLateCreation();
+ }
+ if ( m_pIndexBuffer )
+ {
+ m_pIndexBuffer->HandleLateCreation();
+ }
+ if ( m_pFlexVertexBuffer )
+ {
+ m_pFlexVertexBuffer->HandleLateCreation();
+ }
+
+ if ( m_pColorMesh )
+ {
+ m_pColorMesh->HandleLateCreation();
+ }
+}
+
+
+bool CMeshDX8::HasColorMesh( ) const
+{
+ LOCK_SHADERAPI();
+ return (m_pColorMesh != NULL);
+}
+
+
+//-----------------------------------------------------------------------------
+// Locks/ unlocks the vertex buffer
+//-----------------------------------------------------------------------------
+bool CMeshDX8::Lock( int nVertexCount, bool bAppend, VertexDesc_t &desc )
+{
+ Assert( !m_IsVBLocked );
+
+ // Just give the app crap buffers to fill up while we're suppressed...
+ if ( g_pShaderDeviceDx8->IsDeactivated() || (nVertexCount == 0))
+ {
+ // Set up the vertex descriptor
+ CVertexBufferBase::ComputeVertexDescription( 0, 0, desc );
+ desc.m_nFirstVertex = 0;
+ return false;
+ }
+
+ // Static vertex buffer case
+ if (!m_pVertexBuffer)
+ {
+ int size = g_MeshMgr.VertexFormatSize( m_VertexFormat );
+ m_pVertexBuffer = new CVertexBuffer( Dx9Device(), m_VertexFormat, 0, size, nVertexCount, m_pTextureGroupName, ShaderAPI()->UsingSoftwareVertexProcessing() );
+ }
+
+ // Lock it baby
+ int nMaxVerts, nMaxIndices;
+ g_MeshMgr.GetMaxToRender( this, false, &nMaxVerts, &nMaxIndices );
+ if ( !g_pHardwareConfig->SupportsStreamOffset() )
+ {
+ // Without stream offset, we can't use VBs greater than 65535 verts (due to our using 16-bit indices)
+ Assert( nVertexCount <= nMaxVerts );
+ }
+
+ unsigned char *pVertexMemory = m_pVertexBuffer->Lock( nVertexCount, desc.m_nFirstVertex );
+ if ( !pVertexMemory )
+ {
+ if ( nVertexCount > nMaxVerts )
+ {
+ Assert( 0 );
+ Error( "Too many verts for a dynamic vertex buffer (%d>%d) Tell a programmer to up VERTEX_BUFFER_SIZE.\n",
+ ( int )nVertexCount, ( int )nMaxVerts );
+ }
+ else
+ {
+ // Check if paged pool is in critical state ( < 5% free )
+ PAGED_POOL_INFO_t ppi;
+ if ( ( SYSCALL_SUCCESS == Plat_GetPagedPoolInfo( &ppi ) ) &&
+ ( ( ppi.numPagesFree * 20 ) < ( ppi.numPagesUsed + ppi.numPagesFree ) ) )
+ {
+ Error( "Out of OS Paged Pool Memory! For more information, please see\nhttp://support.steampowered.com/cgi-bin/steampowered.cfg/php/enduser/std_adp.php?p_faqid=150\n" );
+ }
+ else
+ {
+ Assert( 0 );
+ Error( "failed to lock vertex buffer in CMeshDX8::LockVertexBuffer: nVertexCount=%d, nFirstVertex=%d\n", nVertexCount, desc.m_nFirstVertex );
+ }
+ }
+ CVertexBufferBase::ComputeVertexDescription( 0, 0, desc );
+ return false;
+ }
+
+ // Set up the vertex descriptor
+ CVertexBufferBase::ComputeVertexDescription( pVertexMemory, m_VertexFormat, desc );
+ m_IsVBLocked = true;
+
+#ifdef RECORDING
+ m_LockVertexBufferSize = nVertexCount * desc.m_ActualVertexSize;
+ m_LockVertexBuffer = pVertexMemory;
+#endif
+
+ return true;
+}
+
+void CMeshDX8::Unlock( int nVertexCount, VertexDesc_t& desc )
+{
+ // NOTE: This can happen if another application finishes
+ // initializing during the construction of a mesh
+ if (!m_IsVBLocked)
+ return;
+
+ // This is recorded for debugging. . not sent to dx.
+ RECORD_COMMAND( DX8_SET_VERTEX_BUFFER_FORMAT, 2 );
+ RECORD_INT( m_pVertexBuffer->UID() );
+ RECORD_INT( m_VertexFormat );
+
+ RECORD_COMMAND( DX8_VERTEX_DATA, 3 );
+ RECORD_INT( m_pVertexBuffer->UID() );
+ RECORD_INT( m_LockVertexBufferSize );
+ RECORD_STRUCT( m_LockVertexBuffer, m_LockVertexBufferSize );
+
+ Assert(m_pVertexBuffer);
+ m_pVertexBuffer->Unlock(nVertexCount);
+ m_IsVBLocked = false;
+}
+
+//-----------------------------------------------------------------------------
+// Locks/unlocks the index buffer
+//-----------------------------------------------------------------------------
+int CMeshDX8::Lock( bool bReadOnly, int nFirstIndex, int nIndexCount, IndexDesc_t &desc )
+{
+ Assert( !m_IsIBLocked );
+
+ // Just give the app crap buffers to fill up while we're suppressed...
+ if ( g_pShaderDeviceDx8->IsDeactivated() || (nIndexCount == 0))
+ {
+ // Set up a bogus index descriptor
+ desc.m_pIndices = g_nScratchIndexBuffer;
+ desc.m_nIndexSize = 0;
+ return 0;
+ }
+
+ // Static vertex buffer case
+ if (!m_pIndexBuffer)
+ {
+ SafeAssign( &m_pIndexBuffer, new CIndexBuffer( Dx9Device(), nIndexCount, ShaderAPI()->UsingSoftwareVertexProcessing() ) );
+ }
+
+ int startIndex;
+ desc.m_pIndices = m_pIndexBuffer->Lock( bReadOnly, nIndexCount, startIndex, nFirstIndex );
+ if( !desc.m_pIndices )
+ {
+ desc.m_pIndices = g_nScratchIndexBuffer;
+ desc.m_nIndexSize = 0;
+
+ // Check if paged pool is in critical state ( < 5% free )
+ PAGED_POOL_INFO_t ppi;
+ if ( ( SYSCALL_SUCCESS == Plat_GetPagedPoolInfo( &ppi ) ) &&
+ ( ( ppi.numPagesFree * 20 ) < ( ppi.numPagesUsed + ppi.numPagesFree ) ) )
+ {
+ Error( "Out of OS Paged Pool Memory! For more information, please see\nhttp://support.steampowered.com/cgi-bin/steampowered.cfg/php/enduser/std_adp.php?p_faqid=150\n" );
+ }
+ else
+ {
+ Assert( 0 );
+ Error( "failed to lock index buffer in CMeshDX8::LockIndexBuffer\n" );
+ }
+
+ return 0;
+ }
+
+ desc.m_nIndexSize = 1;
+ m_IsIBLocked = true;
+
+#if defined( RECORDING ) || defined( CHECK_INDICES )
+ m_LockIndexBufferSize = nIndexCount * 2;
+ m_LockIndexBuffer = desc.m_pIndices;
+#endif
+
+ return startIndex;
+}
+
+
+void CMeshDX8::Unlock( int nIndexCount, IndexDesc_t &desc )
+{
+ // NOTE: This can happen if another application finishes
+ // initializing during the construction of a mesh
+ if (!m_IsIBLocked)
+ return;
+
+ RECORD_COMMAND( DX8_INDEX_DATA, 3 );
+ RECORD_INT( m_pIndexBuffer->UID() );
+ RECORD_INT( m_LockIndexBufferSize );
+ RECORD_STRUCT( m_LockIndexBuffer, m_LockIndexBufferSize );
+
+ Assert(m_pIndexBuffer);
+
+#ifdef CHECK_INDICES
+ m_pIndexBuffer->UpdateShadowIndices( ( unsigned short * )m_LockIndexBuffer );
+#endif // CHECK_INDICES
+
+ // Unlock, and indicate how many vertices we actually used
+ m_pIndexBuffer->Unlock(nIndexCount);
+ m_IsIBLocked = false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Locks/unlocks the entire mesh
+//-----------------------------------------------------------------------------
+void CMeshDX8::LockMesh( int nVertexCount, int nIndexCount, MeshDesc_t& desc )
+{
+ ShaderUtil()->SyncMatrices();
+
+ g_ShaderMutex.Lock();
+ VPROF( "CMeshDX8::LockMesh" );
+ Lock( nVertexCount, false, *static_cast<VertexDesc_t*>( &desc ) );
+ if ( m_Type != MATERIAL_POINTS )
+ {
+ Lock( false, -1, nIndexCount, *static_cast<IndexDesc_t*>( &desc ) );
+ }
+ else
+ {
+ desc.m_pIndices = g_nScratchIndexBuffer;
+ desc.m_nIndexSize = 0;
+ }
+
+ CBaseMeshDX8::m_bMeshLocked = true;
+}
+
+
+void CMeshDX8::UnlockMesh( int nVertexCount, int nIndexCount, MeshDesc_t& desc )
+{
+ VPROF( "CMeshDX8::UnlockMesh" );
+
+ Assert( CBaseMeshDX8::m_bMeshLocked );
+
+ Unlock( nVertexCount, *static_cast<VertexDesc_t*>( &desc ) );
+ if ( m_Type != MATERIAL_POINTS )
+ {
+ Unlock( nIndexCount, *static_cast<IndexDesc_t*>( &desc ) );
+ }
+
+ // The actual # we wrote
+ m_NumVertices = nVertexCount;
+ m_NumIndices = nIndexCount;
+
+ CBaseMeshDX8::m_bMeshLocked = false;
+ g_ShaderMutex.Unlock();
+}
+
+
+//-----------------------------------------------------------------------------
+// Locks mesh for modifying
+//-----------------------------------------------------------------------------
+void CMeshDX8::ModifyBeginEx( bool bReadOnly, int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t& desc )
+{
+ VPROF( "CMeshDX8::ModifyBegin" );
+
+ // Just give the app crap buffers to fill up while we're suppressed...
+ if ( g_pShaderDeviceDx8->IsDeactivated())
+ {
+ // Set up a bogus descriptor
+ g_MeshMgr.ComputeVertexDescription( 0, 0, desc );
+ desc.m_pIndices = g_nScratchIndexBuffer;
+ desc.m_nIndexSize = 0;
+ return;
+ }
+
+ Assert( m_pVertexBuffer );
+
+ // Lock it baby
+ unsigned char* pVertexMemory = m_pVertexBuffer->Modify( bReadOnly, nFirstVertex, nVertexCount );
+ if ( pVertexMemory )
+ {
+ m_IsVBLocked = true;
+ g_MeshMgr.ComputeVertexDescription( pVertexMemory, m_VertexFormat, desc );
+
+#ifdef RECORDING
+ m_LockVertexBufferSize = nVertexCount * desc.m_ActualVertexSize;
+ m_LockVertexBuffer = pVertexMemory;
+#endif
+ }
+
+ desc.m_nFirstVertex = nFirstVertex;
+
+ Lock( bReadOnly, nFirstIndex, nIndexCount, *static_cast<IndexDesc_t*>( &desc ) );
+}
+
+void CMeshDX8::ModifyBegin( int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t& desc )
+{
+ ModifyBeginEx( false, nFirstVertex, nVertexCount, nFirstIndex, nIndexCount, desc );
+}
+
+void CMeshDX8::ModifyEnd( MeshDesc_t& desc )
+{
+ VPROF( "CMeshDX8::ModifyEnd" );
+ Unlock( 0, *static_cast<IndexDesc_t*>( &desc ) );
+ Unlock( 0, *static_cast<VertexDesc_t*>( &desc ) );
+}
+
+
+//-----------------------------------------------------------------------------
+// returns the # of vertices (static meshes only)
+//-----------------------------------------------------------------------------
+int CMeshDX8::VertexCount() const
+{
+ return m_pVertexBuffer ? m_pVertexBuffer->VertexCount() : 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// returns the # of indices
+//-----------------------------------------------------------------------------
+int CMeshDX8::IndexCount( ) const
+{
+ return m_pIndexBuffer ? m_pIndexBuffer->IndexCount() : 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets up the vertex and index buffers
+//-----------------------------------------------------------------------------
+void CMeshDX8::UseIndexBuffer( CIndexBuffer* pBuffer )
+{
+ SafeAssign( &m_pIndexBuffer, pBuffer );
+}
+
+void CMeshDX8::UseVertexBuffer( CVertexBuffer* pBuffer )
+{
+ m_pVertexBuffer = pBuffer;
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the primitive type
+//-----------------------------------------------------------------------------
+void CMeshDX8::SetPrimitiveType( MaterialPrimitiveType_t type )
+{
+ Assert( IsX360() || ( type != MATERIAL_INSTANCED_QUADS ) );
+ if ( !ShaderUtil()->OnSetPrimitiveType( this, type ) )
+ {
+ return;
+ }
+
+ LOCK_SHADERAPI();
+ m_Type = type;
+ m_Mode = ComputeMode( type );
+}
+
+MaterialPrimitiveType_t CMeshDX8::GetPrimitiveType( ) const
+{
+ return m_Type;
+}
+
+
+//-----------------------------------------------------------------------------
+// Computes the number of primitives we're gonna draw
+//-----------------------------------------------------------------------------
+int CMeshDX8::NumPrimitives( int nVertexCount, int nIndexCount ) const
+{
+ switch(m_Mode)
+ {
+ case D3DPT_POINTLIST:
+ return nVertexCount;
+
+ case D3DPT_LINELIST:
+ return nIndexCount / 2;
+
+ case D3DPT_TRIANGLELIST:
+ return nIndexCount / 3;
+
+ case D3DPT_TRIANGLESTRIP:
+ return nIndexCount - 2;
+
+ default:
+ // invalid, baby!
+ Assert(0);
+ }
+
+ return 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Checks if it's a valid format
+//-----------------------------------------------------------------------------
+#ifdef _DEBUG
+static void OutputVertexFormat( VertexFormat_t format )
+{
+ // FIXME: this is a duplicate of the function in meshdx8.cpp
+ VertexCompressionType_t compressionType = CompressionType( format );
+
+ if ( format & VERTEX_POSITION )
+ {
+ Warning( "VERTEX_POSITION|" );
+ }
+ if ( format & VERTEX_NORMAL )
+ {
+ if ( compressionType == VERTEX_COMPRESSION_ON )
+ Warning( "VERTEX_NORMAL[COMPRESSED]|" );
+ else
+ Warning( "VERTEX_NORMAL|" );
+ }
+ if ( format & VERTEX_COLOR )
+ {
+ Warning( "VERTEX_COLOR|" );
+ }
+ if ( format & VERTEX_SPECULAR )
+ {
+ Warning( "VERTEX_SPECULAR|" );
+ }
+ if ( format & VERTEX_TANGENT_S )
+ {
+ Warning( "VERTEX_TANGENT_S|" );
+ }
+ if ( format & VERTEX_TANGENT_T )
+ {
+ Warning( "VERTEX_TANGENT_T|" );
+ }
+ if ( format & VERTEX_BONE_INDEX )
+ {
+ Warning( "VERTEX_BONE_INDEX|" );
+ }
+ if ( format & VERTEX_FORMAT_VERTEX_SHADER )
+ {
+ Warning( "VERTEX_FORMAT_VERTEX_SHADER|" );
+ }
+ Warning( "\nBone weights: %d (%s)\n", NumBoneWeights( format ),
+ ( CompressionType( format ) == VERTEX_COMPRESSION_ON ? "compressed" : "uncompressed" ) );
+ Warning( "user data size: %d (%s)\n", UserDataSize( format ),
+ ( CompressionType( format ) == VERTEX_COMPRESSION_ON ? "compressed" : "uncompressed" ) );
+ Warning( "num tex coords: %d\n", NumTextureCoordinates( format ) );
+ // NOTE: This doesn't print texcoord sizes.
+}
+#endif
+
+bool CMeshDX8::IsValidVertexFormat( VertexFormat_t vertexFormat )
+{
+ // FIXME: Make this a debug-only check on say 6th July 2007 (after a week or so's testing)
+ // (i.e. avoid the 360 release build perf. hit for when we ship)
+ bool bCheckCompression = ( m_VertexFormat & VERTEX_FORMAT_COMPRESSED ) &&
+ ( ( vertexFormat == VERTEX_FORMAT_INVALID ) || ( ( vertexFormat & VERTEX_FORMAT_COMPRESSED ) == 0 ) );
+
+ if ( bCheckCompression || IsPC() || IsDebug() )
+ {
+ IMaterialInternal* pMaterial = ShaderAPI()->GetBoundMaterial();
+ Assert( pMaterial );
+
+ // the material format should match the vertex usage, unless another format is passed in
+ if ( vertexFormat == VERTEX_FORMAT_INVALID )
+ {
+ vertexFormat = pMaterial->GetVertexUsage() & ~( VERTEX_FORMAT_VERTEX_SHADER | VERTEX_FORMAT_USE_EXACT_FORMAT );
+
+ // Blat out unused fields
+ vertexFormat &= ~g_MeshMgr.UnusedVertexFields();
+ int nUnusedTextureCoords = g_MeshMgr.UnusedTextureCoords();
+ for ( int i = 0; i < VERTEX_MAX_TEXTURE_COORDINATES; ++i )
+ {
+ if ( nUnusedTextureCoords & ( 1 << i ) )
+ {
+ vertexFormat &= ~VERTEX_TEXCOORD_MASK( i );
+ }
+ }
+ }
+ else
+ {
+ vertexFormat &= ~( VERTEX_FORMAT_VERTEX_SHADER | VERTEX_FORMAT_USE_EXACT_FORMAT );
+ }
+
+ bool bIsValid = (( VERTEX_FORMAT_FIELD_MASK & vertexFormat ) & ( VERTEX_FORMAT_FIELD_MASK & ~m_VertexFormat )) == 0;
+
+ if ( m_VertexFormat & VERTEX_FORMAT_COMPRESSED )
+ {
+ // We shouldn't get compressed verts if this material doesn't support them!
+ if ( ( vertexFormat & VERTEX_FORMAT_COMPRESSED ) == 0 )
+ {
+ static int numWarnings = 0;
+ if ( numWarnings++ == 0 )
+ {
+ // NOTE: ComputeVertexFormat() will make sure no materials support VERTEX_FORMAT_COMPRESSED
+ // if vertex compression is disabled in the config
+ if ( g_pHardwareConfig->SupportsCompressedVertices() == VERTEX_COMPRESSION_NONE )
+ Warning( "ERROR: Compressed vertices in use but vertex compression is disabled (or not supported on this hardware)!\n" );
+ else
+ Warning( "ERROR: Compressed vertices in use but material does not support them!\n" );
+ }
+ Assert( 0 );
+ bIsValid = false;
+ }
+ }
+
+ bIsValid = bIsValid && UserDataSize( m_VertexFormat ) >= UserDataSize( vertexFormat );
+
+ for ( int i=0; i < VERTEX_MAX_TEXTURE_COORDINATES; i++ )
+ {
+ if ( TexCoordSize( i, m_VertexFormat ) < TexCoordSize( i, vertexFormat ) )
+ {
+ bIsValid = false;
+ }
+ }
+
+ // NOTE: It can totally be valid to have more weights than the current number of bones.
+ // The -1 here is because if we have N bones, we can have only (N-1) weights,
+ // since the Nth is implied (the weights sum to 1).
+ int nWeightCount = NumBoneWeights( m_VertexFormat );
+ bIsValid = bIsValid && ( nWeightCount >= ( g_pShaderAPI->GetCurrentNumBones() - 1 ) );
+
+#ifdef _DEBUG
+ if ( !bIsValid )
+ {
+ Warning( "Material Format:" );
+ if ( g_pShaderAPI->GetCurrentNumBones() > 0 )
+ {
+ vertexFormat |= VERTEX_BONE_INDEX;
+ vertexFormat &= ~VERTEX_BONE_WEIGHT_MASK;
+ vertexFormat |= VERTEX_BONEWEIGHT( 2 );
+ }
+
+ OutputVertexFormat( vertexFormat );
+ Warning( "Mesh Format:" );
+ OutputVertexFormat( m_VertexFormat );
+ }
+#endif
+ return bIsValid;
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Stream source setting methods
+//-----------------------------------------------------------------------------
+void CMeshDX8::SetVertexIDStreamState()
+{
+ // FIXME: this method duplicates the code in CMeshMgr::SetVertexIDStreamState
+
+ if ( IsX360() )
+ return;
+
+ bool bUsingVertexID = IsUsingVertexID();
+ if ( bUsingVertexID != g_bUsingVertexID )
+ {
+ if ( bUsingVertexID )
+ {
+ // NOTE: Morphing doesn't work with dynamic buffers!!! BLEAH
+ // It's because the indices (which are not 0 based for dynamic buffers)
+ // are accessing both the vertexID buffer + the regular vertex buffer.
+ // This *might* be fixable with baseVertexIndex?
+
+ // NOTE: At the moment, vertex id is only used for hw morphing. I've got it
+ // set up so that a shader that supports hw morphing always says it uses vertex id.
+ // If we ever use vertex id for something other than hw morphing, we're going
+ // to have to revisit how those shaders say they want to use vertex id
+ // or fix this some other way
+ Assert( !g_pShaderAPI->IsHWMorphingEnabled() || !m_pVertexBuffer->IsDynamic() );
+
+ CVertexBuffer *pVertexIDBuffer = g_MeshMgr.GetVertexIDBuffer( );
+ RECORD_COMMAND( DX8_SET_STREAM_SOURCE, 4 );
+ RECORD_INT( pVertexIDBuffer->UID() );
+ RECORD_INT( 3 );
+ RECORD_INT( 0 );
+ RECORD_INT( pVertexIDBuffer->VertexSize() );
+
+ D3DSetStreamSource( 3, pVertexIDBuffer->GetInterface(), 0, pVertexIDBuffer->VertexSize() );
+ pVertexIDBuffer->HandlePerFrameTextureStats( ShaderAPI()->GetCurrentFrameCounter() );
+ }
+ else
+ {
+ RECORD_COMMAND( DX8_SET_STREAM_SOURCE, 4 );
+ RECORD_INT( -1 ); // vertex buffer id
+ RECORD_INT( 3 ); // stream
+ RECORD_INT( 0 ); // vertex offset
+ RECORD_INT( 0 ); // vertex size
+
+ D3DSetStreamSource( 3, 0, 0, 0 );
+ }
+ g_bUsingVertexID = bUsingVertexID;
+ }
+}
+
+void CMeshDX8::SetColorStreamState()
+{
+ if ( ( m_pColorMesh != g_pLastColorMesh ) || ( m_nColorMeshVertOffsetInBytes != g_nLastColorMeshVertOffsetInBytes ) )
+ {
+ if ( m_pColorMesh )
+ {
+ RECORD_COMMAND( DX8_SET_STREAM_SOURCE, 4 );
+ RECORD_INT( m_pColorMesh->GetVertexBuffer()->UID() );
+ RECORD_INT( 1 );
+ RECORD_INT( m_nColorMeshVertOffsetInBytes );
+ RECORD_INT( m_pColorMesh->GetVertexBuffer()->VertexSize() );
+
+ D3DSetStreamSource( 1, m_pColorMesh->GetVertexBuffer()->GetInterface(),
+ m_nColorMeshVertOffsetInBytes, m_pColorMesh->GetVertexBuffer()->VertexSize() );
+ m_pColorMesh->GetVertexBuffer()->HandlePerFrameTextureStats( ShaderAPI()->GetCurrentFrameCounter() );
+ }
+ else
+ {
+ RECORD_COMMAND( DX8_SET_STREAM_SOURCE, 4 );
+ RECORD_INT( -1 ); // vertex buffer id
+ RECORD_INT( 1 ); // stream
+ RECORD_INT( 0 ); // vertex offset
+ RECORD_INT( 0 ); // vertex size
+
+ D3DSetStreamSource( 1, 0, 0, 0 );
+ }
+ g_pLastColorMesh = m_pColorMesh;
+ g_nLastColorMeshVertOffsetInBytes = m_nColorMeshVertOffsetInBytes;
+ }
+}
+
+void CMeshDX8::SetVertexStreamState( int nVertOffsetInBytes )
+{
+ // Calls in here assume shader support...
+ if ( HardwareConfig()->SupportsVertexAndPixelShaders() )
+ {
+ if ( HasFlexMesh() )
+ {
+ // m_pFlexVertexBuffer is the flex buffer down inside the CMeshMgr singleton
+ D3DSetStreamSource( 2, m_pFlexVertexBuffer->GetInterface(), m_nFlexVertOffsetInBytes, m_pFlexVertexBuffer->VertexSize() );
+
+ if ( g_pHardwareConfig->Caps().m_SupportsVertexShaders_2_0 )
+ {
+ float c[4] = { 1.0f, g_pMaterialSystemHardwareConfig->SupportsPixelShaders_2_b() ? 1.0f : 0.0f, 0.0f, 0.0f };
+ ShaderAPI()->SetVertexShaderConstant( VERTEX_SHADER_FLEXSCALE, c, 1 );
+ }
+
+ g_bFlexMeshStreamSet = true;
+ }
+ else
+ {
+ Assert( nVertOffsetInBytes == 0 );
+ Assert( m_pVertexBuffer );
+
+ // HACK...point stream 2 at the same VB which is bound to stream 0...
+ // NOTE: D3D debug DLLs will RIP if stream 0 has a smaller stride than the largest
+ // offset in the stream 2 vertex decl elements (which are position(12)+wrinkle(4)+normal(12))
+ // If this fires, go find the material/shader which is requesting a really 'thin'
+ // stream 0 vertex, and fatten it up slightly (e.g. add a D3DCOLOR element)
+ int minimumStreamZeroStride = 4 * sizeof( float );
+ Assert( m_pVertexBuffer->VertexSize() >= minimumStreamZeroStride );
+ if ( m_pVertexBuffer->VertexSize() < minimumStreamZeroStride )
+ {
+ static bool bWarned = false;
+ if( !bWarned )
+ {
+ Warning( "Shader specifying too-thin vertex format, should be at least %d bytes! (Suppressing furthur warnings)\n", minimumStreamZeroStride );
+ bWarned = true;
+ }
+ }
+
+ // Set a 4kb all-zero static VB into the flex/wrinkle stream with a stride of 1 bytes, so the vertex shader always reads valid floating point values (otherwise it can get NaN's/Inf's, and under OpenGL this is bad on NVidia)
+ // togl requires non-zero strides, but on D3D9 we can set a stride of 0 for a little more efficiency.
+ D3DSetStreamSource( 2, g_MeshMgr.GetZeroVertexBuffer(), 0, IsOpenGL() ? 4 : 0 );
+
+ if ( g_pHardwareConfig->Caps().m_SupportsVertexShaders_2_0 )
+ {
+ float c[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ ShaderAPI()->SetVertexShaderConstant( VERTEX_SHADER_FLEXSCALE, c, 1 );
+ }
+
+ g_bFlexMeshStreamSet = false;
+ }
+ }
+
+ // MESHFIXME: Make sure this jives between the mesh/ib/vb version.
+#ifdef _X360
+ if ( ( g_pLastVertex != m_pVertexBuffer ) || ( m_pVertexBuffer->IsDynamic() ) || ( g_nLastVertOffsetInBytes != nVertOffsetInBytes ) )
+#else
+ if ( ( g_pLastVertex != m_pVertexBuffer ) || ( g_nLastVertOffsetInBytes != nVertOffsetInBytes ) )
+#endif
+ {
+ Assert( m_pVertexBuffer );
+
+ RECORD_COMMAND( DX8_SET_STREAM_SOURCE, 4 );
+ RECORD_INT( m_pVertexBuffer->UID() );
+ RECORD_INT( 0 );
+ RECORD_INT( nVertOffsetInBytes );
+ RECORD_INT( m_pVertexBuffer->VertexSize() );
+
+ D3DSetStreamSource( 0, m_pVertexBuffer->GetInterface(), nVertOffsetInBytes, m_pVertexBuffer->VertexSize() );
+ m_pVertexBuffer->HandlePerFrameTextureStats( ShaderAPI()->GetCurrentFrameCounter() );
+
+ g_pLastVertex = m_pVertexBuffer;
+ g_nLastVertOffsetInBytes = nVertOffsetInBytes;
+ }
+}
+
+void CMeshDX8::SetIndexStreamState( int firstVertexIdx )
+{
+#ifdef _X360
+ if ( ( g_pLastIndexBuffer != NULL ) || (g_pLastIndex != m_pIndexBuffer) || ( m_pIndexBuffer->IsDynamic() ) || ( firstVertexIdx != g_LastVertexIdx ) )
+#else
+ if ( ( g_pLastIndexBuffer != NULL ) || (g_pLastIndex != m_pIndexBuffer) || ( firstVertexIdx != g_LastVertexIdx ) )
+#endif
+ {
+ Assert( m_pIndexBuffer );
+
+ RECORD_COMMAND( DX8_SET_INDICES, 2 );
+ RECORD_INT( m_pIndexBuffer->UID() );
+ RECORD_INT( firstVertexIdx );
+
+ Dx9Device()->SetIndices( m_pIndexBuffer->GetInterface() );
+ m_pIndexBuffer->HandlePerFrameTextureStats( ShaderAPI()->GetCurrentFrameCounter() );
+ m_FirstIndex = firstVertexIdx;
+
+ SafeAssign( &g_pLastIndex, m_pIndexBuffer );
+ g_pLastIndexBuffer = NULL;
+ g_LastVertexIdx = firstVertexIdx;
+ }
+}
+
+bool CMeshDX8::SetRenderState( int nVertexOffsetInBytes, int nFirstVertexIdx, VertexFormat_t vertexFormat )
+{
+ // Can't set the state if we're deactivated
+ if ( g_pShaderDeviceDx8->IsDeactivated() )
+ {
+ ResetMeshRenderState();
+ return false;
+ }
+
+ g_LastVertexFormat = vertexFormat;
+
+ SetVertexIDStreamState();
+ SetColorStreamState();
+ SetVertexStreamState( nVertexOffsetInBytes );
+ SetIndexStreamState( nFirstVertexIdx );
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Draws the static mesh
+//-----------------------------------------------------------------------------
+void CMeshDX8::Draw( int nFirstIndex, int nIndexCount )
+{
+ Assert( m_pVertexBuffer );
+ if ( !m_pVertexBuffer )
+ {
+ return;
+ }
+
+ if ( !ShaderUtil()->OnDrawMesh( this, nFirstIndex, nIndexCount ) )
+ {
+ MarkAsDrawn();
+ return;
+ }
+
+ CPrimList primList;
+ if( nFirstIndex == -1 || nIndexCount == 0 )
+ {
+ primList.m_FirstIndex = 0;
+ primList.m_NumIndices = m_NumIndices;
+ }
+ else
+ {
+ primList.m_FirstIndex = nFirstIndex;
+ primList.m_NumIndices = nIndexCount;
+ }
+ DrawInternal( &primList, 1 );
+}
+
+void CMeshDX8::Draw( CPrimList *pLists, int nLists )
+{
+ Assert( m_pVertexBuffer );
+ if ( !m_pVertexBuffer )
+ {
+ return;
+ }
+
+ if ( !ShaderUtil()->OnDrawMesh( this, pLists, nLists ) )
+ {
+ MarkAsDrawn();
+ return;
+ }
+
+ DrawInternal( pLists, nLists );
+}
+
+
+void CMeshDX8::DrawInternal( CPrimList *pLists, int nLists )
+{
+ HandleLateCreation();
+
+ // Make sure there's something to draw..
+ int i;
+ for ( i=0; i < nLists; i++ )
+ {
+ if ( pLists[i].m_NumIndices > 0 )
+ break;
+ }
+ if ( i == nLists )
+ return;
+
+ // can't do these in selection mode!
+ Assert( !ShaderAPI()->IsInSelectionMode() );
+
+ if ( !SetRenderState( 0, 0 ) )
+ return;
+
+ s_pPrims = pLists;
+ s_nPrims = nLists;
+
+#ifdef _DEBUG
+ for ( i = 0; i < nLists; ++i)
+ {
+ Assert( pLists[i].m_NumIndices > 0 );
+ }
+#endif
+
+ s_FirstVertex = 0;
+ s_NumVertices = m_pVertexBuffer->VertexCount();
+
+ DrawMesh();
+}
+
+
+#ifdef CHECK_INDICES
+void CMeshDX8::CheckIndices( CPrimList *pPrim, int numPrimitives )
+{
+ // g_pLastVertex - this is the current vertex buffer
+ // g_pLastColorMesh - this is the current color mesh, if there is one.
+ // g_pLastIndex - this is the current index buffer.
+ // vertoffset : m_FirstIndex
+ if( m_Mode == D3DPT_TRIANGLELIST || m_Mode == D3DPT_TRIANGLESTRIP )
+ {
+ Assert( pPrim->m_FirstIndex >= 0 && pPrim->m_FirstIndex < g_pLastIndex->IndexCount() );
+ int i;
+ for( i = 0; i < 2; i++ )
+ {
+ CVertexBuffer *pMesh;
+ if( i == 0 )
+ {
+ pMesh = g_pLastVertex;
+ Assert( pMesh );
+ }
+ else
+ {
+ if( !g_pLastColorMesh )
+ {
+ continue;
+ }
+ pMesh = g_pLastColorMesh->m_pVertexBuffer;
+ if( !pMesh )
+ {
+ continue;
+ }
+ }
+ Assert( s_FirstVertex >= 0 &&
+ (int)( s_FirstVertex + m_FirstIndex ) < pMesh->VertexCount() );
+ int nIndexCount = 0;
+ if( m_Mode == D3DPT_TRIANGLELIST )
+ {
+ nIndexCount = numPrimitives * 3;
+ }
+ else if( m_Mode == D3DPT_TRIANGLESTRIP )
+ {
+ nIndexCount = numPrimitives + 2;
+ }
+ else
+ {
+ Assert( 0 );
+ }
+ int j;
+ for( j = 0; j < nIndexCount; j++ )
+ {
+ int index = g_pLastIndex->GetShadowIndex( j + pPrim->m_FirstIndex );
+ if ( ( index < (int)s_FirstVertex ) || ( index >= (int)( s_FirstVertex + s_NumVertices ) ) )
+ Warning("%s invalid index: %d [%u..%u]\n", __FUNCTION__, index, s_FirstVertex, s_FirstVertex + s_NumVertices - 1 );
+ Assert( index >= (int)s_FirstVertex );
+ Assert( index < (int)(s_FirstVertex + s_NumVertices) );
+ }
+ }
+ }
+}
+#endif // CHECK_INDICES
+
+
+//-----------------------------------------------------------------------------
+// Actually does the dirty deed of rendering
+//-----------------------------------------------------------------------------
+void CMeshDX8::RenderPass()
+{
+ LOCK_SHADERAPI();
+ VPROF( "CMeshDX8::RenderPass" );
+
+ HandleLateCreation();
+
+ Assert( m_Type != MATERIAL_HETEROGENOUS );
+
+ // make sure the vertex format is a superset of the current material's
+ // vertex format...
+ if ( !IsValidVertexFormat( g_LastVertexFormat ) )
+ {
+ Warning( "Material %s does not support vertex format used by the mesh (maybe missing fields or mismatched vertex compression?), mesh will not be rendered. Grab a programmer!\n",
+ ShaderAPI()->GetBoundMaterial()->GetName() );
+ return;
+ }
+
+ for ( int iPrim=0; iPrim < s_nPrims; iPrim++ )
+ {
+ CPrimList *pPrim = &s_pPrims[iPrim];
+
+ if ( pPrim->m_NumIndices == 0 )
+ continue;
+
+ if ( ( m_Type == MATERIAL_POINTS ) || ( m_Type == MATERIAL_INSTANCED_QUADS ) )
+ {
+ tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "Dx9Device_DrawPrimitive" );
+
+ // (For point/instanced-quad lists, we don't actually fill in indices, but we treat it as
+ // though there are indices for the list up until here).
+ Dx9Device()->DrawPrimitive( m_Mode, s_FirstVertex, pPrim->m_NumIndices );
+ }
+ else
+ {
+ int numPrimitives = NumPrimitives( s_NumVertices, pPrim->m_NumIndices );
+
+#ifdef CHECK_INDICES
+ CheckIndices( pPrim, numPrimitives );
+#endif // CHECK_INDICES
+ {
+ VPROF( "Dx9Device()->DrawIndexedPrimitive" );
+ VPROF_INCREMENT_COUNTER( "DrawIndexedPrimitive", 1 );
+ VPROF_INCREMENT_COUNTER( "numPrimitives", numPrimitives );
+ VPROF_INCREMENT_GROUP_COUNTER( "render/DrawIndexedPrimitive", COUNTER_GROUP_TELEMETRY, 1 );
+ VPROF_INCREMENT_GROUP_COUNTER( "render/numPrimitives", COUNTER_GROUP_TELEMETRY, 1 );
+
+ Dx9Device()->DrawIndexedPrimitive(
+ m_Mode, // Member of the D3DPRIMITIVETYPE enumerated type, describing the type of primitive to render. D3DPT_POINTLIST is not supported with this method.
+
+ m_FirstIndex, // Offset from the start of the vertex buffer to the first vertex index. An index of 0 in the index buffer refers to this location in the vertex buffer.
+
+ s_FirstVertex, // Minimum vertex index for vertices used during this call. This is a zero based index relative to BaseVertexIndex.
+ // The first Vertex in the vertexbuffer that we are currently using for the current batch.
+
+ s_NumVertices, // Number of vertices used during this call. The first vertex is located at index: BaseVertexIndex + MinIndex.
+
+ pPrim->m_FirstIndex, // Index of the first index to use when accesssing the vertex buffer. Beginning at StartIndex to index vertices from the vertex buffer.
+
+ numPrimitives );// Number of primitives to render. The number of vertices used is a function of the primitive count and the primitive type.
+ }
+ }
+ }
+
+ if ( g_pLastVertex )
+ {
+ g_pLastVertex->MarkUsedInRendering();
+ }
+
+ if( g_pLastIndex )
+ {
+ g_pLastIndex->MarkUsedInRendering();
+ }
+}
+
+//-----------------------------------------------------------------------------
+//
+// Dynamic mesh implementation
+//
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+CDynamicMeshDX8::CDynamicMeshDX8() : CMeshDX8( "CDynamicMeshDX8" )
+{
+ m_nBufferId = 0;
+ ResetVertexAndIndexCounts();
+}
+
+CDynamicMeshDX8::~CDynamicMeshDX8()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Initializes the dynamic mesh
+//-----------------------------------------------------------------------------
+void CDynamicMeshDX8::Init( int nBufferId )
+{
+ m_nBufferId = nBufferId;
+}
+
+
+//-----------------------------------------------------------------------------
+// Resets buffering state
+//-----------------------------------------------------------------------------
+void CDynamicMeshDX8::ResetVertexAndIndexCounts()
+{
+ m_TotalVertices = m_TotalIndices = 0;
+ m_FirstIndex = m_nFirstVertex = -1;
+ m_HasDrawn = false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Resets the state in case of a task switch
+//-----------------------------------------------------------------------------
+void CDynamicMeshDX8::Reset()
+{
+ m_VertexFormat = 0;
+ m_pVertexBuffer = 0;
+ SafeRelease( &m_pIndexBuffer );
+ ResetVertexAndIndexCounts();
+
+ // Force the render state to be updated next time
+ ResetMeshRenderState();
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the vertex format associated with the dynamic mesh
+//-----------------------------------------------------------------------------
+void CDynamicMeshDX8::SetVertexFormat( VertexFormat_t format )
+{
+ if ( g_pShaderDeviceDx8->IsDeactivated())
+ return;
+
+ if ( CompressionType( format ) != VERTEX_COMPRESSION_NONE )
+ {
+ // UNDONE: support compressed dynamic meshes if needed (pro: less VB memory, con: CMeshBuilder gets slower)
+ Warning( "ERROR: dynamic meshes cannot use compressed vertices!\n" );
+ Assert( 0 );
+ format &= ~VERTEX_FORMAT_COMPRESSED;
+ }
+
+ if ((format != m_VertexFormat) || m_VertexOverride || m_IndexOverride)
+ {
+ m_VertexFormat = format;
+ UseVertexBuffer( g_MeshMgr.FindOrCreateVertexBuffer( m_nBufferId, format ) );
+
+ if ( m_nBufferId == 0 )
+ {
+ UseIndexBuffer( g_MeshMgr.GetDynamicIndexBuffer() );
+ }
+
+ m_VertexOverride = m_IndexOverride = false;
+ }
+}
+
+void CDynamicMeshDX8::OverrideVertexBuffer( CVertexBuffer* pVertexBuffer )
+{
+ UseVertexBuffer( pVertexBuffer );
+ m_VertexOverride = true;
+}
+
+void CDynamicMeshDX8::OverrideIndexBuffer( CIndexBuffer* pIndexBuffer )
+{
+ UseIndexBuffer( pIndexBuffer );
+ m_IndexOverride = true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Do I need to reset the vertex format?
+//-----------------------------------------------------------------------------
+bool CDynamicMeshDX8::NeedsVertexFormatReset( VertexFormat_t fmt ) const
+{
+ return m_VertexOverride || m_IndexOverride || (m_VertexFormat != fmt);
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Locks/unlocks the entire mesh
+//-----------------------------------------------------------------------------
+bool CDynamicMeshDX8::HasEnoughRoom( int nVertexCount, int nIndexCount ) const
+{
+ if ( g_pShaderDeviceDx8->IsDeactivated() )
+ return false;
+
+ Assert( m_pVertexBuffer != NULL );
+
+ // We need space in both the vertex and index buffer
+ return m_pVertexBuffer->HasEnoughRoom( nVertexCount ) &&
+ m_pIndexBuffer->HasEnoughRoom( nIndexCount );
+}
+
+
+//-----------------------------------------------------------------------------
+// returns the number of indices in the mesh
+//-----------------------------------------------------------------------------
+int CDynamicMeshDX8::IndexCount( ) const
+{
+ return m_TotalIndices;
+}
+
+
+//-----------------------------------------------------------------------------
+// Operation to do pre-lock (only called for buffered meshes)
+//-----------------------------------------------------------------------------
+void CDynamicMeshDX8::PreLock()
+{
+ if (m_HasDrawn)
+ {
+ // Start again then
+ ResetVertexAndIndexCounts();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Locks/unlocks the entire mesh
+//-----------------------------------------------------------------------------
+void CDynamicMeshDX8::LockMesh( int nVertexCount, int nIndexCount, MeshDesc_t& desc )
+{
+ tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "%s %d %d", __FUNCTION__, nVertexCount, nIndexCount );
+
+ ShaderUtil()->SyncMatrices();
+
+ {
+ tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "g_ShaderMutex.Lock" );
+ g_ShaderMutex.Lock();
+ }
+
+ // Yes, this may well also be called from BufferedMesh but that's ok
+ {
+ tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "PreLock" );
+ PreLock();
+ }
+
+ if (m_VertexOverride)
+ {
+ nVertexCount = 0;
+ }
+
+ if (m_IndexOverride)
+ {
+ nIndexCount = 0;
+ }
+
+ {
+ tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "Lock" );
+ Lock( nVertexCount, false, *static_cast<VertexDesc_t*>( &desc ) );
+ }
+
+ if (m_nFirstVertex < 0)
+ {
+ m_nFirstVertex = desc.m_nFirstVertex;
+ }
+
+ // When we're using a static index buffer or a flex mesh, the indices assume vertices start at 0
+ if ( m_IndexOverride || HasFlexMesh() )
+ {
+ desc.m_nFirstVertex -= m_nFirstVertex;
+ }
+
+ // Don't add indices for points; DrawIndexedPrimitive not supported for them.
+ if ( m_Type != MATERIAL_POINTS )
+ {
+ int nFirstIndex;
+ {
+ tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "Lock nFirstIndex" );
+ nFirstIndex = Lock( false, -1, nIndexCount, *static_cast<IndexDesc_t*>( &desc ) );
+ }
+ if (m_FirstIndex < 0)
+ {
+ m_FirstIndex = nFirstIndex;
+ }
+ }
+ else
+ {
+ desc.m_pIndices = g_nScratchIndexBuffer;
+ desc.m_nIndexSize = 0;
+ }
+
+ CBaseMeshDX8::m_bMeshLocked = true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Unlocks the mesh
+//-----------------------------------------------------------------------------
+void CDynamicMeshDX8::UnlockMesh( int nVertexCount, int nIndexCount, MeshDesc_t& desc )
+{
+ m_TotalVertices += nVertexCount;
+ m_TotalIndices += nIndexCount;
+
+ if (DebugTrace())
+ {
+ Spew( nVertexCount, nIndexCount, desc );
+ }
+
+ CMeshDX8::UnlockMesh( nVertexCount, nIndexCount, desc );
+
+ // This is handled in the CMeshDX8::UnlockMesh above.
+ //CBaseMeshDX8::m_bMeshLocked = false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Draws it
+//-----------------------------------------------------------------------------
+void CDynamicMeshDX8::Draw( int nFirstIndex, int nIndexCount )
+{
+ if ( !ShaderUtil()->OnDrawMesh( this, nFirstIndex, nIndexCount ) )
+ {
+ MarkAsDrawn();
+ return;
+ }
+
+ VPROF( "CDynamicMeshDX8::Draw" );
+
+ m_HasDrawn = true;
+
+ if (m_IndexOverride || m_VertexOverride ||
+ ( ( m_TotalVertices > 0 ) && ( m_TotalIndices > 0 || m_Type == MATERIAL_POINTS || m_Type == MATERIAL_INSTANCED_QUADS ) ) )
+ {
+ Assert( !m_IsDrawing );
+
+ HandleLateCreation( );
+
+ // only have a non-zero first vertex when we are using static indices
+ int nFirstVertex = m_VertexOverride ? 0 : m_nFirstVertex;
+ int actualFirstVertex = m_IndexOverride ? nFirstVertex : 0;
+ int nVertexOffsetInBytes = HasFlexMesh() ? nFirstVertex * g_MeshMgr.VertexFormatSize( GetVertexFormat() ) : 0;
+ int baseIndex = m_IndexOverride ? 0 : m_FirstIndex;
+
+ // Overriding with the dynamic index buffer, preserve state!
+ if ( m_IndexOverride && m_pIndexBuffer == g_MeshMgr.GetDynamicIndexBuffer() )
+ {
+ baseIndex = m_FirstIndex;
+ }
+
+ VertexFormat_t fmt = m_VertexOverride ? GetVertexFormat() : VERTEX_FORMAT_INVALID;
+ if ( !SetRenderState( nVertexOffsetInBytes, actualFirstVertex, fmt ) )
+ return;
+
+ // Draws a portion of the mesh
+ int numVertices = m_VertexOverride ? m_pVertexBuffer->VertexCount() : m_TotalVertices;
+ if ((nFirstIndex != -1) && (nIndexCount != 0))
+ {
+ nFirstIndex += baseIndex;
+ }
+ else
+ {
+ // by default we draw the whole thing
+ nFirstIndex = baseIndex;
+ if( m_IndexOverride )
+ {
+ nIndexCount = m_pIndexBuffer->IndexCount();
+ Assert( nIndexCount != 0 );
+ }
+ else
+ {
+ nIndexCount = m_TotalIndices;
+ // Fake out the index count if we're drawing points/instanced-quads
+ if ( ( m_Type == MATERIAL_POINTS ) || ( m_Type == MATERIAL_INSTANCED_QUADS ) )
+ {
+ nIndexCount = m_TotalVertices;
+ }
+ Assert( nIndexCount != 0 );
+ }
+ }
+
+ // Fix up nFirstVertex to indicate the first vertex used in the data
+ if ( !HasFlexMesh() )
+ {
+ actualFirstVertex = nFirstVertex - actualFirstVertex;
+ }
+
+ s_FirstVertex = actualFirstVertex;
+ s_NumVertices = numVertices;
+
+ // Build a primlist with 1 element..
+ CPrimList prim;
+ prim.m_FirstIndex = nFirstIndex;
+ prim.m_NumIndices = nIndexCount;
+ Assert( nIndexCount != 0 );
+ s_pPrims = &prim;
+ s_nPrims = 1;
+
+ DrawMesh();
+
+ s_pPrims = NULL;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// This is useful when we need to dynamically modify data; just set the
+// render state and draw the pass immediately
+//-----------------------------------------------------------------------------
+void CDynamicMeshDX8::DrawSinglePassImmediately()
+{
+ if ((m_TotalVertices > 0) || (m_TotalIndices > 0))
+ {
+ Assert( !m_IsDrawing );
+
+ // Set the render state
+ if ( SetRenderState( 0, 0 ) )
+ {
+ s_FirstVertex = m_nFirstVertex;
+ s_NumVertices = m_TotalVertices;
+
+ // Make a temporary PrimList to hold the indices.
+ CPrimList prim( m_FirstIndex, m_TotalIndices );
+ Assert( m_TotalIndices != 0 );
+ s_pPrims = &prim;
+ s_nPrims = 1;
+
+ // Render it
+ RenderPass();
+ }
+
+ // We're done with our data
+ ResetVertexAndIndexCounts();
+ }
+}
+
+//-----------------------------------------------------------------------------
+//
+// A mesh that stores temporary vertex data in the correct format (for modification)
+//
+//-----------------------------------------------------------------------------
+// Used in rendering sub-parts of the mesh
+unsigned int CTempMeshDX8::s_NumIndices;
+unsigned int CTempMeshDX8::s_FirstIndex;
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+CTempMeshDX8::CTempMeshDX8( bool isDynamic ) : m_VertexSize(0xFFFF), m_IsDynamic(isDynamic)
+{
+#ifdef DBGFLAG_ASSERT
+ m_Locked = false;
+ m_InPass = false;
+#endif
+}
+
+CTempMeshDX8::~CTempMeshDX8()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Is the temp mesh dynamic?
+//-----------------------------------------------------------------------------
+bool CTempMeshDX8::IsDynamic() const
+{
+ return m_IsDynamic;
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the vertex format
+//-----------------------------------------------------------------------------
+void CTempMeshDX8::SetVertexFormat( VertexFormat_t format )
+{
+ CBaseMeshDX8::SetVertexFormat(format);
+ m_VertexSize = g_MeshMgr.VertexFormatSize( format );
+}
+
+//-----------------------------------------------------------------------------
+// returns the # of vertices (static meshes only)
+//-----------------------------------------------------------------------------
+int CTempMeshDX8::VertexCount() const
+{
+ return m_VertexSize ? m_VertexData.Count() / m_VertexSize : 0;
+}
+
+//-----------------------------------------------------------------------------
+// returns the # of indices
+//-----------------------------------------------------------------------------
+int CTempMeshDX8::IndexCount( ) const
+{
+ return m_IndexData.Count();
+}
+
+void CTempMeshDX8::ModifyBeginEx( bool bReadOnly, int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t& desc )
+{
+ Assert( !m_Locked );
+
+ m_LockedVerts = nVertexCount;
+ m_LockedIndices = nIndexCount;
+
+ if( nVertexCount > 0 )
+ {
+ int vertexByteOffset = m_VertexSize * nFirstVertex;
+
+ // Lock it baby
+ unsigned char* pVertexMemory = &m_VertexData[vertexByteOffset];
+
+ // Compute the vertex index..
+ desc.m_nFirstVertex = vertexByteOffset / m_VertexSize;
+
+ // Set up the mesh descriptor
+ g_MeshMgr.ComputeVertexDescription( pVertexMemory, m_VertexFormat, desc );
+ }
+ else
+ {
+ desc.m_nFirstVertex = 0;
+ // Set up the mesh descriptor
+ g_MeshMgr.ComputeVertexDescription( 0, 0, desc );
+ }
+
+ if (m_Type != MATERIAL_POINTS && nIndexCount > 0 )
+ {
+ desc.m_pIndices = &m_IndexData[nFirstIndex];
+ desc.m_nIndexSize = 1;
+ }
+ else
+ {
+ desc.m_pIndices = g_nScratchIndexBuffer;
+ desc.m_nIndexSize = 0;
+ }
+
+#ifdef DBGFLAG_ASSERT
+ m_Locked = true;
+#endif
+}
+
+void CTempMeshDX8::ModifyBegin( int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t& desc )
+{
+ ModifyBeginEx( false, nFirstVertex, nVertexCount, nFirstIndex, nIndexCount, desc );
+}
+
+void CTempMeshDX8::ModifyEnd( MeshDesc_t& desc )
+{
+#ifdef DBGFLAG_ASSERT
+ Assert( m_Locked );
+ m_Locked = false;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Locks/unlocks the mesh
+//-----------------------------------------------------------------------------
+void CTempMeshDX8::LockMesh( int nVertexCount, int nIndexCount, MeshDesc_t& desc )
+{
+ ShaderUtil()->SyncMatrices();
+
+ g_ShaderMutex.Lock();
+
+ Assert( !m_Locked );
+
+ m_LockedVerts = nVertexCount;
+ m_LockedIndices = nIndexCount;
+
+ if( nVertexCount > 0 )
+ {
+ int vertexByteOffset = m_VertexData.AddMultipleToTail( m_VertexSize * nVertexCount );
+
+ // Lock it baby
+ unsigned char* pVertexMemory = &m_VertexData[vertexByteOffset];
+
+ // Compute the vertex index..
+ desc.m_nFirstVertex = vertexByteOffset / m_VertexSize;
+
+ // Set up the mesh descriptor
+ g_MeshMgr.ComputeVertexDescription( pVertexMemory, m_VertexFormat, desc );
+ }
+ else
+ {
+ desc.m_nFirstVertex = 0;
+ // Set up the mesh descriptor
+ g_MeshMgr.ComputeVertexDescription( 0, 0, desc );
+ }
+
+ if (m_Type != MATERIAL_POINTS && nIndexCount > 0 )
+ {
+ int nFirstIndex = m_IndexData.AddMultipleToTail( nIndexCount );
+ desc.m_pIndices = &m_IndexData[nFirstIndex];
+ desc.m_nIndexSize = 1;
+ }
+ else
+ {
+ desc.m_pIndices = g_nScratchIndexBuffer;
+ desc.m_nIndexSize = 0;
+ }
+
+#ifdef DBGFLAG_ASSERT
+ m_Locked = true;
+#endif
+
+ CBaseMeshDX8::m_bMeshLocked = true;
+}
+
+void CTempMeshDX8::UnlockMesh( int nVertexCount, int nIndexCount, MeshDesc_t& desc )
+{
+ Assert( m_Locked );
+
+ // Remove unused vertices and indices
+ int verticesToRemove = m_LockedVerts - nVertexCount;
+ if( verticesToRemove != 0 )
+ {
+ m_VertexData.RemoveMultiple( m_VertexData.Count() - verticesToRemove, verticesToRemove );
+ }
+
+ int indicesToRemove = m_LockedIndices - nIndexCount;
+ if( indicesToRemove != 0 )
+ {
+ m_IndexData.RemoveMultiple( m_IndexData.Count() - indicesToRemove, indicesToRemove );
+ }
+
+#ifdef DBGFLAG_ASSERT
+ m_Locked = false;
+#endif
+
+ CBaseMeshDX8::m_bMeshLocked = false;
+
+ g_ShaderMutex.Unlock();
+}
+
+//-----------------------------------------------------------------------------
+// Sets the primitive type
+//-----------------------------------------------------------------------------
+void CTempMeshDX8::SetPrimitiveType( MaterialPrimitiveType_t type )
+{
+ // FIXME: Support MATERIAL_INSTANCED_QUADS for CTempMeshDX8 (X360 only)
+ Assert( ( type != MATERIAL_INSTANCED_QUADS ) /* || IsX360() */ );
+ m_Type = type;
+}
+
+MaterialPrimitiveType_t CTempMeshDX8::GetPrimitiveType( ) const
+{
+ return m_Type;
+}
+
+//-----------------------------------------------------------------------------
+// Gets the dynamic mesh
+//-----------------------------------------------------------------------------
+CDynamicMeshDX8* CTempMeshDX8::GetDynamicMesh( )
+{
+ return static_cast<CDynamicMeshDX8*>(g_MeshMgr.GetActualDynamicMesh( m_VertexFormat ));
+}
+
+//-----------------------------------------------------------------------------
+// Draws the entire mesh
+//-----------------------------------------------------------------------------
+void CTempMeshDX8::Draw( int nFirstIndex, int nIndexCount )
+{
+ if ( !ShaderUtil()->OnDrawMesh( this, nFirstIndex, nIndexCount ) )
+ {
+ MarkAsDrawn();
+ return;
+ }
+
+ if (m_VertexData.Count() > 0)
+ {
+ if ( !g_pShaderDeviceDx8->IsDeactivated() )
+ {
+#ifdef DRAW_SELECTION
+ if (!g_bDrawSelection && !ShaderAPI()->IsInSelectionMode())
+#else
+ if (!ShaderAPI()->IsInSelectionMode())
+#endif
+ {
+ s_FirstIndex = nFirstIndex;
+ s_NumIndices = nIndexCount;
+
+ DrawMesh( );
+
+ // This assertion fails if a BeginPass() call was not matched by
+ // a RenderPass() call
+ Assert(!m_InPass);
+ }
+ else
+ {
+ TestSelection();
+ }
+ }
+
+ // Clear out the data if this temp mesh is a dynamic one...
+ if (m_IsDynamic)
+ {
+ m_VertexData.RemoveAll();
+ m_IndexData.RemoveAll();
+ }
+ }
+}
+
+void CTempMeshDX8::CopyToMeshBuilder(
+ int iStartVert, // Which vertices to copy.
+ int nVerts,
+ int iStartIndex, // Which indices to copy.
+ int nIndices,
+ int indexOffset, // This is added to each index.
+ CMeshBuilder &builder )
+{
+ int startOffset = iStartVert * m_VertexSize;
+ int endOffset = (iStartVert + nVerts) * m_VertexSize;
+ Assert( startOffset >= 0 && startOffset <= m_VertexData.Count() );
+ Assert( endOffset >= 0 && endOffset <= m_VertexData.Count() && endOffset >= startOffset );
+ if ( endOffset > startOffset )
+ {
+ // FIXME: make this a method of CMeshBuilder (so the 'Position' pointer accessor can be removed)
+ // make sure it takes a VertexFormat_t parameter for src/dest match validation
+ memcpy( (void*)builder.Position(), &m_VertexData[startOffset], endOffset - startOffset );
+ builder.AdvanceVertices( nVerts );
+ }
+
+ for ( int i = 0; i < nIndices; ++i )
+ {
+ builder.Index( m_IndexData[iStartIndex+i] + indexOffset );
+ builder.AdvanceIndex();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Selection mode helper functions
+//-----------------------------------------------------------------------------
+static void ComputeModelToView( D3DXMATRIX& modelToView )
+{
+ // Get the modelview matrix...
+ D3DXMATRIX world, view;
+ ShaderAPI()->GetMatrix( MATERIAL_MODEL, (float*)&world );
+ ShaderAPI()->GetMatrix( MATERIAL_VIEW, (float*)&view );
+ D3DXMatrixMultiply( &modelToView, &world, &view );
+}
+
+static float ComputeCullFactor( )
+{
+ D3DCULL cullMode = ShaderAPI()->GetCullMode();
+
+ float cullFactor;
+ switch(cullMode)
+ {
+ case D3DCULL_CCW:
+ cullFactor = -1.0f;
+ break;
+
+ case D3DCULL_CW:
+ cullFactor = 1.0f;
+ break;
+
+ default:
+ cullFactor = 0.0f;
+ break;
+ };
+
+ return cullFactor;
+}
+
+//-----------------------------------------------------------------------------
+// Clip to viewport
+//-----------------------------------------------------------------------------
+static int g_NumClipVerts;
+static D3DXVECTOR3 g_ClipVerts[16];
+
+static bool PointInsidePlane( D3DXVECTOR3* pVert, int normalInd, float val, bool nearClip )
+{
+ if ((val > 0) || nearClip)
+ return (val - (*pVert)[normalInd] >= 0);
+ else
+ return ((*pVert)[normalInd] - val >= 0);
+}
+
+static void IntersectPlane( D3DXVECTOR3* pStart, D3DXVECTOR3* pEnd,
+ int normalInd, float val, D3DXVECTOR3* pOutVert )
+{
+ D3DXVECTOR3 dir;
+ D3DXVec3Subtract( &dir, pEnd, pStart );
+ Assert( dir[normalInd] != 0.0f );
+ float t = (val - (*pStart)[normalInd]) / dir[normalInd];
+ pOutVert->x = pStart->x + dir.x * t;
+ pOutVert->y = pStart->y + dir.y * t;
+ pOutVert->z = pStart->z + dir.z * t;
+
+ // Avoid any precision problems.
+ (*pOutVert)[normalInd] = val;
+}
+
+static int ClipTriangleAgainstPlane( D3DXVECTOR3** ppVert, int nVertexCount,
+ D3DXVECTOR3** ppOutVert, int normalInd, float val, bool nearClip = false )
+{
+ // Ye Olde Sutherland-Hodgman clipping algorithm
+ int numOutVerts = 0;
+ D3DXVECTOR3* pStart = ppVert[nVertexCount-1];
+ bool startInside = PointInsidePlane( pStart, normalInd, val, nearClip );
+ for (int i = 0; i < nVertexCount; ++i)
+ {
+ D3DXVECTOR3* pEnd = ppVert[i];
+ bool endInside = PointInsidePlane( pEnd, normalInd, val, nearClip );
+ if (endInside)
+ {
+ if (!startInside)
+ {
+ IntersectPlane( pStart, pEnd, normalInd, val, &g_ClipVerts[g_NumClipVerts] );
+ ppOutVert[numOutVerts++] = &g_ClipVerts[g_NumClipVerts++];
+ }
+ ppOutVert[numOutVerts++] = pEnd;
+ }
+ else
+ {
+ if (startInside)
+ {
+ IntersectPlane( pStart, pEnd, normalInd, val, &g_ClipVerts[g_NumClipVerts] );
+ ppOutVert[numOutVerts++] = &g_ClipVerts[g_NumClipVerts++];
+ }
+ }
+ pStart = pEnd;
+ startInside = endInside;
+ }
+
+ return numOutVerts;
+}
+
+void CTempMeshDX8::ClipTriangle( D3DXVECTOR3** ppVert, float zNear, D3DXMATRIX& projection )
+{
+ int i;
+ int nVertexCount = 3;
+ D3DXVECTOR3* ppClipVert1[10];
+ D3DXVECTOR3* ppClipVert2[10];
+
+ g_NumClipVerts = 0;
+
+ // Clip against the near plane in view space to prevent negative w.
+ // Clip against each plane
+ nVertexCount = ClipTriangleAgainstPlane( ppVert, nVertexCount, ppClipVert1, 2, zNear, true );
+ if (nVertexCount < 3)
+ return;
+
+ // Sucks that I have to do this, but I have to clip near plane in view space
+ // Clipping in projection space is screwy when w < 0
+ // Transform the clipped points into projection space
+ Assert( g_NumClipVerts <= 2 );
+ for (i = 0; i < nVertexCount; ++i)
+ {
+ if (ppClipVert1[i] == &g_ClipVerts[0])
+ {
+ D3DXVec3TransformCoord( &g_ClipVerts[0], ppClipVert1[i], &projection );
+ }
+ else if (ppClipVert1[i] == &g_ClipVerts[1])
+ {
+ D3DXVec3TransformCoord( &g_ClipVerts[1], ppClipVert1[i], &projection );
+ }
+ else
+ {
+ D3DXVec3TransformCoord( &g_ClipVerts[g_NumClipVerts], ppClipVert1[i], &projection );
+ ppClipVert1[i] = &g_ClipVerts[g_NumClipVerts];
+ ++g_NumClipVerts;
+ }
+ }
+
+ nVertexCount = ClipTriangleAgainstPlane( ppClipVert1, nVertexCount, ppClipVert2, 2, 1.0f );
+ if (nVertexCount < 3)
+ return;
+
+ nVertexCount = ClipTriangleAgainstPlane( ppClipVert2, nVertexCount, ppClipVert1, 0, 1.0f );
+ if (nVertexCount < 3)
+ return;
+
+ nVertexCount = ClipTriangleAgainstPlane( ppClipVert1, nVertexCount, ppClipVert2, 0, -1.0f );
+ if (nVertexCount < 3)
+ return;
+
+ nVertexCount = ClipTriangleAgainstPlane( ppClipVert2, nVertexCount, ppClipVert1, 1, 1.0f );
+ if (nVertexCount < 3)
+ return;
+
+ nVertexCount = ClipTriangleAgainstPlane( ppClipVert1, nVertexCount, ppClipVert2, 1, -1.0f );
+ if (nVertexCount < 3)
+ return;
+
+#ifdef DRAW_SELECTION
+ if( 1 || g_bDrawSelection )
+ {
+ srand( *(int*)(&ppClipVert2[0]->x) );
+ unsigned char r = (unsigned char)(rand() * 191.0f / VALVE_RAND_MAX) + 64;
+ unsigned char g = (unsigned char)(rand() * 191.0f / VALVE_RAND_MAX) + 64;
+ unsigned char b = (unsigned char)(rand() * 191.0f / VALVE_RAND_MAX) + 64;
+
+ ShaderAPI()->SetupSelectionModeVisualizationState();
+
+ CMeshBuilder* pMeshBuilder = ShaderAPI()->GetVertexModifyBuilder();
+ IMesh* pMesh = GetDynamicMesh();
+ pMeshBuilder->Begin( pMesh, MATERIAL_POLYGON, nVertexCount );
+
+ for ( i = 0; i < nVertexCount; ++i)
+ {
+ pMeshBuilder->Position3fv( *ppClipVert2[i] );
+ pMeshBuilder->Color3ub( r, g, b );
+ pMeshBuilder->AdvanceVertex();
+ }
+
+ pMeshBuilder->End();
+ pMesh->Draw();
+
+ pMeshBuilder->Begin( pMesh, MATERIAL_LINE_LOOP, nVertexCount );
+
+ for ( i = 0; i < nVertexCount; ++i)
+ {
+ pMeshBuilder->Position3fv( *ppClipVert2[i] );
+ pMeshBuilder->Color3ub( 255, 255, 255 );
+ pMeshBuilder->AdvanceVertex();
+ }
+
+ pMeshBuilder->End();
+ pMesh->Draw();
+ }
+#endif
+
+ // Compute closest and furthest verts
+ float minz = ppClipVert2[0]->z;
+ float maxz = ppClipVert2[0]->z;
+ for ( i = 1; i < nVertexCount; ++i )
+ {
+ if (ppClipVert2[i]->z < minz)
+ minz = ppClipVert2[i]->z;
+ else if (ppClipVert2[i]->z > maxz)
+ maxz = ppClipVert2[i]->z;
+ }
+
+ ShaderAPI()->RegisterSelectionHit( minz, maxz );
+}
+
+//-----------------------------------------------------------------------------
+// Selection mode
+//-----------------------------------------------------------------------------
+void CTempMeshDX8::TestSelection()
+{
+ // Note that this doesn't take into account any vertex modification
+ // done in a vertex shader. Also it doesn't take into account any clipping
+ // done in hardware
+
+ // Blow off points and lines; they don't matter
+ if ((m_Type != MATERIAL_TRIANGLES) && (m_Type != MATERIAL_TRIANGLE_STRIP))
+ return;
+
+ D3DXMATRIX modelToView, projection;
+ ComputeModelToView( modelToView );
+ ShaderAPI()->GetMatrix( MATERIAL_PROJECTION, (float*)&projection );
+ float zNear = -projection.m[3][2] / projection.m[2][2];
+
+ D3DXVECTOR3* pPos[3];
+ D3DXVECTOR3 edge[2];
+ D3DXVECTOR3 normal;
+
+ int numTriangles;
+ if (m_Type == MATERIAL_TRIANGLES)
+ numTriangles = m_IndexData.Count() / 3;
+ else
+ numTriangles = m_IndexData.Count() - 2;
+
+ float cullFactor = ComputeCullFactor();
+
+ // Makes the lovely loop simpler
+ if (m_Type == MATERIAL_TRIANGLE_STRIP)
+ cullFactor *= -1.0f;
+
+ // We'll need some temporary memory to tell us if we're transformed the vert
+ int nVertexCount = m_VertexData.Count() / m_VertexSize;
+ static CUtlVector< unsigned char > transformedVert;
+ int transformedVertSize = (nVertexCount + 7) >> 3;
+ transformedVert.RemoveAll();
+ transformedVert.EnsureCapacity( transformedVertSize );
+ transformedVert.AddMultipleToTail( transformedVertSize );
+ memset( transformedVert.Base(), 0, transformedVertSize );
+
+ int indexPos;
+ for (int i = 0; i < numTriangles; ++i)
+ {
+ // Get the three indices
+ if (m_Type == MATERIAL_TRIANGLES)
+ {
+ indexPos = i * 3;
+ }
+ else
+ {
+ Assert( m_Type == MATERIAL_TRIANGLE_STRIP );
+ cullFactor *= -1.0f;
+ indexPos = i;
+ }
+
+ // BAH. Gotta clip to the near clip plane in view space to prevent
+ // negative w coords; negative coords throw off the projection-space clipper.
+
+ // Get the three positions in view space
+ int inFrontIdx = -1;
+ for (int j = 0; j < 3; ++j)
+ {
+ int index = m_IndexData[indexPos];
+ D3DXVECTOR3* pPosition = (D3DXVECTOR3*)&m_VertexData[index * m_VertexSize];
+ if ((transformedVert[index >> 3] & (1 << (index & 0x7))) == 0)
+ {
+ D3DXVec3TransformCoord( pPosition, pPosition, &modelToView );
+ transformedVert[index >> 3] |= (1 << (index & 0x7));
+ }
+
+ pPos[j] = pPosition;
+ if (pPos[j]->z < 0.0f)
+ inFrontIdx = j;
+ ++indexPos;
+ }
+
+ // all points are behind the camera
+ if (inFrontIdx < 0)
+ continue;
+
+ // backface cull....
+ D3DXVec3Subtract( &edge[0], pPos[1], pPos[0] );
+ D3DXVec3Subtract( &edge[1], pPos[2], pPos[0] );
+ D3DXVec3Cross( &normal, &edge[0], &edge[1] );
+ float dot = D3DXVec3Dot( &normal, pPos[inFrontIdx] );
+ if (dot * cullFactor > 0.0f)
+ continue;
+
+ // Clip to viewport
+ ClipTriangle( pPos, zNear, projection );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Begins a render pass
+//-----------------------------------------------------------------------------
+void CTempMeshDX8::BeginPass( )
+{
+ Assert( !m_InPass );
+
+#ifdef DBGFLAG_ASSERT
+ m_InPass = true;
+#endif
+
+ CMeshBuilder* pMeshBuilder = ShaderAPI()->GetVertexModifyBuilder();
+
+ CDynamicMeshDX8* pMesh = GetDynamicMesh( );
+
+ int nIndexCount;
+ int nFirstIndex;
+ if ((s_FirstIndex == -1) && (s_NumIndices == 0))
+ {
+ nIndexCount = m_IndexData.Count();
+ nFirstIndex = 0;
+ }
+ else
+ {
+ nIndexCount = s_NumIndices;
+ nFirstIndex = s_FirstIndex;
+ }
+
+ int i;
+ int nVertexCount = m_VertexData.Count() / m_VertexSize;
+ pMeshBuilder->Begin( pMesh, m_Type, nVertexCount, nIndexCount );
+
+ // Copy in the vertex data...
+ // Note that since we pad the vertices, it's faster for us to simply
+ // copy the fields we're using...
+ Assert( pMeshBuilder->BaseVertexData() );
+ memcpy( pMeshBuilder->BaseVertexData(), m_VertexData.Base(), m_VertexData.Count() );
+ pMeshBuilder->AdvanceVertices( m_VertexData.Count() / m_VertexSize );
+
+ for ( i = 0; i < nIndexCount; ++i )
+ {
+ pMeshBuilder->Index( m_IndexData[nFirstIndex+i] );
+ pMeshBuilder->AdvanceIndex();
+ }
+
+ // NOTE: The client is expected to modify the data after this call is made
+ pMeshBuilder->Reset();
+}
+
+//-----------------------------------------------------------------------------
+// Draws a single pass
+//-----------------------------------------------------------------------------
+void CTempMeshDX8::RenderPass()
+{
+ Assert( m_InPass );
+
+#ifdef DBGFLAG_ASSERT
+ m_InPass = false;
+#endif
+
+ // Have the shader API modify the vertex data as it needs
+ // This vertex data is modified based on state set by the material
+ ShaderAPI()->ModifyVertexData( );
+
+ // Done building the mesh
+ ShaderAPI()->GetVertexModifyBuilder()->End();
+
+ // Have the dynamic mesh render a single pass...
+ GetDynamicMesh()->DrawSinglePassImmediately();
+}
+
+//-----------------------------------------------------------------------------
+//
+// Buffered mesh implementation
+//
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+
+CBufferedMeshDX8::CBufferedMeshDX8() : m_IsFlushing(false), m_WasRendered(true)
+{
+ m_pMesh = NULL;
+#ifdef DEBUG_BUFFERED_STATE
+ m_BufferedStateSet = false;
+#endif
+}
+
+CBufferedMeshDX8::~CBufferedMeshDX8()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the mesh
+//-----------------------------------------------------------------------------
+void CBufferedMeshDX8::SetMesh( CBaseMeshDX8* pMesh )
+{
+ if (m_pMesh != pMesh)
+ {
+ ShaderAPI()->FlushBufferedPrimitives();
+ m_pMesh = pMesh;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Spews the mesh data
+//-----------------------------------------------------------------------------
+void CBufferedMeshDX8::Spew( int nVertexCount, int nIndexCount, const MeshDesc_t &spewDesc )
+{
+ if ( m_pMesh )
+ {
+ m_pMesh->Spew( nVertexCount, nIndexCount, spewDesc );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the material
+//-----------------------------------------------------------------------------
+void CBufferedMeshDX8::SetVertexFormat( VertexFormat_t format )
+{
+ Assert( m_pMesh );
+ if (m_pMesh->NeedsVertexFormatReset(format))
+ {
+ ShaderAPI()->FlushBufferedPrimitives();
+ m_pMesh->SetVertexFormat( format );
+ }
+}
+
+void CBufferedMeshDX8::SetMorphFormat( MorphFormat_t format )
+{
+ Assert( m_pMesh );
+ m_pMesh->SetMorphFormat( format );
+}
+
+VertexFormat_t CBufferedMeshDX8::GetVertexFormat( ) const
+{
+ Assert( m_pMesh );
+ return m_pMesh->GetVertexFormat();
+}
+
+void CBufferedMeshDX8::SetMaterial( IMaterial* pMaterial )
+{
+#if _DEBUG
+ Assert( m_pMesh );
+ m_pMesh->SetMaterial( pMaterial );
+#endif
+}
+
+void CBufferedMeshDX8::ValidateData( int nVertexCount, int nIndexCount, const MeshDesc_t & spewDesc )
+{
+#if _DEBUG
+ Assert( m_pMesh );
+ m_pMesh->ValidateData( nVertexCount, nIndexCount, spewDesc );
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the flex mesh to render with this mesh
+//-----------------------------------------------------------------------------
+void CBufferedMeshDX8::SetFlexMesh( IMesh *pMesh, int nVertexOffsetInBytes )
+{
+ // FIXME: Probably are situations where we don't need to flush,
+ // but this is going to look different in a very short while, so I'm not going to bother
+ ShaderAPI()->FlushBufferedPrimitives();
+ m_pMesh->SetFlexMesh( pMesh, nVertexOffsetInBytes );
+}
+
+
+//-----------------------------------------------------------------------------
+// checks to see if it was rendered..
+//-----------------------------------------------------------------------------
+void CBufferedMeshDX8::ResetRendered()
+{
+ m_WasRendered = false;
+}
+
+bool CBufferedMeshDX8::WasNotRendered() const
+{
+ return !m_WasRendered;
+}
+
+
+//-----------------------------------------------------------------------------
+// "Draws" it
+//-----------------------------------------------------------------------------
+void CBufferedMeshDX8::Draw( int nFirstIndex, int nIndexCount )
+{
+ if ( !ShaderUtil()->OnDrawMesh( this, nFirstIndex, nIndexCount ) )
+ {
+ m_WasRendered = true;
+ MarkAsDrawn();
+ return;
+ }
+
+ Assert( !m_IsFlushing && !m_WasRendered );
+
+ // Gotta draw all of the buffered mesh
+ Assert( (nFirstIndex == -1) && (nIndexCount == 0) );
+
+ // No need to draw it more than once...
+ m_WasRendered = true;
+
+ // We've got something to flush
+ m_FlushNeeded = true;
+
+ // Less than 0 indices indicates we were using a standard buffer
+ if ( m_pMesh->HasFlexMesh() || !ShaderUtil()->GetConfig().bBufferPrimitives )
+ {
+ ShaderAPI()->FlushBufferedPrimitives();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the primitive mode
+//-----------------------------------------------------------------------------
+
+void CBufferedMeshDX8::SetPrimitiveType( MaterialPrimitiveType_t type )
+{
+ Assert( IsX360() || ( type != MATERIAL_INSTANCED_QUADS ) );
+ Assert( type != MATERIAL_HETEROGENOUS );
+
+ if (type != GetPrimitiveType())
+ {
+ ShaderAPI()->FlushBufferedPrimitives();
+ m_pMesh->SetPrimitiveType(type);
+ }
+}
+
+MaterialPrimitiveType_t CBufferedMeshDX8::GetPrimitiveType( ) const
+{
+ return m_pMesh->GetPrimitiveType();
+}
+
+
+//-----------------------------------------------------------------------------
+// Locks/unlocks the entire mesh
+//-----------------------------------------------------------------------------
+void CBufferedMeshDX8::LockMesh( int nVertexCount, int nIndexCount, MeshDesc_t& desc )
+{
+ ShaderUtil()->SyncMatrices();
+
+ Assert( m_pMesh );
+ Assert( m_WasRendered );
+
+ // Do some pre-lock processing
+ m_pMesh->PreLock();
+
+ // for tristrips, gotta make degenerate ones...
+ m_ExtraIndices = 0;
+ bool tristripFixup = (m_pMesh->IndexCount() != 0) &&
+ (m_pMesh->GetPrimitiveType() == MATERIAL_TRIANGLE_STRIP);
+ if (tristripFixup)
+ {
+ m_ExtraIndices = (m_pMesh->IndexCount() & 0x1) != 0 ? 3 : 2;
+ nIndexCount += m_ExtraIndices;
+ }
+
+ // Flush if we gotta
+ if (!m_pMesh->HasEnoughRoom(nVertexCount, nIndexCount))
+ {
+ ShaderAPI()->FlushBufferedPrimitives();
+ }
+
+ m_pMesh->LockMesh( nVertexCount, nIndexCount, desc );
+
+// This is taken care of in the function above.
+// CBaseMeshDX8::m_bMeshLocked = true;
+
+ // Deal with fixing up the tristrip..
+ if ( tristripFixup && desc.m_nIndexSize )
+ {
+ char buf[32];
+ if (DebugTrace())
+ {
+ if (m_ExtraIndices == 3)
+ sprintf(buf,"Link Index: %d %d\n", m_LastIndex, m_LastIndex);
+ else
+ sprintf(buf,"Link Index: %d\n", m_LastIndex);
+ Plat_DebugString(buf);
+ }
+ *desc.m_pIndices++ = m_LastIndex;
+ if (m_ExtraIndices == 3)
+ {
+ *desc.m_pIndices++ = m_LastIndex;
+ }
+
+ // Leave room for the last padding index
+ ++desc.m_pIndices;
+ }
+
+ m_WasRendered = false;
+
+#ifdef DEBUG_BUFFERED_MESHES
+ if (m_BufferedStateSet)
+ {
+ BufferedState_t compare;
+ ShaderAPI()->GetBufferedState( compare );
+ Assert( !memcmp( &compare, &m_BufferedState, sizeof(compare) ) );
+ }
+ else
+ {
+ ShaderAPI()->GetBufferedState( m_BufferedState );
+ m_BufferedStateSet = true;
+ }
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Locks/unlocks the entire mesh
+//-----------------------------------------------------------------------------
+void CBufferedMeshDX8::UnlockMesh( int nVertexCount, int nIndexCount, MeshDesc_t& desc )
+{
+ Assert( m_pMesh );
+
+ // Gotta fix up the first index to batch strips reasonably
+ if ((m_pMesh->GetPrimitiveType() == MATERIAL_TRIANGLE_STRIP) && desc.m_nIndexSize )
+ {
+ if (m_ExtraIndices > 0)
+ {
+ *(desc.m_pIndices - 1) = *desc.m_pIndices;
+
+ if (DebugTrace())
+ {
+ char buf[32];
+ sprintf(buf,"Link Index: %d\n", *desc.m_pIndices);
+ Plat_DebugString(buf);
+ }
+ }
+
+ // Remember the last index for next time
+ m_LastIndex = desc.m_pIndices[nIndexCount - 1];
+
+ nIndexCount += m_ExtraIndices;
+ }
+
+ m_pMesh->UnlockMesh( nVertexCount, nIndexCount, desc );
+
+// This is taken care of in the function above.
+// CBaseMeshDX8::m_bMeshLocked = false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Renders a pass
+//-----------------------------------------------------------------------------
+
+void CBufferedMeshDX8::RenderPass()
+{
+ // this should never be called!
+ Assert(0);
+}
+
+//-----------------------------------------------------------------------------
+// Flushes queued data
+//-----------------------------------------------------------------------------
+
+void CBufferedMeshDX8::Flush( )
+{
+ // If you are hitting this assert you are causing a flush between a
+ // meshbuilder begin/end and you are more than likely losing rendering data.
+ AssertOnce( !CBaseMeshDX8::m_bMeshLocked );
+
+ if ( m_pMesh && !m_IsFlushing && m_FlushNeeded )
+ {
+ VPROF( "CBufferedMeshDX8::Flush" );
+
+#ifdef DEBUG_BUFFERED_MESHES
+ if( m_BufferedStateSet )
+ {
+ BufferedState_t compare;
+ ShaderAPI()->GetBufferedState( compare );
+ Assert( !memcmp( &compare, &m_BufferedState, sizeof(compare) ) );
+ m_BufferedStateSet = false;
+ }
+#endif
+
+ m_IsFlushing = true;
+
+ // Actually draws the data using the mesh's material
+ static_cast<IMesh*>(m_pMesh)->Draw();
+
+ m_IsFlushing = false;
+ m_FlushNeeded = false;
+
+ m_pMesh->SetFlexMesh( NULL, 0 );
+ }
+}
+
+//-----------------------------------------------------------------------------
+//
+// Mesh manager implementation
+//
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// Constructor, destructor
+//-----------------------------------------------------------------------------
+CMeshMgr::CMeshMgr() :
+ m_pDynamicIndexBuffer(0),
+ m_DynamicTempMesh(true),
+ m_pVertexIDBuffer(0),
+ m_pCurrentVertexBuffer( NULL ),
+ m_CurrentVertexFormat( 0 ),
+ m_pCurrentIndexBuffer( NULL ),
+ m_DynamicIndexBuffer( SHADER_BUFFER_TYPE_DYNAMIC, MATERIAL_INDEX_FORMAT_16BIT, INDEX_BUFFER_SIZE, "dynamic" ),
+ m_DynamicVertexBuffer( SHADER_BUFFER_TYPE_DYNAMIC, VERTEX_FORMAT_UNKNOWN, DYNAMIC_VERTEX_BUFFER_MEMORY, "dynamic" )
+{
+ m_bUseFatVertices = false;
+ m_nIndexBufferOffset = 0;
+ memset( m_pVertexBufferOffset, 0, sizeof(m_pVertexBufferOffset) );
+ memset( m_pCurrentVertexStride, 0, sizeof(m_pCurrentVertexStride) );
+ memset( m_pFirstVertex, 0, sizeof(m_pFirstVertex) );
+ memset( m_pVertexCount, 0, sizeof(m_pVertexCount) );
+ m_nUnusedVertexFields = 0;
+ m_nUnusedTextureCoords = 0;
+ m_pZeroVertexBuffer = NULL;
+}
+
+CMeshMgr::~CMeshMgr()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Initialize, shutdown
+//-----------------------------------------------------------------------------
+void CMeshMgr::Init()
+{
+ m_DynamicMesh.Init( 0 );
+ m_DynamicFlexMesh.Init( 1 );
+
+ CreateDynamicIndexBuffer();
+
+ // If we're running in vs3.0, allocate a vertexID buffer
+ CreateVertexIDBuffer();
+
+ CreateZeroVertexBuffer();
+
+ m_BufferedMode = !IsX360();
+}
+
+void CMeshMgr::Shutdown()
+{
+ CleanUp();
+}
+
+
+//-----------------------------------------------------------------------------
+// Task switch...
+//-----------------------------------------------------------------------------
+void CMeshMgr::ReleaseBuffers()
+{
+ if ( IsPC() && mat_debugalttab.GetBool() )
+ {
+ Warning( "mat_debugalttab: CMeshMgr::ReleaseBuffers\n" );
+ }
+
+ CleanUp();
+ m_DynamicMesh.Reset( );
+ m_DynamicFlexMesh.Reset( );
+}
+
+void CMeshMgr::RestoreBuffers()
+{
+ if ( IsPC() && mat_debugalttab.GetBool() )
+ {
+ Warning( "mat_debugalttab: CMeshMgr::RestoreBuffers\n" );
+ }
+ Init();
+}
+
+
+//-----------------------------------------------------------------------------
+// Cleans up vertex and index buffers
+//-----------------------------------------------------------------------------
+void CMeshMgr::CleanUp()
+{
+ DestroyDynamicIndexBuffer();
+
+ DestroyVertexBuffers();
+
+ // If we're running in vs3.0, allocate a vertexID buffer
+ DestroyVertexIDBuffer();
+ DestroyZeroVertexBuffer();
+}
+
+//-----------------------------------------------------------------------------
+// Fills a vertexID buffer
+//-----------------------------------------------------------------------------
+void CMeshMgr::FillVertexIDBuffer( CVertexBuffer *pVertexIDBuffer, int nCount )
+{
+ if ( IsX360() )
+ return;
+
+ // Fill the buffer with the values 0->(nCount-1)
+ int nBaseVertexIndex = 0;
+ float *pBuffer = (float*)pVertexIDBuffer->Lock( nCount, nBaseVertexIndex );
+ for ( int i = 0; i < nCount; ++i )
+ {
+ *pBuffer++ = (float)i;
+ }
+ pVertexIDBuffer->Unlock( nCount );
+}
+
+//-----------------------------------------------------------------------------
+// Creates, destroys the dynamic index buffer
+//-----------------------------------------------------------------------------
+void CMeshMgr::CreateDynamicIndexBuffer()
+{
+ DestroyDynamicIndexBuffer();
+ SafeAssign( &m_pDynamicIndexBuffer, new CIndexBuffer( Dx9Device(), INDEX_BUFFER_SIZE, ShaderAPI()->UsingSoftwareVertexProcessing(), true ) );
+}
+
+void CMeshMgr::DestroyDynamicIndexBuffer()
+{
+ SafeRelease( &m_pDynamicIndexBuffer );
+}
+
+//-----------------------------------------------------------------------------
+// Creates, destroys the vertexID buffer
+//-----------------------------------------------------------------------------
+void CMeshMgr::CreateVertexIDBuffer()
+{
+ if ( IsX360() )
+ return;
+
+ DestroyVertexIDBuffer();
+
+ // Track mesh allocations
+ g_VBAllocTracker->TrackMeshAllocations( "CreateVertexIDBuffer" );
+ if ( g_pHardwareConfig->HasFastVertexTextures() )
+ {
+ m_pVertexIDBuffer = new CVertexBuffer( Dx9Device(), 0, 0, sizeof(float),
+ VERTEX_BUFFER_SIZE, TEXTURE_GROUP_STATIC_VERTEX_BUFFER_OTHER, ShaderAPI()->UsingSoftwareVertexProcessing() );
+ FillVertexIDBuffer( m_pVertexIDBuffer, VERTEX_BUFFER_SIZE );
+ }
+ g_VBAllocTracker->TrackMeshAllocations( NULL );
+}
+
+void CMeshMgr::CreateZeroVertexBuffer()
+{
+ if ( !m_pZeroVertexBuffer )
+ {
+ // In GL glVertexAttribPointer() doesn't support strides of 0, so we need to allocate a dummy vertex buffer large enough to handle 16-bit indices with a stride of 4 byte per vertex, plus a bit more for safety (in case basevertexindex is > 0).
+ // We could also try just disabling any vertex attribs that fetch from stream 2 and need 0's, but AMD reports this could hit a slow path in the driver. Argh.
+ uint nBufSize = IsOpenGL() ? ( 65536 * 2 * 4 ) : 4096;
+ HRESULT hr = Dx9Device()->CreateVertexBuffer( nBufSize, D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &m_pZeroVertexBuffer, NULL );
+ if ( !FAILED( hr ) )
+ {
+ void *pData = NULL;
+ m_pZeroVertexBuffer->Lock( 0, nBufSize, &pData, D3DLOCK_NOSYSLOCK );
+ if ( pData )
+ {
+ V_memset( pData, 0, nBufSize );
+ m_pZeroVertexBuffer->Unlock();
+ }
+ }
+ }
+}
+
+void CMeshMgr::DestroyZeroVertexBuffer()
+{
+ if ( m_pZeroVertexBuffer )
+ {
+ m_pZeroVertexBuffer->Release();
+ m_pZeroVertexBuffer = NULL;
+ }
+}
+
+void CMeshMgr::DestroyVertexIDBuffer()
+{
+ if ( m_pVertexIDBuffer )
+ {
+ delete m_pVertexIDBuffer;
+ m_pVertexIDBuffer = NULL;
+ }
+}
+
+CVertexBuffer *CMeshMgr::GetVertexIDBuffer( )
+{
+ return m_pVertexIDBuffer;
+}
+
+
+//-----------------------------------------------------------------------------
+// Unused vertex fields
+//-----------------------------------------------------------------------------
+void CMeshMgr::MarkUnusedVertexFields( unsigned int nFlags, int nTexCoordCount, bool *pUnusedTexCoords )
+{
+ m_nUnusedVertexFields = nFlags;
+ m_nUnusedTextureCoords = 0;
+ for ( int i = 0; i < nTexCoordCount; ++i )
+ {
+ if ( pUnusedTexCoords[i] )
+ {
+ m_nUnusedTextureCoords |= ( 1 << i );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Is the mesh dynamic?
+//-----------------------------------------------------------------------------
+bool CMeshMgr::IsDynamicMesh( IMesh* pMesh ) const
+{
+ return ( pMesh == &m_DynamicMesh ) || ( pMesh == &m_DynamicFlexMesh );
+}
+
+bool CMeshMgr::IsBufferedDynamicMesh( IMesh* pMesh ) const
+{
+ return ( pMesh == &m_BufferedMesh );
+}
+
+bool CMeshMgr::IsDynamicVertexBuffer( IVertexBuffer *pVertexBuffer ) const
+{
+ return ( pVertexBuffer == &m_DynamicVertexBuffer );
+}
+
+bool CMeshMgr::IsDynamicIndexBuffer( IIndexBuffer *pIndexBuffer ) const
+{
+ return ( pIndexBuffer == &m_DynamicIndexBuffer );
+}
+
+//-----------------------------------------------------------------------------
+// Discards the dynamic vertex and index buffer
+//-----------------------------------------------------------------------------
+void CMeshMgr::DiscardVertexBuffers()
+{
+ VPROF_BUDGET( "CMeshMgr::DiscardVertexBuffers", VPROF_BUDGETGROUP_SWAP_BUFFERS );
+ // This shouldn't be necessary, but it seems to be on GeForce 2
+ // It helps when running WC and the engine simultaneously.
+ ResetMeshRenderState();
+
+ if ( !g_pShaderDeviceDx8->IsDeactivated() )
+ {
+ for (int i = m_DynamicVertexBuffers.Count(); --i >= 0; )
+ {
+ m_DynamicVertexBuffers[i].m_pBuffer->FlushAtFrameStart();
+ }
+ m_pDynamicIndexBuffer->FlushAtFrameStart();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Releases all dynamic vertex buffers
+//-----------------------------------------------------------------------------
+void CMeshMgr::DestroyVertexBuffers()
+{
+ // Necessary for cleanup
+ RECORD_COMMAND( DX8_SET_STREAM_SOURCE, 4 );
+ RECORD_INT( -1 );
+ RECORD_INT( 0 );
+ RECORD_INT( 0 );
+ RECORD_INT( 0 );
+ D3DSetStreamSource( 0, 0, 0, 0 );
+
+ RECORD_COMMAND( DX8_SET_STREAM_SOURCE, 4 );
+ RECORD_INT( -1 );
+ RECORD_INT( 1 );
+ RECORD_INT( 0 );
+ RECORD_INT( 0 );
+ D3DSetStreamSource( 1, 0, 0, 0 );
+
+ RECORD_COMMAND( DX8_SET_STREAM_SOURCE, 4 );
+ RECORD_INT( -1 );
+ RECORD_INT( 2 );
+ RECORD_INT( 0 );
+ RECORD_INT( 0 );
+ D3DSetStreamSource( 2, 0, 0, 0 );
+
+#ifndef _X360
+ RECORD_COMMAND( DX8_SET_STREAM_SOURCE, 4 );
+ RECORD_INT( -1 );
+ RECORD_INT( 3 );
+ RECORD_INT( 0 );
+ RECORD_INT( 0 );
+ D3DSetStreamSource( 3, 0, 0, 0 );
+#endif
+
+ for (int i = m_DynamicVertexBuffers.Count(); --i >= 0; )
+ {
+ if (m_DynamicVertexBuffers[i].m_pBuffer)
+ {
+ delete m_DynamicVertexBuffers[i].m_pBuffer;
+ }
+ }
+ m_DynamicVertexBuffers.RemoveAll();
+ m_DynamicMesh.Reset();
+ m_DynamicFlexMesh.Reset();
+}
+
+
+//-----------------------------------------------------------------------------
+// Flushes the dynamic mesh
+//-----------------------------------------------------------------------------
+void CMeshMgr::Flush()
+{
+ if ( IsPC() )
+ {
+ m_BufferedMesh.HandleLateCreation();
+ m_BufferedMesh.Flush();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates, destroys static meshes
+//-----------------------------------------------------------------------------
+IMesh* CMeshMgr::CreateStaticMesh( VertexFormat_t format, const char *pTextureBudgetGroup, IMaterial * pMaterial )
+{
+ // FIXME: Use a fixed-size allocator
+ CMeshDX8* pNewMesh = new CMeshDX8( pTextureBudgetGroup );
+ pNewMesh->SetVertexFormat( format );
+ if ( pMaterial != NULL )
+ {
+ pNewMesh->SetMorphFormat( pMaterial->GetMorphFormat() );
+ pNewMesh->SetMaterial( pMaterial );
+ }
+ return pNewMesh;
+}
+
+void CMeshMgr::DestroyStaticMesh( IMesh* pMesh )
+{
+ // Don't destroy the dynamic mesh!
+ Assert( !IsDynamicMesh( pMesh ) );
+ CBaseMeshDX8* pMeshImp = static_cast<CBaseMeshDX8*>(pMesh);
+ if (pMeshImp)
+ {
+ delete pMeshImp;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Gets at the *real* dynamic mesh
+//-----------------------------------------------------------------------------
+IMesh* CMeshMgr::GetActualDynamicMesh( VertexFormat_t format )
+{
+ m_DynamicMesh.SetVertexFormat( format );
+ return &m_DynamicMesh;
+}
+
+//-----------------------------------------------------------------------------
+// Copy a static mesh index buffer to a dynamic mesh index buffer
+//-----------------------------------------------------------------------------
+void CMeshMgr::CopyStaticMeshIndexBufferToTempMeshIndexBuffer( CTempMeshDX8 *pDstIndexMesh,
+ CMeshDX8 *pSrcIndexMesh )
+{
+ tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "%s", __FUNCTION__ );
+
+ Assert( !pSrcIndexMesh->IsDynamic() );
+ int nIndexCount = pSrcIndexMesh->IndexCount();
+
+ CMeshBuilder dstMeshBuilder;
+ dstMeshBuilder.Begin( pDstIndexMesh, pSrcIndexMesh->GetPrimitiveType(), 0, nIndexCount );
+ CIndexBuffer *srcIndexBuffer = pSrcIndexMesh->GetIndexBuffer();
+ int dummy = 0;
+ unsigned short *srcIndexArray = srcIndexBuffer->Lock( false, nIndexCount, dummy, 0 );
+ int i;
+ for( i = 0; i < nIndexCount; i++ )
+ {
+ dstMeshBuilder.Index( srcIndexArray[i] );
+ dstMeshBuilder.AdvanceIndex();
+ }
+ srcIndexBuffer->Unlock( 0 );
+ dstMeshBuilder.End();
+}
+
+
+IMesh *CMeshMgr::GetFlexMesh()
+{
+ if ( g_pMaterialSystemHardwareConfig->SupportsPixelShaders_2_b() )
+ {
+ // FIXME: Kinda ugly size.. 28 bytes
+ m_DynamicFlexMesh.SetVertexFormat( VERTEX_POSITION | VERTEX_NORMAL | VERTEX_WRINKLE | VERTEX_FORMAT_USE_EXACT_FORMAT );
+ }
+ else
+ {
+ // Same size as a pair of float3s (24 bytes)
+ m_DynamicFlexMesh.SetVertexFormat( VERTEX_POSITION | VERTEX_NORMAL | VERTEX_FORMAT_USE_EXACT_FORMAT );
+ }
+ return &m_DynamicFlexMesh;
+}
+
+//-----------------------------------------------------------------------------
+// Gets at the dynamic mesh
+//-----------------------------------------------------------------------------
+IMesh* CMeshMgr::GetDynamicMesh( IMaterial* pMaterial, VertexFormat_t vertexFormat, int nHWSkinBoneCount,
+ bool buffered, IMesh* pVertexOverride, IMesh* pIndexOverride )
+{
+ tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "%s", __FUNCTION__ );
+
+ Assert( (pMaterial == NULL) || ((IMaterialInternal *)pMaterial)->IsRealTimeVersion() );
+
+ if ( IsX360() )
+ {
+ buffered = false;
+ }
+
+ // Can't be buffered if we're overriding the buffers
+ if ( pVertexOverride || pIndexOverride )
+ {
+ buffered = false;
+ }
+
+ // When going from buffered to unbuffered mode, need to flush..
+ if ((m_BufferedMode != buffered) && m_BufferedMode)
+ {
+ m_BufferedMesh.SetMesh(0);
+ }
+ m_BufferedMode = buffered;
+
+ IMaterialInternal* pMatInternal = static_cast<IMaterialInternal*>(pMaterial);
+
+ bool needTempMesh = ShaderAPI()->IsInSelectionMode();
+
+#ifdef DRAW_SELECTION
+ if( g_bDrawSelection )
+ {
+ needTempMesh = true;
+ }
+#endif
+
+ CBaseMeshDX8* pMesh;
+
+ if ( needTempMesh )
+ {
+ // These haven't been implemented yet for temp meshes!
+ // I'm not a hundred percent sure how to implement them; it would
+ // involve a lock and a copy at least, which would stall the entire
+ // rendering pipeline.
+ Assert( !pVertexOverride );
+
+ if( pIndexOverride )
+ {
+ CopyStaticMeshIndexBufferToTempMeshIndexBuffer( &m_DynamicTempMesh,
+ ( CMeshDX8 * )pIndexOverride );
+ }
+ pMesh = &m_DynamicTempMesh;
+ }
+ else
+ {
+ pMesh = &m_DynamicMesh;
+ }
+
+ if ( m_BufferedMode )
+ {
+ Assert( !m_BufferedMesh.WasNotRendered() );
+ m_BufferedMesh.SetMesh( pMesh );
+ pMesh = &m_BufferedMesh;
+ }
+
+ if( !pVertexOverride )
+ {
+ // Remove VERTEX_FORMAT_COMPRESSED from the material's format (dynamic meshes don't
+ // support compression, and all materials should support uncompressed verts too)
+ VertexFormat_t materialFormat = pMatInternal->GetVertexFormat() & ~VERTEX_FORMAT_COMPRESSED;
+ VertexFormat_t fmt = ( vertexFormat != 0 ) ? vertexFormat : materialFormat;
+ if ( vertexFormat != 0 )
+ {
+ int nVertexFormatBoneWeights = NumBoneWeights( vertexFormat );
+ if ( nHWSkinBoneCount < nVertexFormatBoneWeights )
+ {
+ nHWSkinBoneCount = nVertexFormatBoneWeights;
+ }
+ }
+
+ // Force the requested number of bone weights
+ fmt &= ~VERTEX_BONE_WEIGHT_MASK;
+ if ( nHWSkinBoneCount > 0 )
+ {
+ fmt |= VERTEX_BONEWEIGHT( 2 );
+ fmt |= VERTEX_BONE_INDEX;
+ }
+
+ pMesh->SetVertexFormat( fmt );
+ }
+ else
+ {
+ CBaseMeshDX8 *pDX8Mesh = static_cast<CBaseMeshDX8*>(pVertexOverride);
+ pMesh->SetVertexFormat( pDX8Mesh->GetVertexFormat() );
+ }
+ pMesh->SetMorphFormat( pMatInternal->GetMorphFormat() );
+ pMesh->SetMaterial( pMatInternal );
+
+ // Note this works because we're guaranteed to not be using a buffered mesh
+ // when we have overrides on
+ // FIXME: Make work for temp meshes
+ if ( pMesh == &m_DynamicMesh )
+ {
+ CBaseMeshDX8* pBaseVertex = static_cast<CBaseMeshDX8*>( pVertexOverride );
+ if ( pBaseVertex )
+ {
+ m_DynamicMesh.OverrideVertexBuffer( pBaseVertex->GetVertexBuffer() );
+ }
+
+ CBaseMeshDX8* pBaseIndex = static_cast<CBaseMeshDX8*>( pIndexOverride );
+ if ( pBaseIndex )
+ {
+ m_DynamicMesh.OverrideIndexBuffer( pBaseIndex->GetIndexBuffer() );
+ }
+ }
+
+ return pMesh;
+}
+
+
+//-----------------------------------------------------------------------------
+// Used to construct vertex data
+//-----------------------------------------------------------------------------
+void CMeshMgr::ComputeVertexDescription( unsigned char* pBuffer,
+ VertexFormat_t vertexFormat, MeshDesc_t& desc ) const
+{
+ ComputeVertexDesc( pBuffer, vertexFormat, (VertexDesc_t &)desc );
+}
+
+
+//-----------------------------------------------------------------------------
+// Computes the vertex format
+//-----------------------------------------------------------------------------
+VertexFormat_t CMeshMgr::ComputeVertexFormat( unsigned int flags,
+ int nTexCoordArraySize, int* pTexCoordDimensions, int numBoneWeights,
+ int userDataSize ) const
+{
+ // Construct a bitfield that makes sense and is unique from the standard FVF formats
+ VertexFormat_t fmt = flags & ~VERTEX_FORMAT_USE_EXACT_FORMAT;
+
+ if ( g_pHardwareConfig->SupportsCompressedVertices() == VERTEX_COMPRESSION_NONE )
+ {
+ // Vertex compression is disabled - make sure all materials
+ // say "No!" to compressed verts ( tested in IsValidVertexFormat() )
+ fmt &= ~VERTEX_FORMAT_COMPRESSED;
+ }
+
+ // This'll take 3 bits at most
+ Assert( numBoneWeights <= 4 );
+
+ if ( numBoneWeights > 0 )
+ {
+ fmt |= VERTEX_BONEWEIGHT( 2 ); // Always exactly two weights
+ }
+
+ // Size is measured in # of floats
+ Assert( userDataSize <= 4 );
+ fmt |= VERTEX_USERDATA_SIZE(userDataSize);
+
+ // NOTE: If pTexCoordDimensions isn't specified, then nTexCoordArraySize
+ // is interpreted as meaning that we have n 2D texcoords in the first N texcoord slots
+ nTexCoordArraySize = min( nTexCoordArraySize, (int)VERTEX_MAX_TEXTURE_COORDINATES );
+ for ( int i = 0; i < nTexCoordArraySize; ++i )
+ {
+ if ( pTexCoordDimensions )
+ {
+ Assert( pTexCoordDimensions[i] >= 0 && pTexCoordDimensions[i] <= 4 );
+ fmt |= VERTEX_TEXCOORD_SIZE( (TextureStage_t)i, pTexCoordDimensions[i] );
+ }
+ else
+ {
+ fmt |= VERTEX_TEXCOORD_SIZE( (TextureStage_t)i, 2 );
+ }
+ }
+
+ return fmt;
+}
+
+
+//-----------------------------------------------------------------------------
+// Use fat vertices (for tools)
+//-----------------------------------------------------------------------------
+void CMeshMgr::UseFatVertices( bool bUseFat )
+{
+ m_bUseFatVertices = bUseFat;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the number of vertices we can render using the dynamic mesh
+//-----------------------------------------------------------------------------
+void CMeshMgr::GetMaxToRender( IMesh *pMesh, bool bMaxUntilFlush, int *pMaxVerts, int *pMaxIndices )
+{
+ CBaseMeshDX8 *pBaseMesh = static_cast<CBaseMeshDX8*>( pMesh );
+ if ( !pBaseMesh )
+ {
+ *pMaxVerts = 0;
+ *pMaxIndices = m_pDynamicIndexBuffer->IndexCount();
+ return;
+ }
+
+ if ( IsBufferedDynamicMesh( pMesh ) )
+ {
+ pBaseMesh = (CBaseMeshDX8*)static_cast<CBufferedMeshDX8*>( pBaseMesh )->GetMesh();
+ pMesh = pBaseMesh;
+ }
+
+ // Static mesh? Max you can use is 65535
+ if ( !IsDynamicMesh( pMesh ) )
+ {
+ *pMaxVerts = 65535;
+ *pMaxIndices = 65535;
+ return;
+ }
+
+ CVertexBuffer *pVertexBuffer = pBaseMesh->GetVertexBuffer();
+ CIndexBuffer *pIndexBuffer = pBaseMesh->GetIndexBuffer();
+
+ if ( !pVertexBuffer )
+ {
+ *pMaxVerts = 0;
+ *pMaxIndices = 0;
+ return;
+ }
+
+ if ( !bMaxUntilFlush )
+ {
+ *pMaxVerts = ShaderAPI()->GetCurrentDynamicVBSize() / pVertexBuffer->VertexSize();
+ if ( *pMaxVerts > 65535 )
+ {
+ *pMaxVerts = 65535;
+ }
+ *pMaxIndices = pIndexBuffer ? pIndexBuffer->IndexCount() : 0;
+ return;
+ }
+
+ *pMaxVerts = pVertexBuffer->NumVerticesUntilFlush();
+ *pMaxIndices = pIndexBuffer ? pIndexBuffer->IndexCount() - pIndexBuffer->IndexPosition() : 0;
+ if ( *pMaxVerts == 0 )
+ {
+ *pMaxVerts = ShaderAPI()->GetCurrentDynamicVBSize() / pVertexBuffer->VertexSize();
+ }
+ if ( *pMaxVerts > 65535 )
+ {
+ *pMaxVerts = 65535;
+ }
+ if ( *pMaxIndices == 0 )
+ {
+ *pMaxIndices = pIndexBuffer ? pIndexBuffer->IndexCount() : 0;
+ }
+}
+
+int CMeshMgr::GetMaxVerticesToRender( IMaterial *pMaterial )
+{
+ Assert( (pMaterial == NULL) || ((IMaterialInternal *)pMaterial)->IsRealTimeVersion() );
+
+ // Be conservative, assume no compression (in here, we don't know if the caller will used a compressed VB or not)
+ // FIXME: allow the caller to specify which compression type should be used to compute size from the vertex format
+ // (this can vary between multiple VBs/Meshes using the same material)
+ VertexFormat_t fmt = pMaterial->GetVertexFormat() & ~VERTEX_FORMAT_COMPRESSED;
+ int nVertexSize = VertexFormatSize( fmt );
+ if ( nVertexSize == 0 )
+ {
+ // unable to determine vertex format information, possibly due to device loss.
+ Warning( "bad vertex size for material %s\n", pMaterial->GetName() );
+ return 0;
+ }
+
+ int nMaxVerts = ShaderAPI()->GetCurrentDynamicVBSize() / nVertexSize;
+ return MIN( nMaxVerts, 65535 );
+}
+
+int CMeshMgr::GetMaxIndicesToRender( )
+{
+ return INDEX_BUFFER_SIZE;
+}
+
+//-----------------------------------------------------------------------------
+// Returns a vertex buffer appropriate for the flags
+//-----------------------------------------------------------------------------
+CVertexBuffer *CMeshMgr::FindOrCreateVertexBuffer( int nDynamicBufferId, VertexFormat_t vertexFormat )
+{
+ int vertexSize = VertexFormatSize( vertexFormat );
+
+ while ( m_DynamicVertexBuffers.Count() <= nDynamicBufferId )
+ {
+ // Track VB allocations (override any prior allocator string set higher up on the callstack)
+ g_VBAllocTracker->TrackMeshAllocations( NULL );
+ g_VBAllocTracker->TrackMeshAllocations( "CMeshMgr::FindOrCreateVertexBuffer (dynamic VB)" );
+
+ // create the single 1MB dynamic vb that will be shared amongst all consumers
+ // the correct thing is to use the largest expected vertex format size of max elements, but this
+ // creates an undesirably large buffer - instead create the buffer we want, and fix consumers that bork
+ // NOTE: GetCurrentDynamicVBSize returns a smaller value during level transitions
+ int nBufferMemory = ShaderAPI()->GetCurrentDynamicVBSize();
+ int nIndex = m_DynamicVertexBuffers.AddToTail();
+ m_DynamicVertexBuffers[nIndex].m_VertexSize = 0;
+ m_DynamicVertexBuffers[nIndex].m_pBuffer = new CVertexBuffer( Dx9Device(), 0, 0,
+ nBufferMemory / VERTEX_BUFFER_SIZE, VERTEX_BUFFER_SIZE, TEXTURE_GROUP_STATIC_VERTEX_BUFFER_OTHER, ShaderAPI()->UsingSoftwareVertexProcessing(), true );
+
+ g_VBAllocTracker->TrackMeshAllocations( NULL );
+ }
+
+ if ( m_DynamicVertexBuffers[nDynamicBufferId].m_VertexSize != vertexSize )
+ {
+ // provide caller with dynamic vb in expected format
+ // NOTE: GetCurrentDynamicVBSize returns a smaller value during level transitions
+ int nBufferMemory = ShaderAPI()->GetCurrentDynamicVBSize();
+ m_DynamicVertexBuffers[nDynamicBufferId].m_VertexSize = vertexSize;
+ m_DynamicVertexBuffers[nDynamicBufferId].m_pBuffer->ChangeConfiguration( vertexSize, nBufferMemory );
+
+ // size changed means stream stride needs update
+ // mark cached stream state as invalid to reset stream
+ if ( nDynamicBufferId == 0 )
+ {
+ g_pLastVertex = NULL;
+ }
+ }
+
+ return m_DynamicVertexBuffers[nDynamicBufferId].m_pBuffer;
+}
+
+CIndexBuffer *CMeshMgr::GetDynamicIndexBuffer()
+{
+ return m_pDynamicIndexBuffer;
+}
+
+IVertexBuffer *CMeshMgr::GetDynamicVertexBuffer( IMaterial *pMaterial, bool buffered )
+{
+ Assert( 0 );
+ return NULL;
+// return ( IMeshDX8 * )GetDynamicMesh( pMaterial, buffered, NULL, NULL );
+}
+
+IIndexBuffer *CMeshMgr::GetDynamicIndexBuffer( IMaterial *pMaterial, bool buffered )
+{
+ Assert( 0 );
+ return NULL;
+// return ( IMeshDX8 * )GetDynamicMesh( pMaterial, buffered, NULL, NULL );
+}
+
+
+//-----------------------------------------------------------------------------
+IVertexBuffer *CMeshMgr::CreateVertexBuffer( ShaderBufferType_t type, VertexFormat_t fmt, int nVertexCount, const char *pBudgetGroup )
+{
+ // FIXME: Use a fixed-size allocator
+ CVertexBufferDx8 *pNewVertexBuffer = new CVertexBufferDx8( type, fmt, nVertexCount, pBudgetGroup );
+ return pNewVertexBuffer;
+}
+
+IIndexBuffer *CMeshMgr::CreateIndexBuffer( ShaderBufferType_t bufferType, MaterialIndexFormat_t fmt, int nIndexCount, const char *pBudgetGroup )
+{
+ switch( bufferType )
+ {
+ case SHADER_BUFFER_TYPE_STATIC:
+ case SHADER_BUFFER_TYPE_DYNAMIC:
+ {
+ CIndexBufferDx8 *pIndexBuffer = new CIndexBufferDx8( bufferType, fmt, nIndexCount, pBudgetGroup );
+ return pIndexBuffer;
+ }
+ case SHADER_BUFFER_TYPE_STATIC_TEMP:
+ case SHADER_BUFFER_TYPE_DYNAMIC_TEMP:
+ Assert( 0 );
+ return NULL;
+ default:
+ Assert( 0 );
+ return NULL;
+ }
+}
+
+void CMeshMgr::DestroyVertexBuffer( IVertexBuffer *pVertexBuffer )
+{
+ if ( pVertexBuffer && !IsDynamicVertexBuffer( pVertexBuffer ) )
+ {
+ delete pVertexBuffer;
+ }
+}
+
+void CMeshMgr::DestroyIndexBuffer( IIndexBuffer *pIndexBuffer )
+{
+ if ( pIndexBuffer && !IsDynamicIndexBuffer( pIndexBuffer ) )
+ {
+ delete pIndexBuffer;
+ }
+}
+
+// Do we need to specify the stream here in the case of locking multiple dynamic VBs on different streams?
+IVertexBuffer *CMeshMgr::GetDynamicVertexBuffer( int streamID, VertexFormat_t vertexFormat, bool bBuffered )
+{
+ if ( IsX360() )
+ {
+ bBuffered = false;
+ }
+
+ if ( CompressionType( vertexFormat ) != VERTEX_COMPRESSION_NONE )
+ {
+ // UNDONE: support compressed dynamic meshes if needed (pro: less VB memory, con: time spent compressing)
+ DebuggerBreak();
+ return NULL;
+ }
+
+ // MESHFIXME
+#if 0
+ if ( ( m_BufferedMode != bBuffered ) && m_BufferedMode )
+ {
+ m_BufferedIndexBuffer.SetIndexBuffer( NULL );
+ }
+#endif
+
+ m_BufferedMode = bBuffered;
+ Assert( !m_BufferedMode ); // MESHFIXME: don't deal with buffered VBs yet.
+
+ bool needTempMesh = ShaderAPI()->IsInSelectionMode();
+
+#ifdef DRAW_SELECTION
+ if( g_bDrawSelection )
+ {
+ needTempMesh = true;
+ }
+#endif
+
+ Assert( !needTempMesh ); // MESHFIXME: don't support temp meshes here yet.
+
+ CVertexBufferDx8 *pVertexBuffer;
+
+ if ( needTempMesh )
+ {
+ Assert( 0 ); // MESHFIXME: don't do this yet.
+// pVertexBuffer = &m_DynamicTempVertexBuffer;
+ pVertexBuffer = NULL;
+ }
+ else
+ {
+ pVertexBuffer = &m_DynamicVertexBuffer;
+ }
+
+ if ( m_BufferedMode )
+ {
+ Assert( 0 ); // don't support this yet.
+#if 0
+ Assert( !m_BufferedMesh.WasNotRendered() );
+ m_BufferedMesh.SetMesh( pMesh );
+ pMesh = &m_BufferedMesh;
+#endif
+ }
+
+ return pVertexBuffer;
+}
+
+IIndexBuffer *CMeshMgr::GetDynamicIndexBuffer( MaterialIndexFormat_t fmt, bool bBuffered )
+{
+ if ( IsX360() )
+ {
+ bBuffered = false;
+ }
+
+ m_BufferedMode = bBuffered;
+
+ Assert( !m_BufferedMode );
+
+#ifdef DBGFLAG_ASSERT
+ bool needTempMesh =
+#endif
+ ShaderAPI()->IsInSelectionMode();
+
+#ifdef DRAW_SELECTION
+ if( g_bDrawSelection )
+ {
+ needTempMesh = true;
+ }
+#endif
+
+ Assert( !needTempMesh ); // don't handle this yet. MESHFIXME
+
+ CIndexBufferBase *pIndexBuffer = &m_DynamicIndexBuffer;
+ return pIndexBuffer;
+}
+
+void CMeshMgr::SetVertexIDStreamState()
+{
+ if ( IsX360() )
+ return;
+
+ // MESHFIXME : This path is only used for the new index/vertex buffer interfaces.
+ // MESHFIXME : This path is only used for the new index/vertex buffer interfaces.
+ bool bUsingVertexID = false;//IsUsingVertexID();
+// if ( bUsingVertexID != g_bUsingVertexID )
+ {
+ if ( bUsingVertexID )
+ {
+ // NOTE: Morphing doesn't work with dynamic buffers!!! BLEAH
+ // It's because the indices (which are not 0 based for dynamic buffers)
+ // are accessing both the vertexID buffer + the regular vertex buffer.
+ // This *might* be fixable with baseVertexIndex?
+ Assert( !m_pCurrentVertexBuffer->IsDynamic() );
+
+ CVertexBuffer *pVertexIDBuffer = g_MeshMgr.GetVertexIDBuffer( );
+ RECORD_COMMAND( DX8_SET_STREAM_SOURCE, 4 );
+ RECORD_INT( pVertexIDBuffer->UID() );
+ RECORD_INT( 3 );
+ RECORD_INT( 0 );
+ RECORD_INT( pVertexIDBuffer->VertexSize() );
+
+ D3DSetStreamSource( 3, pVertexIDBuffer->GetInterface(), 0, pVertexIDBuffer->VertexSize() );
+ pVertexIDBuffer->HandlePerFrameTextureStats( ShaderAPI()->GetCurrentFrameCounter() );
+ }
+ else
+ {
+ RECORD_COMMAND( DX8_SET_STREAM_SOURCE, 4 );
+ RECORD_INT( -1 ); // vertex buffer id
+ RECORD_INT( 3 ); // stream
+ RECORD_INT( 0 ); // vertex offset
+ RECORD_INT( 0 ); // vertex size
+
+ D3DSetStreamSource( 3, 0, 0, 0 );
+ }
+ g_bUsingVertexID = bUsingVertexID;
+ }
+}
+
+void CMeshMgr::SetColorStreamState()
+{
+ if ( g_pLastColorMesh )
+ {
+ RECORD_COMMAND( DX8_SET_STREAM_SOURCE, 4 );
+ RECORD_INT( -1 ); // vertex buffer id
+ RECORD_INT( 1 ); // stream
+ RECORD_INT( 0 ); // vertex offset
+ RECORD_INT( 0 ); // vertex size
+
+ D3DSetStreamSource( 1, 0, 0, 0 );
+ }
+ g_pLastColorMesh = NULL;
+ g_nLastColorMeshVertOffsetInBytes = 0;
+}
+
+void CMeshMgr::SetVertexStreamState( int nVertOffsetInBytes, int nVertexStride )
+{
+ // Calls in here assume shader support...
+ if ( HardwareConfig()->SupportsVertexAndPixelShaders() )
+ {
+ // Set a 4kb all-zero static VB into the flex/wrinkle stream with a stride of 0 bytes, so the vertex shader always reads valid floating point values (otherwise it can get NaN's/Inf's, and under OpenGL this is bad on NVidia)
+ // togl requires non-zero strides, but on D3D9 we can set a stride of 0 for a little more efficiency.
+ D3DSetStreamSource( 2, g_MeshMgr.GetZeroVertexBuffer(), 0, IsOpenGL() ? 4 : 0 );
+
+ // cFlexScale.x masks flex in vertex shader
+ if ( g_pHardwareConfig->Caps().m_SupportsVertexShaders_2_0 )
+ {
+ float c[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ ShaderAPI()->SetVertexShaderConstant( VERTEX_SHADER_FLEXSCALE, c, 1 );
+ }
+
+ g_bFlexMeshStreamSet = false;
+ }
+
+ // MESHFIXME : This path is only used for the new index/vertex buffer interfaces.
+ if ( g_pLastVertex || ( g_pLastVertexBuffer != m_pCurrentVertexBuffer->GetDx9Buffer() ) ||
+ ( g_nLastVertOffsetInBytes != nVertOffsetInBytes ) || ( g_nLastVertStride != nVertexStride ))
+ {
+ Assert( m_pCurrentVertexBuffer && m_pCurrentVertexBuffer->GetDx9Buffer() );
+
+ D3DSetStreamSource( 0, m_pCurrentVertexBuffer->GetDx9Buffer(), nVertOffsetInBytes, nVertexStride );
+ m_pCurrentVertexBuffer->HandlePerFrameTextureStats( ShaderAPI()->GetCurrentFrameCounter() );
+
+ g_pLastVertex = NULL;
+ g_nLastVertStride = nVertexStride;
+ g_pLastVertexBuffer = m_pCurrentVertexBuffer->GetDx9Buffer();
+ g_nLastVertOffsetInBytes = nVertOffsetInBytes;
+ }
+}
+
+bool CMeshMgr::SetRenderState( int nVertexOffsetInBytes, int nFirstVertexIdx, VertexFormat_t vertexFormat, int nVertexStride )
+{
+ // Can't set the state if we're deactivated
+ if ( g_pShaderDeviceDx8->IsDeactivated() )
+ {
+ ResetMeshRenderState();
+ return false;
+ }
+
+ // make sure the vertex format is a superset of the current material's
+ // vertex format...
+ // MESHFIXME : This path is only used for the new index/vertex buffer interfaces.
+#if 0
+ // FIXME
+ if ( !IsValidVertexFormat( vertexFormat ) )
+ {
+ Warning( "Material %s is being applied to a model, you need $model=1 in the .vmt file!\n",
+ ShaderAPI()->GetBoundMaterial()->GetName() );
+ return false;
+ }
+#endif
+
+ SetVertexIDStreamState();
+ SetColorStreamState();
+ SetVertexStreamState( nVertexOffsetInBytes, nVertexStride );
+ SetIndexStreamState( nFirstVertexIdx );
+
+ return true;
+}
+
+void CMeshMgr::BindVertexBuffer( int nStreamID, IVertexBuffer *pVertexBuffer, int nOffsetInBytes, int nFirstVertex, int nVertexCount, VertexFormat_t fmt, int nRepetitions )
+{
+ // FIXME: Multiple stream support isn't implemented yet
+ Assert( nStreamID == 0 );
+
+ m_pCurrentVertexBuffer = static_cast< CVertexBufferDx8 * >( pVertexBuffer );
+ m_CurrentVertexFormat = fmt;
+ m_pVertexBufferOffset[nStreamID] = nOffsetInBytes;
+ m_pCurrentVertexStride[nStreamID] = m_pCurrentVertexBuffer->VertexSize();
+ m_pFirstVertex[nStreamID] = nFirstVertex;
+ m_pVertexCount[nStreamID] = nVertexCount,
+ m_pVertexIDBuffer = NULL;
+}
+
+void CMeshMgr::BindIndexBuffer( IIndexBuffer *pIndexBuffer, int nOffsetInBytes )
+{
+ m_pCurrentIndexBuffer = static_cast< CIndexBufferBase * >( pIndexBuffer );
+ m_nIndexBufferOffset = nOffsetInBytes;
+}
+
+void CMeshMgr::Draw( MaterialPrimitiveType_t primitiveType, int nFirstIndex, int nIndexCount )
+{
+ // MESHFIXME : This path is only used for the new index/vertex buffer interfaces.
+ // make sure we aren't using a morph stream for this path.
+// Assert( !IsUsingMorphData() );
+// Assert( !m_pColorMesh );
+
+ SetRenderState( m_pVertexBufferOffset[0], /* nFirstVertexIdx */0, m_CurrentVertexFormat, m_pCurrentVertexStride[0] );
+
+ m_PrimitiveType = MATERIAL_TRIANGLES;
+ Assert( primitiveType == MATERIAL_TRIANGLES );
+
+ m_nFirstIndex = nFirstIndex;
+ m_nNumIndices = nIndexCount;
+
+ ShaderAPI()->DrawWithVertexAndIndexBuffers();
+}
+
+void CMeshMgr::RenderPassWithVertexAndIndexBuffers( void )
+{
+// LOCK_SHADERAPI(); MESHFIXME
+ VPROF( "CShaderAPIDX8::RenderPassWithVertexAndIndexBuffers" );
+
+ Assert( m_PrimitiveType != MATERIAL_HETEROGENOUS );
+
+// for ( int iPrim=0; iPrim < s_nPrims; iPrim++ )
+ {
+// CPrimList *pPrim = &s_pPrims[iPrim];
+
+// if ( pPrim->m_NumIndices == 0 )
+// continue;
+
+ if ( m_PrimitiveType == MATERIAL_POINTS )
+ {
+ // (For point lists, we don't actually fill in indices, but we treat it as
+ // though there are indices for the list up until here).
+ Assert( 0 );
+// Dx9Device()->DrawPrimitive( ComputeMode( m_PrimitiveType ), s_FirstVertex, pPrim->m_NumIndices );
+ }
+ else
+ {
+// int numPrimitives = NumPrimitives( s_NumVertices, pPrim->m_NumIndices );
+
+// Warning( "CMeshMgr::RenderPassWithVertexAndIndexBuffers: DrawIndexedPrimitive: m_nFirstIndex = %d numPrimitives = %d\n", ( int )( ( CDynamiCIndexBufferDx8 * )m_pCurrentIndexBuffer )->m_FirstIndex, ( int )( m_nNumIndices / 3 ) );
+ {
+ VPROF( "Dx9Device()->DrawIndexedPrimitive" );
+// VPROF_INCREMENT_COUNTER( "DrawIndexedPrimitive", 1 );
+// VPROF_INCREMENT_COUNTER( "numPrimitives", numPrimitives );
+
+// Dx9Device()->DrawIndexedPrimitive(
+// m_Mode,
+// m_FirstIndex,
+// s_FirstVertex,
+// s_NumVertices,
+// pPrim->m_FirstIndex,
+// numPrimitives );
+
+ Assert( m_nFirstIndex >= 0 );
+
+#ifdef CHECK_INDICES
+ // g_pLastVertex - this is the current vertex buffer
+ // g_pLastColorMesh - this is the curent color mesh, if there is one.
+ // g_pLastIndex - this is the current index buffer.
+ // vertoffset : m_FirstIndex
+ CIndexBufferDx8 *pIndexBuffer = assert_cast< CIndexBufferDx8 * >( m_pCurrentIndexBuffer );
+ if( m_PrimitiveType == MATERIAL_TRIANGLES || m_PrimitiveType == MATERIAL_TRIANGLE_STRIP )
+ {
+ // FIXME: need to be able to deal with multiple stream here, but don't bother for now.
+ int j;
+ int numVerts = m_pVertexCount[0];
+ for( j = 0; j < m_nNumIndices; j++ )
+ {
+ int index = pIndexBuffer->GetShadowIndex( j + m_nFirstIndex );
+ Assert( index >= m_pFirstVertex[0] );
+ Assert( index < m_pFirstVertex[0] + numVerts );
+ }
+ }
+#endif // CHECK_INDICES
+ Dx9Device()->DrawIndexedPrimitive(
+ ComputeMode( m_PrimitiveType ), // Member of the D3DPRIMITIVETYPE enumerated type, describing the type of primitive to render. D3DPT_POINTLIST is not supported with this method.
+
+ /*m_FirstIndex*/ 0, // Offset from the start of the vertex buffer to the first vertex index. An index of 0 in the index buffer refers to this location in the vertex buffer.
+
+ /*s_FirstVertex*/ m_pFirstVertex[0],// Minimum vertex index for vertices used during this call. This is a zero based index relative to BaseVertexIndex.
+ // This is zero for now since we don't do more than one batch yet with the new mesh interface.
+
+ /*s_NumVertices*/ m_pVertexCount[0],
+ // Number of vertices used during this call. The first vertex is located at index: BaseVertexIndex + MinIndex.
+ // This is simple the number of verts in the current vertex buffer for now since we don't do more than one batch with the new mesh interface.
+
+ m_nFirstIndex /*pPrim->m_FirstIndex*/, // Index of the first index to use when accesssing the vertex buffer. Beginning at StartIndex to index vertices from the vertex buffer.
+
+ m_nNumIndices / 3/*numPrimitives*/ // Number of primitives to render. The number of vertices used is a function of the primitive count and the primitive type.
+ );
+
+ Assert( CMeshDX8::s_FirstVertex == 0 );
+ Assert( CMeshDX8::s_NumVertices == 0 );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+void CMeshMgr::SetIndexStreamState( int firstVertexIdx )
+{
+ CIndexBufferDx8 *pIndexBuffer = assert_cast< CIndexBufferDx8* >( m_pCurrentIndexBuffer );
+ IDirect3DIndexBuffer9 *pDx9Buffer = pIndexBuffer ? pIndexBuffer->GetDx9Buffer() : NULL;
+ if ( g_pLastIndex || g_pLastIndexBuffer != pDx9Buffer )
+ {
+ Dx9Device()->SetIndices( pDx9Buffer );
+ pIndexBuffer->HandlePerFrameTextureStats( ShaderAPI()->GetCurrentFrameCounter() );
+
+ g_pLastIndexBuffer = pDx9Buffer;
+ SafeRelease( &g_pLastIndex );
+ g_LastVertexIdx = -1;
+ }
+}
+
+
diff --git a/materialsystem/shaderapidx9/recording.cpp b/materialsystem/shaderapidx9/recording.cpp
new file mode 100644
index 0000000..4d2344a
--- /dev/null
+++ b/materialsystem/shaderapidx9/recording.cpp
@@ -0,0 +1,157 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#include "togl/rendermechanism.h"
+#include "recording.h"
+#include "shaderapi/ishaderutil.h"
+#include "materialsystem/imaterialsystem.h"
+#include "shaderapidx8_global.h"
+#include "utlvector.h"
+#include <stdio.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#ifdef RECORDING
+
+//-----------------------------------------------------------------------------
+// Globals
+//-----------------------------------------------------------------------------
+
+static CUtlVector<unsigned char> g_pRecordingBuffer;
+static int g_ArgsRemaining = 0;
+static int g_CommandStartIdx = 0;
+
+//-----------------------------------------------------------------------------
+// Opens the recording file
+//-----------------------------------------------------------------------------
+
+static FILE* OpenRecordingFile()
+{
+#ifdef CRASH_RECORDING
+ static FILE *fp = 0;
+#else
+ FILE* fp = 0;
+#endif
+ static bool g_CantOpenFile = false;
+ static bool g_NeverOpened = true;
+ if (!g_CantOpenFile)
+ {
+#ifdef CRASH_RECORDING
+ if( g_NeverOpened )
+ {
+ fp = fopen( "shaderdx8.rec", "wbc" );
+ }
+#else
+ fp = fopen( "shaderdx8.rec", g_NeverOpened ? "wb" : "ab" );
+#endif
+ if (!fp)
+ {
+ Warning("Unable to open recording file shaderdx8.rec!\n");
+ g_CantOpenFile = true;
+ }
+ g_NeverOpened = false;
+ }
+ return fp;
+}
+
+//-----------------------------------------------------------------------------
+// Writes to the recording file
+//-----------------------------------------------------------------------------
+
+#define COMMAND_BUFFER_SIZE 32768
+
+static void WriteRecordingFile()
+{
+ // Store the command size
+ *(int*)&g_pRecordingBuffer[g_CommandStartIdx] =
+ g_pRecordingBuffer.Size() - g_CommandStartIdx;
+
+#ifndef CRASH_RECORDING
+ // When not crash recording, flush when buffer gets too big,
+ // or when Present() is called
+ if ((g_pRecordingBuffer.Size() < COMMAND_BUFFER_SIZE) &&
+ (g_pRecordingBuffer[g_CommandStartIdx+4] != DX8_PRESENT))
+ return;
+#endif
+
+ FILE* fp = OpenRecordingFile();
+ if (fp)
+ {
+ // store the command size
+ fwrite( g_pRecordingBuffer.Base(), 1, g_pRecordingBuffer.Size(), fp );
+ fflush( fp );
+#ifndef CRASH_RECORDING
+ fclose( fp );
+#endif
+ }
+
+ g_pRecordingBuffer.RemoveAll();
+}
+
+// Write the buffered crap out on shutdown.
+void FinishRecording()
+{
+#ifndef CRASH_RECORDING
+ FILE* fp = OpenRecordingFile();
+ if (fp)
+ {
+ // store the command size
+ fwrite( g_pRecordingBuffer.Base(), 1, g_pRecordingBuffer.Size(), fp );
+ fflush( fp );
+ }
+
+ g_pRecordingBuffer.RemoveAll();
+#endif
+}
+
+// set this to true in the debugger to actually record commands.
+static bool g_bDoRecord = true;
+
+//-----------------------------------------------------------------------------
+// Records a command
+//-----------------------------------------------------------------------------
+
+void RecordCommand( RecordingCommands_t cmd, int numargs )
+{
+ if( !g_bDoRecord )
+ {
+ return;
+ }
+ Assert( g_ArgsRemaining == 0 );
+
+ g_CommandStartIdx = g_pRecordingBuffer.AddMultipleToTail( 6 );
+
+ // save space for the total command size
+ g_pRecordingBuffer[g_CommandStartIdx+4] = cmd;
+ g_pRecordingBuffer[g_CommandStartIdx+5] = numargs;
+ g_ArgsRemaining = numargs;
+ if (g_ArgsRemaining == 0)
+ WriteRecordingFile();
+}
+
+//-----------------------------------------------------------------------------
+// Records an argument for a command, flushes when the command is done
+//-----------------------------------------------------------------------------
+
+void RecordArgument( void const* pMemory, int size )
+{
+ if( !g_bDoRecord )
+ {
+ return;
+ }
+ Assert( g_ArgsRemaining > 0 );
+ int tail = g_pRecordingBuffer.Size();
+ g_pRecordingBuffer.AddMultipleToTail( size );
+ memcpy( &g_pRecordingBuffer[tail], pMemory, size );
+ if (--g_ArgsRemaining == 0)
+ WriteRecordingFile();
+}
+
+
+#endif // RECORDING
diff --git a/materialsystem/shaderapidx9/recording.h b/materialsystem/shaderapidx9/recording.h
new file mode 100644
index 0000000..81c50fc
--- /dev/null
+++ b/materialsystem/shaderapidx9/recording.h
@@ -0,0 +1,198 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#ifndef RECORDING_H
+#define RECORDING_H
+#pragma once
+
+//-----------------------------------------------------------------------------
+// Use this to put us into a 'recording' mode
+//-----------------------------------------------------------------------------
+
+//#define RECORDING
+
+//-----------------------------------------------------------------------------
+// Uncomment these to record special frames in the recording
+// that reset the entire render state.
+//-----------------------------------------------------------------------------
+
+//#define RECORD_KEYFRAMES 1
+#define KEYFRAME_INTERVAL 100 // number of actual frames between each keyframe
+
+//-----------------------------------------------------------------------------
+// Use this to allow us to record crashes (write every command immediately)
+//-----------------------------------------------------------------------------
+
+//#define CRASH_RECORDING
+
+//-----------------------------------------------------------------------------
+// Use this to record textures (checkboards are used for textures otherwise)
+//-----------------------------------------------------------------------------
+
+#define RECORD_TEXTURES
+
+//-----------------------------------------------------------------------------
+// Use this to record debug strings . .these are only useful if you are doing "playback -list"
+//-----------------------------------------------------------------------------
+
+#define RECORD_DEBUG_STRINGS
+
+//-----------------------------------------------------------------------------
+// Recording state, if you change this, change the table in playback/playback.cpp
+//-----------------------------------------------------------------------------
+
+enum RecordingCommands_t
+{
+ DX8_CREATE_DEVICE = 0,
+ DX8_DESTROY_DEVICE,
+ DX8_RESET,
+ DX8_SHOW_CURSOR,
+ DX8_BEGIN_SCENE,
+ DX8_END_SCENE,
+ DX8_PRESENT,
+ DX8_CREATE_TEXTURE,
+ DX8_DESTROY_TEXTURE,
+ DX8_SET_TEXTURE,
+ DX8_SET_TRANSFORM,
+ DX8_CREATE_VERTEX_SHADER,
+ DX8_CREATE_PIXEL_SHADER,
+ DX8_DESTROY_VERTEX_SHADER,
+ DX8_DESTROY_PIXEL_SHADER,
+ DX8_SET_VERTEX_SHADER,
+ DX8_SET_PIXEL_SHADER,
+ DX8_SET_VERTEX_SHADER_CONSTANT,
+ DX8_SET_PIXEL_SHADER_CONSTANT,
+ DX8_SET_MATERIAL,
+ DX8_LIGHT_ENABLE,
+ DX8_SET_LIGHT,
+ DX8_SET_VIEWPORT,
+ DX8_CLEAR,
+ DX8_VALIDATE_DEVICE,
+ DX8_SET_RENDER_STATE,
+ DX8_SET_TEXTURE_STAGE_STATE,
+
+ DX8_CREATE_VERTEX_BUFFER,
+ DX8_DESTROY_VERTEX_BUFFER,
+ DX8_LOCK_VERTEX_BUFFER,
+ DX8_VERTEX_DATA,
+ DX8_UNLOCK_VERTEX_BUFFER,
+
+ DX8_CREATE_INDEX_BUFFER,
+ DX8_DESTROY_INDEX_BUFFER,
+ DX8_LOCK_INDEX_BUFFER,
+ DX8_INDEX_DATA,
+ DX8_UNLOCK_INDEX_BUFFER,
+
+ DX8_SET_STREAM_SOURCE,
+ DX8_SET_INDICES,
+ DX8_DRAW_PRIMITIVE,
+ DX8_DRAW_INDEXED_PRIMITIVE,
+
+ DX8_LOCK_TEXTURE,
+ DX8_UNLOCK_TEXTURE,
+
+ DX8_KEYFRAME, // isn't actually a dx8 command, used to help find particular frames
+
+ DX8_SET_TEXTURE_DATA,
+ DX8_BLIT_TEXTURE_BITS,
+
+ DX8_GET_DEVICE_CAPS,
+ DX8_GET_ADAPTER_IDENTIFIER,
+
+ DX8_HARDWARE_SYNC,
+
+ DX8_COPY_FRAMEBUFFER_TO_TEXTURE,
+ DX8_DEBUG_STRING,
+ DX8_CREATE_DEPTH_TEXTURE,
+ DX8_DESTROY_DEPTH_TEXTURE,
+ DX8_SET_RENDER_TARGET,
+
+ DX8_TEST_COOPERATIVE_LEVEL,
+
+ DX8_SET_VERTEX_BUFFER_FORMAT, // isn't actually a dx8 command. . let's playback know what format a buffer is for listing info
+
+ DX8_SET_SAMPLER_STATE,
+ DX8_SET_VERTEX_DECLARATION,
+ DX8_CREATE_VERTEX_DECLARATION,
+ DX8_SET_FVF,
+ DX8_SET_CLIP_PLANE,
+
+ DX8_SYNC_TOKEN,
+
+ DX8_LOCK_VERTEX_TEXTURE,
+ DX8_UNLOCK_VERTEX_TEXTURE,
+
+ DX8_SET_SCISSOR_RECT,
+
+ DX8_NUM_RECORDING_COMMANDS
+};
+
+#ifdef RECORDING
+
+void RecordCommand( RecordingCommands_t cmd, int numargs );
+void RecordArgument( void const* pMemory, int size );
+void FinishRecording( void );
+
+inline void RecordInt( int i )
+{
+ RecordArgument( &i, sizeof(int) );
+}
+
+inline void RecordFloat( float f )
+{
+ RecordArgument( &f, sizeof(float) );
+}
+
+# define RECORD_COMMAND( _cmd, _numargs ) RecordCommand( _cmd, _numargs )
+# define RECORD_INT( _int ) RecordInt( _int )
+# define RECORD_FLOAT( _float ) RecordFloat( _float )
+# define RECORD_STRING( _string ) RecordArgument( _string, strlen(_string) + 1 )
+# define RECORD_STRUCT( _struct, _size ) RecordArgument( _struct, _size )
+
+# define RECORD_RENDER_STATE( _state, _val ) \
+ RECORD_COMMAND( DX8_SET_RENDER_STATE, 2 ); \
+ RECORD_INT( _state ); \
+ RECORD_INT( _val )
+
+# define RECORD_TEXTURE_STAGE_STATE( _stage, _state, _val ) \
+ RECORD_COMMAND( DX8_SET_TEXTURE_STAGE_STATE, 3 ); \
+ RECORD_INT( _stage ); \
+ RECORD_INT( _state ); \
+ RECORD_INT( _val )
+
+# define RECORD_SAMPLER_STATE( _stage, _state, _val ) \
+ RECORD_COMMAND( DX8_SET_SAMPLER_STATE, 3 ); \
+ RECORD_INT( _stage ); \
+ RECORD_INT( _state ); \
+ RECORD_INT( _val )
+
+# ifdef RECORD_DEBUG_STRINGS
+# define RECORD_DEBUG_STRING( _str ) \
+ RECORD_COMMAND( DX8_DEBUG_STRING, 1 ); \
+ RECORD_STRING( _str )
+# else
+# define RECORD_DEBUG_STRING( _str ) 0
+# endif
+
+#else // not RECORDING
+
+# undef RECORD_TEXTURES
+
+# define RECORD_COMMAND( _cmd, _numargs ) 0
+# define RECORD_INT( _int ) 0
+# define RECORD_FLOAT( _float ) 0
+# define RECORD_STRING( _string ) 0
+# define RECORD_STRUCT( _struct, _size ) 0
+# define RECORD_RENDER_STATE( _state, _val ) 0
+# define RECORD_TEXTURE_STAGE_STATE( _stage, _state, _val ) 0
+# define RECORD_SAMPLER_STATE( _stage, _state, _val ) 0
+# define RECORD_DEBUG_STRING( _str ) 0
+
+#endif // RECORDING
+
+#endif // RECORDING_H
diff --git a/materialsystem/shaderapidx9/shaderapi_global.h b/materialsystem/shaderapidx9/shaderapi_global.h
new file mode 100644
index 0000000..ae8f6ab
--- /dev/null
+++ b/materialsystem/shaderapidx9/shaderapi_global.h
@@ -0,0 +1,105 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#ifndef SHADERAPI_GLOBAL_H
+#define SHADERAPI_GLOBAL_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier0/threadtools.h"
+
+//-----------------------------------------------------------------------------
+// Use this to fill in structures with the current board state
+//-----------------------------------------------------------------------------
+#ifdef _DEBUG
+#define DEBUG_BOARD_STATE 0
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class IShaderUtil;
+class CShaderDeviceBase;
+class CShaderDeviceMgrBase;
+class CShaderAPIBase;
+class IShaderShadow;
+
+
+//-----------------------------------------------------------------------------
+// Global interfaces
+//-----------------------------------------------------------------------------
+extern IShaderUtil* g_pShaderUtil;
+inline IShaderUtil* ShaderUtil()
+{
+ return g_pShaderUtil;
+}
+
+extern CShaderDeviceBase *g_pShaderDevice;
+extern CShaderDeviceMgrBase *g_pShaderDeviceMgr;
+extern CShaderAPIBase *g_pShaderAPI;
+extern IShaderShadow *g_pShaderShadow;
+
+
+//-----------------------------------------------------------------------------
+// Memory debugging
+//-----------------------------------------------------------------------------
+#define MEM_ALLOC_D3D_CREDIT() MEM_ALLOC_CREDIT_("D3D:" __FILE__)
+#define BEGIN_D3D_ALLOCATION() MemAlloc_PushAllocDbgInfo("D3D:" __FILE__, __LINE__)
+#define END_D3D_ALLOCATION() MemAlloc_PopAllocDbgInfo()
+
+
+//-----------------------------------------------------------------------------
+// Threading
+//-----------------------------------------------------------------------------
+extern bool g_bUseShaderMutex;
+
+//#define USE_SHADER_DISALLOW 1
+//#define STRICT_MT_SHADERAPI 1
+
+#if defined(_DEBUG)
+#if !defined(STRICT_MT_SHADERAPI)
+#define UNCONDITIONAL_MT_SHADERAPI 1
+#endif
+#else
+#if !defined(STRICT_MT_SHADERAPI) && !defined(UNCONDITIONAL_MT_SHADERAPI)
+#define ST_SHADERAPI 1
+#endif
+#endif
+
+
+#if defined(ST_SHADERAPI)
+typedef CThreadNullMutex CShaderMutex;
+#elif defined(STRICT_MT_SHADERAPI)
+typedef CThreadConditionalMutex<CThreadTerminalMutex<CThreadFastMutex>, &g_bUseShaderMutex> CShaderMutex;
+#elif defined(UNCONDITIONAL_MT_SHADERAPI)
+typedef CThreadFastMutex CShaderMutex;
+#else
+typedef CThreadConditionalMutex<CThreadFastMutex, &g_bUseShaderMutex> CShaderMutex;
+#endif
+
+extern CShaderMutex g_ShaderMutex;
+
+extern bool g_bShaderAccessDisallowed;
+
+#ifdef USE_SHADER_DISALLOW
+#define TestShaderPermission() do { if ( (!g_bUseShaderMutex || g_ShaderMutex.GetDepth() == 0) && g_bShaderAccessDisallowed ) { ExecuteOnce( DebuggerBreakIfDebugging() ); } } while (0)
+#define LOCK_SHADERAPI() TestShaderPermission(); AUTO_LOCK_( CShaderMutex, g_ShaderMutex )
+#define LockShaderMutex() TestShaderPermission(); g_ShaderMutex.Lock();
+#define UnlockShaderMutex() TestShaderPermission(); g_ShaderMutex.Unlock();
+#else
+#define TestShaderPermission() ((void)0)
+#define LOCK_SHADERAPI() ((void)0)
+#define LockShaderMutex() ((void)0)
+#define UnlockShaderMutex() ((void)0)
+#endif
+
+
+#endif // SHADERAPI_GLOBAL_H
diff --git a/materialsystem/shaderapidx9/shaderapibase.cpp b/materialsystem/shaderapidx9/shaderapibase.cpp
new file mode 100644
index 0000000..1563a12
--- /dev/null
+++ b/materialsystem/shaderapidx9/shaderapibase.cpp
@@ -0,0 +1,42 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#undef PROTECTED_THINGS_ENABLE // prevent warnings when windows.h gets included
+
+#include "shaderapibase.h"
+#include "shaderapi/ishaderutil.h"
+
+
+//-----------------------------------------------------------------------------
+//
+// The Base implementation of the shader render class
+//
+//-----------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+CShaderAPIBase::CShaderAPIBase()
+{
+}
+
+CShaderAPIBase::~CShaderAPIBase()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Methods of IShaderDynamicAPI
+//-----------------------------------------------------------------------------
+void CShaderAPIBase::GetCurrentColorCorrection( ShaderColorCorrectionInfo_t* pInfo )
+{
+ g_pShaderUtil->GetCurrentColorCorrection( pInfo );
+}
+
+
diff --git a/materialsystem/shaderapidx9/shaderapibase.h b/materialsystem/shaderapidx9/shaderapibase.h
new file mode 100644
index 0000000..fe8d928
--- /dev/null
+++ b/materialsystem/shaderapidx9/shaderapibase.h
@@ -0,0 +1,86 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#ifndef SHADERRENDERBASE_H
+#define SHADERRENDERBASE_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "togl/rendermechanism.h"
+#include "shaderapi/ishaderapi.h"
+#include "shaderapi_global.h"
+#include "locald3dtypes.h"
+
+// Colors for PIX graphs
+#define PIX_VALVE_ORANGE 0xFFF5940F
+
+
+//-----------------------------------------------------------------------------
+// The Base implementation of the shader rendering interface
+//-----------------------------------------------------------------------------
+class CShaderAPIBase : public IShaderAPI
+{
+public:
+ // constructor, destructor
+ CShaderAPIBase();
+ virtual ~CShaderAPIBase();
+
+ // Called when the device is initializing or shutting down
+ virtual bool OnDeviceInit() = 0;
+ virtual void OnDeviceShutdown() = 0;
+
+ // Pix events
+ virtual void BeginPIXEvent( unsigned long color, const char *szName ) = 0;
+ virtual void EndPIXEvent() = 0;
+ virtual void AdvancePIXFrame() = 0;
+
+ // Release, reacquire objects
+ virtual void ReleaseShaderObjects() = 0;
+ virtual void RestoreShaderObjects() = 0;
+
+ // Resets the render state to its well defined initial value
+ virtual void ResetRenderState( bool bFullReset = true ) = 0;
+
+ // Returns a d3d texture associated with a texture handle
+ virtual IDirect3DBaseTexture* GetD3DTexture( ShaderAPITextureHandle_t hTexture ) = 0;
+
+ // Queues a non-full reset of render state next BeginFrame.
+ virtual void QueueResetRenderState() = 0;
+
+ // Methods of IShaderDynamicAPI
+public:
+ virtual void GetCurrentColorCorrection( ShaderColorCorrectionInfo_t* pInfo );
+
+protected:
+};
+
+
+//-----------------------------------------------------------------------------
+// Pix measurement class
+//-----------------------------------------------------------------------------
+class CPixEvent
+{
+public:
+ CPixEvent( unsigned long color, const char *szName )
+ {
+ if ( g_pShaderAPI )
+ g_pShaderAPI->BeginPIXEvent( color, szName );
+ }
+
+ ~CPixEvent()
+ {
+ if ( g_pShaderAPI )
+ g_pShaderAPI->EndPIXEvent();
+ }
+};
+
+
+#endif // SHADERRENDERBASE_H
diff --git a/materialsystem/shaderapidx9/shaderapidx10.cpp b/materialsystem/shaderapidx9/shaderapidx10.cpp
new file mode 100644
index 0000000..9bd1039
--- /dev/null
+++ b/materialsystem/shaderapidx9/shaderapidx10.cpp
@@ -0,0 +1,1461 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#include "shaderapidx10.h"
+#include "shaderapibase.h"
+#include "shaderapi/ishaderutil.h"
+#include "materialsystem/idebugtextureinfo.h"
+#include "materialsystem/materialsystem_config.h"
+#include "meshdx10.h"
+#include "shadershadowdx10.h"
+#include "shaderdevicedx10.h"
+#include "shaderapidx10_global.h"
+#include "imaterialinternal.h"
+
+
+//-----------------------------------------------------------------------------
+// Methods related to queuing functions to be called prior to rendering
+//-----------------------------------------------------------------------------
+CFunctionCommit::CFunctionCommit()
+{
+ m_pCommitFlags = NULL;
+ m_nCommitBufferSize = 0;
+}
+
+CFunctionCommit::~CFunctionCommit()
+{
+ if ( m_pCommitFlags )
+ {
+ delete[] m_pCommitFlags;
+ m_pCommitFlags = NULL;
+ }
+}
+
+void CFunctionCommit::Init( int nFunctionCount )
+{
+ m_nCommitBufferSize = ( nFunctionCount + 7 ) >> 3;
+ Assert( !m_pCommitFlags );
+ m_pCommitFlags = new unsigned char[ m_nCommitBufferSize ];
+ memset( m_pCommitFlags, 0, m_nCommitBufferSize );
+}
+
+
+//-----------------------------------------------------------------------------
+// Methods related to queuing functions to be called per-(pMesh->Draw call) or per-pass
+//-----------------------------------------------------------------------------
+inline bool CFunctionCommit::IsCommitFuncInUse( int nFunc ) const
+{
+ Assert( nFunc >> 3 < m_nCommitBufferSize );
+ return ( m_pCommitFlags[ nFunc >> 3 ] & ( 1 << ( nFunc & 0x7 ) ) ) != 0;
+}
+
+inline void CFunctionCommit::MarkCommitFuncInUse( int nFunc )
+{
+ Assert( nFunc >> 3 < m_nCommitBufferSize );
+ m_pCommitFlags[ nFunc >> 3 ] |= 1 << ( nFunc & 0x7 );
+}
+
+inline void CFunctionCommit::AddCommitFunc( StateCommitFunc_t f )
+{
+ m_CommitFuncs.AddToTail( f );
+}
+
+
+//-----------------------------------------------------------------------------
+// Clears all commit functions
+//-----------------------------------------------------------------------------
+inline void CFunctionCommit::ClearAllCommitFuncs( )
+{
+ memset( m_pCommitFlags, 0, m_nCommitBufferSize );
+ m_CommitFuncs.RemoveAll();
+}
+
+
+//-----------------------------------------------------------------------------
+// Calls all commit functions in a particular list
+//-----------------------------------------------------------------------------
+void CFunctionCommit::CallCommitFuncs( ID3D10Device *pDevice, const ShaderStateDx10_t &desiredState, ShaderStateDx10_t &currentState, bool bForce )
+{
+ int nCount = m_CommitFuncs.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ m_CommitFuncs[i]( pDevice, desiredState, currentState, bForce );
+ }
+
+ ClearAllCommitFuncs( );
+}
+
+
+//-----------------------------------------------------------------------------
+// Helpers for commit functions
+//-----------------------------------------------------------------------------
+#define ADD_COMMIT_FUNC( _func_name ) \
+ if ( !m_Commit.IsCommitFuncInUse( COMMIT_FUNC_ ## _func_name ) ) \
+ { \
+ m_Commit.AddCommitFunc( _func_name ); \
+ m_Commit.MarkCommitFuncInUse( COMMIT_FUNC_ ## _func_name ); \
+ }
+
+#define ADD_RENDERSTATE_FUNC( _func_name, _state, _val ) \
+ if ( m_bResettingRenderState || ( m_DesiredState. ## _state != _val ) ) \
+ { \
+ m_DesiredState. ## _state = _val; \
+ ADD_COMMIT_FUNC( _func_name ) \
+ }
+
+#define IMPLEMENT_RENDERSTATE_FUNC( _func_name, _state, _d3dFunc ) \
+ static void _func_name( ID3D10Device *pDevice, const ShaderStateDx10_t &desiredState, ShaderStateDx10_t &currentState, bool bForce ) \
+ { \
+ if ( bForce || ( desiredState. ## _state != currentState. ## _state ) ) \
+ { \
+ pDevice->_d3dFunc( desiredState. ## _state ); \
+ currentState. ## _state = desiredState. ## _state; \
+ } \
+ }
+
+//-----------------------------------------------------------------------------
+// D3D state setting methods
+//-----------------------------------------------------------------------------
+
+// NOTE: For each commit func you create, add to this enumeration.
+enum CommitFunc_t
+{
+ COMMIT_FUNC_CommitSetViewports = 0,
+ COMMIT_FUNC_CommitSetVertexShader,
+ COMMIT_FUNC_CommitSetGeometryShader,
+ COMMIT_FUNC_CommitSetPixelShader,
+ COMMIT_FUNC_CommitSetVertexBuffer,
+ COMMIT_FUNC_CommitSetIndexBuffer,
+ COMMIT_FUNC_CommitSetInputLayout,
+ COMMIT_FUNC_CommitSetTopology,
+ COMMIT_FUNC_CommitSetRasterState,
+
+ COMMIT_FUNC_COUNT,
+};
+
+IMPLEMENT_RENDERSTATE_FUNC( CommitSetTopology, m_Topology, IASetPrimitiveTopology )
+IMPLEMENT_RENDERSTATE_FUNC( CommitSetVertexShader, m_pVertexShader, VSSetShader )
+IMPLEMENT_RENDERSTATE_FUNC( CommitSetGeometryShader, m_pGeometryShader, GSSetShader )
+IMPLEMENT_RENDERSTATE_FUNC( CommitSetPixelShader, m_pPixelShader, PSSetShader )
+
+static void CommitSetInputLayout( ID3D10Device *pDevice, const ShaderStateDx10_t &desiredState, ShaderStateDx10_t &currentState, bool bForce )
+{
+ const ShaderInputLayoutStateDx10_t& newState = desiredState.m_InputLayout;
+ if ( bForce || memcmp( &newState, &currentState.m_InputLayout, sizeof(ShaderInputLayoutStateDx10_t) ) )
+ {
+ // FIXME: Deal with multiple streams
+ ID3D10InputLayout *pInputLayout = g_pShaderDeviceDx10->GetInputLayout(
+ newState.m_hVertexShader, newState.m_pVertexDecl[0] );
+ pDevice->IASetInputLayout( pInputLayout );
+
+ currentState.m_InputLayout = newState;
+ }
+}
+
+static void CommitSetViewports( ID3D10Device *pDevice, const ShaderStateDx10_t &desiredState, ShaderStateDx10_t &currentState, bool bForce )
+{
+ bool bChanged = bForce || ( desiredState.m_nViewportCount != currentState.m_nViewportCount );
+ if ( !bChanged && desiredState.m_nViewportCount > 0 )
+ {
+ bChanged = memcmp( desiredState.m_pViewports, currentState.m_pViewports,
+ desiredState.m_nViewportCount * sizeof( D3D10_VIEWPORT ) ) != 0;
+ }
+
+ if ( !bChanged )
+ return;
+
+ pDevice->RSSetViewports( desiredState.m_nViewportCount, desiredState.m_pViewports );
+ currentState.m_nViewportCount = desiredState.m_nViewportCount;
+
+#ifdef _DEBUG
+ memset( currentState.m_pViewports, 0xDD, sizeof( currentState.m_pViewports ) );
+#endif
+
+ memcpy( currentState.m_pViewports, desiredState.m_pViewports,
+ desiredState.m_nViewportCount * sizeof( D3D10_VIEWPORT ) );
+}
+
+static void CommitSetIndexBuffer( ID3D10Device *pDevice, const ShaderStateDx10_t &desiredState, ShaderStateDx10_t &currentState, bool bForce )
+{
+ const ShaderIndexBufferStateDx10_t &newState = desiredState.m_IndexBuffer;
+ bool bChanged = bForce || memcmp( &newState, &currentState.m_IndexBuffer, sizeof(ShaderIndexBufferStateDx10_t) );
+ if ( !bChanged )
+ return;
+
+ pDevice->IASetIndexBuffer( newState.m_pBuffer, newState.m_Format, newState.m_nOffset );
+ memcpy( &currentState.m_IndexBuffer, &newState, sizeof( ShaderIndexBufferStateDx10_t ) );
+}
+
+static void CommitSetVertexBuffer( ID3D10Device *pDevice, const ShaderStateDx10_t &desiredState, ShaderStateDx10_t &currentState, bool bForce )
+{
+ ID3D10Buffer *ppVertexBuffers[ MAX_DX10_STREAMS ];
+ UINT pStrides[ MAX_DX10_STREAMS ];
+ UINT pOffsets[ MAX_DX10_STREAMS ];
+
+ UINT nFirstBuffer = 0;
+ UINT nBufferCount = 0;
+ bool bInMatch = true;
+ for ( int i = 0; i < MAX_DX10_STREAMS; ++i )
+ {
+ const ShaderVertexBufferStateDx10_t &newState = desiredState.m_pVertexBuffer[i];
+ bool bMatch = !bForce && !memcmp( &newState, &currentState.m_pVertexBuffer[i], sizeof(ShaderVertexBufferStateDx10_t) );
+ if ( !bMatch )
+ {
+ ppVertexBuffers[i] = newState.m_pBuffer;
+ pStrides[i] = newState.m_nStride;
+ pOffsets[i] = newState.m_nOffset;
+ ++nBufferCount;
+ memcpy( &currentState.m_pVertexBuffer[i], &newState, sizeof( ShaderVertexBufferStateDx10_t ) );
+ }
+
+ if ( bInMatch )
+ {
+ if ( !bMatch )
+ {
+ bInMatch = false;
+ nFirstBuffer = i;
+ }
+ continue;
+ }
+
+ if ( bMatch )
+ {
+ bInMatch = true;
+ pDevice->IASetVertexBuffers( nFirstBuffer, nBufferCount,
+ &ppVertexBuffers[nFirstBuffer], &pStrides[nFirstBuffer], &pOffsets[nFirstBuffer] );
+ nBufferCount = 0;
+ }
+ }
+
+ if ( !bInMatch )
+ {
+ pDevice->IASetVertexBuffers( nFirstBuffer, nBufferCount,
+ &ppVertexBuffers[nFirstBuffer], &pStrides[nFirstBuffer], &pOffsets[nFirstBuffer] );
+ }
+}
+
+static void GenerateRasterizerDesc( D3D10_RASTERIZER_DESC* pDesc, const ShaderRasterState_t& state )
+{
+ pDesc->FillMode = ( state.m_FillMode == SHADER_FILL_WIREFRAME ) ? D3D10_FILL_WIREFRAME : D3D10_FILL_SOLID;
+
+ // Cull state
+ if ( state.m_bCullEnable )
+ {
+ pDesc->CullMode = D3D10_CULL_NONE;
+ }
+ else
+ {
+ pDesc->CullMode = ( state.m_CullMode == MATERIAL_CULLMODE_CW ) ? D3D10_CULL_BACK : D3D10_CULL_FRONT;
+ }
+ pDesc->FrontCounterClockwise = TRUE;
+
+ // Depth bias state
+ if ( !state.m_bDepthBias )
+ {
+ pDesc->DepthBias = 0;
+ pDesc->DepthBiasClamp = 0.0f;
+ pDesc->SlopeScaledDepthBias = 0.0f;
+ pDesc->DepthClipEnable = FALSE;
+ }
+ else
+ {
+ // FIXME: Implement! Read ConVars
+ }
+
+ pDesc->ScissorEnable = state.m_bScissorEnable ? TRUE : FALSE;
+ pDesc->MultisampleEnable = state.m_bMultisampleEnable ? TRUE : FALSE;
+ pDesc->AntialiasedLineEnable = FALSE;
+}
+
+static void CommitSetRasterState( ID3D10Device *pDevice, const ShaderStateDx10_t &desiredState, ShaderStateDx10_t &currentState, bool bForce )
+{
+ const ShaderRasterState_t& newState = desiredState.m_RasterState;
+ if ( bForce || memcmp( &newState, &currentState.m_RasterState, sizeof(ShaderRasterState_t) ) )
+ {
+ // Clear out the existing state
+ if ( currentState.m_pRasterState )
+ {
+ currentState.m_pRasterState->Release();
+ }
+
+ D3D10_RASTERIZER_DESC desc;
+ GenerateRasterizerDesc( &desc, newState );
+
+ // NOTE: This does a search for existing matching state objects
+ ID3D10RasterizerState *pState = NULL;
+ HRESULT hr = pDevice->CreateRasterizerState( &desc, &pState );
+ if ( !FAILED(hr) )
+ {
+ Warning( "Unable to create rasterizer state object!\n" );
+ }
+
+ pDevice->RSSetState( pState );
+
+ currentState.m_pRasterState = pState;
+ memcpy( &currentState.m_RasterState, &newState, sizeof( ShaderRasterState_t ) );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// Shader API Dx10
+//
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// Class Factory
+//-----------------------------------------------------------------------------
+static CShaderAPIDx10 s_ShaderAPIDx10;
+CShaderAPIDx10* g_pShaderAPIDx10 = &s_ShaderAPIDx10;
+
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CShaderAPIDx10, IShaderAPI,
+ SHADERAPI_INTERFACE_VERSION, s_ShaderAPIDx10 )
+
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CShaderAPIDx10, IDebugTextureInfo,
+ DEBUG_TEXTURE_INFO_VERSION, s_ShaderAPIDx10 )
+
+
+//-----------------------------------------------------------------------------
+// Constructor, destructor
+//-----------------------------------------------------------------------------
+CShaderAPIDx10::CShaderAPIDx10()
+{
+ m_bResettingRenderState = false;
+ m_Commit.Init( COMMIT_FUNC_COUNT );
+ ClearShaderState( &m_DesiredState );
+ ClearShaderState( &m_CurrentState );
+}
+
+CShaderAPIDx10::~CShaderAPIDx10()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Clears the shader state to a well-defined value
+//-----------------------------------------------------------------------------
+void CShaderAPIDx10::ClearShaderState( ShaderStateDx10_t* pState )
+{
+ memset( pState, 0, sizeof( ShaderStateDx10_t ) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Resets the render state
+//-----------------------------------------------------------------------------
+void CShaderAPIDx10::ResetRenderState( bool bFullReset )
+{
+ D3D10_RASTERIZER_DESC rDesc;
+ memset( &rDesc, 0, sizeof(rDesc) );
+ rDesc.FillMode = D3D10_FILL_SOLID;
+ rDesc.CullMode = D3D10_CULL_NONE;
+ rDesc.FrontCounterClockwise = TRUE; // right-hand rule
+
+ ID3D10RasterizerState *pRasterizerState;
+ HRESULT hr = D3D10Device()->CreateRasterizerState( &rDesc, &pRasterizerState );
+ Assert( !FAILED(hr) );
+ D3D10Device()->RSSetState( pRasterizerState );
+
+ D3D10_DEPTH_STENCIL_DESC dsDesc;
+ memset( &dsDesc, 0, sizeof(dsDesc) );
+
+ ID3D10DepthStencilState *pDepthStencilState;
+ hr = D3D10Device()->CreateDepthStencilState( &dsDesc, &pDepthStencilState );
+ Assert( !FAILED(hr) );
+ D3D10Device()->OMSetDepthStencilState( pDepthStencilState, 0 );
+
+ D3D10_BLEND_DESC bDesc;
+ memset( &bDesc, 0, sizeof(bDesc) );
+ bDesc.SrcBlend = D3D10_BLEND_ONE;
+ bDesc.DestBlend = D3D10_BLEND_ZERO;
+ bDesc.BlendOp = D3D10_BLEND_OP_ADD;
+ bDesc.SrcBlendAlpha = D3D10_BLEND_ONE;
+ bDesc.DestBlendAlpha = D3D10_BLEND_ZERO;
+ bDesc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
+ bDesc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
+
+ FLOAT pBlendFactor[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
+ ID3D10BlendState *pBlendState;
+ hr = D3D10Device()->CreateBlendState( &bDesc, &pBlendState );
+ Assert( !FAILED(hr) );
+ D3D10Device()->OMSetBlendState( pBlendState, pBlendFactor, 0xFFFFFFFF );
+}
+
+
+//-----------------------------------------------------------------------------
+// Commits queued-up state change requests
+//-----------------------------------------------------------------------------
+void CShaderAPIDx10::CommitStateChanges( bool bForce )
+{
+ // Don't bother committing anything if we're deactivated
+ if ( g_pShaderDevice->IsDeactivated() )
+ return;
+
+ m_Commit.CallCommitFuncs( D3D10Device(), m_DesiredState, m_CurrentState, bForce );
+}
+
+
+//-----------------------------------------------------------------------------
+// Methods of IShaderDynamicAPI
+//-----------------------------------------------------------------------------
+void CShaderAPIDx10::GetBackBufferDimensions( int& nWidth, int& nHeight ) const
+{
+ g_pShaderDeviceDx10->GetBackBufferDimensions( nWidth, nHeight );
+}
+
+
+//-----------------------------------------------------------------------------
+// Viewport-related methods
+//-----------------------------------------------------------------------------
+void CShaderAPIDx10::SetViewports( int nCount, const ShaderViewport_t* pViewports )
+{
+ nCount = min( nCount, MAX_DX10_VIEWPORTS );
+ m_DesiredState.m_nViewportCount = nCount;
+
+ for ( int i = 0; i < nCount; ++i )
+ {
+ Assert( pViewports[i].m_nVersion == SHADER_VIEWPORT_VERSION );
+
+ D3D10_VIEWPORT& viewport = m_DesiredState.m_pViewports[i];
+ viewport.TopLeftX = pViewports[i].m_nTopLeftX;
+ viewport.TopLeftY = pViewports[i].m_nTopLeftY;
+ viewport.Width = pViewports[i].m_nWidth;
+ viewport.Height = pViewports[i].m_nHeight;
+ viewport.MinDepth = pViewports[i].m_flMinZ;
+ viewport.MaxDepth = pViewports[i].m_flMaxZ;
+ }
+
+ ADD_COMMIT_FUNC( CommitSetViewports );
+}
+
+int CShaderAPIDx10::GetViewports( ShaderViewport_t* pViewports, int nMax ) const
+{
+ int nCount = m_DesiredState.m_nViewportCount;
+ if ( pViewports && nMax )
+ {
+ nCount = min( nCount, nMax );
+ memcpy( pViewports, m_DesiredState.m_pViewports, nCount * sizeof( ShaderViewport_t ) );
+ }
+ return nCount;
+}
+
+
+//-----------------------------------------------------------------------------
+// Methods related to state objects
+//-----------------------------------------------------------------------------
+void CShaderAPIDx10::SetRasterState( const ShaderRasterState_t& state )
+{
+ if ( memcmp( &state, &m_DesiredState.m_RasterState, sizeof(ShaderRasterState_t) ) )
+ {
+ memcpy( &m_DesiredState.m_RasterState, &state, sizeof(ShaderRasterState_t) );
+ ADD_COMMIT_FUNC( CommitSetRasterState );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Methods related to clearing buffers
+//-----------------------------------------------------------------------------
+void CShaderAPIDx10::ClearColor3ub( unsigned char r, unsigned char g, unsigned char b )
+{
+ m_DesiredState.m_ClearColor[0] = r / 255.0f;
+ m_DesiredState.m_ClearColor[1] = g / 255.0f;
+ m_DesiredState.m_ClearColor[2] = b / 255.0f;
+ m_DesiredState.m_ClearColor[3] = 1.0f;
+}
+
+void CShaderAPIDx10::ClearColor4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a )
+{
+ m_DesiredState.m_ClearColor[0] = r / 255.0f;
+ m_DesiredState.m_ClearColor[1] = g / 255.0f;
+ m_DesiredState.m_ClearColor[2] = b / 255.0f;
+ m_DesiredState.m_ClearColor[3] = a / 255.0f;
+}
+
+void CShaderAPIDx10::ClearBuffers( bool bClearColor, bool bClearDepth, bool bClearStencil, int renderTargetWidth, int renderTargetHeight )
+{
+ // NOTE: State change commit isn't necessary since clearing doesn't use state
+// CommitStateChanges();
+
+ // FIXME: This implementation is totally bust0red [doesn't guarantee exact color specified]
+ if ( bClearColor )
+ {
+ D3D10Device()->ClearRenderTargetView( D3D10RenderTargetView(), m_DesiredState.m_ClearColor );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Methods related to binding shaders
+//-----------------------------------------------------------------------------
+void CShaderAPIDx10::BindVertexShader( VertexShaderHandle_t hVertexShader )
+{
+ ID3D10VertexShader *pVertexShader = g_pShaderDeviceDx10->GetVertexShader( hVertexShader );
+ ADD_RENDERSTATE_FUNC( CommitSetVertexShader, m_pVertexShader, pVertexShader );
+
+ if ( m_bResettingRenderState || ( m_DesiredState.m_InputLayout.m_hVertexShader != hVertexShader ) )
+ {
+ m_DesiredState.m_InputLayout.m_hVertexShader = hVertexShader;
+ ADD_COMMIT_FUNC( CommitSetInputLayout );
+ }
+}
+
+void CShaderAPIDx10::BindGeometryShader( GeometryShaderHandle_t hGeometryShader )
+{
+ ID3D10GeometryShader *pGeometryShader = g_pShaderDeviceDx10->GetGeometryShader( hGeometryShader );
+ ADD_RENDERSTATE_FUNC( CommitSetGeometryShader, m_pGeometryShader, pGeometryShader );
+}
+
+void CShaderAPIDx10::BindPixelShader( PixelShaderHandle_t hPixelShader )
+{
+ ID3D10PixelShader *pPixelShader = g_pShaderDeviceDx10->GetPixelShader( hPixelShader );
+ ADD_RENDERSTATE_FUNC( CommitSetPixelShader, m_pPixelShader, pPixelShader );
+}
+
+void CShaderAPIDx10::BindVertexBuffer( int nStreamID, IVertexBuffer *pVertexBuffer, int nOffsetInBytes, int nFirstVertex, int nVertexCount, VertexFormat_t fmt, int nRepetitions )
+{
+ // FIXME: What to do about repetitions?
+ CVertexBufferDx10 *pVertexBufferDx10 = static_cast<CVertexBufferDx10 *>( pVertexBuffer );
+
+ ShaderVertexBufferStateDx10_t state;
+ if ( pVertexBufferDx10 )
+ {
+ state.m_pBuffer = pVertexBufferDx10->GetDx10Buffer();
+ state.m_nStride = pVertexBufferDx10->VertexSize();
+ }
+ else
+ {
+ state.m_pBuffer = NULL;
+ state.m_nStride = 0;
+ }
+ state.m_nOffset = nOffsetInBytes;
+
+ if ( m_bResettingRenderState || memcmp( &m_DesiredState.m_pVertexBuffer[ nStreamID ], &state, sizeof( ShaderVertexBufferStateDx10_t ) ) )
+ {
+ m_DesiredState.m_pVertexBuffer[ nStreamID ] = state;
+ ADD_COMMIT_FUNC( CommitSetVertexBuffer );
+ }
+
+ if ( m_bResettingRenderState || ( m_DesiredState.m_InputLayout.m_pVertexDecl[ nStreamID ] != fmt ) )
+ {
+ m_DesiredState.m_InputLayout.m_pVertexDecl[ nStreamID ] = fmt;
+ ADD_COMMIT_FUNC( CommitSetInputLayout );
+ }
+}
+
+void CShaderAPIDx10::BindIndexBuffer( IIndexBuffer *pIndexBuffer, int nOffsetInBytes )
+{
+ CIndexBufferDx10 *pIndexBufferDx10 = static_cast<CIndexBufferDx10 *>( pIndexBuffer );
+
+ ShaderIndexBufferStateDx10_t state;
+ if ( pIndexBufferDx10 )
+ {
+ state.m_pBuffer = pIndexBufferDx10->GetDx10Buffer();
+ state.m_Format = ( pIndexBufferDx10->GetIndexFormat() == MATERIAL_INDEX_FORMAT_16BIT ) ?
+ DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT;
+ }
+ else
+ {
+ state.m_pBuffer = NULL;
+ state.m_Format = DXGI_FORMAT_R16_UINT;
+ }
+ state.m_nOffset = nOffsetInBytes;
+
+ ADD_RENDERSTATE_FUNC( CommitSetIndexBuffer, m_IndexBuffer, state );
+}
+
+
+//-----------------------------------------------------------------------------
+// Unbinds resources because they are about to be deleted
+//-----------------------------------------------------------------------------
+void CShaderAPIDx10::Unbind( VertexShaderHandle_t hShader )
+{
+ ID3D10VertexShader* pShader = g_pShaderDeviceDx10->GetVertexShader( hShader );
+ Assert ( pShader );
+ if ( m_DesiredState.m_pVertexShader == pShader )
+ {
+ BindVertexShader( VERTEX_SHADER_HANDLE_INVALID );
+ }
+ if ( m_CurrentState.m_pVertexShader == pShader )
+ {
+ CommitStateChanges();
+ }
+}
+
+void CShaderAPIDx10::Unbind( GeometryShaderHandle_t hShader )
+{
+ ID3D10GeometryShader* pShader = g_pShaderDeviceDx10->GetGeometryShader( hShader );
+ Assert ( pShader );
+ if ( m_DesiredState.m_pGeometryShader == pShader )
+ {
+ BindGeometryShader( GEOMETRY_SHADER_HANDLE_INVALID );
+ }
+ if ( m_CurrentState.m_pGeometryShader == pShader )
+ {
+ CommitStateChanges();
+ }
+}
+
+void CShaderAPIDx10::Unbind( PixelShaderHandle_t hShader )
+{
+ ID3D10PixelShader* pShader = g_pShaderDeviceDx10->GetPixelShader( hShader );
+ Assert ( pShader );
+ if ( m_DesiredState.m_pPixelShader == pShader )
+ {
+ BindPixelShader( PIXEL_SHADER_HANDLE_INVALID );
+ }
+ if ( m_CurrentState.m_pPixelShader == pShader )
+ {
+ CommitStateChanges();
+ }
+}
+
+void CShaderAPIDx10::UnbindVertexBuffer( ID3D10Buffer *pBuffer )
+{
+ Assert ( pBuffer );
+
+ for ( int i = 0; i < MAX_DX10_STREAMS; ++i )
+ {
+ if ( m_DesiredState.m_pVertexBuffer[i].m_pBuffer == pBuffer )
+ {
+ BindVertexBuffer( i, NULL, 0, 0, 0, VERTEX_POSITION, 0 );
+ }
+ }
+ for ( int i = 0; i < MAX_DX10_STREAMS; ++i )
+ {
+ if ( m_CurrentState.m_pVertexBuffer[i].m_pBuffer == pBuffer )
+ {
+ CommitStateChanges();
+ break;
+ }
+ }
+}
+
+void CShaderAPIDx10::UnbindIndexBuffer( ID3D10Buffer *pBuffer )
+{
+ Assert ( pBuffer );
+
+ if ( m_DesiredState.m_IndexBuffer.m_pBuffer == pBuffer )
+ {
+ BindIndexBuffer( NULL, 0 );
+ }
+ if ( m_CurrentState.m_IndexBuffer.m_pBuffer == pBuffer )
+ {
+ CommitStateChanges();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the topology state
+//-----------------------------------------------------------------------------
+void CShaderAPIDx10::SetTopology( MaterialPrimitiveType_t topology )
+{
+ D3D10_PRIMITIVE_TOPOLOGY d3dTopology;
+ switch( topology )
+ {
+ case MATERIAL_POINTS:
+ d3dTopology = D3D10_PRIMITIVE_TOPOLOGY_POINTLIST;
+ break;
+
+ case MATERIAL_LINES:
+ d3dTopology = D3D10_PRIMITIVE_TOPOLOGY_LINELIST;
+ break;
+
+ case MATERIAL_TRIANGLES:
+ d3dTopology = D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
+ break;
+
+ case MATERIAL_TRIANGLE_STRIP:
+ d3dTopology = D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
+ break;
+
+ case MATERIAL_LINE_STRIP:
+ d3dTopology = D3D10_PRIMITIVE_TOPOLOGY_LINESTRIP;
+ break;
+
+ default:
+ case MATERIAL_LINE_LOOP:
+ case MATERIAL_POLYGON:
+ case MATERIAL_QUADS:
+ Assert( 0 );
+ d3dTopology = D3D10_PRIMITIVE_TOPOLOGY_UNDEFINED;
+ break;
+ }
+
+ ADD_RENDERSTATE_FUNC( CommitSetTopology, m_Topology, d3dTopology );
+}
+
+
+//-----------------------------------------------------------------------------
+// Main entry point for rendering
+//-----------------------------------------------------------------------------
+void CShaderAPIDx10::Draw( MaterialPrimitiveType_t primitiveType, int nFirstIndex, int nIndexCount )
+{
+ SetTopology( primitiveType );
+
+ CommitStateChanges();
+
+ // FIXME: How do I set the base vertex location!?
+ D3D10Device()->DrawIndexed( (UINT)nIndexCount, (UINT)nFirstIndex, 0 );
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// Abandon all hope below this point
+//
+//-----------------------------------------------------------------------------
+
+bool CShaderAPIDx10::DoRenderTargetsNeedSeparateDepthBuffer() const
+{
+ return false;
+}
+
+// Can we download textures?
+bool CShaderAPIDx10::CanDownloadTextures() const
+{
+ return false;
+}
+
+// Used to clear the transition table when we know it's become invalid.
+void CShaderAPIDx10::ClearSnapshots()
+{
+}
+
+// Sets the default *dynamic* state
+void CShaderAPIDx10::SetDefaultState()
+{
+}
+
+
+// Returns the snapshot id for the shader state
+StateSnapshot_t CShaderAPIDx10::TakeSnapshot( )
+{
+ StateSnapshot_t id = 0;
+ if (g_pShaderShadowDx10->m_IsTranslucent)
+ id |= TRANSLUCENT;
+ if (g_pShaderShadowDx10->m_IsAlphaTested)
+ id |= ALPHATESTED;
+ if (g_pShaderShadowDx10->m_bUsesVertexAndPixelShaders)
+ id |= VERTEX_AND_PIXEL_SHADERS;
+ if (g_pShaderShadowDx10->m_bIsDepthWriteEnabled)
+ id |= DEPTHWRITE;
+ return id;
+}
+
+// Returns true if the state snapshot is transparent
+bool CShaderAPIDx10::IsTranslucent( StateSnapshot_t id ) const
+{
+ return (id & TRANSLUCENT) != 0;
+}
+
+bool CShaderAPIDx10::IsAlphaTested( StateSnapshot_t id ) const
+{
+ return (id & ALPHATESTED) != 0;
+}
+
+bool CShaderAPIDx10::IsDepthWriteEnabled( StateSnapshot_t id ) const
+{
+ return (id & DEPTHWRITE) != 0;
+}
+
+bool CShaderAPIDx10::UsesVertexAndPixelShaders( StateSnapshot_t id ) const
+{
+ return (id & VERTEX_AND_PIXEL_SHADERS) != 0;
+}
+
+// Gets the vertex format for a set of snapshot ids
+VertexFormat_t CShaderAPIDx10::ComputeVertexFormat( int numSnapshots, StateSnapshot_t* pIds ) const
+{
+ return 0;
+}
+
+// Gets the vertex format for a set of snapshot ids
+VertexFormat_t CShaderAPIDx10::ComputeVertexUsage( int numSnapshots, StateSnapshot_t* pIds ) const
+{
+ return 0;
+}
+
+// Uses a state snapshot
+void CShaderAPIDx10::UseSnapshot( StateSnapshot_t snapshot )
+{
+}
+
+// Sets the color to modulate by
+void CShaderAPIDx10::Color3f( float r, float g, float b )
+{
+}
+
+void CShaderAPIDx10::Color3fv( float const* pColor )
+{
+}
+
+void CShaderAPIDx10::Color4f( float r, float g, float b, float a )
+{
+}
+
+void CShaderAPIDx10::Color4fv( float const* pColor )
+{
+}
+
+// Faster versions of color
+void CShaderAPIDx10::Color3ub( unsigned char r, unsigned char g, unsigned char b )
+{
+}
+
+void CShaderAPIDx10::Color3ubv( unsigned char const* rgb )
+{
+}
+
+void CShaderAPIDx10::Color4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a )
+{
+}
+
+void CShaderAPIDx10::Color4ubv( unsigned char const* rgba )
+{
+}
+
+void CShaderAPIDx10::GetStandardTextureDimensions( int *pWidth, int *pHeight, StandardTextureId_t id )
+{
+ ShaderUtil()->GetStandardTextureDimensions( pWidth, pHeight, id );
+}
+
+
+// The shade mode
+void CShaderAPIDx10::ShadeMode( ShaderShadeMode_t mode )
+{
+}
+
+// Binds a particular material to render with
+void CShaderAPIDx10::Bind( IMaterial* pMaterial )
+{
+}
+
+// Cull mode
+void CShaderAPIDx10::CullMode( MaterialCullMode_t cullMode )
+{
+}
+
+void CShaderAPIDx10::ForceDepthFuncEquals( bool bEnable )
+{
+}
+
+// Forces Z buffering on or off
+void CShaderAPIDx10::OverrideDepthEnable( bool bEnable, bool bDepthEnable )
+{
+}
+
+void CShaderAPIDx10::OverrideAlphaWriteEnable( bool bOverrideEnable, bool bAlphaWriteEnable )
+{
+}
+
+void CShaderAPIDx10::OverrideColorWriteEnable( bool bOverrideEnable, bool bColorWriteEnable )
+{
+}
+
+
+//legacy fast clipping linkage
+void CShaderAPIDx10::SetHeightClipZ( float z )
+{
+}
+
+void CShaderAPIDx10::SetHeightClipMode( enum MaterialHeightClipMode_t heightClipMode )
+{
+}
+
+
+// Sets the lights
+void CShaderAPIDx10::SetLight( int lightNum, const LightDesc_t& desc )
+{
+}
+
+void CShaderAPIDx10::SetAmbientLight( float r, float g, float b )
+{
+}
+
+void CShaderAPIDx10::SetAmbientLightCube( Vector4D cube[6] )
+{
+}
+
+// Get lights
+int CShaderAPIDx10::GetMaxLights( void ) const
+{
+ return 0;
+}
+
+const LightDesc_t& CShaderAPIDx10::GetLight( int lightNum ) const
+{
+ static LightDesc_t blah;
+ return blah;
+}
+
+// Render state for the ambient light cube (vertex shaders)
+void CShaderAPIDx10::SetVertexShaderStateAmbientLightCube()
+{
+}
+
+void CShaderAPIDx10::SetSkinningMatrices()
+{
+}
+
+// Lightmap texture binding
+void CShaderAPIDx10::BindLightmap( TextureStage_t stage )
+{
+}
+
+void CShaderAPIDx10::BindBumpLightmap( TextureStage_t stage )
+{
+}
+
+void CShaderAPIDx10::BindFullbrightLightmap( TextureStage_t stage )
+{
+}
+
+void CShaderAPIDx10::BindWhite( TextureStage_t stage )
+{
+}
+
+void CShaderAPIDx10::BindBlack( TextureStage_t stage )
+{
+}
+
+void CShaderAPIDx10::BindGrey( TextureStage_t stage )
+{
+}
+
+// Gets the lightmap dimensions
+void CShaderAPIDx10::GetLightmapDimensions( int *w, int *h )
+{
+ g_pShaderUtil->GetLightmapDimensions( w, h );
+}
+
+// Special system flat normal map binding.
+void CShaderAPIDx10::BindFlatNormalMap( TextureStage_t stage )
+{
+}
+
+void CShaderAPIDx10::BindNormalizationCubeMap( TextureStage_t stage )
+{
+}
+
+void CShaderAPIDx10::BindSignedNormalizationCubeMap( TextureStage_t stage )
+{
+}
+
+void CShaderAPIDx10::BindFBTexture( TextureStage_t stage, int textureIndex )
+{
+}
+
+// Flushes any primitives that are buffered
+void CShaderAPIDx10::FlushBufferedPrimitives()
+{
+}
+
+// Creates/destroys Mesh
+IMesh* CShaderAPIDx10::CreateStaticMesh( VertexFormat_t fmt, const char *pTextureBudgetGroup, IMaterial * pMaterial )
+{
+ return &m_Mesh;
+}
+
+void CShaderAPIDx10::DestroyStaticMesh( IMesh* mesh )
+{
+}
+
+// Gets the dynamic mesh; note that you've got to render the mesh
+// before calling this function a second time. Clients should *not*
+// call DestroyStaticMesh on the mesh returned by this call.
+IMesh* CShaderAPIDx10::GetDynamicMesh( IMaterial* pMaterial, int nHWSkinBoneCount, bool buffered, IMesh* pVertexOverride, IMesh* pIndexOverride )
+{
+ Assert( (pMaterial == NULL) || ((IMaterialInternal *)pMaterial)->IsRealTimeVersion() );
+ return &m_Mesh;
+}
+
+IMesh* CShaderAPIDx10::GetDynamicMeshEx( IMaterial* pMaterial, VertexFormat_t fmt, int nHWSkinBoneCount, bool buffered, IMesh* pVertexOverride, IMesh* pIndexOverride )
+{
+ // UNDONE: support compressed dynamic meshes if needed (pro: less VB memory, con: time spent compressing)
+ Assert( CompressionType( pVertexOverride->GetVertexFormat() ) != VERTEX_COMPRESSION_NONE );
+ Assert( (pMaterial == NULL) || ((IMaterialInternal *)pMaterial)->IsRealTimeVersion() );
+ return &m_Mesh;
+}
+
+IMesh* CShaderAPIDx10::GetFlexMesh()
+{
+ return &m_Mesh;
+}
+
+// Begins a rendering pass that uses a state snapshot
+void CShaderAPIDx10::BeginPass( StateSnapshot_t snapshot )
+{
+}
+
+// Renders a single pass of a material
+void CShaderAPIDx10::RenderPass( int nPass, int nPassCount )
+{
+}
+
+// stuff related to matrix stacks
+void CShaderAPIDx10::MatrixMode( MaterialMatrixMode_t matrixMode )
+{
+}
+
+void CShaderAPIDx10::PushMatrix()
+{
+}
+
+void CShaderAPIDx10::PopMatrix()
+{
+}
+
+void CShaderAPIDx10::LoadMatrix( float *m )
+{
+}
+
+void CShaderAPIDx10::MultMatrix( float *m )
+{
+}
+
+void CShaderAPIDx10::MultMatrixLocal( float *m )
+{
+}
+
+void CShaderAPIDx10::GetMatrix( MaterialMatrixMode_t matrixMode, float *dst )
+{
+}
+
+void CShaderAPIDx10::LoadIdentity( void )
+{
+}
+
+void CShaderAPIDx10::LoadCameraToWorld( void )
+{
+}
+
+void CShaderAPIDx10::Ortho( double left, double top, double right, double bottom, double zNear, double zFar )
+{
+}
+
+void CShaderAPIDx10::PerspectiveX( double fovx, double aspect, double zNear, double zFar )
+{
+}
+
+void CShaderAPIDx10::PerspectiveOffCenterX( double fovx, double aspect, double zNear, double zFar, double bottom, double top, double left, double right )
+{
+}
+
+void CShaderAPIDx10::PickMatrix( int x, int y, int width, int height )
+{
+}
+
+void CShaderAPIDx10::Rotate( float angle, float x, float y, float z )
+{
+}
+
+void CShaderAPIDx10::Translate( float x, float y, float z )
+{
+}
+
+void CShaderAPIDx10::Scale( float x, float y, float z )
+{
+}
+
+void CShaderAPIDx10::ScaleXY( float x, float y )
+{
+}
+
+// Fog methods...
+void CShaderAPIDx10::FogMode( MaterialFogMode_t fogMode )
+{
+}
+
+void CShaderAPIDx10::FogStart( float fStart )
+{
+}
+
+void CShaderAPIDx10::FogEnd( float fEnd )
+{
+}
+
+void CShaderAPIDx10::SetFogZ( float fogZ )
+{
+}
+
+void CShaderAPIDx10::FogMaxDensity( float flMaxDensity )
+{
+}
+
+
+void CShaderAPIDx10::GetFogDistances( float *fStart, float *fEnd, float *fFogZ )
+{
+}
+
+
+void CShaderAPIDx10::SceneFogColor3ub( unsigned char r, unsigned char g, unsigned char b )
+{
+}
+
+
+void CShaderAPIDx10::SceneFogMode( MaterialFogMode_t fogMode )
+{
+}
+
+void CShaderAPIDx10::GetSceneFogColor( unsigned char *rgb )
+{
+}
+
+MaterialFogMode_t CShaderAPIDx10::GetSceneFogMode( )
+{
+ return MATERIAL_FOG_NONE;
+}
+
+int CShaderAPIDx10::GetPixelFogCombo( )
+{
+ return 0; //FIXME
+}
+
+void CShaderAPIDx10::FogColor3f( float r, float g, float b )
+{
+}
+
+void CShaderAPIDx10::FogColor3fv( float const* rgb )
+{
+}
+
+void CShaderAPIDx10::FogColor3ub( unsigned char r, unsigned char g, unsigned char b )
+{
+}
+
+void CShaderAPIDx10::FogColor3ubv( unsigned char const* rgb )
+{
+}
+
+void CShaderAPIDx10::Viewport( int x, int y, int width, int height )
+{
+}
+
+void CShaderAPIDx10::GetViewport( int& x, int& y, int& width, int& height ) const
+{
+}
+
+// Sets the vertex and pixel shaders
+void CShaderAPIDx10::SetVertexShaderIndex( int vshIndex )
+{
+}
+
+void CShaderAPIDx10::SetPixelShaderIndex( int pshIndex )
+{
+}
+
+// Sets the constant register for vertex and pixel shaders
+void CShaderAPIDx10::SetVertexShaderConstant( int var, float const* pVec, int numConst, bool bForce )
+{
+}
+
+void CShaderAPIDx10::SetPixelShaderConstant( int var, float const* pVec, int numConst, bool bForce )
+{
+}
+
+void CShaderAPIDx10::InvalidateDelayedShaderConstants( void )
+{
+}
+
+//Set's the linear->gamma conversion textures to use for this hardware for both srgb writes enabled and disabled(identity)
+void CShaderAPIDx10::SetLinearToGammaConversionTextures( ShaderAPITextureHandle_t hSRGBWriteEnabledTexture, ShaderAPITextureHandle_t hIdentityTexture )
+{
+}
+
+
+// Returns the nearest supported format
+ImageFormat CShaderAPIDx10::GetNearestSupportedFormat( ImageFormat fmt, bool bFilteringRequired /* = true */ ) const
+{
+ return fmt;
+}
+
+ImageFormat CShaderAPIDx10::GetNearestRenderTargetFormat( ImageFormat fmt ) const
+{
+ return fmt;
+}
+
+// Sets the texture state
+void CShaderAPIDx10::BindTexture( Sampler_t stage, ShaderAPITextureHandle_t textureHandle )
+{
+}
+
+// Indicates we're going to be modifying this texture
+// TexImage2D, TexSubImage2D, TexWrap, TexMinFilter, and TexMagFilter
+// all use the texture specified by this function.
+void CShaderAPIDx10::ModifyTexture( ShaderAPITextureHandle_t textureHandle )
+{
+}
+
+// Texture management methods
+void CShaderAPIDx10::TexImage2D( int level, int cubeFace, ImageFormat dstFormat, int zOffset, int width, int height,
+ ImageFormat srcFormat, bool bSrcIsTiled, void *imageData )
+{
+}
+
+void CShaderAPIDx10::TexSubImage2D( int level, int cubeFace, int xOffset, int yOffset, int zOffset, int width, int height,
+ ImageFormat srcFormat, int srcStride, bool bSrcIsTiled, void *imageData )
+{
+}
+
+void CShaderAPIDx10::TexImageFromVTF( IVTFTexture *pVTF, int iVTFFrame )
+{
+}
+
+bool CShaderAPIDx10::TexLock( int level, int cubeFaceID, int xOffset, int yOffset,
+ int width, int height, CPixelWriter& writer )
+{
+ return false;
+}
+
+void CShaderAPIDx10::TexUnlock( )
+{
+}
+
+
+// These are bound to the texture, not the texture environment
+void CShaderAPIDx10::TexMinFilter( ShaderTexFilterMode_t texFilterMode )
+{
+}
+
+void CShaderAPIDx10::TexMagFilter( ShaderTexFilterMode_t texFilterMode )
+{
+}
+
+void CShaderAPIDx10::TexWrap( ShaderTexCoordComponent_t coord, ShaderTexWrapMode_t wrapMode )
+{
+}
+
+void CShaderAPIDx10::TexSetPriority( int priority )
+{
+}
+
+ShaderAPITextureHandle_t CShaderAPIDx10::CreateTexture(
+ int width,
+ int height,
+ int depth,
+ ImageFormat dstImageFormat,
+ int numMipLevels,
+ int numCopies,
+ int flags,
+ const char *pDebugName,
+ const char *pTextureGroupName )
+{
+ ShaderAPITextureHandle_t handle;
+ CreateTextures( &handle, 1, width, height, depth, dstImageFormat, numMipLevels, numCopies, flags, pDebugName, pTextureGroupName );
+ return handle;
+}
+
+void CShaderAPIDx10::CreateTextures(
+ ShaderAPITextureHandle_t *pHandles,
+ int count,
+ int width,
+ int height,
+ int depth,
+ ImageFormat dstImageFormat,
+ int numMipLevels,
+ int numCopies,
+ int flags,
+ const char *pDebugName,
+ const char *pTextureGroupName )
+{
+ for ( int k = 0; k < count; ++ k )
+ {
+ pHandles[ k ] = 0;
+ }
+}
+
+ShaderAPITextureHandle_t CShaderAPIDx10::CreateDepthTexture( ImageFormat renderFormat, int width, int height, const char *pDebugName, bool bTexture )
+{
+ return 0;
+}
+
+void CShaderAPIDx10::DeleteTexture( ShaderAPITextureHandle_t textureHandle )
+{
+}
+
+bool CShaderAPIDx10::IsTexture( ShaderAPITextureHandle_t textureHandle )
+{
+ return true;
+}
+
+bool CShaderAPIDx10::IsTextureResident( ShaderAPITextureHandle_t textureHandle )
+{
+ return false;
+}
+
+// stuff that isn't to be used from within a shader
+void CShaderAPIDx10::ClearBuffersObeyStencil( bool bClearColor, bool bClearDepth )
+{
+}
+
+void CShaderAPIDx10::ClearBuffersObeyStencilEx( bool bClearColor, bool bClearAlpha, bool bClearDepth )
+{
+}
+
+void CShaderAPIDx10::PerformFullScreenStencilOperation( void )
+{
+}
+
+void CShaderAPIDx10::ReadPixels( int x, int y, int width, int height, unsigned char *data, ImageFormat dstFormat )
+{
+}
+
+void CShaderAPIDx10::ReadPixels( Rect_t *pSrcRect, Rect_t *pDstRect, unsigned char *data, ImageFormat dstFormat, int nDstStride )
+{
+}
+
+void CShaderAPIDx10::FlushHardware()
+{
+}
+
+// Set the number of bone weights
+void CShaderAPIDx10::SetNumBoneWeights( int numBones )
+{
+}
+
+// Selection mode methods
+int CShaderAPIDx10::SelectionMode( bool selectionMode )
+{
+ return 0;
+}
+
+void CShaderAPIDx10::SelectionBuffer( unsigned int* pBuffer, int size )
+{
+}
+
+void CShaderAPIDx10::ClearSelectionNames( )
+{
+}
+
+void CShaderAPIDx10::LoadSelectionName( int name )
+{
+}
+
+void CShaderAPIDx10::PushSelectionName( int name )
+{
+}
+
+void CShaderAPIDx10::PopSelectionName()
+{
+}
+
+
+// Use this to get the mesh builder that allows us to modify vertex data
+CMeshBuilder* CShaderAPIDx10::GetVertexModifyBuilder()
+{
+ return 0;
+}
+
+// Board-independent calls, here to unify how shaders set state
+// Implementations should chain back to IShaderUtil->BindTexture(), etc.
+
+// Use this to begin and end the frame
+void CShaderAPIDx10::BeginFrame()
+{
+}
+
+void CShaderAPIDx10::EndFrame()
+{
+}
+
+// returns the current time in seconds....
+double CShaderAPIDx10::CurrentTime() const
+{
+ return Sys_FloatTime();
+}
+
+// Get the current camera position in world space.
+void CShaderAPIDx10::GetWorldSpaceCameraPosition( float * pPos ) const
+{
+}
+
+void CShaderAPIDx10::ForceHardwareSync( void )
+{
+}
+
+void CShaderAPIDx10::SetClipPlane( int index, const float *pPlane )
+{
+}
+
+void CShaderAPIDx10::EnableClipPlane( int index, bool bEnable )
+{
+}
+
+void CShaderAPIDx10::SetFastClipPlane( const float *pPlane )
+{
+}
+
+void CShaderAPIDx10::EnableFastClip( bool bEnable )
+{
+}
+
+int CShaderAPIDx10::GetCurrentNumBones( void ) const
+{
+ return 0;
+}
+
+// Is hardware morphing enabled?
+bool CShaderAPIDx10::IsHWMorphingEnabled( ) const
+{
+ return false;
+}
+
+int CShaderAPIDx10::GetCurrentLightCombo( void ) const
+{
+ return 0;
+}
+
+int CShaderAPIDx10::MapLightComboToPSLightCombo( int nLightCombo ) const
+{
+ return 0;
+}
+
+MaterialFogMode_t CShaderAPIDx10::GetCurrentFogType( void ) const
+{
+ return MATERIAL_FOG_NONE;
+}
+
+void CShaderAPIDx10::RecordString( const char *pStr )
+{
+}
+
+void CShaderAPIDx10::DestroyVertexBuffers( bool bExitingLevel )
+{
+}
+
+int CShaderAPIDx10::GetCurrentDynamicVBSize( void )
+{
+ return 0;
+}
+
+void CShaderAPIDx10::EvictManagedResources()
+{
+}
+
+void CShaderAPIDx10::ReleaseShaderObjects()
+{
+}
+
+void CShaderAPIDx10::RestoreShaderObjects()
+{
+}
+
+void CShaderAPIDx10::SetTextureTransformDimension( TextureStage_t textureStage, int dimension, bool projected )
+{
+}
+
+void CShaderAPIDx10::SetBumpEnvMatrix( TextureStage_t textureStage, float m00, float m01, float m10, float m11 )
+{
+}
+
+void CShaderAPIDx10::SyncToken( const char *pToken )
+{
+}
diff --git a/materialsystem/shaderapidx9/shaderapidx10.h b/materialsystem/shaderapidx9/shaderapidx10.h
new file mode 100644
index 0000000..c6b131f
--- /dev/null
+++ b/materialsystem/shaderapidx9/shaderapidx10.h
@@ -0,0 +1,940 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#ifndef SHADERAPIDX10_H
+#define SHADERAPIDX10_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <d3d10.h>
+
+#include "shaderapibase.h"
+#include "materialsystem/idebugtextureinfo.h"
+#include "meshdx10.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+struct MaterialSystemHardwareIdentifier_t;
+
+
+//-----------------------------------------------------------------------------
+// DX10 enumerations that don't appear to exist
+//-----------------------------------------------------------------------------
+#define MAX_DX10_VIEWPORTS 16
+#define MAX_DX10_STREAMS 16
+
+
+//-----------------------------------------------------------------------------
+// A record describing the state on the board
+//-----------------------------------------------------------------------------
+struct ShaderIndexBufferStateDx10_t
+{
+ ID3D10Buffer *m_pBuffer;
+ DXGI_FORMAT m_Format;
+ UINT m_nOffset;
+
+ bool operator!=( const ShaderIndexBufferStateDx10_t& src ) const
+ {
+ return memcmp( this, &src, sizeof(ShaderIndexBufferStateDx10_t) ) != 0;
+ }
+};
+
+struct ShaderVertexBufferStateDx10_t
+{
+ ID3D10Buffer *m_pBuffer;
+ UINT m_nStride;
+ UINT m_nOffset;
+};
+
+struct ShaderInputLayoutStateDx10_t
+{
+ VertexShaderHandle_t m_hVertexShader;
+ VertexFormat_t m_pVertexDecl[ MAX_DX10_STREAMS ];
+};
+
+struct ShaderStateDx10_t
+{
+ int m_nViewportCount;
+ D3D10_VIEWPORT m_pViewports[ MAX_DX10_VIEWPORTS ];
+ FLOAT m_ClearColor[4];
+ ShaderRasterState_t m_RasterState;
+ ID3D10RasterizerState *m_pRasterState;
+ ID3D10VertexShader *m_pVertexShader;
+ ID3D10GeometryShader *m_pGeometryShader;
+ ID3D10PixelShader *m_pPixelShader;
+ ShaderVertexBufferStateDx10_t m_pVertexBuffer[ MAX_DX10_STREAMS ];
+ ShaderIndexBufferStateDx10_t m_IndexBuffer;
+ ShaderInputLayoutStateDx10_t m_InputLayout;
+ D3D10_PRIMITIVE_TOPOLOGY m_Topology;
+};
+
+
+//-----------------------------------------------------------------------------
+// Commit function helper class
+//-----------------------------------------------------------------------------
+typedef void (*StateCommitFunc_t)( ID3D10Device *pDevice, const ShaderStateDx10_t &desiredState, ShaderStateDx10_t &currentState, bool bForce );
+
+class CFunctionCommit
+{
+public:
+ CFunctionCommit();
+ ~CFunctionCommit();
+
+ void Init( int nFunctionCount );
+
+ // Methods related to queuing functions to be called per-(pMesh->Draw call) or per-pass
+ void ClearAllCommitFuncs( );
+ void CallCommitFuncs( bool bForce );
+ bool IsCommitFuncInUse( int nFunc ) const;
+ void MarkCommitFuncInUse( int nFunc );
+ void AddCommitFunc( StateCommitFunc_t f );
+ void CallCommitFuncs( ID3D10Device *pDevice, const ShaderStateDx10_t &desiredState, ShaderStateDx10_t &currentState, bool bForce = false );
+
+private:
+ // A list of state commit functions to run as per-draw call commit time
+ unsigned char* m_pCommitFlags;
+ int m_nCommitBufferSize;
+ CUtlVector< StateCommitFunc_t > m_CommitFuncs;
+};
+
+
+//-----------------------------------------------------------------------------
+// The Dx10 implementation of the shader API
+//-----------------------------------------------------------------------------
+class CShaderAPIDx10 : public CShaderAPIBase, public IDebugTextureInfo
+{
+ typedef CShaderAPIBase BaseClass;
+
+public:
+ // constructor, destructor
+ CShaderAPIDx10( );
+ virtual ~CShaderAPIDx10();
+
+ // Methods of IShaderAPI
+ // NOTE: These methods have been ported over
+public:
+ virtual void SetViewports( int nCount, const ShaderViewport_t* pViewports );
+ virtual int GetViewports( ShaderViewport_t* pViewports, int nMax ) const;
+ virtual void ClearBuffers( bool bClearColor, bool bClearDepth, bool bClearStencil, int renderTargetWidth, int renderTargetHeight );
+ virtual void ClearColor3ub( unsigned char r, unsigned char g, unsigned char b );
+ virtual void ClearColor4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a );
+ virtual void SetRasterState( const ShaderRasterState_t& state );
+ virtual void BindVertexShader( VertexShaderHandle_t hVertexShader );
+ virtual void BindGeometryShader( GeometryShaderHandle_t hGeometryShader );
+ virtual void BindPixelShader( PixelShaderHandle_t hPixelShader );
+ virtual void BindVertexBuffer( int nStreamID, IVertexBuffer *pVertexBuffer, int nOffsetInBytes, int nFirstVertex, int nVertexCount, VertexFormat_t fmt, int nRepetitions = 1 );
+ virtual void BindIndexBuffer( IIndexBuffer *pIndexBuffer, int nOffsetInBytes );
+ virtual void Draw( MaterialPrimitiveType_t primitiveType, int nFirstIndex, int nIndexCount );
+
+ // Methods of IShaderDynamicAPI
+public:
+ virtual void GetBackBufferDimensions( int& nWidth, int& nHeight ) const;
+
+public:
+ // Methods of CShaderAPIBase
+ virtual bool OnDeviceInit() { ResetRenderState(); return true; }
+ virtual void OnDeviceShutdown() {}
+ virtual void ReleaseShaderObjects();
+ virtual void RestoreShaderObjects();
+ virtual void BeginPIXEvent( unsigned long color, const char *szName ) {}
+ virtual void EndPIXEvent() {}
+ virtual void AdvancePIXFrame() {}
+
+ // NOTE: These methods have not been ported over.
+ // IDebugTextureInfo implementation.
+public:
+
+ virtual bool IsDebugTextureListFresh( int numFramesAllowed = 1 ) { return false; }
+ virtual void EnableDebugTextureList( bool bEnable ) {}
+ virtual void EnableGetAllTextures( bool bEnable ) {}
+ virtual KeyValues* GetDebugTextureList() { return NULL; }
+ virtual int GetTextureMemoryUsed( TextureMemoryType eTextureMemory ) { return 0; }
+ virtual bool SetDebugTextureRendering( bool bEnable ) { return false; }
+
+public:
+ // Other public methods
+ void Unbind( VertexShaderHandle_t hShader );
+ void Unbind( GeometryShaderHandle_t hShader );
+ void Unbind( PixelShaderHandle_t hShader );
+ void UnbindVertexBuffer( ID3D10Buffer *pBuffer );
+ void UnbindIndexBuffer( ID3D10Buffer *pBuffer );
+
+ void PrintfVA( char *fmt, va_list vargs ) {}
+ void Printf( PRINTF_FORMAT_STRING const char *fmt, ... ) {}
+ float Knob( char *knobname, float *setvalue = NULL ) { return 0.0f;}
+
+private:
+
+ // Returns a d3d texture associated with a texture handle
+ virtual IDirect3DBaseTexture* GetD3DTexture( ShaderAPITextureHandle_t hTexture ) { Assert(0); return NULL; }
+ virtual void QueueResetRenderState() {}
+
+ void SetTopology( MaterialPrimitiveType_t topology );
+
+ virtual bool DoRenderTargetsNeedSeparateDepthBuffer() const;
+
+ void SetHardwareGammaRamp( float fGamma )
+ {
+ }
+
+ // Used to clear the transition table when we know it's become invalid.
+ void ClearSnapshots();
+
+ // Sets the mode...
+ bool SetMode( void* hwnd, int nAdapter, const ShaderDeviceInfo_t &info )
+ {
+ return true;
+ }
+
+ void ChangeVideoMode( const ShaderDeviceInfo_t &info )
+ {
+ }
+
+ // Called when the dx support level has changed
+ virtual void DXSupportLevelChanged() {}
+
+ virtual void EnableUserClipTransformOverride( bool bEnable ) {}
+ virtual void UserClipTransform( const VMatrix &worldToView ) {}
+ virtual bool GetUserClipTransform( VMatrix &worldToView ) { return false; }
+
+ // Sets the default *dynamic* state
+ void SetDefaultState( );
+
+ // Returns the snapshot id for the shader state
+ StateSnapshot_t TakeSnapshot( );
+
+ // Returns true if the state snapshot is transparent
+ bool IsTranslucent( StateSnapshot_t id ) const;
+ bool IsAlphaTested( StateSnapshot_t id ) const;
+ bool UsesVertexAndPixelShaders( StateSnapshot_t id ) const;
+ virtual bool IsDepthWriteEnabled( StateSnapshot_t id ) const;
+
+ // Gets the vertex format for a set of snapshot ids
+ VertexFormat_t ComputeVertexFormat( int numSnapshots, StateSnapshot_t* pIds ) const;
+
+ // Gets the vertex format for a set of snapshot ids
+ VertexFormat_t ComputeVertexUsage( int numSnapshots, StateSnapshot_t* pIds ) const;
+
+ // Begins a rendering pass that uses a state snapshot
+ void BeginPass( StateSnapshot_t snapshot );
+
+ // Uses a state snapshot
+ void UseSnapshot( StateSnapshot_t snapshot );
+
+ // Use this to get the mesh builder that allows us to modify vertex data
+ CMeshBuilder* GetVertexModifyBuilder();
+
+ // Sets the color to modulate by
+ void Color3f( float r, float g, float b );
+ void Color3fv( float const* pColor );
+ void Color4f( float r, float g, float b, float a );
+ void Color4fv( float const* pColor );
+
+ // Faster versions of color
+ void Color3ub( unsigned char r, unsigned char g, unsigned char b );
+ void Color3ubv( unsigned char const* rgb );
+ void Color4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a );
+ void Color4ubv( unsigned char const* rgba );
+
+ // Sets the lights
+ void SetLight( int lightNum, const LightDesc_t& desc );
+ void SetAmbientLight( float r, float g, float b );
+ void SetAmbientLightCube( Vector4D cube[6] );
+ virtual void SetLightingOrigin( Vector vLightingOrigin ) {}
+
+ // Get the lights
+ int GetMaxLights( void ) const;
+ const LightDesc_t& GetLight( int lightNum ) const;
+
+ // Render state for the ambient light cube (vertex shaders)
+ void SetVertexShaderStateAmbientLightCube();
+ virtual void SetPixelShaderStateAmbientLightCube( int pshReg, bool bForceToBlack = false ) {}
+ void SetPixelShaderStateAmbientLightCube( int pshReg )
+ {
+ }
+ virtual void GetDX9LightState( LightState_t *state ) const {}
+
+ float GetAmbientLightCubeLuminance(void)
+ {
+ return 0.0f;
+ }
+
+ void SetSkinningMatrices();
+
+ // Lightmap texture binding
+ void BindLightmap( TextureStage_t stage );
+ void BindLightmapAlpha( TextureStage_t stage )
+ {
+ }
+ void BindBumpLightmap( TextureStage_t stage );
+ void BindFullbrightLightmap( TextureStage_t stage );
+ void BindWhite( TextureStage_t stage );
+ void BindBlack( TextureStage_t stage );
+ void BindGrey( TextureStage_t stage );
+ void BindFBTexture( TextureStage_t stage, int textureIdex );
+ void CopyRenderTargetToTexture( ShaderAPITextureHandle_t texID )
+ {
+ }
+
+ void CopyRenderTargetToTextureEx( ShaderAPITextureHandle_t texID, int nRenderTargetID, Rect_t *pSrcRect, Rect_t *pDstRect )
+ {
+ }
+
+ void CopyTextureToRenderTargetEx( int nRenderTargetID, ShaderAPITextureHandle_t textureHandle, Rect_t *pSrcRect = NULL, Rect_t *pDstRect = NULL )
+ {
+ }
+
+ // Special system flat normal map binding.
+ void BindFlatNormalMap( TextureStage_t stage );
+ void BindNormalizationCubeMap( TextureStage_t stage );
+ void BindSignedNormalizationCubeMap( TextureStage_t stage );
+
+ // Set the number of bone weights
+ void SetNumBoneWeights( int numBones );
+
+ // Flushes any primitives that are buffered
+ void FlushBufferedPrimitives();
+
+ // Creates/destroys Mesh
+ IMesh* CreateStaticMesh( VertexFormat_t fmt, const char *pTextureBudgetGroup, IMaterial * pMaterial = NULL );
+ void DestroyStaticMesh( IMesh* mesh );
+
+ // Gets the dynamic mesh; note that you've got to render the mesh
+ // before calling this function a second time. Clients should *not*
+ // call DestroyStaticMesh on the mesh returned by this call.
+ IMesh* GetDynamicMesh( IMaterial* pMaterial, int nHWSkinBoneCount, bool buffered, IMesh* pVertexOverride, IMesh* pIndexOverride );
+ IMesh* GetDynamicMeshEx( IMaterial* pMaterial, VertexFormat_t fmt, int nHWSkinBoneCount, bool buffered, IMesh* pVertexOverride, IMesh* pIndexOverride );
+ IVertexBuffer *GetDynamicVertexBuffer( IMaterial* pMaterial, bool buffered )
+ {
+ Assert( 0 );
+ return NULL;
+ }
+ IIndexBuffer *GetDynamicIndexBuffer( IMaterial* pMaterial, bool buffered )
+ {
+ Assert( 0 );
+ return NULL;
+ }
+ IMesh* GetFlexMesh();
+
+ // Renders a single pass of a material
+ void RenderPass( int nPass, int nPassCount );
+
+ // stuff related to matrix stacks
+ void MatrixMode( MaterialMatrixMode_t matrixMode );
+ void PushMatrix();
+ void PopMatrix();
+ void LoadMatrix( float *m );
+ void LoadBoneMatrix( int boneIndex, const float *m ) {}
+ void MultMatrix( float *m );
+ void MultMatrixLocal( float *m );
+ void GetMatrix( MaterialMatrixMode_t matrixMode, float *dst );
+ void LoadIdentity( void );
+ void LoadCameraToWorld( void );
+ void Ortho( double left, double top, double right, double bottom, double zNear, double zFar );
+ void PerspectiveX( double fovx, double aspect, double zNear, double zFar );
+ void PerspectiveOffCenterX( double fovx, double aspect, double zNear, double zFar, double bottom, double top, double left, double right );
+ void PickMatrix( int x, int y, int width, int height );
+ void Rotate( float angle, float x, float y, float z );
+ void Translate( float x, float y, float z );
+ void Scale( float x, float y, float z );
+ void ScaleXY( float x, float y );
+
+ void Viewport( int x, int y, int width, int height );
+ void GetViewport( int& x, int& y, int& width, int& height ) const;
+
+ // Fog methods...
+ void FogMode( MaterialFogMode_t fogMode );
+ void FogStart( float fStart );
+ void FogEnd( float fEnd );
+ void SetFogZ( float fogZ );
+ void FogMaxDensity( float flMaxDensity );
+ void GetFogDistances( float *fStart, float *fEnd, float *fFogZ );
+ void FogColor3f( float r, float g, float b );
+ void FogColor3fv( float const* rgb );
+ void FogColor3ub( unsigned char r, unsigned char g, unsigned char b );
+ void FogColor3ubv( unsigned char const* rgb );
+
+ virtual void SceneFogColor3ub( unsigned char r, unsigned char g, unsigned char b );
+ virtual void SceneFogMode( MaterialFogMode_t fogMode );
+ virtual void GetSceneFogColor( unsigned char *rgb );
+ virtual MaterialFogMode_t GetSceneFogMode( );
+ virtual int GetPixelFogCombo( );
+
+ void SetHeightClipZ( float z );
+ void SetHeightClipMode( enum MaterialHeightClipMode_t heightClipMode );
+
+ void SetClipPlane( int index, const float *pPlane );
+ void EnableClipPlane( int index, bool bEnable );
+
+ void SetFastClipPlane( const float *pPlane );
+ void EnableFastClip( bool bEnable );
+
+ // We use smaller dynamic VBs during level transitions, to free up memory
+ virtual int GetCurrentDynamicVBSize( void );
+ virtual void DestroyVertexBuffers( bool bExitingLevel = false );
+
+ // Sets the vertex and pixel shaders
+ void SetVertexShaderIndex( int vshIndex );
+ void SetPixelShaderIndex( int pshIndex );
+
+ // Sets the constant register for vertex and pixel shaders
+ void SetVertexShaderConstant( int var, float const* pVec, int numConst = 1, bool bForce = false );
+ void SetPixelShaderConstant( int var, float const* pVec, int numConst = 1, bool bForce = false );
+
+ void SetBooleanVertexShaderConstant( int var, BOOL const* pVec, int numBools = 1, bool bForce = false )
+ {
+ Assert(0);
+ }
+
+
+ void SetIntegerVertexShaderConstant( int var, int const* pVec, int numIntVecs = 1, bool bForce = false )
+ {
+ Assert(0);
+ }
+
+
+ void SetBooleanPixelShaderConstant( int var, BOOL const* pVec, int numBools = 1, bool bForce = false )
+ {
+ Assert(0);
+ }
+
+ void SetIntegerPixelShaderConstant( int var, int const* pVec, int numIntVecs = 1, bool bForce = false )
+ {
+ Assert(0);
+ }
+
+ bool ShouldWriteDepthToDestAlpha( void ) const
+ {
+ Assert(0);
+ return false;
+ }
+
+
+ void InvalidateDelayedShaderConstants( void );
+
+ // Gamma<->Linear conversions according to the video hardware we're running on
+ float GammaToLinear_HardwareSpecific( float fGamma ) const
+ {
+ return 0.;
+ }
+
+ float LinearToGamma_HardwareSpecific( float fLinear ) const
+ {
+ return 0.;
+ }
+
+ //Set's the linear->gamma conversion textures to use for this hardware for both srgb writes enabled and disabled(identity)
+ void SetLinearToGammaConversionTextures( ShaderAPITextureHandle_t hSRGBWriteEnabledTexture, ShaderAPITextureHandle_t hIdentityTexture );
+
+ // Cull mode
+ void CullMode( MaterialCullMode_t cullMode );
+
+ // Force writes only when z matches. . . useful for stenciling things out
+ // by rendering the desired Z values ahead of time.
+ void ForceDepthFuncEquals( bool bEnable );
+
+ // Forces Z buffering on or off
+ void OverrideDepthEnable( bool bEnable, bool bDepthEnable );
+ // Forces alpha writes on or off
+ void OverrideAlphaWriteEnable( bool bOverrideEnable, bool bAlphaWriteEnable );
+ //forces color writes on or off
+ void OverrideColorWriteEnable( bool bOverrideEnable, bool bColorWriteEnable );
+
+ // Sets the shade mode
+ void ShadeMode( ShaderShadeMode_t mode );
+
+ // Binds a particular material to render with
+ void Bind( IMaterial* pMaterial );
+
+ // Returns the nearest supported format
+ ImageFormat GetNearestSupportedFormat( ImageFormat fmt, bool bFilteringRequired = true ) const;
+ ImageFormat GetNearestRenderTargetFormat( ImageFormat fmt ) const;
+
+ // Sets the texture state
+ void BindTexture( Sampler_t stage, ShaderAPITextureHandle_t textureHandle );
+
+ void SetRenderTarget( ShaderAPITextureHandle_t colorTextureHandle, ShaderAPITextureHandle_t depthTextureHandle )
+ {
+ }
+
+ void SetRenderTargetEx( int nRenderTargetID, ShaderAPITextureHandle_t colorTextureHandle, ShaderAPITextureHandle_t depthTextureHandle )
+ {
+ }
+
+ // Indicates we're going to be modifying this texture
+ // TexImage2D, TexSubImage2D, TexWrap, TexMinFilter, and TexMagFilter
+ // all use the texture specified by this function.
+ void ModifyTexture( ShaderAPITextureHandle_t textureHandle );
+
+ // Texture management methods
+ void TexImage2D( int level, int cubeFace, ImageFormat dstFormat, int zOffset, int width, int height,
+ ImageFormat srcFormat, bool bSrcIsTiled, void *imageData );
+ void TexSubImage2D( int level, int cubeFace, int xOffset, int yOffset, int zOffset, int width, int height,
+ ImageFormat srcFormat, int srcStride, bool bSrcIsTiled, void *imageData );
+ void TexImageFromVTF( IVTFTexture *pVTF, int iVTFFrame );
+
+ bool TexLock( int level, int cubeFaceID, int xOffset, int yOffset,
+ int width, int height, CPixelWriter& writer );
+ void TexUnlock( );
+
+ // These are bound to the texture, not the texture environment
+ void TexMinFilter( ShaderTexFilterMode_t texFilterMode );
+ void TexMagFilter( ShaderTexFilterMode_t texFilterMode );
+ void TexWrap( ShaderTexCoordComponent_t coord, ShaderTexWrapMode_t wrapMode );
+ void TexSetPriority( int priority );
+
+ ShaderAPITextureHandle_t CreateTexture(
+ int width,
+ int height,
+ int depth,
+ ImageFormat dstImageFormat,
+ int numMipLevels,
+ int numCopies,
+ int flags,
+ const char *pDebugName,
+ const char *pTextureGroupName );
+ void CreateTextures(
+ ShaderAPITextureHandle_t *pHandles,
+ int count,
+ int width,
+ int height,
+ int depth,
+ ImageFormat dstImageFormat,
+ int numMipLevels,
+ int numCopies,
+ int flags,
+ const char *pDebugName,
+ const char *pTextureGroupName );
+ ShaderAPITextureHandle_t CreateDepthTexture( ImageFormat renderFormat, int width, int height, const char *pDebugName, bool bTexture );
+ void DeleteTexture( ShaderAPITextureHandle_t textureHandle );
+ bool IsTexture( ShaderAPITextureHandle_t textureHandle );
+ bool IsTextureResident( ShaderAPITextureHandle_t textureHandle );
+
+ // stuff that isn't to be used from within a shader
+ void ClearBuffersObeyStencil( bool bClearColor, bool bClearDepth );
+ void ClearBuffersObeyStencilEx( bool bClearColor, bool bClearAlpha, bool bClearDepth );
+ void PerformFullScreenStencilOperation( void );
+ void ReadPixels( int x, int y, int width, int height, unsigned char *data, ImageFormat dstFormat );
+ virtual void ReadPixels( Rect_t *pSrcRect, Rect_t *pDstRect, unsigned char *data, ImageFormat dstFormat, int nDstStride );
+
+ // Selection mode methods
+ int SelectionMode( bool selectionMode );
+ void SelectionBuffer( unsigned int* pBuffer, int size );
+ void ClearSelectionNames( );
+ void LoadSelectionName( int name );
+ void PushSelectionName( int name );
+ void PopSelectionName();
+
+ void FlushHardware();
+ void ResetRenderState( bool bFullReset = true );
+
+ // Can we download textures?
+ virtual bool CanDownloadTextures() const;
+
+ // Board-independent calls, here to unify how shaders set state
+ // Implementations should chain back to IShaderUtil->BindTexture(), etc.
+
+ // Use this to begin and end the frame
+ void BeginFrame();
+ void EndFrame();
+
+ // returns current time
+ double CurrentTime() const;
+
+ // Get the current camera position in world space.
+ void GetWorldSpaceCameraPosition( float * pPos ) const;
+
+ void ForceHardwareSync( void );
+
+ int GetCurrentNumBones( void ) const;
+ bool IsHWMorphingEnabled( ) const;
+ int GetCurrentLightCombo( void ) const;
+ int MapLightComboToPSLightCombo( int nLightCombo ) const;
+ MaterialFogMode_t GetCurrentFogType( void ) const;
+
+ void RecordString( const char *pStr );
+
+ void EvictManagedResources();
+
+ void SetTextureTransformDimension( TextureStage_t textureStage, int dimension, bool projected );
+ void DisableTextureTransform( TextureStage_t textureStage )
+ {
+ }
+ void SetBumpEnvMatrix( TextureStage_t textureStage, float m00, float m01, float m10, float m11 );
+
+ // Gets the lightmap dimensions
+ virtual void GetLightmapDimensions( int *w, int *h );
+
+ virtual void SyncToken( const char *pToken );
+
+ // Setup standard vertex shader constants (that don't change)
+ // This needs to be called anytime that overbright changes.
+ virtual void SetStandardVertexShaderConstants( float fOverbright )
+ {
+ }
+
+ // Scissor Rect
+ virtual void SetScissorRect( const int nLeft, const int nTop, const int nRight, const int nBottom, const bool bEnableScissor ) {}
+
+ // Reports support for a given CSAA mode
+ bool SupportsCSAAMode( int nNumSamples, int nQualityLevel ) { return false; }
+
+ // Level of anisotropic filtering
+ virtual void SetAnisotropicLevel( int nAnisotropyLevel )
+ {
+ }
+
+ void SetDefaultDynamicState()
+ {
+ }
+ virtual void CommitPixelShaderLighting( int pshReg )
+ {
+ }
+
+ virtual void MarkUnusedVertexFields( unsigned int nFlags, int nTexCoordCount, bool *pUnusedTexCoords )
+ {
+ }
+
+ ShaderAPIOcclusionQuery_t CreateOcclusionQueryObject( void )
+ {
+ return INVALID_SHADERAPI_OCCLUSION_QUERY_HANDLE;
+ }
+
+ void DestroyOcclusionQueryObject( ShaderAPIOcclusionQuery_t handle )
+ {
+ }
+
+ void BeginOcclusionQueryDrawing( ShaderAPIOcclusionQuery_t handle )
+ {
+ }
+
+ void EndOcclusionQueryDrawing( ShaderAPIOcclusionQuery_t handle )
+ {
+ }
+
+ int OcclusionQuery_GetNumPixelsRendered( ShaderAPIOcclusionQuery_t handle, bool bFlush )
+ {
+ return 0;
+ }
+
+ virtual void AcquireThreadOwnership() {}
+ virtual void ReleaseThreadOwnership() {}
+
+ virtual bool SupportsBorderColor() const { return false; }
+ virtual bool SupportsFetch4() const { return false; }
+ virtual void EnableBuffer2FramesAhead( bool bEnable ) {}
+
+ virtual void SetDepthFeatheringPixelShaderConstant( int iConstant, float fDepthBlendScale ) {}
+
+ void SetPixelShaderFogParams( int reg )
+ {
+ }
+
+ virtual bool InFlashlightMode() const
+ {
+ return false;
+ }
+
+ virtual bool InEditorMode() const
+ {
+ return false;
+ }
+
+ // What fields in the morph do we actually use?
+ virtual MorphFormat_t ComputeMorphFormat( int numSnapshots, StateSnapshot_t* pIds ) const
+ {
+ return 0;
+ }
+
+ // Gets the bound morph's vertex format; returns 0 if no morph is bound
+ virtual MorphFormat_t GetBoundMorphFormat()
+ {
+ return 0;
+ }
+
+ void GetStandardTextureDimensions( int *pWidth, int *pHeight, StandardTextureId_t id );
+
+ // Binds a standard texture
+ virtual void BindStandardTexture( Sampler_t stage, StandardTextureId_t id )
+ {
+ }
+
+ virtual void BindStandardVertexTexture( VertexTextureSampler_t stage, StandardTextureId_t id )
+ {
+ }
+
+ virtual void SetFlashlightState( const FlashlightState_t &state, const VMatrix &worldToTexture )
+ {
+ }
+
+ virtual void SetFlashlightStateEx( const FlashlightState_t &state, const VMatrix &worldToTexture, ITexture *pFlashlightDepthTexture )
+ {
+ }
+
+ virtual const FlashlightState_t &GetFlashlightState( VMatrix &worldToTexture ) const
+ {
+ static FlashlightState_t blah;
+ return blah;
+ }
+
+ virtual const FlashlightState_t &GetFlashlightStateEx( VMatrix &worldToTexture, ITexture **pFlashlightDepthTexture ) const
+ {
+ static FlashlightState_t blah;
+ return blah;
+ }
+
+ virtual void SetModeChangeCallback( ModeChangeCallbackFunc_t func )
+ {
+ }
+
+
+ virtual void ClearVertexAndPixelShaderRefCounts()
+ {
+ }
+
+ virtual void PurgeUnusedVertexAndPixelShaders()
+ {
+ }
+
+ // Binds a vertex texture to a particular texture stage in the vertex pipe
+ virtual void BindVertexTexture( VertexTextureSampler_t nStage, ShaderAPITextureHandle_t hTexture )
+ {
+ }
+
+ // Sets morph target factors
+ virtual void SetFlexWeights( int nFirstWeight, int nCount, const MorphWeight_t* pWeights )
+ {
+ }
+
+ // NOTE: Stuff after this is added after shipping HL2.
+ ITexture *GetRenderTargetEx( int nRenderTargetID )
+ {
+ return NULL;
+ }
+
+ void SetToneMappingScaleLinear( const Vector &scale )
+ {
+ }
+
+ const Vector &GetToneMappingScaleLinear( void ) const
+ {
+ static Vector dummy;
+ return dummy;
+ }
+
+ virtual float GetLightMapScaleFactor( void ) const
+ {
+ return 1.0;
+ }
+
+ // For dealing with device lost in cases where SwapBuffers isn't called all the time (Hammer)
+ virtual void HandleDeviceLost()
+ {
+ }
+
+ virtual void EnableLinearColorSpaceFrameBuffer( bool bEnable )
+ {
+ }
+
+ // Lets the shader know about the full-screen texture so it can
+ virtual void SetFullScreenTextureHandle( ShaderAPITextureHandle_t h )
+ {
+ }
+
+ void SetFloatRenderingParameter(int parm_number, float value)
+ {
+ }
+
+ void SetIntRenderingParameter(int parm_number, int value)
+ {
+ }
+ void SetVectorRenderingParameter(int parm_number, Vector const &value)
+ {
+ }
+
+ float GetFloatRenderingParameter(int parm_number) const
+ {
+ return 0;
+ }
+
+ int GetIntRenderingParameter(int parm_number) const
+ {
+ return 0;
+ }
+
+ Vector GetVectorRenderingParameter(int parm_number) const
+ {
+ return Vector(0,0,0);
+ }
+
+ // Methods related to stencil
+ void SetStencilEnable(bool onoff)
+ {
+ }
+
+ void SetStencilFailOperation(StencilOperation_t op)
+ {
+ }
+
+ void SetStencilZFailOperation(StencilOperation_t op)
+ {
+ }
+
+ void SetStencilPassOperation(StencilOperation_t op)
+ {
+ }
+
+ void SetStencilCompareFunction(StencilComparisonFunction_t cmpfn)
+ {
+ }
+
+ void SetStencilReferenceValue(int ref)
+ {
+ }
+
+ void SetStencilTestMask(uint32 msk)
+ {
+ }
+
+ void SetStencilWriteMask(uint32 msk)
+ {
+ }
+
+ void ClearStencilBufferRectangle( int xmin, int ymin, int xmax, int ymax,int value)
+ {
+ }
+
+ virtual void GetDXLevelDefaults(uint &max_dxlevel,uint &recommended_dxlevel)
+ {
+ max_dxlevel=recommended_dxlevel=90;
+ }
+
+ virtual void GetMaxToRender( IMesh *pMesh, bool bMaxUntilFlush, int *pMaxVerts, int *pMaxIndices )
+ {
+ *pMaxVerts = 32768;
+ *pMaxIndices = 32768;
+ }
+
+ // Returns the max possible vertices + indices to render in a single draw call
+ virtual int GetMaxVerticesToRender( IMaterial *pMaterial )
+ {
+ return 32768;
+ }
+
+ virtual int GetMaxIndicesToRender( )
+ {
+ return 32768;
+ }
+ virtual int CompareSnapshots( StateSnapshot_t snapshot0, StateSnapshot_t snapshot1 ) { return 0; }
+
+ virtual void DisableAllLocalLights() {}
+
+ virtual bool SupportsMSAAMode( int nMSAAMode ) { return false; }
+
+ // Hooks for firing PIX events from outside the Material System...
+ virtual void SetPIXMarker( unsigned long color, const char *szName ) {}
+
+ virtual void ComputeVertexDescription( unsigned char* pBuffer, VertexFormat_t vertexFormat, MeshDesc_t& desc ) const {}
+
+ virtual bool SupportsShadowDepthTextures() { return false; }
+
+ virtual int NeedsShaderSRGBConversion(void) const { return 1; }
+
+ virtual bool SupportsFetch4() { return false; }
+
+ virtual void SetShadowDepthBiasFactors( float fShadowSlopeScaleDepthBias, float fShadowDepthBias ) {}
+
+ virtual void SetDisallowAccess( bool ) {}
+ virtual void EnableShaderShaderMutex( bool ) {}
+ virtual void ShaderLock() {}
+ virtual void ShaderUnlock() {}
+ virtual void EnableHWMorphing( bool bEnable ) {}
+ ImageFormat GetNullTextureFormat( void ) { return IMAGE_FORMAT_ABGR8888; } // stub
+ virtual void PushDeformation( DeformationBase_t const *Deformation )
+ {
+ }
+
+ virtual void PopDeformation( )
+ {
+ }
+
+ virtual int GetNumActiveDeformations() const
+ {
+ return 0;
+ }
+
+
+ virtual void ExecuteCommandBuffer( uint8 *pBuf )
+ {
+ }
+
+ void SetStandardTextureHandle(StandardTextureId_t,ShaderAPITextureHandle_t)
+ {
+ }
+
+ virtual void SetPSNearAndFarZ( int pshReg )
+ {
+ }
+
+ int GetPackedDeformationInformation( int nMaskOfUnderstoodDeformations,
+ float *pConstantValuesOut,
+ int nBufferSize,
+ int nMaximumDeformations,
+ int *pNumDefsOut ) const
+ {
+ *pNumDefsOut = 0;
+ return 0;
+ }
+
+ virtual bool OwnGPUResources( bool bEnable )
+ {
+ return false;
+ }
+
+private:
+ enum
+ {
+ TRANSLUCENT = 0x1,
+ ALPHATESTED = 0x2,
+ VERTEX_AND_PIXEL_SHADERS = 0x4,
+ DEPTHWRITE = 0x8,
+ };
+ void EnableAlphaToCoverage() {} ;
+ void DisableAlphaToCoverage() {} ;
+
+ ImageFormat GetShadowDepthTextureFormat() { return IMAGE_FORMAT_UNKNOWN; };
+
+ //
+ // NOTE: Under here are real methods being used by dx10 implementation
+ // above is stuff I still have to port over.
+ //
+private:
+ void ClearShaderState( ShaderStateDx10_t* pState );
+ void CommitStateChanges( bool bForce = false );
+
+private:
+ CMeshDx10 m_Mesh;
+
+ bool m_bResettingRenderState : 1;
+ CFunctionCommit m_Commit;
+ ShaderStateDx10_t m_DesiredState;
+ ShaderStateDx10_t m_CurrentState;
+};
+
+
+//-----------------------------------------------------------------------------
+// Singleton global
+//-----------------------------------------------------------------------------
+extern CShaderAPIDx10* g_pShaderAPIDx10;
+
+#endif // SHADERAPIDX10_H
+
diff --git a/materialsystem/shaderapidx9/shaderapidx10.vpc b/materialsystem/shaderapidx9/shaderapidx10.vpc
new file mode 100644
index 0000000..20243b0
--- /dev/null
+++ b/materialsystem/shaderapidx9/shaderapidx10.vpc
@@ -0,0 +1,174 @@
+//-----------------------------------------------------------------------------
+// SHADERAPIDX10.VPC
+//
+// Project Script
+//-----------------------------------------------------------------------------
+
+$macro SRCDIR "..\.."
+$Macro OUTBINDIR "$SRCDIR\..\game\bin"
+
+$Include "$SRCDIR\vpc_scripts\source_dll_base.vpc"
+
+$Configuration "Debug"
+{
+ $General
+ {
+ $OutputDirectory ".\Debug_dx10"
+ $IntermediateDirectory ".\Debug_dx10"
+ }
+}
+
+$Configuration "Release"
+{
+ $General
+ {
+ $OutputDirectory ".\Release_dx10"
+ $IntermediateDirectory ".\Release_dx10"
+ }
+}
+
+// Common Configuration
+$Configuration
+{
+ $Compiler
+ {
+ $AdditionalIncludeDirectories "$BASE;$SRCDIR\dx10sdk\include;..\"
+ $PreprocessorDefinitions "$BASE;SHADERAPIDX10;SHADER_DLL_EXPORT;PROTECTED_THINGS_ENABLE;strncpy=use_Q_strncpy_instead;_snprintf=use_Q_snprintf_instead"
+ $PreprocessorDefinitions "$BASE;USE_ACTUAL_DX" [$WIN32]
+
+// $AdditionalOptions "/FC"
+ }
+}
+
+$Project "shaderapidx10"
+{
+ $Folder "Source Files"
+ {
+ // Shared riles
+ $File "cvballoctracker.cpp"
+ $File "shaderdevicebase.cpp"
+ $File "shaderapibase.cpp"
+ $File "meshbase.cpp"
+
+ // DX10 related files
+ $File "ShaderDeviceDx10.cpp" \
+ "ShaderAPIDx10.cpp" \
+ "MeshDx10.cpp" \
+ "InputLayoutDx10.cpp" \
+ "ShaderShadowDx10.cpp"
+ {
+ $Configuration
+ {
+ $Compiler
+ {
+ $PreprocessorDefinitions "$BASE;DX10"
+ }
+ }
+ }
+
+ // DX9 related files
+ $File "ColorFormatDX8.cpp"
+ $File "d3d_async.cpp"
+ $File "$SRCDIR\public\filesystem_helpers.cpp"
+ $File "HardwareConfig.cpp"
+ $File "MeshDX8.cpp"
+ $File "Recording.cpp"
+ $File "ShaderAPIDX8.cpp"
+ $File "ShaderDeviceDX8.cpp"
+ $File "ShaderShadowDX8.cpp"
+ $File "TextureDX8.cpp"
+ $File "TransitionTable.cpp"
+ $File "vertexdecl.cpp"
+ $File "VertexShaderDX8.cpp"
+ $File "wmi.cpp"
+ }
+
+ $Folder "DirectX Header Files"
+ {
+ $File "$SRCDIR\dx10sdk\include\d3d10.h"
+ $File "$SRCDIR\dx10sdk\include\d3dx10.h"
+ $File "$SRCDIR\dx10sdk\include\d3dx10core.h"
+ $File "$SRCDIR\dx10sdk\include\d3dx10math.h"
+ $File "$SRCDIR\dx10sdk\include\d3dx10math.inl"
+ $File "$SRCDIR\dx10sdk\include\d3dx10mesh.h"
+ $File "$SRCDIR\dx10sdk\include\d3dx10tex.h"
+ }
+
+ $Folder "Public Header Files"
+ {
+ $File "$SRCDIR\public\shaderapi\ishaderdevice.h"
+ $File "$SRCDIR\public\shaderapi\ishaderutil.h"
+ $File "$SRCDIR\public\shaderapi\ishaderapi.h"
+ $File "$SRCDIR\public\shaderapi\ishaderdynamic.h"
+ $File "$SRCDIR\public\shaderapi\ishadershadow.h"
+ $File "$SRCDIR\public\materialsystem\idebugtextureinfo.h"
+ $File "$SRCDIR\public\materialsystem\ivballoctracker.h"
+ $File "$SRCDIR\public\materialsystem\shader_vcs_version.h"
+ }
+
+ $Folder "Header Files"
+ {
+ // Shared files
+ $File "meshbase.h"
+ $File "shaderdevicebase.h"
+ $File "shaderapibase.h"
+ $File "shaderapi_global.h"
+ $File "HardwareConfig.h"
+
+ // DX10 related files
+ $File "ShaderDeviceDx10.h"
+ $File "ShaderAPIDx10.h"
+ $File "MeshDx10.h"
+ $File "ShaderShadowDx10.h"
+ $File "shaderapidx10_global.h"
+ $File "inputlayoutdx10.h"
+
+ // DX9 related files
+ $File "TransitionTable.h"
+ $File "vertexdecl.h"
+ $File "ColorFormatDX8.h"
+ $File "d3d_async.h"
+ $File "dynamicib.h"
+ $File "dynamicvb.h"
+ $File "IMeshDX8.h"
+ $File "locald3dtypes.h"
+ $File "Recording.h"
+ $File "ShaderAPIDX8.h"
+ $File "ShaderAPIDX8_Global.h"
+ $File "ShaderShadowDX8.h"
+ $File "stubd3ddevice.h"
+ $File "TextureDX8.h"
+ $File "VertexShaderDX8.h"
+ $File "wmi.h"
+ }
+
+ $Folder "Link Libraries"
+ {
+ $DynamicFile "$SRCDIR\lib\public\tier2.lib"
+ $DynamicFile "$SRCDIR\lib\public\bitmap.lib"
+ $DynamicFile "$SRCDIR\lib\public\mathlib.lib"
+ $DynamicFile "$SRCDIR\lib\common\vc7\bzip2.lib"
+
+ $File "$SRCDIR\dx10sdk\lib\x86\d3d9.lib"
+ $File "$SRCDIR\dx10sdk\lib\x86\d3d10.lib"
+ $File "$SRCDIR\dx10sdk\lib\x86\dxgi.lib"
+
+ $File "$SRCDIR\dx10sdk\lib\x86\d3dx10.lib" \
+ "$SRCDIR\dx10sdk\lib\x86\d3dx9.lib"
+ {
+ $Configuration "Debug"
+ {
+ $ExcludedFromBuild "Yes"
+ }
+ }
+
+ $File "$SRCDIR\dx10sdk\lib\x86\d3dx10d.lib" \
+ "$SRCDIR\dx10sdk\lib\x86\d3dx9d.lib"
+ {
+ $Configuration "Release"
+ {
+ $ExcludedFromBuild "Yes"
+ }
+ }
+ }
+}
diff --git a/materialsystem/shaderapidx9/shaderapidx10_global.h b/materialsystem/shaderapidx9/shaderapidx10_global.h
new file mode 100644
index 0000000..62416b4
--- /dev/null
+++ b/materialsystem/shaderapidx9/shaderapidx10_global.h
@@ -0,0 +1,19 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#ifndef SHADERAPIDX10_GLOBAL_H
+#define SHADERAPIDX10_GLOBAL_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "shaderapi_global.h"
+
+
+#endif // SHADERAPIDX10_GLOBAL_H
diff --git a/materialsystem/shaderapidx9/shaderapidx8.cpp b/materialsystem/shaderapidx9/shaderapidx8.cpp
new file mode 100644
index 0000000..6aa025c
--- /dev/null
+++ b/materialsystem/shaderapidx9/shaderapidx8.cpp
@@ -0,0 +1,14354 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//
+// The dx8 implementation of the shader API
+//===========================================================================//
+
+/*
+DX9 todo:
+-make the transforms in the older shaders match the transforms in lightmappedgeneric
+-fix polyoffset for hardware that doesn't support D3DRS_SLOPESCALEDEPTHBIAS and D3DRS_DEPTHBIAS
+ - code is there, I think matrix offset just needs tweaking
+-fix forcehardwaresync - implement texture locking for hardware that doesn't support async query
+-get the format for GetAdapterModeCount and EnumAdapterModes from somewhere (shaderapidx8.cpp, GetModeCount, GetModeInfo)
+-record frame sync objects (allocframesyncobjects, free framesync objects, ForceHardwareSync)
+-Need to fix ENVMAPMASKSCALE, BUMPOFFSET in lightmappedgeneric*.cpp and vertexlitgeneric*.cpp
+fix this:
+ // FIXME: This also depends on the vertex format and whether or not we are static lit in dx9
+ #ifndef SHADERAPIDX9
+ if (m_DynamicState.m_VertexShader != shader) // garymcthack
+ #endif // !SHADERAPIDX9
+unrelated to dx9:
+mat_fullbright 1 doesn't work properly on alpha materials in testroom_standards
+*/
+#define DISABLE_PROTECTED_THINGS
+#include "shaderapidx8.h"
+#include "shaderapidx8_global.h"
+#include "shadershadowdx8.h"
+#include "locald3dtypes.h"
+#include "utlvector.h"
+#include "IHardwareConfigInternal.h"
+#include "utlstack.h"
+#include "shaderapi/ishaderutil.h"
+#include "shaderapi/commandbuffer.h"
+#include "shaderapidx8_global.h"
+#include "materialsystem/imaterialsystem.h"
+#include "materialsystem/itexture.h"
+#include "imaterialinternal.h"
+#include "imeshdx8.h"
+#include "materialsystem/imorph.h"
+#include "colorformatdx8.h"
+#include "texturedx8.h"
+#include "textureheap.h"
+#include <malloc.h>
+#include "interface.h"
+#include "utlrbtree.h"
+#include "utlsymbol.h"
+#include "tier1/strtools.h"
+#include "recording.h"
+#ifndef _X360
+#include <crtmemdebug.h>
+#endif
+#include "vertexshaderdx8.h"
+#include "filesystem.h"
+#include "mathlib/mathlib.h"
+#include "materialsystem/materialsystem_config.h"
+#include "worldsize.h"
+#include "TransitionTable.h"
+#include "tier0/vcrmode.h"
+#include "tier0/vprof.h"
+#include "tier1/tier1.h"
+#include "tier1/utlbuffer.h"
+#include "vertexdecl.h"
+#include "tier0/icommandline.h"
+#include "IShaderSystem.h"
+#include "tier1/convar.h"
+#include "tier1/KeyValues.h"
+#include "Color.h"
+#ifdef RECORDING
+#include "materialsystem/IShader.h"
+#endif
+#include "../stdshaders/common_hlsl_cpp_consts.h" // hack hack hack!
+#include "KeyValues.h"
+#include "bitmap/imageformat.h"
+#include "materialsystem/idebugtextureinfo.h"
+#include "tier1/utllinkedlist.h"
+#include "vtf/vtf.h"
+#include "datacache/idatacache.h"
+#include "renderparm.h"
+#include "tier2/tier2.h"
+#include "materialsystem/deformations.h"
+#include "bitmap/tgawriter.h"
+#include "tier0/icommandline.h"
+#include "togl/rendermechanism.h" // provides GLMPRINTF/GLMPRINTSTR / GLMPRINTEXT macros which only activate if GLMDEBUG is nonzero and POSIX is defined.
+
+#if defined( _X360 )
+#include "xbox/xbox_console.h"
+#include "xbox/xbox_win32stubs.h"
+#include "xbox/xbox_launch.h"
+#endif
+#include "tier0/tslist.h"
+#ifndef _X360
+#include "wmi.h"
+#endif
+#include "filesystem/IQueuedLoader.h"
+#include "shaderdevicedx8.h"
+#include "togl/rendermechanism.h"
+
+// Define this if you want to use a stubbed d3d.
+//#define STUBD3D
+
+#ifdef STUBD3D
+#include "stubd3ddevice.h"
+#endif
+
+#include "winutils.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#if defined( OSX )
+ typedef unsigned int DWORD;
+ typedef DWORD* LPDWORD;
+#endif
+
+#ifdef _WIN32
+#pragma warning (disable:4189)
+#endif
+
+ConVar mat_texture_limit( "mat_texture_limit", "-1", FCVAR_NEVER_AS_STRING,
+ "If this value is not -1, the material system will limit the amount of texture memory it uses in a frame."
+ " Useful for identifying performance cliffs. The value is in kilobytes." );
+
+ConVar mat_frame_sync_enable( "mat_frame_sync_enable", "1", FCVAR_CHEAT );
+ConVar mat_frame_sync_force_texture( "mat_frame_sync_force_texture", "0", FCVAR_CHEAT, "Force frame syncing to lock a managed texture." );
+
+
+#if defined( _X360 )
+ConVar mat_texturecachesize( "mat_texturecachesize", "176" );
+ConVar mat_force_flush_texturecache( "mat_force_flush_texturecache", "0" );
+#endif
+
+extern ConVar mat_debugalttab;
+
+#define ALLOW_SMP_ACCESS 0
+
+#if ALLOW_SMP_ACCESS
+static ConVar mat_use_smp( "mat_use_smp", "0" );
+#endif
+
+// Convars for driving PIX (not all hooked up yet...JasonM)
+static ConVar r_pix_start( "r_pix_start", "0" );
+static ConVar r_pix_recordframes( "r_pix_recordframes", "0" );
+
+
+#define D3DDeviceWrapper IDirect3DDevice9
+
+//-----------------------------------------------------------------------------
+// Some important enumerations
+//-----------------------------------------------------------------------------
+enum
+{
+ MAX_VERTEX_TEXTURE_COUNT = 4,
+};
+
+
+//-----------------------------------------------------------------------------
+// These board states change with high frequency; are not shadowed
+//-----------------------------------------------------------------------------
+struct TextureStageState_t
+{
+ D3DTEXTURETRANSFORMFLAGS m_TextureTransformFlags;
+ float m_BumpEnvMat00;
+ float m_BumpEnvMat01;
+ float m_BumpEnvMat10;
+ float m_BumpEnvMat11;
+};
+
+struct SamplerState_t
+{
+ ShaderAPITextureHandle_t m_BoundTexture;
+ D3DTEXTUREADDRESS m_UTexWrap;
+ D3DTEXTUREADDRESS m_VTexWrap;
+ D3DTEXTUREADDRESS m_WTexWrap;
+ D3DTEXTUREFILTERTYPE m_MagFilter;
+ D3DTEXTUREFILTERTYPE m_MinFilter;
+ D3DTEXTUREFILTERTYPE m_MipFilter;
+ int m_FinestMipmapLevel;
+ float m_LodBias;
+ int m_nAnisotropicLevel;
+ bool m_TextureEnable;
+ bool m_SRGBReadEnable;
+};
+
+
+//-----------------------------------------------------------------------------
+// State related to vertex textures
+//-----------------------------------------------------------------------------
+struct VertexTextureState_t
+{
+ ShaderAPITextureHandle_t m_BoundTexture;
+ D3DTEXTUREADDRESS m_UTexWrap;
+ D3DTEXTUREADDRESS m_VTexWrap;
+ D3DTEXTUREFILTERTYPE m_MagFilter;
+ D3DTEXTUREFILTERTYPE m_MinFilter;
+ D3DTEXTUREFILTERTYPE m_MipFilter;
+};
+
+
+enum TransformType_t
+{
+ TRANSFORM_IS_IDENTITY = 0,
+ TRANSFORM_IS_CAMERA_TO_WORLD,
+ TRANSFORM_IS_GENERAL,
+};
+
+enum TransformDirtyBits_t
+{
+ STATE_CHANGED_VERTEX_SHADER = 0x1,
+ STATE_CHANGED_FIXED_FUNCTION = 0x2,
+ STATE_CHANGED = 0x3
+};
+
+enum
+{
+#if !defined( _X360 )
+ MAX_NUM_RENDERSTATES = ( D3DRS_BLENDOPALPHA+1 ),
+#else
+ MAX_NUM_RENDERSTATES = D3DRS_MAX,
+#endif
+// MORPH_TARGET_FACTOR_COUNT = VERTEX_SHADER_MORPH_TARGET_FACTOR_COUNT * 4,
+};
+
+struct DynamicState_t
+{
+ // Constant color
+ unsigned int m_ConstantColor;
+
+ // Normalize normals?
+ bool m_NormalizeNormals;
+
+ // Viewport state
+ D3DVIEWPORT9 m_Viewport;
+
+ // Transform state
+ D3DXMATRIX m_Transform[NUM_MATRIX_MODES];
+ unsigned char m_TransformType[NUM_MATRIX_MODES];
+ unsigned char m_TransformChanged[NUM_MATRIX_MODES];
+
+ // Ambient light color
+ D3DCOLOR m_Ambient;
+ D3DLIGHT m_Lights[MAX_NUM_LIGHTS];
+ LightDesc_t m_LightDescs[MAX_NUM_LIGHTS];
+ bool m_LightEnable[MAX_NUM_LIGHTS];
+ Vector4D m_AmbientLightCube[6];
+ unsigned char m_LightChanged[MAX_NUM_LIGHTS];
+ unsigned char m_LightEnableChanged[MAX_NUM_LIGHTS];
+ VertexShaderLightTypes_t m_LightType[MAX_NUM_LIGHTS];
+ Vector m_vLightingOrigin;
+ int m_NumLights;
+
+ // Shade mode
+ D3DSHADEMODE m_ShadeMode;
+
+ // Clear color
+ D3DCOLOR m_ClearColor;
+
+ // Fog
+ D3DCOLOR m_FogColor;
+ float m_PixelFogColor[4];
+ bool m_bFogGammaCorrectionDisabled;
+ bool m_FogEnable;
+ MaterialFogMode_t m_SceneFog;
+ D3DFOGMODE m_FogMode;
+ float m_FogStart;
+ float m_FogEnd;
+ float m_FogZ;
+ float m_FogMaxDensity;
+
+ float m_HeightClipZ;
+ MaterialHeightClipMode_t m_HeightClipMode;
+
+ // user clip planes
+ int m_UserClipPlaneEnabled;
+ int m_UserClipPlaneChanged;
+ D3DXPLANE m_UserClipPlaneWorld[MAXUSERCLIPPLANES];
+ D3DXPLANE m_UserClipPlaneProj[MAXUSERCLIPPLANES];
+ bool m_UserClipLastUpdatedUsingFixedFunction;
+
+ bool m_FastClipEnabled;
+ bool m_bFastClipPlaneChanged;
+ D3DXPLANE m_FastClipPlane;
+
+ // Used when overriding the user clip plane
+ bool m_bUserClipTransformOverride;
+ D3DXMATRIX m_UserClipTransform;
+
+ // Cull mode
+ D3DCULL m_DesiredCullMode;
+ D3DCULL m_CullMode;
+ bool m_bCullEnabled;
+
+ // Skinning
+ D3DVERTEXBLENDFLAGS m_VertexBlend;
+ int m_NumBones;
+
+ // Pixel and vertex shader constants...
+ Vector4D* m_pVectorVertexShaderConstant;
+ BOOL* m_pBooleanVertexShaderConstant;
+ IntVector4D* m_pIntegerVertexShaderConstant;
+ Vector4D* m_pVectorPixelShaderConstant;
+ BOOL* m_pBooleanPixelShaderConstant;
+ IntVector4D* m_pIntegerPixelShaderConstant;
+
+ // Texture stage state
+ TextureStageState_t m_TextureStage[MAX_TEXTURE_STAGES];
+ SamplerState_t m_SamplerState[MAX_SAMPLERS];
+
+ // Vertex texture stage state
+ VertexTextureState_t m_VertexTextureState[MAX_VERTEX_TEXTURE_COUNT];
+
+ DWORD m_RenderState[MAX_NUM_RENDERSTATES];
+
+ RECT m_ScissorRect;
+
+ IDirect3DVertexDeclaration9 *m_pVertexDecl;
+
+ bool m_bSRGBWritesEnabled;
+ bool m_bHWMorphingEnabled;
+
+ float m_DestAlphaDepthRange; //Dest alpha writes compress the depth to get better results. This holds the default setting that can be overriden with r_destalpharange
+
+#if defined( _X360 )
+ int m_iVertexShaderGPRAllocation; //only need to track vertex shader
+ bool m_bBuffer2Frames;
+#endif
+
+ DynamicState_t() {}
+
+private:
+ DynamicState_t( DynamicState_t const& );
+};
+
+//-----------------------------------------------------------------------------
+// Method to queue up dirty dynamic state change calls
+//-----------------------------------------------------------------------------
+typedef void (*StateCommitFunc_t)( IDirect3DDevice9 *pDevice, const DynamicState_t &desiredState, DynamicState_t &currentState, bool bForce );
+static void CommitSetViewports( IDirect3DDevice9 *pDevice, const DynamicState_t &desiredState, DynamicState_t &currentState, bool bForce );
+
+// NOTE: It's slightly memory inefficient, and definitely not typesafe,
+// to put all commit funcs into the same table (vs, ff, per-draw, per-pass),
+// but it makes the code a heck of a lot simpler and smaller.
+enum CommitFunc_t
+{
+ COMMIT_FUNC_CommitVertexTextures = 0,
+ COMMIT_FUNC_CommitFlexWeights,
+ COMMIT_FUNC_CommitSetScissorRect,
+ COMMIT_FUNC_CommitSetViewports,
+
+#if defined( _X360 )
+ COMMIT_FUNC_CommitShaderGPRs,
+#endif
+
+ COMMIT_FUNC_COUNT,
+ COMMIT_FUNC_BYTE_COUNT = ( COMMIT_FUNC_COUNT + 0x7 ) >> 3,
+};
+
+enum CommitFuncType_t
+{
+ COMMIT_PER_DRAW = 0,
+ COMMIT_PER_PASS,
+
+ COMMIT_FUNC_TYPE_COUNT,
+};
+
+enum CommitShaderType_t
+{
+ COMMIT_FIXED_FUNCTION = 0,
+ COMMIT_VERTEX_SHADER,
+ COMMIT_ALWAYS,
+
+ COMMIT_SHADER_TYPE_COUNT,
+};
+
+
+#define ADD_COMMIT_FUNC( _func, _shader, _func_name ) \
+ if ( !IsCommitFuncInUse( _func, _shader, COMMIT_FUNC_ ## _func_name ) ) \
+ { \
+ AddCommitFunc( _func, _shader, _func_name ); \
+ MarkCommitFuncInUse( _func, _shader, COMMIT_FUNC_ ## _func_name ); \
+ }
+
+#define ADD_RENDERSTATE_FUNC( _func, _shader, _func_name, _state, _val ) \
+ if ( m_bResettingRenderState || (m_DesiredState._state != _val) ) \
+ { \
+ m_DesiredState._state = _val; \
+ ADD_COMMIT_FUNC( _func, _shader, _func_name ) \
+ }
+
+#define ADD_VERTEX_TEXTURE_FUNC( _func, _shader, _func_name, _stage, _state, _val ) \
+ Assert( ( int )_stage < MAX_VERTEX_TEXTURE_COUNT ); \
+ if ( m_bResettingRenderState || (m_DesiredState.m_VertexTextureState[_stage]._state != _val) ) \
+ { \
+ m_DesiredState.m_VertexTextureState[_stage]._state = _val; \
+ ADD_COMMIT_FUNC( _func, _shader, _func_name ) \
+ }
+
+
+//-----------------------------------------------------------------------------
+// Check render state support at compile time instead of runtime
+//-----------------------------------------------------------------------------
+#define SetSupportedRenderState( _state, _val ) \
+ { \
+ if( _state != D3DRS_NOTSUPPORTED ) \
+ { \
+ SetRenderState( _state, _val, false ); \
+ } \
+ }
+
+#define SetSupportedRenderStateForce( _state, _val ) \
+ { \
+ if( _state != D3DRS_NOTSUPPORTED ) \
+ { \
+ SetRenderStateForce( _state, _val ); \
+ } \
+ }
+
+//-----------------------------------------------------------------------------
+// Allocated textures
+//-----------------------------------------------------------------------------
+struct Texture_t
+{
+ Texture_t()
+ {
+ m_Flags = 0;
+ m_Count = 1;
+ m_CountIndex = 0;
+ m_nTimesBoundMax = 0;
+ m_nTimesBoundThisFrame = 0;
+ m_pTexture = NULL;
+ m_ppTexture = NULL;
+ m_ImageFormat = IMAGE_FORMAT_RGBA8888;
+ m_pTextureGroupCounterGlobal = NULL;
+ m_pTextureGroupCounterFrame = NULL;
+ m_FinestMipmapLevel = 0;
+ m_LodBias = 0.0f;
+ }
+
+ // FIXME: Compress this info
+ D3DTEXTUREADDRESS m_UTexWrap;
+ D3DTEXTUREADDRESS m_VTexWrap;
+ D3DTEXTUREADDRESS m_WTexWrap;
+ D3DTEXTUREFILTERTYPE m_MagFilter;
+ D3DTEXTUREFILTERTYPE m_MinFilter;
+ D3DTEXTUREFILTERTYPE m_MipFilter;
+ int m_FinestMipmapLevel;
+ float m_LodBias;
+
+ unsigned char m_NumLevels;
+ unsigned char m_SwitchNeeded; // Do we need to advance the current copy?
+ unsigned char m_NumCopies; // copies are used to optimize procedural textures
+ unsigned char m_CurrentCopy; // the current copy we're using...
+
+ int m_CreationFlags;
+
+ CUtlSymbol m_DebugName;
+ CUtlSymbol m_TextureGroupName;
+ int *m_pTextureGroupCounterGlobal; // Global counter for this texture's group.
+ int *m_pTextureGroupCounterFrame; // Per-frame global counter for this texture's group.
+
+ // stats stuff
+ int m_SizeBytes;
+ int m_SizeTexels;
+ int m_LastBoundFrame;
+ int m_nTimesBoundMax;
+ int m_nTimesBoundThisFrame;
+
+ enum Flags_t
+ {
+ IS_ALLOCATED = 0x0001,
+ IS_DEPTH_STENCIL = 0x0002,
+ IS_DEPTH_STENCIL_TEXTURE = 0x0004, // depth stencil texture, not surface
+ IS_RENDERABLE = ( IS_DEPTH_STENCIL | IS_ALLOCATED ),
+ IS_LOCKABLE = 0x0008,
+ IS_FINALIZED = 0x0010, // 360: completed async hi-res load
+ IS_FAILED = 0x0020, // 360: failed during load
+ CAN_CONVERT_FORMAT = 0x0040, // 360: allow format conversion
+ IS_LINEAR = 0x0080, // 360: unswizzled linear format
+ IS_RENDER_TARGET = 0x0100, // 360: marks a render target texture source
+ IS_RENDER_TARGET_SURFACE = 0x0200, // 360: marks a render target surface target
+ IS_VERTEX_TEXTURE = 0x0800,
+ };
+
+ short m_Width;
+ short m_Height;
+ short m_Depth;
+ unsigned short m_Flags;
+
+ typedef IDirect3DBaseTexture *IDirect3DBaseTexturePtr;
+ typedef IDirect3DBaseTexture **IDirect3DBaseTexturePtrPtr;
+ typedef IDirect3DSurface *IDirect3DSurfacePtr;
+
+ IDirect3DBaseTexturePtr GetTexture( void )
+ {
+ Assert( m_NumCopies == 1 );
+ Assert( !( m_Flags & IS_DEPTH_STENCIL ) );
+ return m_pTexture;
+ }
+ IDirect3DBaseTexturePtr GetTexture( int copy )
+ {
+ Assert( m_NumCopies > 1 );
+ Assert( !( m_Flags & IS_DEPTH_STENCIL ) );
+ return m_ppTexture[copy];
+ }
+ IDirect3DBaseTexturePtrPtr &GetTextureArray( void )
+ {
+ Assert( m_NumCopies > 1 );
+ Assert( !( m_Flags & IS_DEPTH_STENCIL ) );
+ return m_ppTexture;
+ }
+
+ IDirect3DSurfacePtr &GetDepthStencilSurface( void )
+ {
+ Assert( m_NumCopies == 1 );
+ Assert( (m_Flags & IS_DEPTH_STENCIL) );
+ return m_pDepthStencilSurface;
+ }
+
+ IDirect3DSurfacePtr &GetRenderTargetSurface( bool bSRGB )
+ {
+ Assert( m_NumCopies == 1 );
+ Assert( m_Flags & IS_RENDER_TARGET_SURFACE );
+ return m_pRenderTargetSurface[bSRGB];
+ }
+
+ void SetTexture( IDirect3DBaseTexturePtr pPtr )
+ {
+ m_pTexture = pPtr;
+ }
+ void SetTexture( int copy, IDirect3DBaseTexturePtr pPtr )
+ {
+ m_ppTexture[copy] = pPtr;
+ }
+
+ int GetMemUsage() const
+ {
+ return m_SizeBytes;
+ }
+
+ int GetWidth() const
+ {
+ return ( int )m_Width;
+ }
+
+ int GetHeight() const
+ {
+ return ( int )m_Height;
+ }
+
+ int GetDepth() const
+ {
+ return ( int )m_Depth;
+ }
+
+ int GetLodClamp() const
+ {
+ return m_FinestMipmapLevel;
+ }
+
+ void SetImageFormat( ImageFormat format )
+ {
+ m_ImageFormat = format;
+ }
+ ImageFormat GetImageFormat() const
+ {
+ return m_ImageFormat;
+ }
+
+private:
+ union
+ {
+ IDirect3DBaseTexture *m_pTexture; // used when there's one copy
+ IDirect3DBaseTexture **m_ppTexture; // used when there are more than one copies
+ IDirect3DSurface *m_pDepthStencilSurface; // used when there's one depth stencil surface
+ IDirect3DSurface *m_pRenderTargetSurface[2];
+ };
+
+ ImageFormat m_ImageFormat;
+
+public:
+ short m_Count;
+ short m_CountIndex;
+
+ short GetCount() const
+ {
+ return m_Count;
+ }
+};
+
+#define MAX_DEFORMATION_PARAMETERS 16
+#define DEFORMATION_STACK_DEPTH 10
+
+struct Deformation_t
+{
+ int m_nDeformationType;
+ int m_nNumParameters;
+ float m_flDeformationParameters[MAX_DEFORMATION_PARAMETERS];
+};
+
+
+//-----------------------------------------------------------------------------
+// The DX8 implementation of the shader API
+//-----------------------------------------------------------------------------
+class CShaderAPIDx8 : public CShaderDeviceDx8, public IShaderAPIDX8, public IDebugTextureInfo
+{
+ typedef CShaderDeviceDx8 BaseClass;
+
+public:
+ // constructor, destructor
+ CShaderAPIDx8( );
+ virtual ~CShaderAPIDx8();
+
+ // Methods of IShaderAPI
+public:
+ virtual void SetViewports( int nCount, const ShaderViewport_t* pViewports );
+ virtual int GetViewports( ShaderViewport_t* pViewports, int nMax ) const;
+ virtual void ClearBuffers( bool bClearColor, bool bClearDepth, bool bClearStencil, int renderTargetWidth, int renderTargetHeight );
+ virtual void ClearColor3ub( unsigned char r, unsigned char g, unsigned char b );
+ virtual void ClearColor4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a );
+ virtual void BindVertexShader( VertexShaderHandle_t hVertexShader );
+ virtual void BindGeometryShader( GeometryShaderHandle_t hGeometryShader );
+ virtual void BindPixelShader( PixelShaderHandle_t hPixelShader );
+ virtual void SetRasterState( const ShaderRasterState_t& state );
+ virtual void SetFlexWeights( int nFirstWeight, int nCount, const MorphWeight_t* pWeights );
+
+ // Methods of IShaderDynamicAPI
+public:
+ virtual void GetBackBufferDimensions( int &nWidth, int &nHeight ) const
+ {
+ // Chain to the device
+ BaseClass::GetBackBufferDimensions( nWidth, nHeight );
+ }
+ virtual void MarkUnusedVertexFields( unsigned int nFlags, int nTexCoordCount, bool *pUnusedTexCoords );
+
+public:
+ // Methods of CShaderAPIBase
+ virtual bool OnDeviceInit();
+ virtual void OnDeviceShutdown();
+ virtual void ReleaseShaderObjects();
+ virtual void RestoreShaderObjects();
+ virtual void BeginPIXEvent( unsigned long color, const char *szName );
+ virtual void EndPIXEvent();
+ virtual void AdvancePIXFrame();
+
+public:
+ // Methods of IShaderAPIDX8
+ virtual void QueueResetRenderState();
+
+ //
+ // Abandon all hope ye who pass below this line which hasn't been ported.
+ //
+
+ // Sets the mode...
+ bool SetMode( void* VD3DHWND, int nAdapter, const ShaderDeviceInfo_t &info );
+
+ // Change the video mode after it's already been set.
+ void ChangeVideoMode( const ShaderDeviceInfo_t &info );
+
+ // Sets the default render state
+ void SetDefaultState();
+
+ // Methods to ask about particular state snapshots
+ virtual bool IsTranslucent( StateSnapshot_t id ) const;
+ virtual bool IsAlphaTested( StateSnapshot_t id ) const;
+ virtual bool UsesVertexAndPixelShaders( StateSnapshot_t id ) const;
+ virtual int CompareSnapshots( StateSnapshot_t snapshot0, StateSnapshot_t snapshot1 );
+
+ // Computes the vertex format for a particular set of snapshot ids
+ VertexFormat_t ComputeVertexFormat( int num, StateSnapshot_t* pIds ) const;
+ VertexFormat_t ComputeVertexUsage( int num, StateSnapshot_t* pIds ) const;
+
+ // What fields in the morph do we actually use?
+ virtual MorphFormat_t ComputeMorphFormat( int numSnapshots, StateSnapshot_t* pIds ) const;
+
+ // Uses a state snapshot
+ void UseSnapshot( StateSnapshot_t snapshot );
+
+ // Color state
+ void Color3f( float r, float g, float b );
+ void Color4f( float r, float g, float b, float a );
+ void Color3fv( float const* c );
+ void Color4fv( float const* c );
+
+ void Color3ub( unsigned char r, unsigned char g, unsigned char b );
+ void Color3ubv( unsigned char const* pColor );
+ void Color4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a );
+ void Color4ubv( unsigned char const* pColor );
+
+ // Set the number of bone weights
+ virtual void SetNumBoneWeights( int numBones );
+ virtual void EnableHWMorphing( bool bEnable );
+
+ // Sets the vertex and pixel shaders
+ virtual void SetVertexShaderIndex( int vshIndex = -1 );
+ virtual void SetPixelShaderIndex( int pshIndex = 0 );
+
+ // Matrix state
+ void MatrixMode( MaterialMatrixMode_t matrixMode );
+ void PushMatrix();
+ void PopMatrix();
+ void LoadMatrix( float *m );
+ void LoadBoneMatrix( int boneIndex, const float *m );
+ void MultMatrix( float *m );
+ void MultMatrixLocal( float *m );
+ void GetMatrix( MaterialMatrixMode_t matrixMode, float *dst );
+ void LoadIdentity( void );
+ void LoadCameraToWorld( void );
+ void Ortho( double left, double top, double right, double bottom, double zNear, double zFar );
+ void PerspectiveX( double fovx, double aspect, double zNear, double zFar );
+ void PerspectiveOffCenterX( double fovx, double aspect, double zNear, double zFar, double bottom, double top, double left, double right );
+ void PickMatrix( int x, int y, int width, int height );
+ void Rotate( float angle, float x, float y, float z );
+ void Translate( float x, float y, float z );
+ void Scale( float x, float y, float z );
+ void ScaleXY( float x, float y );
+
+ // Binds a particular material to render with
+ void Bind( IMaterial* pMaterial );
+ IMaterialInternal* GetBoundMaterial();
+
+ // Level of anisotropic filtering
+ virtual void SetAnisotropicLevel( int nAnisotropyLevel );
+
+ virtual void SyncToken( const char *pToken );
+
+ // Cull mode
+ void CullMode( MaterialCullMode_t cullMode );
+
+ // Force writes only when z matches. . . useful for stenciling things out
+ // by rendering the desired Z values ahead of time.
+ void ForceDepthFuncEquals( bool bEnable );
+
+ // Turns off Z buffering
+ void OverrideDepthEnable( bool bEnable, bool bDepthEnable );
+
+ void OverrideAlphaWriteEnable( bool bOverrideEnable, bool bAlphaWriteEnable );
+ void OverrideColorWriteEnable( bool bOverrideEnable, bool bColorWriteEnable );
+
+ void SetHeightClipZ( float z );
+ void SetHeightClipMode( enum MaterialHeightClipMode_t heightClipMode );
+
+ void SetClipPlane( int index, const float *pPlane );
+ void EnableClipPlane( int index, bool bEnable );
+
+ void SetFastClipPlane(const float *pPlane);
+ void EnableFastClip(bool bEnable);
+
+ // The shade mode
+ void ShadeMode( ShaderShadeMode_t mode );
+
+ // Vertex blend state
+ void SetVertexBlendState( int numBones );
+
+ // Gets the dynamic mesh
+ IMesh* GetDynamicMesh( IMaterial* pMaterial, int nHWSkinBoneCount, bool buffered,
+ IMesh* pVertexOverride, IMesh* pIndexOverride );
+ IMesh* GetDynamicMeshEx( IMaterial* pMaterial, VertexFormat_t vertexFormat, int nHWSkinBoneCount,
+ bool bBuffered, IMesh* pVertexOverride, IMesh* pIndexOverride );
+ IMesh *GetFlexMesh();
+
+ // Returns the number of vertices we can render using the dynamic mesh
+ virtual void GetMaxToRender( IMesh *pMesh, bool bMaxUntilFlush, int *pMaxVerts, int *pMaxIndices );
+ virtual int GetMaxVerticesToRender( IMaterial *pMaterial );
+ virtual int GetMaxIndicesToRender( );
+
+ // Draws the mesh
+ void DrawMesh( CMeshBase* mesh );
+
+ // modifies the vertex data when necessary
+ void ModifyVertexData( );
+
+ // Draws
+ void BeginPass( StateSnapshot_t snapshot );
+ void RenderPass( int nPass, int nPassCount );
+
+ // We use smaller dynamic VBs during level transitions, to free up memory
+ virtual int GetCurrentDynamicVBSize( void );
+ virtual void DestroyVertexBuffers( bool bExitingLevel = false );
+
+ void SetVertexDecl( VertexFormat_t vertexFormat, bool bHasColorMesh, bool bUsingFlex, bool bUsingMorph );
+
+ // Sets the constant register for vertex and pixel shaders
+ FORCEINLINE void SetVertexShaderConstantInternal( int var, float const* pVec, int numVecs = 1, bool bForce = false );
+
+ void SetVertexShaderConstant( int var, float const* pVec, int numVecs = 1, bool bForce = false );
+ void SetBooleanVertexShaderConstant( int var, BOOL const* pVec, int numBools = 1, bool bForce = false );
+ void SetIntegerVertexShaderConstant( int var, int const* pVec, int numIntVecs = 1, bool bForce = false );
+
+ void SetPixelShaderConstant( int var, float const* pVec, int numVecs = 1, bool bForce = false );
+ FORCEINLINE void SetPixelShaderConstantInternal( int var, float const* pValues, int nNumConsts, bool bForce );
+
+ void SetBooleanPixelShaderConstant( int var, BOOL const* pVec, int numBools = 1, bool bForce = false );
+ void SetIntegerPixelShaderConstant( int var, int const* pVec, int numIntVecs = 1, bool bForce = false );
+
+ void InvalidateDelayedShaderConstants( void );
+
+ // Returns the nearest supported format
+ ImageFormat GetNearestSupportedFormat( ImageFormat fmt, bool bFilteringRequired = true ) const;
+ ImageFormat GetNearestRenderTargetFormat( ImageFormat format ) const;
+ virtual bool DoRenderTargetsNeedSeparateDepthBuffer() const;
+
+ // stuff that shouldn't be used from within a shader
+ void ModifyTexture( ShaderAPITextureHandle_t textureHandle );
+ void BindTexture( Sampler_t sampler, ShaderAPITextureHandle_t textureHandle );
+ virtual void BindVertexTexture( VertexTextureSampler_t nStage, ShaderAPITextureHandle_t textureHandle );
+ void DeleteTexture( ShaderAPITextureHandle_t textureHandle );
+
+ void WriteTextureToFile( ShaderAPITextureHandle_t hTexture, const char *szFileName );
+
+ bool IsTexture( ShaderAPITextureHandle_t textureHandle );
+ bool IsTextureResident( ShaderAPITextureHandle_t textureHandle );
+ FORCEINLINE bool TextureIsAllocated( ShaderAPITextureHandle_t hTexture )
+ {
+ return m_Textures.IsValidIndex( hTexture ) && ( GetTexture( hTexture ).m_Flags & Texture_t::IS_ALLOCATED );
+ }
+ FORCEINLINE void AssertValidTextureHandle( ShaderAPITextureHandle_t textureHandle )
+ {
+#ifdef _DEBUG
+ Assert( TextureIsAllocated( textureHandle ) );
+#endif
+ }
+
+ // Lets the shader know about the full-screen texture so it can
+ virtual void SetFullScreenTextureHandle( ShaderAPITextureHandle_t h );
+
+ virtual void SetLinearToGammaConversionTextures( ShaderAPITextureHandle_t hSRGBWriteEnabledTexture, ShaderAPITextureHandle_t hIdentityTexture );
+
+ // Set the render target to a texID.
+ // Set to SHADER_RENDERTARGET_BACKBUFFER if you want to use the regular framebuffer.
+ void SetRenderTarget( ShaderAPITextureHandle_t colorTextureHandle = SHADER_RENDERTARGET_BACKBUFFER,
+ ShaderAPITextureHandle_t depthTextureHandle = SHADER_RENDERTARGET_DEPTHBUFFER );
+ // Set the render target to a texID.
+ // Set to SHADER_RENDERTARGET_BACKBUFFER if you want to use the regular framebuffer.
+ void SetRenderTargetEx( int nRenderTargetID, ShaderAPITextureHandle_t colorTextureHandle = SHADER_RENDERTARGET_BACKBUFFER,
+ ShaderAPITextureHandle_t depthTextureHandle = SHADER_RENDERTARGET_DEPTHBUFFER );
+
+ // These are bound to the texture, not the texture environment
+ void TexMinFilter( ShaderTexFilterMode_t texFilterMode );
+ void TexMagFilter( ShaderTexFilterMode_t texFilterMode );
+ void TexWrap( ShaderTexCoordComponent_t coord, ShaderTexWrapMode_t wrapMode );
+ void TexSetPriority( int priority );
+ void TexLodClamp( int finest );
+ void TexLodBias( float bias );
+
+ ShaderAPITextureHandle_t CreateTextureHandle( void );
+ void CreateTextureHandles( ShaderAPITextureHandle_t *handles, int count );
+
+ ShaderAPITextureHandle_t CreateTexture(
+ int width,
+ int height,
+ int depth,
+ ImageFormat dstImageFormat,
+ int numMipLevels,
+ int numCopies,
+ int creationFlags,
+ const char *pDebugName,
+ const char *pTextureGroupName );
+
+ // Create a multi-frame texture (equivalent to calling "CreateTexture" multiple times, but more efficient)
+ void CreateTextures(
+ ShaderAPITextureHandle_t *pHandles,
+ int count,
+ int width,
+ int height,
+ int depth,
+ ImageFormat dstImageFormat,
+ int numMipLevels,
+ int numCopies,
+ int flags,
+ const char *pDebugName,
+ const char *pTextureGroupName );
+
+ ShaderAPITextureHandle_t CreateDepthTexture(
+ ImageFormat renderTargetFormat,
+ int width,
+ int height,
+ const char *pDebugName,
+ bool bTexture );
+
+ void TexImage2D(
+ int level,
+ int cubeFaceID,
+ ImageFormat dstFormat,
+ int zOffset,
+ int width,
+ int height,
+ ImageFormat srcFormat,
+ bool bSrcIsTiled,
+ void *imageData );
+
+ void TexSubImage2D(
+ int level,
+ int cubeFaceID,
+ int xOffset,
+ int yOffset,
+ int zOffset,
+ int width,
+ int height,
+ ImageFormat srcFormat,
+ int srcStride,
+ bool bSrcIsTiled,
+ void *imageData );
+
+ void TexImageFromVTF( IVTFTexture *pVTF, int iVTFFrame );
+
+ bool TexLock( int level, int cubeFaceID, int xOffset, int yOffset, int width, int height, CPixelWriter& writer );
+ void TexUnlock( );
+
+ // stuff that isn't to be used from within a shader
+ // what's the best way to hide this? subclassing?
+ virtual void ClearBuffersObeyStencil( bool bClearColor, bool bClearDepth );
+ virtual void ClearBuffersObeyStencilEx( bool bClearColor, bool bClearAlpha, bool bClearDepth );
+ virtual void PerformFullScreenStencilOperation( void );
+ void ReadPixels( int x, int y, int width, int height, unsigned char *data, ImageFormat dstFormat );
+ virtual void ReadPixels( Rect_t *pSrcRect, Rect_t *pDstRect, unsigned char *data, ImageFormat dstFormat, int nDstStride );
+
+ // Gets the current buffered state... (debug only)
+ void GetBufferedState( BufferedState_t& state );
+
+ // Buffered primitives
+ void FlushBufferedPrimitives();
+ void FlushBufferedPrimitivesInternal( );
+
+ // Make sure we finish drawing everything that has been requested
+ void FlushHardware();
+
+ // Use this to begin and end the frame
+ void BeginFrame();
+ void EndFrame();
+
+ // Used to clear the transition table when we know it's become invalid.
+ void ClearSnapshots();
+
+ // Backward compat
+ virtual int GetActualTextureStageCount() const;
+ virtual int GetActualSamplerCount() const;
+ virtual int StencilBufferBits() const;
+ virtual bool IsAAEnabled() const; // Is antialiasing being used?
+ virtual bool OnAdapterSet( );
+ bool m_bAdapterSet;
+
+ void UpdateFastClipUserClipPlane( void );
+ bool ReadPixelsFromFrontBuffer() const;
+
+ // returns the current time in seconds....
+ double CurrentTime() const;
+
+ // Get the current camera position in world space.
+ void GetWorldSpaceCameraPosition( float* pPos ) const;
+
+ // Fog methods
+ void FogMode( MaterialFogMode_t fogMode );
+ void FogStart( float fStart );
+ void FogEnd( float fEnd );
+ void FogMaxDensity( float flMaxDensity );
+ void SetFogZ( float fogZ );
+ void GetFogDistances( float *fStart, float *fEnd, float *fFogZ );
+
+ void SceneFogMode( MaterialFogMode_t fogMode );
+ MaterialFogMode_t GetSceneFogMode( );
+ MaterialFogMode_t GetPixelFogMode( );
+ int GetPixelFogCombo( );//0 is either range fog, or no fog simulated with rigged range fog values. 1 is height fog
+ bool ShouldUsePixelFogForMode( MaterialFogMode_t fogMode );
+ void SceneFogColor3ub( unsigned char r, unsigned char g, unsigned char b );
+ void GetSceneFogColor( unsigned char *rgb );
+ void GetSceneFogColor( unsigned char *r, unsigned char *g, unsigned char *b );
+
+ // Selection mode methods
+ int SelectionMode( bool selectionMode );
+ void SelectionBuffer( unsigned int* pBuffer, int size );
+ void ClearSelectionNames( );
+ void LoadSelectionName( int name );
+ void PushSelectionName( int name );
+ void PopSelectionName();
+ bool IsInSelectionMode() const;
+ void RegisterSelectionHit( float minz, float maxz );
+ void WriteHitRecord();
+
+ // Binds a standard texture
+ virtual void BindStandardTexture( Sampler_t sampler, StandardTextureId_t id );
+ virtual void BindStandardVertexTexture( VertexTextureSampler_t sampler, StandardTextureId_t id );
+ virtual void GetStandardTextureDimensions( int *pWidth, int *pHeight, StandardTextureId_t id );
+
+ // Gets the lightmap dimensions
+ virtual void GetLightmapDimensions( int *w, int *h );
+
+ // Use this to get the mesh builder that allows us to modify vertex data
+ CMeshBuilder* GetVertexModifyBuilder();
+
+ virtual bool InFlashlightMode() const;
+ virtual bool InEditorMode() const;
+
+ // Gets the bound morph's vertex format; returns 0 if no morph is bound
+ virtual MorphFormat_t GetBoundMorphFormat();
+
+ // Helper to get at the texture state stage
+ TextureStageState_t& TextureStage( int stage ) { return m_DynamicState.m_TextureStage[stage]; }
+ const TextureStageState_t& TextureStage( int stage ) const { return m_DynamicState.m_TextureStage[stage]; }
+ SamplerState_t& SamplerState( int nSampler ) { return m_DynamicState.m_SamplerState[nSampler]; }
+ const SamplerState_t& SamplerState( int nSampler ) const { return m_DynamicState.m_SamplerState[nSampler]; }
+
+ void SetAmbientLight( float r, float g, float b );
+ void SetLight( int lightNum, const LightDesc_t& desc );
+ void SetLightingOrigin( Vector vLightingOrigin );
+ void DisableAllLocalLights();
+ void SetAmbientLightCube( Vector4D colors[6] );
+ float GetAmbientLightCubeLuminance( void );
+
+ int GetMaxLights( void ) const;
+ const LightDesc_t& GetLight( int lightNum ) const;
+
+ void SetVertexShaderStateAmbientLightCube();
+ void SetPixelShaderStateAmbientLightCube( int pshReg, bool bForceToBlack = false );
+
+ void CopyRenderTargetToTexture( ShaderAPITextureHandle_t textureHandle );
+ void CopyRenderTargetToTextureEx( ShaderAPITextureHandle_t textureHandle, int nRenderTargetID, Rect_t *pSrcRect = NULL, Rect_t *pDstRect = NULL );
+ void CopyTextureToRenderTargetEx( int nRenderTargetID, ShaderAPITextureHandle_t textureHandle, Rect_t *pSrcRect = NULL, Rect_t *pDstRect = NULL );
+ void CopyRenderTargetToScratchTexture( ShaderAPITextureHandle_t srcHandle, ShaderAPITextureHandle_t dstHandle, Rect_t *pSrcRect = NULL, Rect_t *pDstRect = NULL );
+
+ virtual void LockRect( void** pOutBits, int* pOutPitch, ShaderAPITextureHandle_t texHandle, int mipmap, int x, int y, int w, int h, bool bWrite, bool bRead );
+ virtual void UnlockRect( ShaderAPITextureHandle_t texHandle, int mipmap );
+
+ virtual void CopyTextureToTexture( ShaderAPITextureHandle_t srcTex, ShaderAPITextureHandle_t dstTex );
+
+ // Returns the cull mode (for fill rate computation)
+ D3DCULL GetCullMode() const;
+ void SetCullModeState( bool bEnable, D3DCULL nDesiredCullMode );
+ void ApplyCullEnable( bool bEnable );
+
+ // Alpha to coverage
+ void ApplyAlphaToCoverage( bool bEnable );
+
+#if defined( _X360 )
+ void ApplySRGBReadState( int iTextureStage, bool bSRGBReadEnabled );
+#endif
+
+ // Applies Z Bias
+ void ApplyZBias( const ShadowState_t& shaderState );
+
+ // Applies texture enable
+ void ApplyTextureEnable( const ShadowState_t& state, int stage );
+
+ void ApplyFogMode( ShaderFogMode_t fogMode, bool bSRGBWritesEnabled, bool bDisableFogGammaCorrection );
+ void UpdatePixelFogColorConstant( void );
+
+ void EnabledSRGBWrite( bool bEnabled );
+
+ // Gamma<->Linear conversions according to the video hardware we're running on
+ float GammaToLinear_HardwareSpecific( float fGamma ) const;
+ float LinearToGamma_HardwareSpecific( float fLinear ) const;
+
+ // Applies alpha blending
+ void ApplyAlphaBlend( bool bEnable, D3DBLEND srcBlend, D3DBLEND destBlend );
+
+ // Applies alpha texture op
+ void ApplyColorTextureStage( int stage, D3DTEXTUREOP op, int arg1, int arg2 );
+ void ApplyAlphaTextureStage( int stage, D3DTEXTUREOP op, int arg1, int arg2 );
+
+ // Sets texture stage stage + render stage state
+ void SetSamplerState( int stage, D3DSAMPLERSTATETYPE state, DWORD val );
+ void SetTextureStageState( int stage, D3DTEXTURESTAGESTATETYPE state, DWORD val);
+ void SetRenderStateForce( D3DRENDERSTATETYPE state, DWORD val );
+ void SetRenderState( D3DRENDERSTATETYPE state, DWORD val,
+ bool bFlushBufferedPrimitivesIfChanged = false);
+
+ // Scissor Rect
+ void SetScissorRect( const int nLeft, const int nTop, const int nRight, const int nBottom, const bool bEnableScissor );
+ // Can we download textures?
+ virtual bool CanDownloadTextures() const;
+
+ void ForceHardwareSync_WithManagedTexture();
+ void ForceHardwareSync( void );
+ void UpdateFrameSyncQuery( int queryIndex, bool bIssue );
+
+ void EvictManagedResources();
+
+ virtual void EvictManagedResourcesInternal();
+
+ // Gets at a particular transform
+ inline D3DXMATRIX& GetTransform( int i )
+ {
+ return *m_pMatrixStack[i]->GetTop();
+ }
+
+ int GetCurrentNumBones( void ) const;
+ bool IsHWMorphingEnabled( ) const;
+ int GetCurrentLightCombo( void ) const; // Used for DX8 only
+ void GetDX9LightState( LightState_t *state ) const; // Used for DX9 only
+
+ MaterialFogMode_t GetCurrentFogType( void ) const;
+
+ void RecordString( const char *pStr );
+
+ virtual bool IsRenderingMesh() const { return m_pRenderMesh != 0; }
+
+ void SetTextureTransformDimension( TextureStage_t textureStage, int dimension, bool projected );
+ void DisableTextureTransform( TextureStage_t textureMatrix );
+ void SetBumpEnvMatrix( TextureStage_t textureStage, float m00, float m01, float m10, float m11 );
+
+ int GetCurrentFrameCounter( void ) const
+ {
+ return m_CurrentFrame;
+ }
+
+ // Workaround hack for visualization of selection mode
+ virtual void SetupSelectionModeVisualizationState();
+
+ // Allocate and delete query objects.
+ virtual ShaderAPIOcclusionQuery_t CreateOcclusionQueryObject( void );
+ virtual void DestroyOcclusionQueryObject( ShaderAPIOcclusionQuery_t h );
+
+ // Bracket drawing with begin and end so that we can get counts next frame.
+ virtual void BeginOcclusionQueryDrawing( ShaderAPIOcclusionQuery_t h );
+ virtual void EndOcclusionQueryDrawing( ShaderAPIOcclusionQuery_t h );
+
+ // Get the number of pixels rendered between begin and end on an earlier frame.
+ // Calling this in the same frame is a huge perf hit!
+ virtual int OcclusionQuery_GetNumPixelsRendered( ShaderAPIOcclusionQuery_t h, bool bFlush );
+
+ void SetFlashlightState( const FlashlightState_t &state, const VMatrix &worldToTexture );
+ void SetFlashlightStateEx( const FlashlightState_t &state, const VMatrix &worldToTexture, ITexture *pFlashlightDepthTexture );
+ const FlashlightState_t &GetFlashlightState( VMatrix &worldToTexture ) const;
+ const FlashlightState_t &GetFlashlightStateEx( VMatrix &worldToTexture, ITexture **pFlashlightDepthTexture ) const;
+
+ // Gets at the shadow state for a particular state snapshot
+ virtual bool IsDepthWriteEnabled( StateSnapshot_t id ) const;
+
+// IDebugTextureInfo implementation.
+
+ virtual bool IsDebugTextureListFresh( int numFramesAllowed = 1 );
+ virtual void EnableDebugTextureList( bool bEnable );
+ virtual bool SetDebugTextureRendering( bool bEnable );
+ virtual void EnableGetAllTextures( bool bEnable );
+ virtual KeyValues* GetDebugTextureList();
+ virtual int GetTextureMemoryUsed( TextureMemoryType eTextureMemory );
+
+ virtual void ClearVertexAndPixelShaderRefCounts();
+ virtual void PurgeUnusedVertexAndPixelShaders();
+
+ // Called when the dx support level has changed
+ virtual void DXSupportLevelChanged();
+
+ // User clip plane override
+ virtual void EnableUserClipTransformOverride( bool bEnable );
+ virtual void UserClipTransform( const VMatrix &worldToProjection );
+
+ bool UsingSoftwareVertexProcessing() const;
+
+ // Mark all user clip planes as being dirty
+ void MarkAllUserClipPlanesDirty();
+
+ // Converts a D3DXMatrix to a VMatrix and back
+ void D3DXMatrixToVMatrix( const D3DXMATRIX &in, VMatrix &out );
+ void VMatrixToD3DXMatrix( const VMatrix &in, D3DXMATRIX &out );
+
+ ITexture *GetRenderTargetEx( int nRenderTargetID );
+
+ virtual void SetToneMappingScaleLinear( const Vector &scale );
+ virtual const Vector &GetToneMappingScaleLinear( void ) const;
+ float GetLightMapScaleFactor( void ) const;
+
+ void SetFloatRenderingParameter(int parm_number, float value);
+
+ void SetIntRenderingParameter(int parm_number, int value);
+ void SetVectorRenderingParameter(int parm_number, Vector const &value);
+
+ float GetFloatRenderingParameter(int parm_number) const;
+
+ int GetIntRenderingParameter(int parm_number) const;
+
+ Vector GetVectorRenderingParameter(int parm_number) const;
+
+ // For dealing with device lost in cases where Present isn't called all the time (Hammer)
+ virtual void HandleDeviceLost();
+
+ virtual void EnableLinearColorSpaceFrameBuffer( bool bEnable );
+
+ virtual void SetPSNearAndFarZ( int pshReg );
+
+ // stencil methods
+ void SetStencilEnable(bool onoff);
+ void SetStencilFailOperation(StencilOperation_t op);
+ void SetStencilZFailOperation(StencilOperation_t op);
+ void SetStencilPassOperation(StencilOperation_t op);
+ void SetStencilCompareFunction(StencilComparisonFunction_t cmpfn);
+ void SetStencilReferenceValue(int ref);
+ void SetStencilTestMask(uint32 msk);
+ void SetStencilWriteMask(uint32 msk);
+ void ClearStencilBufferRectangle(int xmin, int ymin, int xmax, int ymax,int value);
+
+ virtual void GetDXLevelDefaults(uint &max_dxlevel,uint &recommended_dxlevel);
+
+#if defined( _X360 )
+ HXUIFONT OpenTrueTypeFont( const char *pFontname, int tall, int style );
+ void CloseTrueTypeFont( HXUIFONT hFont );
+ bool GetTrueTypeFontMetrics( HXUIFONT hFont, XUIFontMetrics *pFontMetrics, XUICharMetrics charMetrics[256] );
+ // Render a sequence of characters and extract the data into a buffer
+ // For each character, provide the width+height of the font texture subrect,
+ // an offset to apply when rendering the glyph, and an offset into a buffer to receive the RGBA data
+ bool GetTrueTypeGlyphs( HXUIFONT hFont, int numChars, wchar_t *pWch, int *pOffsetX, int *pOffsetY, int *pWidth, int *pHeight, unsigned char *pRGBA, int *pRGBAOffset );
+ ShaderAPITextureHandle_t CreateRenderTargetSurface( int width, int height, ImageFormat format, const char *pDebugName, const char *pTextureGroupName );
+ void PersistDisplay();
+ bool PostQueuedTexture( const void *pData, int nSize, ShaderAPITextureHandle_t *pHandles, int nHandles, int nWidth, int nHeight, int nDepth, int nMips, int *pRefCount );
+ void *GetD3DDevice();
+
+ void PushVertexShaderGPRAllocation( int iVertexShaderCount = 64 );
+ void PopVertexShaderGPRAllocation( void );
+
+ void EnableVSync_360( bool bEnable );
+#endif
+
+ virtual bool OwnGPUResources( bool bEnable );
+
+// ------------ New Vertex/Index Buffer interface ----------------------------
+ void BindVertexBuffer( int streamID, IVertexBuffer *pVertexBuffer, int nOffsetInBytes, int nFirstVertex, int nVertexCount, VertexFormat_t fmt, int nRepetitions = 1 );
+ void BindIndexBuffer( IIndexBuffer *pIndexBuffer, int nOffsetInBytes );
+ void Draw( MaterialPrimitiveType_t primitiveType, int nFirstIndex, int nIndexCount );
+
+ // Draw the mesh with the currently bound vertex and index buffers.
+ void DrawWithVertexAndIndexBuffers( void );
+// ------------ End ----------------------------
+
+ // deformations
+ virtual void PushDeformation( const DeformationBase_t *pDeformation );
+ virtual void PopDeformation( );
+ virtual int GetNumActiveDeformations( ) const ;
+
+
+ // for shaders to set vertex shader constants. returns a packed state which can be used to set the dynamic combo
+ virtual int GetPackedDeformationInformation( int nMaskOfUnderstoodDeformations,
+ float *pConstantValuesOut,
+ int nBufferSize,
+ int nMaximumDeformations,
+ int *pNumDefsOut ) const ;
+
+ inline Texture_t &GetTexture( ShaderAPITextureHandle_t hTexture )
+ {
+ return m_Textures[hTexture];
+ }
+
+ // Gets the texture
+ IDirect3DBaseTexture* GetD3DTexture( ShaderAPITextureHandle_t hTexture );
+
+
+ virtual bool ShouldWriteDepthToDestAlpha( void ) const;
+
+ virtual void AcquireThreadOwnership();
+ virtual void ReleaseThreadOwnership();
+private:
+ enum
+ {
+ SMALL_BACK_BUFFER_SURFACE_WIDTH = 256,
+ SMALL_BACK_BUFFER_SURFACE_HEIGHT = 256,
+ };
+
+ bool m_bEnableDebugTextureList;
+ bool m_bDebugGetAllTextures;
+ bool m_bDebugTexturesRendering;
+ KeyValues *m_pDebugTextureList;
+ int m_nTextureMemoryUsedLastFrame, m_nTextureMemoryUsedTotal;
+ int m_nTextureMemoryUsedPicMip1, m_nTextureMemoryUsedPicMip2;
+ int m_nDebugDataExportFrame;
+
+ FlashlightState_t m_FlashlightState;
+ VMatrix m_FlashlightWorldToTexture;
+ ITexture *m_pFlashlightDepthTexture;
+
+ CShaderAPIDx8( CShaderAPIDx8 const& );
+
+ enum
+ {
+ INVALID_TRANSITION_OP = 0xFFFF
+ };
+
+ // State transition table for the device is as follows:
+
+ // Other app init causes transition from OK to OtherAppInit, during transition we must release resources
+ // !Other app init causes transition from OtherAppInit to OK, during transition we must restore resources
+ // Minimized or device lost or device not reset causes transition from OK to LOST_DEVICE, during transition we must release resources
+ // Minimized or device lost or device not reset causes transition from OtherAppInit to LOST_DEVICE
+
+ // !minimized AND !device lost causes transition from LOST_DEVICE to NEEDS_RESET
+ // minimized or device lost causes transition from NEEDS_RESET to LOST_DEVICE
+
+ // Successful TryDeviceReset and !Other app init causes transition from NEEDS_RESET to OK, during transition we must restore resources
+ // Successful TryDeviceReset and Other app init causes transition from NEEDS_RESET to OtherAppInit
+
+ void ExportTextureList();
+ void AddBufferToTextureList( const char *pName, D3DSURFACE_DESC &desc );
+
+ void SetupTextureGroup( ShaderAPITextureHandle_t hTexture, const char *pTextureGroupName );
+
+ // Creates the matrix stack
+ void CreateMatrixStacks();
+
+ // Initializes the render state
+ void InitRenderState( );
+
+ // Resets all dx renderstates to dx default so that our shadows are correct.
+ void ResetDXRenderState( );
+
+ // Resets the render state
+ void ResetRenderState( bool bFullReset = true );
+
+ // Setup standard vertex shader constants (that don't change)
+ void SetStandardVertexShaderConstants( float fOverbright );
+
+ // Initializes vertex and pixel shaders
+ void InitVertexAndPixelShaders();
+
+ // Discards the vertex and index buffers
+ void DiscardVertexBuffers();
+
+ // Computes the fill rate
+ void ComputeFillRate();
+
+ // Takes a snapshot
+ virtual StateSnapshot_t TakeSnapshot( );
+
+ // Converts the clear color to be appropriate for HDR
+ D3DCOLOR GetActualClearColor( D3DCOLOR clearColor );
+
+ // We lost the device
+ void OnDeviceLost();
+
+ // Gets the matrix stack from the matrix mode
+ int GetMatrixStack( MaterialMatrixMode_t mode ) const;
+
+ // Flushes the matrix state, returns false if we don't need to
+ // do any more work
+ bool MatrixIsChanging( TransformType_t transform = TRANSFORM_IS_GENERAL );
+
+ // Updates the matrix transform state
+ void UpdateMatrixTransform( TransformType_t transform = TRANSFORM_IS_GENERAL );
+
+ // Sets the vertex shader modelView state..
+ // NOTE: GetProjectionMatrix should only be called from the Commit functions!
+ const D3DXMATRIX &GetProjectionMatrix( void );
+ void SetVertexShaderViewProj();
+ void SetVertexShaderModelViewProjAndModelView();
+
+ void SetPixelShaderFogParams( int reg );
+ void SetPixelShaderFogParams( int reg, ShaderFogMode_t fogMode );
+
+ FORCEINLINE void UpdateVertexShaderFogParams( void )
+ {
+ if ( g_pHardwareConfig->Caps().m_SupportsPixelShaders )
+ {
+ float ooFogRange = 1.0f;
+
+ float fStart = m_VertexShaderFogParams[0];
+ float fEnd = m_VertexShaderFogParams[1];
+
+ // Check for divide by zero
+ if ( fEnd != fStart )
+ {
+ ooFogRange = 1.0f / ( fEnd - fStart );
+ }
+
+ float fogParams[4];
+ fogParams[0] = ooFogRange * fEnd;
+ fogParams[1] = 1.0f;
+ fogParams[2] = 1.0f - clamp( m_flFogMaxDensity, 0.0f, 1.0f ); // Max fog density
+
+ fogParams[3] = ooFogRange;
+
+ float vertexShaderCameraPos[4];
+ vertexShaderCameraPos[0] = m_WorldSpaceCameraPositon[0];
+ vertexShaderCameraPos[1] = m_WorldSpaceCameraPositon[1];
+ vertexShaderCameraPos[2] = m_WorldSpaceCameraPositon[2];
+ vertexShaderCameraPos[3] = m_DynamicState.m_FogZ; // waterheight
+
+ // cFogEndOverFogRange, cFogOne, unused, cOOFogRange
+ SetVertexShaderConstant( VERTEX_SHADER_FOG_PARAMS, fogParams, 1 );
+
+ // eyepos.x eyepos.y eyepos.z cWaterZ
+ SetVertexShaderConstant( VERTEX_SHADER_CAMERA_POS, vertexShaderCameraPos );
+ }
+ }
+
+ // Compute stats info for a texture
+ void ComputeStatsInfo( ShaderAPITextureHandle_t hTexture, bool isCubeMap, bool isVolumeTexture );
+
+ // For procedural textures
+ void AdvanceCurrentCopy( ShaderAPITextureHandle_t hTexture );
+
+ // Deletes a D3D texture
+ void DeleteD3DTexture( ShaderAPITextureHandle_t hTexture );
+
+ // Unbinds a texture
+ void UnbindTexture( ShaderAPITextureHandle_t hTexture );
+
+ // Releases all D3D textures
+ void ReleaseAllTextures();
+
+ // Deletes all textures
+ void DeleteAllTextures();
+
+ // Gets the currently modified texture handle
+ ShaderAPITextureHandle_t GetModifyTextureHandle() const;
+
+ // Gets the bind id
+ ShaderAPITextureHandle_t GetBoundTextureBindId( Sampler_t sampler ) const;
+
+ // If mat_texture_limit is enabled, then this tells us if binding the specified texture would
+ // take us over the limit.
+ bool WouldBeOverTextureLimit( ShaderAPITextureHandle_t hTexture );
+
+ // Sets the texture state
+ void SetTextureState( Sampler_t sampler, ShaderAPITextureHandle_t hTexture, bool force = false );
+
+ // Grab/release the internal render targets such as the back buffer and the save game thumbnail
+ void AcquireInternalRenderTargets();
+ void ReleaseInternalRenderTargets();
+
+ // create/release linear->gamma table texture lookups. Only used by hardware supporting pixel shader 2b and up
+ void AcquireLinearToGammaTableTextures();
+ void ReleaseLinearToGammaTableTextures();
+
+ // Gets the texture being modified
+ IDirect3DBaseTexture* GetModifyTexture();
+ void SetModifyTexture( IDirect3DBaseTexture *pTex );
+
+ // returns true if we're using texture coordinates at a given stage
+ bool IsUsingTextureCoordinates( int stage, int flags ) const;
+
+ // Returns true if the board thinks we're generating spheremap coordinates
+ bool IsSpheremapRenderStateActive( int stage ) const;
+
+ // Returns true if we're modulating constant color into the vertex color
+ bool IsModulatingVertexColor() const;
+
+ // Recomputes ambient light cube
+ void RecomputeAmbientLightCube( );
+
+ // Debugging spew
+ void SpewBoardState();
+
+ // Compute and save the world space camera position.
+ void CacheWorldSpaceCameraPosition();
+
+ // Compute and save the projection atrix with polyoffset built in if we need it.
+ void CachePolyOffsetProjectionMatrix();
+
+ // Vertex shader helper functions
+ int FindVertexShader( VertexFormat_t fmt, char const* pFileName ) const;
+ int FindPixelShader( char const* pFileName ) const;
+
+ // Returns copies of the front and back buffers
+ IDirect3DSurface* GetFrontBufferImage( ImageFormat& format );
+ IDirect3DSurface* GetBackBufferImage( Rect_t *pSrcRect, Rect_t *pDstRect, ImageFormat& format );
+ IDirect3DSurface* GetBackBufferImageHDR( Rect_t *pSrcRect, Rect_t *pDstRect, ImageFormat& format );
+
+ // Copy bits from a host-memory surface
+ void CopyBitsFromHostSurface( IDirect3DSurface* pSurfaceBits,
+ const Rect_t &dstRect, unsigned char *pData, ImageFormat srcFormat, ImageFormat dstFormat, int nDstStride );
+
+ FORCEINLINE void SetTransform( D3DTRANSFORMSTATETYPE State, CONST D3DXMATRIX *pMatrix )
+ {
+#if !defined( _X360 )
+ Dx9Device()->SetTransform( State, pMatrix );
+#endif
+ }
+
+ FORCEINLINE void SetLight( DWORD Index, CONST D3DLIGHT9 *pLight )
+ {
+#if !defined( _X360 )
+ Dx9Device()->SetLight( Index, pLight );
+#endif
+ }
+
+ FORCEINLINE void LightEnable( DWORD LightIndex, bool bEnable )
+ {
+#if !defined( _X360 )
+ Dx9Device()->LightEnable( LightIndex, bEnable );
+#endif
+ }
+
+
+ void ExecuteCommandBuffer( uint8 *pCmdBuffer );
+ void SetStandardTextureHandle( StandardTextureId_t nId, ShaderAPITextureHandle_t );
+
+ // Methods related to queuing functions to be called per-(pMesh->Draw call) or per-pass
+ void ClearAllCommitFuncs( CommitFuncType_t func, CommitShaderType_t shader );
+ void CallCommitFuncs( CommitFuncType_t func, CommitShaderType_t shader, bool bForce );
+ bool IsCommitFuncInUse( CommitFuncType_t func, CommitShaderType_t shader, int nFunc ) const;
+ void MarkCommitFuncInUse( CommitFuncType_t func, CommitShaderType_t shader, int nFunc );
+ void AddCommitFunc( CommitFuncType_t func, CommitShaderType_t shader, StateCommitFunc_t f );
+ void CallCommitFuncs( CommitFuncType_t func, bool bUsingFixedFunction, bool bForce = false );
+
+ // Commits transforms and lighting
+ void CommitStateChanges();
+
+ // Commits transforms that have to be dealt with on a per pass basis (ie. projection matrix for polyoffset)
+ void CommitPerPassStateChanges( StateSnapshot_t id );
+
+ // Need to handle fog mode on a per-pass basis
+ void CommitPerPassFogMode( bool bUsingVertexAndPixelShaders );
+
+ void CommitPerPassXboxFixups();
+
+ // Commits user clip planes
+ void CommitUserClipPlanes( bool bUsingFixedFunction );
+
+ // Gets the user clip transform (world->view)
+ D3DXMATRIX & GetUserClipTransform( );
+
+ // transform commit
+ bool VertexShaderTransformChanged( int i );
+ bool FixedFunctionTransformChanged( int i );
+
+ void UpdateVertexShaderMatrix( int iMatrix );
+ void SetVertexShaderStateSkinningMatrices();
+ void CommitVertexShaderTransforms();
+ void CommitPerPassVertexShaderTransforms();
+
+ void UpdateFixedFunctionMatrix( int iMatrix );
+ void SetFixedFunctionStateSkinningMatrices();
+ void CommitFixedFunctionTransforms();
+ void CommitPerPassFixedFunctionTransforms();
+
+ // Recomputes the fast-clip plane matrices based on the current fast-clip plane
+ void CommitFastClipPlane( );
+
+ // Computes a matrix which includes the poly offset given an initial projection matrix
+ void ComputePolyOffsetMatrix( const D3DXMATRIX& matProjection, D3DXMATRIX &matProjectionOffset );
+
+ void SetSkinningMatrices();
+
+ // lighting commit
+ bool VertexShaderLightingChanged( int i );
+ bool VertexShaderLightingEnableChanged( int i );
+ bool FixedFunctionLightingChanged( int i );
+ bool FixedFunctionLightingEnableChanged( int i );
+ VertexShaderLightTypes_t ComputeLightType( int i ) const;
+ void SortLights( int* index );
+ void CommitVertexShaderLighting();
+ void CommitPixelShaderLighting( int pshReg );
+ void CommitFixedFunctionLighting();
+
+ // Gets the surface associated with a texture (refcount of surface is increased)
+ IDirect3DSurface* GetTextureSurface( ShaderAPITextureHandle_t textureHandle );
+ IDirect3DSurface* GetDepthTextureSurface( ShaderAPITextureHandle_t textureHandle );
+
+ //
+ // Methods related to hardware config
+ //
+ void SetDefaultConfigValuesForDxLevel( int dxLevelFromCaps, ShaderDeviceInfo_t &info, unsigned int nFlagsUsed );
+
+ // Determines hardware capabilities
+ bool DetermineHardwareCaps( );
+
+ // Alpha To Coverage entrypoints and states - much of this involves vendor-dependent paths and states...
+ bool CheckVendorDependentAlphaToCoverage();
+ void EnableAlphaToCoverage();
+ void DisableAlphaToCoverage();
+
+ // Vendor-dependent shadow mapping detection
+ void CheckVendorDependentShadowMappingSupport( bool &bSupportsShadowDepthTextures, bool &bSupportsFetch4 );
+
+ // Override caps based on a requested dx level
+ void OverrideCaps( int nForcedDXLevel );
+
+ // Reports support for a given MSAA mode
+ bool SupportsMSAAMode( int nMSAAMode );
+
+ // Reports support for a given CSAA mode
+ bool SupportsCSAAMode( int nNumSamples, int nQualityLevel );
+
+ // Gamma correction of fog color, or not...
+ D3DCOLOR ComputeGammaCorrectedFogColor( unsigned char r, unsigned char g, unsigned char b, bool bSRGBWritesEnabled );
+
+ void SetDefaultMaterial();
+
+ bool RestorePersistedDisplay( bool bUseFrontBuffer );
+
+ void ClearStdTextureHandles( void );
+
+ // debug logging
+ void PrintfVA( char *fmt, va_list vargs );
+ void Printf( const char *fmt, ... );
+ float Knob( char *knobname, float *setvalue = NULL );
+
+ // "normal" back buffer and depth buffer. Need to keep this around so that we
+ // know what to set the render target to when we are done rendering to a texture.
+ IDirect3DSurface *m_pBackBufferSurface;
+ IDirect3DSurface *m_pBackBufferSurfaceSRGB;
+ IDirect3DSurface *m_pZBufferSurface;
+
+ // Optimization for screenshots
+ IDirect3DSurface *m_pSmallBackBufferFP16TempSurface;
+
+ ShaderAPITextureHandle_t m_hFullScreenTexture;
+
+ ShaderAPITextureHandle_t m_hLinearToGammaTableTexture;
+ ShaderAPITextureHandle_t m_hLinearToGammaTableIdentityTexture;
+
+ //
+ // State needed at the time of rendering (after snapshots have been applied)
+ //
+
+ // Interface for the D3DXMatrixStack
+ ID3DXMatrixStack* m_pMatrixStack[NUM_MATRIX_MODES];
+ matrix3x4_t m_boneMatrix[NUM_MODEL_TRANSFORMS];
+ int m_maxBoneLoaded;
+
+ // Current matrix mode
+ D3DTRANSFORMSTATETYPE m_MatrixMode;
+ int m_CurrStack;
+
+ // The current camera position in world space.
+ Vector4D m_WorldSpaceCameraPositon;
+
+ // The current projection matrix with polyoffset baked into it.
+ D3DXMATRIX m_CachedPolyOffsetProjectionMatrix;
+ D3DXMATRIX m_CachedFastClipProjectionMatrix;
+ D3DXMATRIX m_CachedFastClipPolyOffsetProjectionMatrix;
+
+ // The texture stage state that changes frequently
+ DynamicState_t m_DynamicState;
+
+ // The *desired* dynamic state. Most dynamic state is committed into actual hardware state
+ // at either per-pass or per-material time. This can also be used to force the hardware
+ // to match the desired state after returning from alt-tab.
+ DynamicState_t m_DesiredState;
+
+ // A list of state commit functions to run as per-draw call commit time
+ unsigned char m_pCommitFlags[COMMIT_FUNC_TYPE_COUNT][COMMIT_SHADER_TYPE_COUNT][ COMMIT_FUNC_BYTE_COUNT ];
+ CUtlVector< StateCommitFunc_t > m_CommitFuncs[COMMIT_FUNC_TYPE_COUNT][COMMIT_SHADER_TYPE_COUNT];
+
+ // Render data
+ CMeshBase *m_pRenderMesh;
+ int m_nDynamicVBSize;
+ IMaterialInternal *m_pMaterial;
+
+ // Shadow depth bias states
+ float m_fShadowSlopeScaleDepthBias;
+ float m_fShadowDepthBias;
+
+ bool m_bReadPixelsEnabled;
+
+ // Render-to-texture stuff...
+ bool m_UsingTextureRenderTarget;
+
+ int m_ViewportMaxWidth;
+ int m_ViewportMaxHeight;
+
+ ShaderAPITextureHandle_t m_hCachedRenderTarget;
+ bool m_bUsingSRGBRenderTarget;
+
+ // Ambient cube map ok?
+ int m_CachedAmbientLightCube;
+
+ // The current frame
+ int m_CurrentFrame;
+
+ // The texture we're currently modifying
+ ShaderAPITextureHandle_t m_ModifyTextureHandle;
+ char m_ModifyTextureLockedLevel;
+ unsigned char m_ModifyTextureLockedFace;
+
+ // Stores all textures
+ CUtlFixedLinkedList< Texture_t > m_Textures;
+
+ // Mesh builder used to modify vertex data
+ CMeshBuilder m_ModifyBuilder;
+
+ float m_VertexShaderFogParams[2];
+ float m_flFogMaxDensity;
+
+ // Shadow state transition table
+ CTransitionTable m_TransitionTable;
+ StateSnapshot_t m_nCurrentSnapshot;
+
+ // Depth test override...
+ bool m_bOverrideMaterialIgnoreZ;
+ bool m_bIgnoreZValue;
+
+ // Are we in the middle of resetting the render state?
+ bool m_bResettingRenderState;
+
+ // Can we buffer 2 frames ahead?
+ bool m_bBuffer2FramesAhead;
+
+ // Selection name stack
+ CUtlStack< int > m_SelectionNames;
+ bool m_InSelectionMode;
+ unsigned int* m_pSelectionBufferEnd;
+ unsigned int* m_pSelectionBuffer;
+ unsigned int* m_pCurrSelectionRecord;
+ float m_SelectionMinZ;
+ float m_SelectionMaxZ;
+ int m_NumHits;
+
+ // fog
+ unsigned char m_SceneFogColor[3];
+ MaterialFogMode_t m_SceneFogMode;
+
+ // Tone Mapping state ( w is gamma scale )
+ Vector4D m_ToneMappingScale;
+
+ Deformation_t m_DeformationStack[DEFORMATION_STACK_DEPTH];
+
+ Deformation_t *m_pDeformationStackPtr;
+
+ void WriteShaderConstantsToGPU();
+
+ // rendering parameter storage
+ int IntRenderingParameters[MAX_INT_RENDER_PARMS];
+ float FloatRenderingParameters[MAX_FLOAT_RENDER_PARMS];
+ Vector VectorRenderingParameters[MAX_VECTOR_RENDER_PARMS];
+
+ ShaderAPITextureHandle_t m_StdTextureHandles[TEXTURE_MAX_STD_TEXTURES];
+
+ // PIX instrumentation utlities...enable these with PIX_INSTRUMENTATION
+ void StartPIXInstrumentation();
+ void EndPIXInstrumentation();
+ void SetPIXMarker( unsigned long color, const char *szName );
+ void IncrementPIXError();
+ bool PIXError();
+ int m_nPIXErrorCount;
+ int m_nPixFrame;
+ bool m_bPixCapturing;
+
+ void ComputeVertexDescription( unsigned char* pBuffer, VertexFormat_t vertexFormat, MeshDesc_t& desc ) const
+ {
+ return MeshMgr()->ComputeVertexDescription( pBuffer, vertexFormat, desc );
+ }
+
+ // Reports support for shadow depth texturing
+ bool SupportsShadowDepthTextures( void );
+ bool SupportsFetch4( void );
+
+ void SetShadowDepthBiasFactors( float fShadowSlopeScaleDepthBias, float fShadowDepthBias );
+
+ // Vendor-dependent depth stencil texture format
+ ImageFormat GetShadowDepthTextureFormat( void );
+
+ bool SupportsBorderColor( void ) const;
+ bool SupportsFetch4( void ) const;
+
+ void EnableBuffer2FramesAhead( bool bEnable );
+
+ void SetDepthFeatheringPixelShaderConstant( int iConstant, float fDepthBlendScale );
+
+ void SetDisallowAccess( bool b )
+ {
+ g_bShaderAccessDisallowed = b;
+ }
+
+ void EnableShaderShaderMutex( bool b )
+ {
+ Assert( g_ShaderMutex.GetOwnerId() == 0 );
+ g_bUseShaderMutex = b;
+ }
+
+ void ShaderLock()
+ {
+ g_ShaderMutex.Lock();
+ }
+
+ void ShaderUnlock()
+ {
+ g_ShaderMutex.Unlock();
+ }
+
+ // Vendor-dependent slim texture format
+ ImageFormat GetNullTextureFormat( void );
+
+ //The idea behind a delayed constant is this.
+ // Some shaders set constants based on rendering states, and some rendering states aren't updated until after a shader's already called Draw().
+ // So, for some functions that are state based, we save the constant we set and if the state changes between when it's set in the shader setup code
+ // and when the shader is drawn, we update that constant.
+ struct DelayedConstants_t
+ {
+ int iPixelShaderFogParams;
+
+ void Invalidate( void )
+ {
+ iPixelShaderFogParams = -1;
+ }
+ DelayedConstants_t( void ) { this->Invalidate(); }
+ };
+ DelayedConstants_t m_DelayedShaderConstants;
+
+ bool SetRenderTargetInternalXbox( ShaderAPITextureHandle_t hTexture, bool bForce = false );
+
+#if defined( _X360 )
+ CUtlStack<int> m_VertexShaderGPRAllocationStack;
+#endif
+
+ int m_MaxVectorVertexShaderConstant;
+ int m_MaxBooleanVertexShaderConstant;
+ int m_MaxIntegerVertexShaderConstant;
+ int m_MaxVectorPixelShaderConstant;
+ int m_MaxBooleanPixelShaderConstant;
+ int m_MaxIntegerPixelShaderConstant;
+
+ bool m_bGPUOwned;
+ bool m_bResetRenderStateNeeded;
+
+#ifdef ENABLE_NULLREF_DEVICE_SUPPORT
+ bool m_NullDevice;
+#endif
+};
+
+
+//-----------------------------------------------------------------------------
+// Class Factory
+//-----------------------------------------------------------------------------
+static CShaderAPIDx8 g_ShaderAPIDX8;
+IShaderAPIDX8 *g_pShaderAPIDX8 = &g_ShaderAPIDX8;
+CShaderDeviceDx8* g_pShaderDeviceDx8 = &g_ShaderAPIDX8;
+
+// FIXME: Remove IShaderAPI + IShaderDevice; they change after SetMode
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CShaderAPIDx8, IShaderAPI,
+ SHADERAPI_INTERFACE_VERSION, g_ShaderAPIDX8 )
+
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CShaderAPIDx8, IShaderDevice,
+ SHADER_DEVICE_INTERFACE_VERSION, g_ShaderAPIDX8 )
+
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CShaderAPIDx8, IDebugTextureInfo,
+ DEBUG_TEXTURE_INFO_VERSION, g_ShaderAPIDX8 )
+
+//-----------------------------------------------------------------------------
+// Accessors for major interfaces
+//-----------------------------------------------------------------------------
+
+// Pix wants a max of 32 characters
+// We'll give it the right-most substrings separated by slashes
+static char s_pPIXMaterialName[32];
+void PIXifyName( char *pDst, int destSize, const char *pSrc )
+{
+ char *pSrcWalk = (char *)pSrc;
+
+ while ( V_strlen( pSrcWalk ) > 31 ) // While we still have too many characters
+ {
+ char *pTok = strpbrk( pSrcWalk, "/\\" ); // Find next token
+
+ if ( pTok )
+ pSrcWalk = pTok + 1;
+ else
+ break;
+ }
+
+ V_strncpy( pDst, pSrcWalk, min( 32, destSize ) );
+}
+
+static int AdjustUpdateRange( float const* pVec, void const *pOut, int numVecs, int* pSkip )
+{
+ int skip = 0;
+ uint32* pSrc = (uint32*)pVec;
+ uint32* pDst = (uint32*)pOut;
+ while( numVecs && !( ( pSrc[0] ^ pDst[0] ) | ( pSrc[1] ^ pDst[1] ) | ( pSrc[2] ^ pDst[2] ) | ( pSrc[3] ^ pDst[3] ) ) )
+ {
+ pSrc += 4;
+ pDst += 4;
+ numVecs--;
+ skip++;
+ }
+ *pSkip = skip;
+ if ( !numVecs )
+ return 0;
+
+ uint32* pSrcLast = pSrc + numVecs * 4 - 4;
+ uint32* pDstLast = pDst + numVecs * 4 - 4;
+ while( numVecs > 1 && !( ( pSrcLast[0] ^ pDstLast[0] ) | ( pSrcLast[1] ^ pDstLast[1] ) | ( pSrcLast[2] ^ pDstLast[2] ) | ( pSrcLast[3] ^ pDstLast[3] ) ) )
+ {
+ pSrcLast -= 4;
+ pDstLast -= 4;
+ numVecs--;
+ }
+
+ return numVecs;
+}
+
+//-----------------------------------------------------------------------------
+// Constructor, destructor
+//-----------------------------------------------------------------------------
+CShaderAPIDx8::CShaderAPIDx8() :
+ m_Textures( 32 ),
+ m_CurrStack( -1 ),
+ m_ModifyTextureHandle( INVALID_SHADERAPI_TEXTURE_HANDLE ),
+ m_pRenderMesh( 0 ),
+ m_nDynamicVBSize( DYNAMIC_VERTEX_BUFFER_MEMORY ),
+ m_pMaterial( NULL ),
+ m_CurrentFrame( 0 ),
+ m_CachedAmbientLightCube( STATE_CHANGED ),
+ m_InSelectionMode( false ),
+ m_SelectionMinZ( FLT_MAX ),
+ m_SelectionMaxZ( FLT_MIN ),
+ m_pSelectionBuffer( 0 ),
+ m_pSelectionBufferEnd( 0 ),
+ m_bResetRenderStateNeeded( false ),
+ m_ModifyTextureLockedLevel( -1 ),
+ m_nPixFrame(0),
+ m_bPixCapturing(false),
+ m_nPIXErrorCount(0),
+ m_pBackBufferSurface( 0 ),
+ m_pBackBufferSurfaceSRGB( 0 ),
+ m_pZBufferSurface( 0 ),
+ m_bResettingRenderState( false ),
+ m_bReadPixelsEnabled( false ),
+ m_ToneMappingScale( 1.0f, 1.0f, 1.0f, 1.0f ),
+ m_hFullScreenTexture( INVALID_SHADERAPI_TEXTURE_HANDLE ),
+ m_hLinearToGammaTableTexture( INVALID_SHADERAPI_TEXTURE_HANDLE ),
+ m_hLinearToGammaTableIdentityTexture( INVALID_SHADERAPI_TEXTURE_HANDLE ),
+ m_fShadowSlopeScaleDepthBias( 16.0f ),
+ m_fShadowDepthBias( 0.00008f ),
+ m_hCachedRenderTarget( INVALID_SHADERAPI_TEXTURE_HANDLE ),
+ m_bUsingSRGBRenderTarget( false )
+{
+ // FIXME: Remove! Backward compat
+ m_bAdapterSet = false;
+ m_bBuffer2FramesAhead = false;
+ m_bReadPixelsEnabled = true;
+
+ memset( m_pMatrixStack, 0, sizeof(ID3DXMatrixStack*) * NUM_MATRIX_MODES );
+ memset( &m_DynamicState, 0, sizeof(m_DynamicState) );
+ //m_DynamicState.m_HeightClipMode = MATERIAL_HEIGHTCLIPMODE_DISABLE;
+ m_nWindowHeight = m_nWindowWidth = 0;
+ m_maxBoneLoaded = 0;
+
+ m_bEnableDebugTextureList = 0;
+ m_bDebugTexturesRendering = 0;
+ m_pDebugTextureList = NULL;
+ m_nTextureMemoryUsedLastFrame = 0;
+ m_nTextureMemoryUsedTotal = 0;
+ m_nTextureMemoryUsedPicMip1 = 0;
+ m_nTextureMemoryUsedPicMip2 = 0;
+ m_nDebugDataExportFrame = 0;
+
+ m_SceneFogColor[0] = 0;
+ m_SceneFogColor[1] = 0;
+ m_SceneFogColor[2] = 0;
+ m_SceneFogMode = MATERIAL_FOG_NONE;
+
+ // We haven't yet detected whether we support CreateQuery or not yet.
+ memset(IntRenderingParameters,0,sizeof(IntRenderingParameters));
+ memset(FloatRenderingParameters,0,sizeof(FloatRenderingParameters));
+ memset(VectorRenderingParameters,0,sizeof(VectorRenderingParameters));
+
+ m_pDeformationStackPtr = m_DeformationStack + DEFORMATION_STACK_DEPTH;
+
+ m_bGPUOwned = false;
+ m_MaxVectorVertexShaderConstant = 0;
+ m_MaxBooleanVertexShaderConstant = 0;
+ m_MaxIntegerVertexShaderConstant = 0;
+ m_MaxVectorPixelShaderConstant = 0;
+ m_MaxBooleanPixelShaderConstant = 0;
+ m_MaxIntegerPixelShaderConstant = 0;
+
+ ClearStdTextureHandles();
+
+ //Debugger();
+#ifdef ENABLE_NULLREF_DEVICE_SUPPORT
+ m_NullDevice = !!CommandLine()->FindParm( "-nulldevice" );
+#endif
+}
+
+CShaderAPIDx8::~CShaderAPIDx8()
+{
+ if ( m_DynamicState.m_pVectorVertexShaderConstant )
+ {
+ delete[] m_DynamicState.m_pVectorVertexShaderConstant;
+ m_DynamicState.m_pVectorVertexShaderConstant = NULL;
+ }
+
+ if ( m_DynamicState.m_pBooleanVertexShaderConstant )
+ {
+ delete[] m_DynamicState.m_pBooleanVertexShaderConstant;
+ m_DynamicState.m_pBooleanVertexShaderConstant = NULL;
+ }
+
+ if ( m_DynamicState.m_pIntegerVertexShaderConstant )
+ {
+ delete[] m_DynamicState.m_pIntegerVertexShaderConstant;
+ m_DynamicState.m_pIntegerVertexShaderConstant = NULL;
+ }
+
+ if ( m_DynamicState.m_pVectorPixelShaderConstant )
+ {
+ delete[] m_DynamicState.m_pVectorPixelShaderConstant;
+ m_DynamicState.m_pVectorPixelShaderConstant = NULL;
+ }
+
+ if ( m_DynamicState.m_pBooleanPixelShaderConstant )
+ {
+ delete[] m_DynamicState.m_pBooleanPixelShaderConstant;
+ m_DynamicState.m_pBooleanPixelShaderConstant = NULL;
+ }
+
+ if ( m_DynamicState.m_pIntegerPixelShaderConstant )
+ {
+ delete[] m_DynamicState.m_pIntegerPixelShaderConstant;
+ m_DynamicState.m_pIntegerPixelShaderConstant = NULL;
+ }
+
+ if ( m_pDebugTextureList )
+ {
+ m_pDebugTextureList->deleteThis();
+ m_pDebugTextureList = NULL;
+ }
+}
+
+
+void CShaderAPIDx8::ClearStdTextureHandles( void )
+{
+ for(int i = 0 ; i < ARRAYSIZE( m_StdTextureHandles ) ; i++ )
+ m_StdTextureHandles[i] = INVALID_SHADERAPI_TEXTURE_HANDLE;
+}
+
+
+//-----------------------------------------------------------------------------
+// FIXME: Remove! Backward compat.
+//-----------------------------------------------------------------------------
+bool CShaderAPIDx8::OnAdapterSet()
+{
+ if ( !DetermineHardwareCaps( ) )
+ return false;
+
+ // Modify the caps based on requested DXlevels
+ int nForcedDXLevel = CommandLine()->ParmValue( "-dxlevel", 0 );
+
+ if ( nForcedDXLevel > 0 )
+ {
+ nForcedDXLevel = MAX( nForcedDXLevel, ABSOLUTE_MINIMUM_DXLEVEL );
+ }
+
+
+ // FIXME: Check g_pHardwareConfig->ActualCaps() for a preferred DX level
+ OverrideCaps( nForcedDXLevel );
+
+ m_bAdapterSet = true;
+ return true;
+}
+
+
+void CShaderAPIDx8::GetDXLevelDefaults(uint &max_dxlevel,uint &recommended_dxlevel)
+{
+ max_dxlevel=g_pHardwareConfig->ActualCaps().m_nMaxDXSupportLevel;
+ recommended_dxlevel=g_pHardwareConfig->ActualCaps().m_nDXSupportLevel;
+}
+
+//-----------------------------------------------------------------------------
+// Can we download textures?
+//-----------------------------------------------------------------------------
+bool CShaderAPIDx8::CanDownloadTextures() const
+{
+ if ( IsDeactivated() )
+ return false;
+
+ return IsActive();
+}
+
+
+//-----------------------------------------------------------------------------
+// Grab the render targets
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::AcquireInternalRenderTargets()
+{
+ GLMPRINTF(( ">-A- CShaderAPIDx8::AcquireInternalRenderTargets... "));
+ if ( mat_debugalttab.GetBool() )
+ {
+ Warning( "mat_debugalttab: CShaderAPIDx8::AcquireInternalRenderTargets\n" );
+ }
+
+ if ( !m_pBackBufferSurface )
+ {
+ Dx9Device()->GetRenderTarget( 0, &m_pBackBufferSurface );
+#ifdef ENABLE_NULLREF_DEVICE_SUPPORT
+ if( !m_NullDevice )
+#endif
+ {
+ Assert( m_pBackBufferSurface );
+ }
+ }
+
+#if defined( _X360 )
+ if ( !m_pBackBufferSurfaceSRGB )
+ {
+ // create a SRGB back buffer clone
+ int backWidth, backHeight;
+ ShaderAPI()->GetBackBufferDimensions( backWidth, backHeight );
+ D3DFORMAT backBufferFormat = ImageLoader::ImageFormatToD3DFormat( g_pShaderDevice->GetBackBufferFormat() );
+ m_pBackBufferSurfaceSRGB = g_TextureHeap.AllocRenderTargetSurface( backWidth, backHeight, (D3DFORMAT)MAKESRGBFMT( backBufferFormat ), true, 0 );
+ }
+#endif
+
+#ifdef ENABLE_NULLREF_DEVICE_SUPPORT
+ if ( !m_pZBufferSurface && !m_NullDevice )
+#else
+ if ( !m_pZBufferSurface )
+#endif
+ {
+ Dx9Device()->GetDepthStencilSurface( &m_pZBufferSurface );
+ Assert( m_pZBufferSurface );
+ }
+ GLMPRINTF(( "<-A- CShaderAPIDx8::AcquireInternalRenderTargets...complete "));
+}
+
+
+//-----------------------------------------------------------------------------
+// Release the render targets
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::ReleaseInternalRenderTargets( )
+{
+ GLMPRINTF(( ">-A- CShaderAPIDx8::ReleaseInternalRenderTargets... "));
+ if( mat_debugalttab.GetBool() )
+ {
+ Warning( "mat_debugalttab: CShaderAPIDx8::ReleaseInternalRenderTargets\n" );
+ }
+
+ // Note: This function does not release renderable textures created elsewhere
+ // Those should be released separately via the texure manager
+ if ( m_pBackBufferSurface )
+ {
+#if POSIX
+ // dxabstract's AddRef/Release have optional args to help track usage
+ int nRetVal = m_pBackBufferSurface->Release( 0, "-B CShaderAPIDx8::ReleaseInternalRenderTargets public release color buffer");
+#else
+ int nRetVal = m_pBackBufferSurface->Release();
+#endif
+ //Assert( nRetVal == 0 );
+ m_pBackBufferSurface = NULL;
+ }
+
+ if ( m_pZBufferSurface )
+ {
+#if POSIX
+ // dxabstract's AddRef/Release have optional args to help track usage
+ int nRetVal = m_pZBufferSurface->Release( 0, "-B CShaderAPIDx8::ReleaseInternalRenderTargets public release zbuffer");
+#else
+ int nRetVal = m_pZBufferSurface->Release();
+#endif
+
+ //Assert( nRetVal == 0 ); //FIXME not sure why we're seeing a refcount of 3 here
+ m_pZBufferSurface = NULL;
+ }
+ GLMPRINTF(( "<-A- CShaderAPIDx8::ReleaseInternalRenderTargets... complete"));
+}
+
+//-----------------------------------------------------------------------------
+// During init, places the persisted texture back into the back buffer.
+// The initial 360 fixup present will then not flash. This routine has to be
+// self contained, no other shader api systems are viable during init.
+//-----------------------------------------------------------------------------
+bool CShaderAPIDx8::RestorePersistedDisplay( bool bUseFrontBuffer )
+{
+#if defined( _X360 )
+ if ( !( XboxLaunch()->GetLaunchFlags() & LF_INTERNALLAUNCH ) )
+ {
+ // there is no persisted screen
+ return false;
+ }
+
+ OwnGPUResources( false );
+
+ const char *strVertexShaderProgram =
+ " float4x4 matWVP : register(c0);"
+ " struct VS_IN"
+ " {"
+ " float4 ObjPos : POSITION;"
+ " float2 TexCoord : TEXCOORD;"
+ " };"
+ " struct VS_OUT"
+ " {"
+ " float4 ProjPos : POSITION;"
+ " float2 TexCoord : TEXCOORD;"
+ " };"
+ " VS_OUT main( VS_IN In )"
+ " {"
+ " VS_OUT Out; "
+ " Out.ProjPos = mul( matWVP, In.ObjPos );"
+ " Out.TexCoord = In.TexCoord;"
+ " return Out;"
+ " }";
+
+ const char *strPixelShaderProgram =
+ " struct PS_IN"
+ " {"
+ " float2 TexCoord : TEXCOORD;"
+ " };"
+ " sampler detail;"
+ " float4 main( PS_IN In ) : COLOR"
+ " {"
+ " return tex2D( detail, In.TexCoord );"
+ " }";
+
+ D3DVERTEXELEMENT9 VertexElements[3] =
+ {
+ { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
+ { 0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
+ D3DDECL_END()
+ };
+
+
+ IDirect3DTexture *pTexture;
+ if ( bUseFrontBuffer )
+ {
+ Dx9Device()->GetFrontBuffer( &pTexture );
+ }
+ else
+ {
+ // 360 holds a persistent image across restarts
+ Dx9Device()->GetPersistedTexture( &pTexture );
+ }
+
+ ID3DXBuffer *pErrorMsg = NULL;
+ ID3DXBuffer *pShaderCode = NULL;
+
+ HRESULT hr = D3DXCompileShader( strVertexShaderProgram, (UINT)strlen( strVertexShaderProgram ), NULL, NULL, "main", "vs_2_0", 0, &pShaderCode, &pErrorMsg, NULL );
+ if ( FAILED( hr ) )
+ {
+ return false;
+ }
+ IDirect3DVertexShader9 *pVertexShader;
+ Dx9Device()->CreateVertexShader( (DWORD*)pShaderCode->GetBufferPointer(), &pVertexShader );
+ pShaderCode->Release();
+
+ pErrorMsg = NULL;
+ pShaderCode = NULL;
+ hr = D3DXCompileShader( strPixelShaderProgram, (UINT)strlen( strPixelShaderProgram ), NULL, NULL, "main", "ps_2_0", 0, &pShaderCode, &pErrorMsg, NULL );
+ if ( FAILED(hr) )
+ {
+ return false;
+ }
+ IDirect3DPixelShader9 *pPixelShader;
+ Dx9Device()->CreatePixelShader( (DWORD*)pShaderCode->GetBufferPointer(), &pPixelShader );
+ pShaderCode->Release();
+
+ int w, h;
+ GetBackBufferDimensions( w, h );
+
+ // Create a vertex declaration from the element descriptions.
+ IDirect3DVertexDeclaration9 *pVertexDecl;
+ Dx9Device()->CreateVertexDeclaration( VertexElements, &pVertexDecl );
+ XMMATRIX matWVP = XMMatrixOrthographicOffCenterLH( 0, (FLOAT)w, (FLOAT)h, 0, 0, 1 );
+
+ ConVarRef mat_monitorgamma( "mat_monitorgamma" );
+ ConVarRef mat_monitorgamma_tv_range_min( "mat_monitorgamma_tv_range_min" );
+ ConVarRef mat_monitorgamma_tv_range_max( "mat_monitorgamma_tv_range_max" );
+ ConVarRef mat_monitorgamma_tv_exp( "mat_monitorgamma_tv_exp" );
+ ConVarRef mat_monitorgamma_tv_enabled( "mat_monitorgamma_tv_enabled" );
+ g_pShaderDeviceDx8->SetHardwareGammaRamp( mat_monitorgamma.GetFloat(), mat_monitorgamma_tv_range_min.GetFloat(), mat_monitorgamma_tv_range_max.GetFloat(),
+ mat_monitorgamma_tv_exp.GetFloat(), mat_monitorgamma_tv_enabled.GetBool() );
+
+ // Structure to hold vertex data.
+ struct COLORVERTEX
+ {
+ FLOAT Position[3];
+ float TexCoord[2];
+ };
+ COLORVERTEX Vertices[4];
+
+ Vertices[0].Position[0] = 0;
+ Vertices[0].Position[1] = 0;
+ Vertices[0].Position[2] = 0;
+ Vertices[0].TexCoord[0] = 0;
+ Vertices[0].TexCoord[1] = 0;
+
+ Vertices[1].Position[0] = w-1;
+ Vertices[1].Position[1] = 0;
+ Vertices[1].Position[2] = 0;
+ Vertices[1].TexCoord[0] = 1;
+ Vertices[1].TexCoord[1] = 0;
+
+ Vertices[2].Position[0] = w-1;
+ Vertices[2].Position[1] = h-1;
+ Vertices[2].Position[2] = 0;
+ Vertices[2].TexCoord[0] = 1;
+ Vertices[2].TexCoord[1] = 1;
+
+ Vertices[3].Position[0] = 0;
+ Vertices[3].Position[1] = h-1;
+ Vertices[3].Position[2] = 0;
+ Vertices[3].TexCoord[0] = 0;
+ Vertices[3].TexCoord[1] = 1;
+
+ Dx9Device()->SetTexture( 0, pTexture );
+ Dx9Device()->SetVertexShader( pVertexShader );
+ Dx9Device()->SetPixelShader( pPixelShader );
+ Dx9Device()->SetVertexShaderConstantF( 0, (FLOAT*)&matWVP, 4 );
+ Dx9Device()->SetVertexDeclaration( pVertexDecl );
+ Dx9Device()->DrawPrimitiveUP( D3DPT_QUADLIST, 1, Vertices, sizeof( COLORVERTEX ) );
+
+ Dx9Device()->SetVertexShader( NULL );
+ Dx9Device()->SetPixelShader( NULL );
+ Dx9Device()->SetTexture( 0, NULL );
+ Dx9Device()->SetVertexDeclaration( NULL );
+
+ pVertexShader->Release();
+ pPixelShader->Release();
+ pVertexDecl->Release();
+ pTexture->Release();
+
+ OwnGPUResources( true );
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Initialize, shutdown the Device....
+//-----------------------------------------------------------------------------
+bool CShaderAPIDx8::OnDeviceInit()
+{
+ AcquireInternalRenderTargets();
+
+ g_pHardwareConfig->CapsForEdit().m_TextureMemorySize = g_pShaderDeviceMgrDx8->GetVidMemBytes( m_nAdapter );
+
+ CreateMatrixStacks();
+
+ // Hide the cursor
+ RECORD_COMMAND( DX8_SHOW_CURSOR, 1 );
+ RECORD_INT( false );
+
+#if !defined( _X360 )
+ Dx9Device()->ShowCursor( false );
+#endif
+
+ // Initialize the shader manager
+ ShaderManager()->Init();
+
+ // Initialize the shader shadow
+ ShaderShadow()->Init();
+
+ // Initialize the mesh manager
+ MeshMgr()->Init();
+
+ bool bToolsMode = IsWindows() && ( CommandLine()->CheckParm( "-tools" ) != NULL );
+
+ // Use fat vertices when running in tools
+ MeshMgr()->UseFatVertices( bToolsMode );
+
+ // Initialize the transition table.
+ m_TransitionTable.Init();
+
+ // Initialize the render state
+ InitRenderState();
+
+ // Clear the z and color buffers
+ ClearBuffers( true, true, true, -1, -1 );
+
+ AllocFrameSyncObjects();
+ AllocNonInteractiveRefreshObjects();
+
+ RECORD_COMMAND( DX8_BEGIN_SCENE, 0 );
+
+ // Apply mandatory initialization HW fixups, GPU state will be left as expected
+ if ( IsX360() )
+ {
+ // place the possible persisted display into the back buffer, ready for present()
+ RestorePersistedDisplay( false );
+
+ // 360 MUST perform an initial swap to stabilize the state
+ // this ensures any states (e.g. gamma) are respected
+ // without this, the 360 resets to internal default state on the first swap
+ OwnGPUResources( false );
+ Dx9Device()->Present( 0, 0, 0, 0 );
+
+ // present corrupts the GPU state and back buffer (according to docs)
+ // re-clear the back buffer in order to re-establish the expected contents
+ ResetRenderState( false );
+ ClearBuffers( true, true, true, -1, -1 );
+
+ // place the front buffer image in the back buffer, later systems will detect and grab
+ // other systems will detect and grab
+ RestorePersistedDisplay( true );
+ }
+
+ Dx9Device()->BeginScene();
+
+ return true;
+}
+
+void CShaderAPIDx8::OnDeviceShutdown()
+{
+ if ( !IsPC() || !IsActive() )
+ return;
+
+ // Deallocate all textures
+ DeleteAllTextures();
+
+ // Release render targets
+ ReleaseInternalRenderTargets();
+
+ // Free objects that are used for frame syncing.
+ FreeFrameSyncObjects();
+ FreeNonInteractiveRefreshObjects();
+
+ for (int i = 0; i < NUM_MATRIX_MODES; ++i)
+ {
+ if (m_pMatrixStack[i])
+ {
+ int ref = m_pMatrixStack[i]->Release();
+ Assert( ref == 0 );
+ }
+ }
+
+ // Shutdown the transition table.
+ m_TransitionTable.Shutdown();
+
+ MeshMgr()->Shutdown();
+
+ ShaderManager()->Shutdown();
+
+ ReleaseAllVertexDecl( );
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the mode...
+//-----------------------------------------------------------------------------
+bool CShaderAPIDx8::SetMode( void* VD3DHWND, int nAdapter, const ShaderDeviceInfo_t &info )
+{
+ //
+ // FIXME: Note that this entire function is backward compat and will go soon
+ //
+
+ bool bRestoreNeeded = false;
+
+ if ( IsActive() )
+ {
+ ReleaseResources();
+ OnDeviceShutdown();
+ ShutdownDevice();
+ bRestoreNeeded = true;
+ }
+
+ LOCK_SHADERAPI();
+ Assert( D3D() );
+ Assert( nAdapter < g_pShaderDeviceMgr->GetAdapterCount() );
+
+ const HardwareCaps_t& actualCaps = g_pShaderDeviceMgr->GetHardwareCaps( nAdapter );
+
+ ShaderDeviceInfo_t actualInfo = info;
+ int nDXLevel = actualInfo.m_nDXLevel ? actualInfo.m_nDXLevel : actualCaps.m_nDXSupportLevel;
+
+ static bool bSetModeOnce = false;
+ if ( !bSetModeOnce )
+ {
+ nDXLevel = MAX( ABSOLUTE_MINIMUM_DXLEVEL, CommandLine()->ParmValue( "-dxlevel", nDXLevel ) );
+ bSetModeOnce = true;
+ }
+ if ( nDXLevel > actualCaps.m_nMaxDXSupportLevel )
+ {
+ nDXLevel = actualCaps.m_nMaxDXSupportLevel;
+ }
+ actualInfo.m_nDXLevel = g_pShaderDeviceMgr->GetClosestActualDXLevel( nDXLevel );
+
+ if ( !g_pShaderDeviceMgrDx8->ValidateMode( nAdapter, actualInfo ) )
+ return false;
+
+ g_pShaderAPI = this;
+ g_pShaderDevice = this;
+ g_pShaderShadow = ShaderShadow();
+ bool bOk = InitDevice( VD3DHWND, nAdapter, actualInfo );
+ if ( !bOk )
+ return false;
+
+ if ( !OnDeviceInit() )
+ return false;
+
+ if ( bRestoreNeeded && IsPC() )
+ {
+ ReacquireResources();
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates the matrix stack
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::CreateMatrixStacks()
+{
+ MEM_ALLOC_D3D_CREDIT();
+
+ for (int i = 0; i < NUM_MATRIX_MODES; ++i)
+ {
+ HRESULT hr = D3DXCreateMatrixStack( 0, &m_pMatrixStack[i] );
+ Assert( hr == D3D_OK );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Vendor-dependent code to turn on alpha to coverage
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::EnableAlphaToCoverage( void )
+{
+ if( !g_pHardwareConfig->ActualCaps().m_bSupportsAlphaToCoverage || !IsAAEnabled() )
+ return;
+
+ D3DRENDERSTATETYPE renderState = (D3DRENDERSTATETYPE)g_pHardwareConfig->Caps().m_AlphaToCoverageState;
+ SetRenderState( renderState, g_pHardwareConfig->Caps().m_AlphaToCoverageEnableValue ); // Vendor dependent state
+}
+
+//-----------------------------------------------------------------------------
+// Vendor-dependent code to turn off alpha to coverage
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::DisableAlphaToCoverage()
+{
+ if( !g_pHardwareConfig->ActualCaps().m_bSupportsAlphaToCoverage || !IsAAEnabled() )
+ return;
+
+ D3DRENDERSTATETYPE renderState = (D3DRENDERSTATETYPE)g_pHardwareConfig->Caps().m_AlphaToCoverageState;
+ SetRenderState( renderState, g_pHardwareConfig->Caps().m_AlphaToCoverageDisableValue ); // Vendor dependent state
+}
+
+//-----------------------------------------------------------------------------
+// Determine capabilities
+//-----------------------------------------------------------------------------
+bool CShaderAPIDx8::DetermineHardwareCaps( )
+{
+ HardwareCaps_t& actualCaps = g_pHardwareConfig->ActualCapsForEdit();
+ if ( !g_pShaderDeviceMgrDx8->ComputeCapsFromD3D( &actualCaps, m_DisplayAdapter ) )
+ return false;
+
+ // See if the file tells us otherwise
+ g_pShaderDeviceMgrDx8->ReadDXSupportLevels( actualCaps );
+
+ // Read dxsupport.cfg which has config overrides for particular cards.
+ g_pShaderDeviceMgrDx8->ReadHardwareCaps( actualCaps, actualCaps.m_nMaxDXSupportLevel );
+
+ // What's in "-shader" overrides dxsupport.cfg
+ const char *pShaderParam = CommandLine()->ParmValue( "-shader" );
+ if ( pShaderParam )
+ {
+ Q_strncpy( actualCaps.m_pShaderDLL, pShaderParam, sizeof( actualCaps.m_pShaderDLL ) );
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Override caps based on a particular dx level
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::OverrideCaps( int nForcedDXLevel )
+{
+ // Just use the actual caps if we can't use what was requested or if the default is requested
+ if ( nForcedDXLevel <= 0 )
+ {
+ nForcedDXLevel = g_pHardwareConfig->ActualCaps().m_nDXSupportLevel;
+ }
+ nForcedDXLevel = g_pShaderDeviceMgr->GetClosestActualDXLevel( nForcedDXLevel );
+
+ g_pHardwareConfig->SetupHardwareCaps( nForcedDXLevel, g_pHardwareConfig->ActualCaps() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when the dx support level has changed
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::DXSupportLevelChanged()
+{
+ LOCK_SHADERAPI();
+ if ( IsPC() )
+ {
+ OverrideCaps( ShaderUtil()->GetConfig().dxSupportLevel );
+ }
+ else
+ {
+ Assert( 0 );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// FIXME: Remove! Backward compat only
+//-----------------------------------------------------------------------------
+int CShaderAPIDx8::GetActualTextureStageCount() const
+{
+ return g_pHardwareConfig->GetActualTextureStageCount();
+}
+
+int CShaderAPIDx8::GetActualSamplerCount() const
+{
+ return g_pHardwareConfig->GetActualSamplerCount();
+}
+
+int CShaderAPIDx8::StencilBufferBits() const
+{
+ return m_bUsingStencil ? m_iStencilBufferBits : 0;
+}
+
+bool CShaderAPIDx8::IsAAEnabled() const
+{
+ bool bAntialiasing = ( m_PresentParameters.MultiSampleType != D3DMULTISAMPLE_NONE );
+ return bAntialiasing;
+}
+
+
+//-----------------------------------------------------------------------------
+// Methods related to queuing functions to be called per-(pMesh->Draw call) or per-pass
+//-----------------------------------------------------------------------------
+bool CShaderAPIDx8::IsCommitFuncInUse( CommitFuncType_t func, CommitShaderType_t shader, int nFunc ) const
+{
+ Assert( nFunc < COMMIT_FUNC_COUNT );
+ return ( m_pCommitFlags[func][shader][ nFunc >> 3 ] & ( 1 << ( nFunc & 0x7 ) ) ) != 0;
+}
+
+void CShaderAPIDx8::MarkCommitFuncInUse( CommitFuncType_t func, CommitShaderType_t shader, int nFunc )
+{
+ m_pCommitFlags[func][shader][ nFunc >> 3 ] |= 1 << ( nFunc & 0x7 );
+}
+
+void CShaderAPIDx8::AddCommitFunc( CommitFuncType_t func, CommitShaderType_t shader, StateCommitFunc_t f )
+{
+ m_CommitFuncs[func][shader].AddToTail( f );
+}
+
+
+//-----------------------------------------------------------------------------
+// Clears all commit functions
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::ClearAllCommitFuncs( CommitFuncType_t func, CommitShaderType_t shader )
+{
+ memset( m_pCommitFlags[func][shader], 0, COMMIT_FUNC_BYTE_COUNT );
+ m_CommitFuncs[func][shader].RemoveAll();
+}
+
+
+//-----------------------------------------------------------------------------
+// Calls all commit functions in a particular list
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::CallCommitFuncs( CommitFuncType_t func, CommitShaderType_t shader, bool bForce )
+{
+ // 360 does not have have a FF pipe
+ Assert ( IsPC() || ( IsX360() && shader != COMMIT_FIXED_FUNCTION ) );
+
+ // Don't bother committing anything if we're deactivated
+ if ( IsDeactivated() )
+ return;
+
+ CUtlVector< StateCommitFunc_t > &funcList = m_CommitFuncs[func][shader];
+ int nCount = funcList.Count();
+ if ( nCount == 0 )
+ return;
+
+ for ( int i = 0; i < nCount; ++i )
+ {
+ funcList[i]( Dx9Device(), m_DesiredState, m_DynamicState, bForce );
+ }
+ ClearAllCommitFuncs( func, shader );
+}
+
+
+//-----------------------------------------------------------------------------
+// Calls all per-mesh draw commit functions
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::CallCommitFuncs( CommitFuncType_t func, bool bUsingFixedFunction, bool bForce )
+{
+ // Fixed-Function only funcs
+ if ( IsPC() && ( bUsingFixedFunction || bForce ) )
+ {
+ CallCommitFuncs( func, COMMIT_FIXED_FUNCTION, bForce );
+ }
+
+ // Vertex-shader only funcs
+ if ( !bUsingFixedFunction || bForce )
+ {
+ CallCommitFuncs( func, COMMIT_VERTEX_SHADER, bForce );
+ }
+
+ // State set in both FF + VS
+ CallCommitFuncs( func, COMMIT_ALWAYS, bForce );
+}
+
+//-----------------------------------------------------------------------------
+// Sets the sampler state
+//-----------------------------------------------------------------------------
+static FORCEINLINE void SetSamplerState( IDirect3DDevice9 *pDevice, int stage, D3DSAMPLERSTATETYPE state, DWORD val )
+{
+ RECORD_SAMPLER_STATE( stage, state, val );
+
+#if defined( _X360 )
+ if ( state == D3DSAMP_NOTSUPPORTED )
+ return;
+#endif
+
+ pDevice->SetSamplerState( stage, state, val );
+}
+
+inline void CShaderAPIDx8::SetSamplerState( int stage, D3DSAMPLERSTATETYPE state, DWORD val )
+{
+#ifndef DX_TO_GL_ABSTRACTION
+ if ( IsDeactivated() )
+ return;
+#endif
+
+ ::SetSamplerState( Dx9Device(), stage, state, val );
+}
+
+//-----------------------------------------------------------------------------
+// Sets the texture stage state
+//-----------------------------------------------------------------------------
+inline void CShaderAPIDx8::SetTextureStageState( int stage, D3DTEXTURESTAGESTATETYPE state, DWORD val )
+{
+#if !defined( _X360 )
+ if ( IsDeactivated() )
+ return;
+
+ Dx9Device()->SetTextureStageState( stage, state, val );
+#endif
+}
+
+inline void CShaderAPIDx8::SetRenderState( D3DRENDERSTATETYPE state, DWORD val, bool bFlushIfChanged )
+{
+#if ( !defined( _X360 ) && !defined( DX_TO_GL_ABSTRACTION ) )
+ {
+ if ( IsDeactivated() )
+ return;
+ }
+#else
+ {
+ Assert( state != D3DRS_NOTSUPPORTED ); //Use SetSupportedRenderState() macro to avoid this at compile time
+ //if ( state == D3DRS_NOTSUPPORTED )
+ // return;
+ }
+#endif
+
+ Assert( state >= 0 && ( int )state < MAX_NUM_RENDERSTATES );
+ if ( m_DynamicState.m_RenderState[state] != val )
+ {
+ if ( bFlushIfChanged )
+ {
+ FlushBufferedPrimitives();
+ }
+#ifdef DX_TO_GL_ABSTRACTION
+ Dx9Device()->SetRenderStateInline( state, val );
+#else
+ Dx9Device()->SetRenderState( state, val );
+#endif
+ m_DynamicState.m_RenderState[state] = val;
+ }
+}
+
+#ifdef DX_TO_GL_ABSTRACTION
+ // Purposely always writing the new state (even if it's not changed), in case SetRenderStateConstInline() compiles away to nothing (it sometimes does)
+ #define SetRenderStateConstMacro(t, state, val ) \
+ do \
+ { \
+ Assert( state >= 0 && ( int )state < MAX_NUM_RENDERSTATES ); \
+ if ( t->m_DynamicState.m_RenderState[state] != (DWORD)val ) \
+ { \
+ Dx9Device()->SetRenderStateConstInline( state, val ); \
+ } \
+ t->m_DynamicState.m_RenderState[state] = val; \
+ } while(0)
+#else
+ #define SetRenderStateConstMacro(t, state, val ) t->SetRenderState( state, val );
+#endif
+
+//-----------------------------------------------------------------------------
+// Commits viewports
+//-----------------------------------------------------------------------------
+static void CommitSetScissorRect( IDirect3DDevice9 *pDevice, const DynamicState_t &desiredState, DynamicState_t &currentState, bool bForce )
+{
+ // Set the enable/disable renderstate
+
+ bool bEnableChanged = desiredState.m_RenderState[D3DRS_SCISSORTESTENABLE] != currentState.m_RenderState[D3DRS_SCISSORTESTENABLE];
+ if ( bEnableChanged )
+ {
+ Dx9Device()->SetRenderState( D3DRS_SCISSORTESTENABLE, desiredState.m_RenderState[D3DRS_SCISSORTESTENABLE] );
+ currentState.m_RenderState[D3DRS_SCISSORTESTENABLE] = desiredState.m_RenderState[D3DRS_SCISSORTESTENABLE];
+ }
+
+ // Only bother with the rect if we're enabling
+ if ( desiredState.m_RenderState[D3DRS_SCISSORTESTENABLE] )
+ {
+ int nWidth, nHeight;
+ ITexture *pTexture = ShaderAPI()->GetRenderTargetEx( 0 );
+ if ( pTexture == NULL )
+ {
+ ShaderAPI()->GetBackBufferDimensions( nWidth, nHeight );
+ }
+ else
+ {
+ nWidth = pTexture->GetActualWidth();
+ nHeight = pTexture->GetActualHeight();
+ }
+
+ Assert( (desiredState.m_ScissorRect.left <= nWidth) && (desiredState.m_ScissorRect.bottom <= nHeight) &&
+ ( desiredState.m_ScissorRect.top >= 0 ) && (desiredState.m_ScissorRect.left >= 0) );
+
+ clamp( desiredState.m_ScissorRect.right, 0, nWidth );
+ clamp( desiredState.m_ScissorRect.left, 0, nWidth );
+ clamp( desiredState.m_ScissorRect.top, 0, nHeight );
+ clamp( desiredState.m_ScissorRect.bottom, 0, nHeight );
+
+ Dx9Device()->SetScissorRect( &desiredState.m_ScissorRect );
+ currentState.m_ScissorRect = desiredState.m_ScissorRect;
+ }
+}
+
+// Routine for setting scissor rect
+// If pScissorRect is NULL, disable scissoring by setting the render state
+// If pScissorRect is non-NULL, set the RECT state in Direct3D AND set the renderstate
+inline void CShaderAPIDx8::SetScissorRect( const int nLeft, const int nTop, const int nRight, const int nBottom, const bool bEnableScissor )
+{
+ Assert( (nLeft <= nRight) && (nTop <= nBottom) ); //360 craps itself if this isn't true
+ if ( !g_pHardwareConfig->Caps().m_bScissorSupported )
+ return;
+
+ // If we're turning it on, check the validity of the rect
+ if ( bEnableScissor )
+ {
+ int nWidth, nHeight;
+ ITexture *pTexture = GetRenderTargetEx( 0 );
+ if ( pTexture == NULL )
+ {
+ GetBackBufferDimensions( nWidth, nHeight );
+ }
+ else
+ {
+ nWidth = pTexture->GetActualWidth();
+ nHeight = pTexture->GetActualHeight();
+ }
+
+ Assert( (nRight <= nWidth) && (nBottom <= nHeight) && ( nTop >= 0 ) && (nLeft >= 0) );
+
+ clamp( nRight, 0, nWidth );
+ clamp( nLeft, 0, nWidth );
+ clamp( nTop, 0, nHeight );
+ clamp( nBottom, 0, nHeight );
+ }
+
+ DWORD dwEnableScissor = bEnableScissor ? TRUE : FALSE;
+ RECT newScissorRect;
+ newScissorRect.left = nLeft;
+ newScissorRect.top = nTop;
+ newScissorRect.right = nRight;
+ newScissorRect.bottom = nBottom;
+
+ if ( !m_bResettingRenderState )
+ {
+ bool bEnableChanged = m_DesiredState.m_RenderState[D3DRS_SCISSORTESTENABLE] != dwEnableScissor;
+ bool bRectChanged = memcmp( &newScissorRect, &m_DesiredState.m_ScissorRect, sizeof(RECT) ) != 0;
+
+ if ( !bEnableChanged && !bRectChanged )
+ return;
+ }
+
+ if ( !IsDeactivated() )
+ {
+ // Do we need to do this always?
+ FlushBufferedPrimitives();
+ }
+
+ m_DesiredState.m_RenderState[D3DRS_SCISSORTESTENABLE] = dwEnableScissor;
+ memcpy( &m_DesiredState.m_ScissorRect, &newScissorRect, sizeof(RECT) );
+
+ ADD_COMMIT_FUNC( COMMIT_PER_DRAW, COMMIT_ALWAYS, CommitSetScissorRect );
+}
+
+inline void CShaderAPIDx8::SetRenderStateForce( D3DRENDERSTATETYPE state, DWORD val )
+{
+#if ( !defined( _X360 ) && !defined( DX_TO_GL_ABSTRACTION ) )
+ {
+ if ( IsDeactivated() )
+ return;
+ }
+#else
+ {
+ Assert( state != D3DRS_NOTSUPPORTED ); //Use SetSupportedRenderStateForce() macro to avoid this at compile time
+ //if ( state == D3DRS_NOTSUPPORTED )
+ // return;
+ }
+#endif
+
+ Dx9Device()->SetRenderState( state, val );
+ m_DynamicState.m_RenderState[state] = val;
+}
+
+
+//-----------------------------------------------------------------------------
+// Set the values for pixel shader constants that don't change.
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::SetStandardVertexShaderConstants( float fOverbright )
+{
+ LOCK_SHADERAPI();
+ if ( g_pHardwareConfig->GetDXSupportLevel() < 80 )
+ return;
+
+ // Set a couple standard constants....
+ Vector4D standardVertexShaderConstant( 0.0f, 1.0f, 2.0f, 0.5f );
+ SetVertexShaderConstant( VERTEX_SHADER_MATH_CONSTANTS0, standardVertexShaderConstant.Base(), 1 );
+
+ // [ gamma, overbright, 1/3, 1/overbright ]
+ standardVertexShaderConstant.Init( 1.0f/2.2f, fOverbright, 1.0f / 3.0f, 1.0f / fOverbright );
+ SetVertexShaderConstant( VERTEX_SHADER_MATH_CONSTANTS1, standardVertexShaderConstant.Base(), 1 );
+
+ int nModelIndex = g_pHardwareConfig->Caps().m_nDXSupportLevel < 90 ? VERTEX_SHADER_MODEL - 10 : VERTEX_SHADER_MODEL;
+
+/*
+ if ( g_pHardwareConfig->Caps().m_SupportsVertexShaders_3_0 )
+ {
+ Vector4D factors[4];
+ factors[0].Init( 1, 0, 0, 0 );
+ factors[1].Init( 0, 1, 0, 0 );
+ factors[2].Init( 0, 0, 1, 0 );
+ factors[3].Init( 0, 0, 0, 1 );
+ SetVertexShaderConstant( VERTEX_SHADER_DOT_PRODUCT_FACTORS, factors[0].Base(), 4 );
+ }
+*/
+
+ if ( g_pHardwareConfig->Caps().m_SupportsVertexShaders_2_0 )
+ {
+ float c[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ SetVertexShaderConstant( VERTEX_SHADER_FLEXSCALE, c, 1 );
+ }
+ else
+ {
+ // These point to the lighting and the transforms
+ standardVertexShaderConstant.Init(
+ VERTEX_SHADER_LIGHTS,
+ VERTEX_SHADER_LIGHTS + 5,
+ // Use COLOR instead of UBYTE4 since Geforce3 does not support it
+ // vConst.w should be 3, but due to about hack, mul by 255 and add epsilon
+ // 360 supports UBYTE4, so no fixup required
+ (IsPC() || !IsX360()) ? 765.01f : 3.0f,
+ nModelIndex ); // DX8 has different constant packing
+
+ SetVertexShaderConstant( VERTEX_SHADER_LIGHT_INDEX, standardVertexShaderConstant.Base(), 1 );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Initialize vertex and pixel shaders
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::InitVertexAndPixelShaders()
+{
+ // Allocate space for the pixel and vertex shader constants...
+ if ( g_pHardwareConfig->Caps().m_SupportsPixelShaders )
+ {
+ // pixel shaders
+ {
+ if (m_DynamicState.m_pVectorPixelShaderConstant)
+ {
+ delete[] m_DynamicState.m_pVectorPixelShaderConstant;
+ }
+ m_DynamicState.m_pVectorPixelShaderConstant = new Vector4D[g_pHardwareConfig->Caps().m_NumPixelShaderConstants];
+
+ if (m_DesiredState.m_pVectorPixelShaderConstant)
+ {
+ delete[] m_DesiredState.m_pVectorPixelShaderConstant;
+ }
+ m_DesiredState.m_pVectorPixelShaderConstant = new Vector4D[g_pHardwareConfig->Caps().m_NumPixelShaderConstants];
+
+ if (m_DynamicState.m_pBooleanPixelShaderConstant)
+ {
+ delete[] m_DynamicState.m_pBooleanPixelShaderConstant;
+ }
+ m_DynamicState.m_pBooleanPixelShaderConstant = new BOOL[g_pHardwareConfig->Caps().m_NumBooleanPixelShaderConstants];
+
+ if (m_DesiredState.m_pBooleanPixelShaderConstant)
+ {
+ delete[] m_DesiredState.m_pBooleanPixelShaderConstant;
+ }
+ m_DesiredState.m_pBooleanPixelShaderConstant = new BOOL[g_pHardwareConfig->Caps().m_NumBooleanPixelShaderConstants];
+
+ if (m_DynamicState.m_pIntegerPixelShaderConstant)
+ {
+ delete[] m_DynamicState.m_pIntegerPixelShaderConstant;
+ }
+ m_DynamicState.m_pIntegerPixelShaderConstant = new IntVector4D[g_pHardwareConfig->Caps().m_NumIntegerPixelShaderConstants];
+
+ if (m_DesiredState.m_pIntegerPixelShaderConstant)
+ {
+ delete[] m_DesiredState.m_pIntegerPixelShaderConstant;
+ }
+ m_DesiredState.m_pIntegerPixelShaderConstant = new IntVector4D[g_pHardwareConfig->Caps().m_NumIntegerPixelShaderConstants];
+
+ // force reset vector pixel constants
+ int i;
+ for ( i = 0; i < g_pHardwareConfig->Caps().m_NumPixelShaderConstants; ++i )
+ {
+ m_DesiredState.m_pVectorPixelShaderConstant[i].Init();
+ }
+ SetPixelShaderConstant( 0, m_DesiredState.m_pVectorPixelShaderConstant[0].Base(), g_pHardwareConfig->Caps().m_NumPixelShaderConstants, true );
+
+ // force reset boolean pixel constants
+ int nNumBooleanPixelShaderConstants = g_pHardwareConfig->Caps().m_NumBooleanPixelShaderConstants;
+ if ( nNumBooleanPixelShaderConstants )
+ {
+ for ( i = 0; i < nNumBooleanPixelShaderConstants; ++i )
+ {
+ m_DesiredState.m_pBooleanPixelShaderConstant[i] = 0;
+ }
+ SetBooleanPixelShaderConstant( 0, m_DesiredState.m_pBooleanPixelShaderConstant, nNumBooleanPixelShaderConstants, true );
+ }
+
+ // force reset integer pixel constants
+ int nNumIntegerPixelShaderConstants = g_pHardwareConfig->Caps().m_NumIntegerPixelShaderConstants;
+ if ( nNumIntegerPixelShaderConstants )
+ {
+ for ( i = 0; i < nNumIntegerPixelShaderConstants; ++i )
+ {
+ m_DesiredState.m_pIntegerPixelShaderConstant[i].Init();
+ }
+ SetIntegerPixelShaderConstant( 0, m_DesiredState.m_pIntegerPixelShaderConstant[0].Base(), nNumIntegerPixelShaderConstants, true );
+ }
+ }
+
+ // vertex shaders
+ {
+ if (m_DynamicState.m_pVectorVertexShaderConstant)
+ {
+ delete[] m_DynamicState.m_pVectorVertexShaderConstant;
+ }
+ m_DynamicState.m_pVectorVertexShaderConstant = new Vector4D[g_pHardwareConfig->Caps().m_NumVertexShaderConstants];
+
+ if (m_DesiredState.m_pVectorVertexShaderConstant)
+ {
+ delete[] m_DesiredState.m_pVectorVertexShaderConstant;
+ }
+ m_DesiredState.m_pVectorVertexShaderConstant = new Vector4D[g_pHardwareConfig->Caps().m_NumVertexShaderConstants];
+
+ if (m_DynamicState.m_pBooleanVertexShaderConstant)
+ {
+ delete[] m_DynamicState.m_pBooleanVertexShaderConstant;
+ }
+ m_DynamicState.m_pBooleanVertexShaderConstant = new BOOL[g_pHardwareConfig->Caps().m_NumBooleanVertexShaderConstants];
+
+ if (m_DesiredState.m_pBooleanVertexShaderConstant)
+ {
+ delete[] m_DesiredState.m_pBooleanVertexShaderConstant;
+ }
+ m_DesiredState.m_pBooleanVertexShaderConstant = new BOOL[g_pHardwareConfig->Caps().m_NumBooleanVertexShaderConstants];
+
+ if (m_DynamicState.m_pIntegerVertexShaderConstant)
+ {
+ delete[] m_DynamicState.m_pIntegerVertexShaderConstant;
+ }
+ m_DynamicState.m_pIntegerVertexShaderConstant = new IntVector4D[g_pHardwareConfig->Caps().m_NumIntegerVertexShaderConstants];
+
+ if (m_DesiredState.m_pIntegerVertexShaderConstant)
+ {
+ delete[] m_DesiredState.m_pIntegerVertexShaderConstant;
+ }
+ m_DesiredState.m_pIntegerVertexShaderConstant = new IntVector4D[g_pHardwareConfig->Caps().m_NumIntegerVertexShaderConstants];
+
+ // force reset vector vertex constants
+ int i;
+ for ( i = 0; i < g_pHardwareConfig->Caps().m_NumVertexShaderConstants; ++i )
+ {
+ m_DesiredState.m_pVectorVertexShaderConstant[i].Init();
+ }
+ SetVertexShaderConstant( 0, m_DesiredState.m_pVectorVertexShaderConstant[0].Base(), g_pHardwareConfig->Caps().m_NumVertexShaderConstants, true );
+
+ // force reset boolean vertex constants
+ for ( i = 0; i < g_pHardwareConfig->Caps().m_NumBooleanVertexShaderConstants; ++i )
+ {
+ m_DesiredState.m_pBooleanVertexShaderConstant[i] = 0;
+ }
+ SetBooleanVertexShaderConstant( 0, m_DesiredState.m_pBooleanVertexShaderConstant, g_pHardwareConfig->Caps().m_NumBooleanVertexShaderConstants, true );
+
+ // force reset integer vertex constants
+ for ( i = 0; i < g_pHardwareConfig->Caps().m_NumIntegerVertexShaderConstants; ++i )
+ {
+ m_DesiredState.m_pIntegerVertexShaderConstant[i].Init();
+ }
+ SetIntegerVertexShaderConstant( 0, m_DesiredState.m_pIntegerVertexShaderConstant[0].Base(), g_pHardwareConfig->Caps().m_NumIntegerVertexShaderConstants, true );
+ }
+
+ if ( IsX360() )
+ {
+ // to init/update all constants, must disable ownership
+ bool bPreviousState = OwnGPUResources( false );
+ WriteShaderConstantsToGPU();
+ OwnGPUResources( bPreviousState );
+ }
+ SetStandardVertexShaderConstants( OVERBRIGHT );
+ }
+
+ // Set up the vertex and pixel shader stuff
+ ShaderManager()->ResetShaderState();
+}
+
+
+//-----------------------------------------------------------------------------
+// Initialize render state
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::InitRenderState()
+{
+ // Set the default shadow state
+ g_pShaderShadowDx8->SetDefaultState();
+
+ // Grab a snapshot of this state; we'll be using it to set the board
+ // state to something well defined.
+ m_TransitionTable.TakeDefaultStateSnapshot();
+
+ if ( !IsDeactivated() )
+ {
+ ResetRenderState();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Commits vertex textures
+//-----------------------------------------------------------------------------
+static void CommitVertexTextures( IDirect3DDevice9 *pDevice, const DynamicState_t &desiredState, DynamicState_t &currentState, bool bForce )
+{
+ int nCount = g_pMaterialSystemHardwareConfig->GetVertexTextureCount();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ VertexTextureState_t &currentVTState = currentState.m_VertexTextureState[i];
+ ShaderAPITextureHandle_t textureHandle = desiredState.m_VertexTextureState[i].m_BoundTexture;
+
+ Texture_t *pTexture = ( textureHandle != INVALID_SHADERAPI_TEXTURE_HANDLE ) ? &g_ShaderAPIDX8.GetTexture( textureHandle ) : NULL;
+ if ( pTexture && ( pTexture->m_Flags & Texture_t::IS_VERTEX_TEXTURE ) == 0 )
+ {
+ Warning( "Attempting to bind a vertex texture (%s) which was not created as a vertex texture!\n", pTexture->m_DebugName.String() );
+ }
+
+ if ( bForce || ( currentVTState.m_BoundTexture != textureHandle ) )
+ {
+ currentVTState.m_BoundTexture = textureHandle;
+
+// RECORD_COMMAND( DX8_SET_VERTEXTEXTURE, 3 );
+// RECORD_INT( D3DVERTEXTEXTURESAMPLER0 + nStage );
+// RECORD_INT( pTexture ? pTexture->GetUniqueID() : 0xFFFF );
+// RECORD_INT( 0 );
+
+ IDirect3DBaseTexture *pD3DTexture = ( textureHandle >= 0 ) ? g_ShaderAPIDX8.GetD3DTexture( textureHandle ) : NULL;
+
+ pDevice->SetTexture( D3DVERTEXTEXTURESAMPLER0 + i, pD3DTexture );
+ }
+
+ if ( !pTexture )
+ continue;
+
+ D3DTEXTUREADDRESS nNewUTexWrap = pTexture->m_UTexWrap;
+ if ( bForce || ( currentVTState.m_UTexWrap != nNewUTexWrap ) )
+ {
+ currentVTState.m_UTexWrap = nNewUTexWrap;
+ SetSamplerState( pDevice, D3DVERTEXTEXTURESAMPLER0 + i, D3DSAMP_ADDRESSU, currentVTState.m_UTexWrap );
+ }
+
+ D3DTEXTUREADDRESS nNewVTexWrap = pTexture->m_VTexWrap;
+ if ( bForce || ( currentVTState.m_VTexWrap != nNewVTexWrap ) )
+ {
+ currentVTState.m_VTexWrap = nNewVTexWrap;
+ SetSamplerState( pDevice, D3DVERTEXTEXTURESAMPLER0 + i, D3DSAMP_ADDRESSV, currentVTState.m_VTexWrap );
+ }
+
+ /*
+ D3DTEXTUREADDRESS nNewWTexWrap = pTexture->GetWTexWrap();
+ if ( bForce || ( currentVTState.m_WTexWrap != nNewWTexWrap ) )
+ {
+ currentVTState.m_WTexWrap = nNewWTexWrap;
+ SetSamplerState( pDevice, D3DVERTEXTEXTURESAMPLER0 + i, D3DSAMP_ADDRESSW, currentVTState.m_WTexWrap );
+ }
+ */
+
+ D3DTEXTUREFILTERTYPE nNewMinFilter = pTexture->m_MinFilter;
+ if ( bForce || ( currentVTState.m_MinFilter != nNewMinFilter ) )
+ {
+ currentVTState.m_MinFilter = nNewMinFilter;
+ SetSamplerState( pDevice, D3DVERTEXTEXTURESAMPLER0 + i, D3DSAMP_MINFILTER, currentVTState.m_MinFilter );
+ }
+
+ D3DTEXTUREFILTERTYPE nNewMagFilter = pTexture->m_MagFilter;
+ if ( bForce || ( currentVTState.m_MagFilter != nNewMagFilter ) )
+ {
+ currentVTState.m_MagFilter = nNewMagFilter;
+ SetSamplerState( pDevice, D3DVERTEXTEXTURESAMPLER0 + i, D3DSAMP_MAGFILTER, currentVTState.m_MagFilter );
+ }
+
+ D3DTEXTUREFILTERTYPE nNewMipFilter = pTexture->m_MipFilter;
+ if ( bForce || ( currentVTState.m_MipFilter != nNewMipFilter ) )
+ {
+ currentVTState.m_MipFilter = nNewMipFilter;
+ SetSamplerState( pDevice, D3DVERTEXTEXTURESAMPLER0 + i, D3DSAMP_MIPFILTER, currentVTState.m_MipFilter );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns true if the state snapshot is translucent
+//-----------------------------------------------------------------------------
+bool CShaderAPIDx8::IsTranslucent( StateSnapshot_t id ) const
+{
+ LOCK_SHADERAPI();
+ return m_TransitionTable.GetSnapshot(id).m_AlphaBlendEnable;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns true if the state snapshot is alpha tested
+//-----------------------------------------------------------------------------
+bool CShaderAPIDx8::IsAlphaTested( StateSnapshot_t id ) const
+{
+ LOCK_SHADERAPI();
+ return m_TransitionTable.GetSnapshot(id).m_AlphaTestEnable;
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets at the shadow state for a particular state snapshot
+//-----------------------------------------------------------------------------
+bool CShaderAPIDx8::IsDepthWriteEnabled( StateSnapshot_t id ) const
+{
+ LOCK_SHADERAPI();
+ return m_TransitionTable.GetSnapshot(id).m_ZWriteEnable;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Returns true if the state snapshot uses shaders
+//-----------------------------------------------------------------------------
+bool CShaderAPIDx8::UsesVertexAndPixelShaders( StateSnapshot_t id ) const
+{
+ LOCK_SHADERAPI();
+ return m_TransitionTable.GetSnapshotShader(id).m_VertexShader != INVALID_SHADER;
+}
+
+
+//-----------------------------------------------------------------------------
+// Takes a snapshot
+//-----------------------------------------------------------------------------
+StateSnapshot_t CShaderAPIDx8::TakeSnapshot( )
+{
+ LOCK_SHADERAPI();
+
+ return m_TransitionTable.TakeSnapshot();
+}
+
+void CShaderAPIDx8::ResetDXRenderState( void )
+{
+ float zero = 0.0f;
+ float one = 1.0f;
+ DWORD dZero = *((DWORD*)(&zero));
+ DWORD dOne = *((DWORD*)(&one));
+
+ // Set default values for all dx render states.
+ // NOTE: this does not include states encapsulated by the transition table,
+ // which are reset in CTransitionTable::UseDefaultState
+ SetSupportedRenderStateForce( D3DRS_FILLMODE, D3DFILL_SOLID );
+ SetSupportedRenderStateForce( D3DRS_SHADEMODE, D3DSHADE_GOURAUD );
+ SetSupportedRenderStateForce( D3DRS_LASTPIXEL, TRUE );
+ SetSupportedRenderStateForce( D3DRS_CULLMODE, D3DCULL_CCW );
+ SetSupportedRenderStateForce( D3DRS_DITHERENABLE, FALSE );
+ SetSupportedRenderStateForce( D3DRS_FOGENABLE, FALSE );
+ SetSupportedRenderStateForce( D3DRS_SPECULARENABLE, FALSE );
+ SetSupportedRenderStateForce( D3DRS_FOGCOLOR, 0 );
+ SetSupportedRenderStateForce( D3DRS_FOGTABLEMODE, D3DFOG_NONE );
+ SetSupportedRenderStateForce( D3DRS_FOGSTART, dZero );
+ SetSupportedRenderStateForce( D3DRS_FOGEND, dOne );
+ SetSupportedRenderStateForce( D3DRS_FOGDENSITY, dZero );
+ SetSupportedRenderStateForce( D3DRS_RANGEFOGENABLE, FALSE );
+ SetSupportedRenderStateForce( D3DRS_STENCILENABLE, FALSE);
+ SetSupportedRenderStateForce( D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP );
+ SetSupportedRenderStateForce( D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP );
+ SetSupportedRenderStateForce( D3DRS_STENCILPASS, D3DSTENCILOP_KEEP );
+ SetSupportedRenderStateForce( D3DRS_STENCILFUNC, D3DCMP_ALWAYS );
+ SetSupportedRenderStateForce( D3DRS_STENCILREF, 0 );
+ SetSupportedRenderStateForce( D3DRS_STENCILMASK, 0xFFFFFFFF );
+ SetSupportedRenderStateForce( D3DRS_STENCILWRITEMASK, 0xFFFFFFFF );
+ SetSupportedRenderStateForce( D3DRS_TEXTUREFACTOR, 0xFFFFFFFF );
+ SetSupportedRenderStateForce( D3DRS_WRAP0, 0 );
+ SetSupportedRenderStateForce( D3DRS_WRAP1, 0 );
+ SetSupportedRenderStateForce( D3DRS_WRAP2, 0 );
+ SetSupportedRenderStateForce( D3DRS_WRAP3, 0 );
+ SetSupportedRenderStateForce( D3DRS_WRAP4, 0 );
+ SetSupportedRenderStateForce( D3DRS_WRAP5, 0 );
+ SetSupportedRenderStateForce( D3DRS_WRAP6, 0 );
+ SetSupportedRenderStateForce( D3DRS_WRAP7, 0 );
+ SetSupportedRenderStateForce( D3DRS_CLIPPING, TRUE );
+ SetSupportedRenderStateForce( D3DRS_LIGHTING, TRUE );
+ SetSupportedRenderStateForce( D3DRS_AMBIENT, 0 );
+ SetSupportedRenderStateForce( D3DRS_FOGVERTEXMODE, D3DFOG_NONE);
+ SetSupportedRenderStateForce( D3DRS_COLORVERTEX, TRUE );
+ SetSupportedRenderStateForce( D3DRS_LOCALVIEWER, TRUE );
+ SetSupportedRenderStateForce( D3DRS_NORMALIZENORMALS, FALSE );
+ SetSupportedRenderStateForce( D3DRS_SPECULARMATERIALSOURCE, D3DMCS_COLOR2 );
+ SetSupportedRenderStateForce( D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL );
+ SetSupportedRenderStateForce( D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_MATERIAL );
+ SetSupportedRenderStateForce( D3DRS_VERTEXBLEND, D3DVBF_DISABLE );
+ SetSupportedRenderStateForce( D3DRS_CLIPPLANEENABLE, 0 );
+
+ // -disable_d3d9_hacks is for debugging. For example, the "CENT" driver hack thing causes the flashlight pass to appear much brighter on NVidia drivers.
+ if ( IsPC() && !IsOpenGL() && !CommandLine()->CheckParm( "-disable_d3d9_hacks" ) )
+ {
+ if ( g_pHardwareConfig->Caps().m_bNeedsATICentroidHack && ( g_pHardwareConfig->Caps().m_VendorID == VENDORID_ATI ) )
+ {
+ SetSupportedRenderStateForce( D3DRS_POINTSIZE, MAKEFOURCC( 'C', 'E', 'N', 'T' ) );
+ }
+
+ if( g_pHardwareConfig->Caps().m_bDisableShaderOptimizations )
+ {
+ SetSupportedRenderStateForce( D3DRS_ADAPTIVETESS_Y, MAKEFOURCC( 'C', 'O', 'P', 'M' ) );
+ }
+ }
+ SetSupportedRenderStateForce( D3DRS_POINTSIZE, dOne );
+ SetSupportedRenderStateForce( D3DRS_POINTSIZE_MIN, dOne );
+ SetSupportedRenderStateForce( D3DRS_POINTSPRITEENABLE, FALSE );
+ SetSupportedRenderStateForce( D3DRS_POINTSCALEENABLE, FALSE );
+ SetSupportedRenderStateForce( D3DRS_POINTSCALE_A, dOne );
+ SetSupportedRenderStateForce( D3DRS_POINTSCALE_B, dZero );
+ SetSupportedRenderStateForce( D3DRS_POINTSCALE_C, dZero );
+ SetSupportedRenderStateForce( D3DRS_MULTISAMPLEANTIALIAS, TRUE );
+ SetSupportedRenderStateForce( D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF );
+ SetSupportedRenderStateForce( D3DRS_PATCHEDGESTYLE, D3DPATCHEDGE_DISCRETE );
+ SetSupportedRenderStateForce( D3DRS_DEBUGMONITORTOKEN, D3DDMT_ENABLE );
+ float sixtyFour = 64.0f;
+ SetSupportedRenderStateForce( D3DRS_POINTSIZE_MAX, *((DWORD*)(&sixtyFour)));
+ SetSupportedRenderStateForce( D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE );
+ SetSupportedRenderStateForce( D3DRS_TWEENFACTOR, dZero );
+ SetSupportedRenderStateForce( D3DRS_POSITIONDEGREE, D3DDEGREE_CUBIC );
+ SetSupportedRenderStateForce( D3DRS_NORMALDEGREE, D3DDEGREE_LINEAR );
+ SetSupportedRenderStateForce( D3DRS_SCISSORTESTENABLE, FALSE);
+ SetSupportedRenderStateForce( D3DRS_SLOPESCALEDEPTHBIAS, dZero );
+ SetSupportedRenderStateForce( D3DRS_ANTIALIASEDLINEENABLE, FALSE );
+ SetSupportedRenderStateForce( D3DRS_MINTESSELLATIONLEVEL, dOne );
+ SetSupportedRenderStateForce( D3DRS_MAXTESSELLATIONLEVEL, dOne );
+ SetSupportedRenderStateForce( D3DRS_ADAPTIVETESS_X, dZero );
+ SetSupportedRenderStateForce( D3DRS_ADAPTIVETESS_Y, dZero );
+ SetSupportedRenderStateForce( D3DRS_ADAPTIVETESS_Z, dOne );
+ SetSupportedRenderStateForce( D3DRS_ADAPTIVETESS_W, dZero );
+ SetSupportedRenderStateForce( D3DRS_ENABLEADAPTIVETESSELLATION, FALSE );
+ SetSupportedRenderStateForce( D3DRS_TWOSIDEDSTENCILMODE, FALSE );
+ SetSupportedRenderStateForce( D3DRS_CCW_STENCILFAIL, D3DSTENCILOP_KEEP );
+ SetSupportedRenderStateForce( D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_KEEP );
+ SetSupportedRenderStateForce( D3DRS_CCW_STENCILPASS, D3DSTENCILOP_KEEP );
+ SetSupportedRenderStateForce( D3DRS_CCW_STENCILFUNC, D3DCMP_ALWAYS );
+ SetSupportedRenderStateForce( D3DRS_COLORWRITEENABLE1, 0x0000000f );
+ SetSupportedRenderStateForce( D3DRS_COLORWRITEENABLE2, 0x0000000f );
+ SetSupportedRenderStateForce( D3DRS_COLORWRITEENABLE3, 0x0000000f );
+ SetSupportedRenderStateForce( D3DRS_BLENDFACTOR, 0xffffffff );
+ SetSupportedRenderStateForce( D3DRS_SRGBWRITEENABLE, 0);
+ SetSupportedRenderStateForce( D3DRS_DEPTHBIAS, dZero );
+ SetSupportedRenderStateForce( D3DRS_WRAP8, 0 );
+ SetSupportedRenderStateForce( D3DRS_WRAP9, 0 );
+ SetSupportedRenderStateForce( D3DRS_WRAP10, 0 );
+ SetSupportedRenderStateForce( D3DRS_WRAP11, 0 );
+ SetSupportedRenderStateForce( D3DRS_WRAP12, 0 );
+ SetSupportedRenderStateForce( D3DRS_WRAP13, 0 );
+ SetSupportedRenderStateForce( D3DRS_WRAP14, 0 );
+ SetSupportedRenderStateForce( D3DRS_WRAP15, 0 );
+ SetSupportedRenderStateForce( D3DRS_BLENDOP, D3DBLENDOP_ADD );
+ SetSupportedRenderStateForce( D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD );
+
+#if defined( _X360 )
+ SetSupportedRenderStateForce( D3DRS_HIZENABLE, D3DHIZ_AUTOMATIC );
+ SetSupportedRenderStateForce( D3DRS_HIZWRITEENABLE, D3DHIZ_AUTOMATIC );
+
+ SetSupportedRenderStateForce( D3DRS_HISTENCILENABLE, FALSE );
+ SetSupportedRenderStateForce( D3DRS_HISTENCILWRITEENABLE, FALSE );
+ SetSupportedRenderStateForce( D3DRS_HISTENCILFUNC, D3DHSCMP_EQUAL );
+ SetSupportedRenderStateForce( D3DRS_HISTENCILREF, 0 );
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Own GPU Resources. Return previous state.
+//-----------------------------------------------------------------------------
+bool CShaderAPIDx8::OwnGPUResources( bool bEnable )
+{
+#if defined( _X360 )
+ if ( m_bGPUOwned == bEnable )
+ {
+ return m_bGPUOwned;
+ }
+
+ if ( !bEnable )
+ {
+ Dx9Device()->GpuDisownAll();
+ }
+ else
+ {
+ // owned GPU constants can be set very fast, and must be in blocks of 4
+ // there are 256, but the game only uses 217 (snapped to 220), leaving just enough room for shader literals
+ COMPILE_TIME_ASSERT( VERTEX_SHADER_MODEL + 3*NUM_MODEL_TRANSFORMS == 217 );
+ Dx9Device()->GpuOwnVertexShaderConstantF( 0, AlignValue( VERTEX_SHADER_MODEL + 3*NUM_MODEL_TRANSFORMS, 4 ) );
+ // there are 256, but the game only utilizes 32, leaving lots of room for shader literals
+ Dx9Device()->GpuOwnPixelShaderConstantF( 0, 32 );
+ }
+
+ bool bPrevious = m_bGPUOwned;
+ m_bGPUOwned = bEnable;
+
+ return bPrevious;
+#else
+ return false;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Reset render state (to its initial value)
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::ResetRenderState( bool bFullReset )
+{
+ LOCK_SHADERAPI();
+ RECORD_DEBUG_STRING( "BEGIN ResetRenderState" );
+
+ if ( !CanDownloadTextures() )
+ {
+ QueueResetRenderState();
+ return;
+ }
+
+ m_bResettingRenderState = true;
+
+ OwnGPUResources( true );
+
+ ResetDXRenderState();
+
+ // We're not currently rendering anything
+ m_nCurrentSnapshot = -1;
+
+ D3DXMatrixIdentity( &m_CachedPolyOffsetProjectionMatrix );
+ D3DXMatrixIdentity( &m_CachedFastClipProjectionMatrix );
+ D3DXMatrixIdentity( &m_CachedFastClipPolyOffsetProjectionMatrix );
+ m_UsingTextureRenderTarget = false;
+
+ m_SceneFogColor[0] = 0;
+ m_SceneFogColor[1] = 0;
+ m_SceneFogColor[2] = 0;
+ m_SceneFogMode = MATERIAL_FOG_NONE;
+
+ // This is state that isn't part of the snapshot per-se, because we
+ // don't need it when it's actually time to render. This just helps us
+ // to construct the shadow state.
+ m_DynamicState.m_ClearColor = D3DCOLOR_XRGB(0,0,0);
+
+ if ( bFullReset )
+ {
+ InitVertexAndPixelShaders();
+ }
+ else
+ {
+ // just need to dirty the dynamic state, desired state gets copied into below
+ Q_memset( m_DynamicState.m_pVectorPixelShaderConstant, 0, g_pHardwareConfig->Caps().m_NumPixelShaderConstants * sizeof( Vector4D ) );
+ Q_memset( m_DynamicState.m_pBooleanPixelShaderConstant, 0, g_pHardwareConfig->Caps().m_NumBooleanPixelShaderConstants * sizeof( BOOL ) );
+ Q_memset( m_DynamicState.m_pIntegerPixelShaderConstant, 0, g_pHardwareConfig->Caps().m_NumIntegerPixelShaderConstants * sizeof( IntVector4D ) );
+
+ Q_memset( m_DynamicState.m_pVectorVertexShaderConstant, 0, g_pHardwareConfig->Caps().m_NumVertexShaderConstants * sizeof( Vector4D ) );
+ Q_memset( m_DynamicState.m_pBooleanVertexShaderConstant, 0, g_pHardwareConfig->Caps().m_NumBooleanVertexShaderConstants * sizeof( BOOL ) );
+ Q_memset( m_DynamicState.m_pIntegerVertexShaderConstant, 0, g_pHardwareConfig->Caps().m_NumIntegerVertexShaderConstants * sizeof( IntVector4D ) );
+
+ SetStandardVertexShaderConstants( OVERBRIGHT );
+ }
+
+ //Set the default compressed depth range written to dest alpha. Only need to compress it for 8bit alpha to get a useful gradient.
+ m_DynamicState.m_DestAlphaDepthRange = (g_pHardwareConfig->GetHDRType() == HDR_TYPE_FLOAT) ? 8192.0f : 192.0f;
+
+ m_CachedAmbientLightCube = STATE_CHANGED;
+
+ // Set the constant color
+ m_DynamicState.m_ConstantColor = 0xFFFFFFFF;
+ Color4ub( 255, 255, 255, 255 );
+
+ // Ambient light color
+ m_DynamicState.m_Ambient = 0;
+ SetSupportedRenderState( D3DRS_AMBIENT, m_DynamicState.m_Ambient );
+
+ // Fog
+ m_VertexShaderFogParams[0] = m_VertexShaderFogParams[1] = 0.0f;
+ m_WorldSpaceCameraPositon.Init( 0, 0, 0.01f, 0 ); // Don't let z be zero, as some pixel shaders will divide by this
+ m_DynamicState.m_FogColor = 0xFFFFFFFF;
+ m_DynamicState.m_PixelFogColor[0] = m_DynamicState.m_PixelFogColor[1] =
+ m_DynamicState.m_PixelFogColor[2] = m_DynamicState.m_PixelFogColor[3] = 0.0f;
+ m_DynamicState.m_bFogGammaCorrectionDisabled = false;
+ m_DynamicState.m_FogEnable = false;
+ m_DynamicState.m_SceneFog = MATERIAL_FOG_NONE;
+ m_DynamicState.m_FogMode = D3DFOG_NONE;
+ m_DynamicState.m_FogStart = -1;
+ m_DynamicState.m_FogEnd = -1;
+ m_DynamicState.m_FogMaxDensity = -1.0f;
+ m_DynamicState.m_FogZ = 0.0f;
+
+ SetSupportedRenderState( D3DRS_FOGCOLOR, m_DynamicState.m_FogColor );
+ SetSupportedRenderState( D3DRS_FOGENABLE, m_DynamicState.m_FogEnable );
+ SetSupportedRenderState( D3DRS_FOGTABLEMODE, D3DFOG_NONE );
+ SetSupportedRenderState( D3DRS_FOGVERTEXMODE, D3DFOG_NONE );
+ SetSupportedRenderState( D3DRS_RANGEFOGENABLE, false );
+
+ FogStart( 0 );
+ FogEnd( 0 );
+ FogMaxDensity( 1.0f );
+
+ m_DynamicState.m_bSRGBWritesEnabled = false;
+
+ // Set the cull mode
+ m_DynamicState.m_bCullEnabled = true;
+ m_DynamicState.m_CullMode = D3DCULL_CCW;
+ m_DynamicState.m_DesiredCullMode = D3DCULL_CCW;
+ SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW );
+
+ // No shade mode yet
+ m_DynamicState.m_ShadeMode = (D3DSHADEMODE)-1;
+ ShadeMode( SHADER_SMOOTH );
+
+ m_DynamicState.m_bHWMorphingEnabled = false;
+
+ // Skinning...
+ m_DynamicState.m_NumBones = 0;
+ m_DynamicState.m_VertexBlend = (D3DVERTEXBLENDFLAGS)-1;
+ SetSupportedRenderState( D3DRS_VERTEXBLEND, D3DVBF_DISABLE );
+ SetSupportedRenderState( D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE );
+
+ // No normal normalization
+ m_DynamicState.m_NormalizeNormals = false;
+ SetSupportedRenderState( D3DRS_NORMALIZENORMALS, m_DynamicState.m_NormalizeNormals );
+
+ bool bAntialiasing = ( m_PresentParameters.MultiSampleType != D3DMULTISAMPLE_NONE );
+ if ( g_pHardwareConfig->GetHDRType() == HDR_TYPE_FLOAT )
+ {
+ bAntialiasing = false;
+ }
+ SetRenderState( D3DRS_MULTISAMPLEANTIALIAS, bAntialiasing );
+
+ // Anisotropic filtering is disabled by default
+ if ( bFullReset )
+ {
+ SetAnisotropicLevel( 1 );
+ }
+
+ int i;
+ for ( i = 0; i < g_pHardwareConfig->ActualCaps().m_NumTextureStages; ++i )
+ {
+ TextureStage(i).m_TextureTransformFlags = D3DTTFF_DISABLE;
+ TextureStage(i).m_BumpEnvMat00 = 1.0f;
+ TextureStage(i).m_BumpEnvMat01 = 0.0f;
+ TextureStage(i).m_BumpEnvMat10 = 0.0f;
+ TextureStage(i).m_BumpEnvMat11 = 1.0f;
+
+ SetTextureStageState( i, D3DTSS_TEXTURETRANSFORMFLAGS, TextureStage(i).m_TextureTransformFlags );
+ SetTextureStageState( i, D3DTSS_BUMPENVMAT00, *( ( LPDWORD ) (&TextureStage(i).m_BumpEnvMat00) ) );
+ SetTextureStageState( i, D3DTSS_BUMPENVMAT01, *( ( LPDWORD ) (&TextureStage(i).m_BumpEnvMat01) ) );
+ SetTextureStageState( i, D3DTSS_BUMPENVMAT10, *( ( LPDWORD ) (&TextureStage(i).m_BumpEnvMat10) ) );
+ SetTextureStageState( i, D3DTSS_BUMPENVMAT11, *( ( LPDWORD ) (&TextureStage(i).m_BumpEnvMat11) ) );
+ }
+
+ for ( i = 0; i < g_pHardwareConfig->ActualCaps().m_NumSamplers; ++i )
+ {
+ SamplerState(i).m_BoundTexture = INVALID_SHADERAPI_TEXTURE_HANDLE;
+ SamplerState(i).m_UTexWrap = D3DTADDRESS_WRAP;
+ SamplerState(i).m_VTexWrap = D3DTADDRESS_WRAP;
+ SamplerState(i).m_WTexWrap = D3DTADDRESS_WRAP;
+ SamplerState(i).m_MagFilter = D3DTEXF_POINT;
+ SamplerState(i).m_MinFilter = D3DTEXF_POINT;
+ SamplerState(i).m_MipFilter = D3DTEXF_NONE;
+ SamplerState(i).m_FinestMipmapLevel = 0;
+ SamplerState(i).m_LodBias = 0.0f;
+ SamplerState(i).m_TextureEnable = false;
+ SamplerState(i).m_SRGBReadEnable = false;
+
+ // Just some initial state...
+ Dx9Device()->SetTexture( i, 0 );
+
+ SetSamplerState( i, D3DSAMP_ADDRESSU, SamplerState(i).m_UTexWrap );
+ SetSamplerState( i, D3DSAMP_ADDRESSV, SamplerState(i).m_VTexWrap );
+ SetSamplerState( i, D3DSAMP_ADDRESSW, SamplerState(i).m_WTexWrap );
+ SetSamplerState( i, D3DSAMP_MINFILTER, SamplerState(i).m_MinFilter );
+ SetSamplerState( i, D3DSAMP_MAGFILTER, SamplerState(i).m_MagFilter );
+ SetSamplerState( i, D3DSAMP_MIPFILTER, SamplerState(i).m_MipFilter );
+ SetSamplerState( i, D3DSAMP_MAXMIPLEVEL, SamplerState(i).m_FinestMipmapLevel );
+ SetSamplerState( i, D3DSAMP_MIPMAPLODBIAS, SamplerState(i).m_LodBias );
+
+ SetSamplerState( i, D3DSAMP_BORDERCOLOR, RGB( 0,0,0 ) );
+ }
+
+ // FIXME!!!!! : This barfs with the debug runtime on 6800.
+ for( i = 0; i < g_pHardwareConfig->ActualCaps().m_nVertexTextureCount; i++ )
+ {
+ m_DynamicState.m_VertexTextureState[i].m_BoundTexture = INVALID_SHADERAPI_TEXTURE_HANDLE;
+ Dx9Device()->SetTexture( D3DVERTEXTEXTURESAMPLER0 + i, NULL );
+
+ m_DynamicState.m_VertexTextureState[i].m_UTexWrap = D3DTADDRESS_CLAMP;
+ m_DynamicState.m_VertexTextureState[i].m_VTexWrap = D3DTADDRESS_CLAMP;
+// m_DynamicState.m_VertexTextureState[i].m_WTexWrap = D3DTADDRESS_CLAMP;
+ m_DynamicState.m_VertexTextureState[i].m_MinFilter = D3DTEXF_POINT;
+ m_DynamicState.m_VertexTextureState[i].m_MagFilter = D3DTEXF_POINT;
+ m_DynamicState.m_VertexTextureState[i].m_MipFilter = D3DTEXF_POINT;
+ SetSamplerState( D3DVERTEXTEXTURESAMPLER0 + i, D3DSAMP_ADDRESSU, m_DynamicState.m_VertexTextureState[i].m_UTexWrap );
+ SetSamplerState( D3DVERTEXTEXTURESAMPLER0 + i, D3DSAMP_ADDRESSV, m_DynamicState.m_VertexTextureState[i].m_VTexWrap );
+// SetSamplerState( D3DVERTEXTEXTURESAMPLER0 + i, D3DSAMP_ADDRESSW, m_DynamicState.m_VertexTextureState[i].m_WTexWrap );
+ SetSamplerState( D3DVERTEXTEXTURESAMPLER0 + i, D3DSAMP_MINFILTER, m_DynamicState.m_VertexTextureState[i].m_MinFilter );
+ SetSamplerState( D3DVERTEXTEXTURESAMPLER0 + i, D3DSAMP_MAGFILTER, m_DynamicState.m_VertexTextureState[i].m_MagFilter );
+ SetSamplerState( D3DVERTEXTEXTURESAMPLER0 + i, D3DSAMP_MIPFILTER, m_DynamicState.m_VertexTextureState[i].m_MipFilter );
+ }
+
+ m_DynamicState.m_NumLights = 0;
+ for ( i = 0; i < MAX_NUM_LIGHTS; ++i)
+ {
+ m_DynamicState.m_LightEnable[i] = false;
+ m_DynamicState.m_LightChanged[i] = STATE_CHANGED;
+ m_DynamicState.m_LightEnableChanged[i] = STATE_CHANGED;
+ }
+
+ for ( i = 0; i < NUM_MATRIX_MODES; ++i)
+ {
+ // By setting this to *not* be identity, we force an update...
+ m_DynamicState.m_TransformType[i] = TRANSFORM_IS_GENERAL;
+ m_DynamicState.m_TransformChanged[i] = STATE_CHANGED;
+ }
+
+ // set the board state to match the default state
+ m_TransitionTable.UseDefaultState();
+
+ // Set the default render state
+ SetDefaultState();
+
+ // Constant for all time
+ SetSupportedRenderState( D3DRS_CLIPPING, TRUE );
+ SetSupportedRenderState( D3DRS_LOCALVIEWER, TRUE );
+ SetSupportedRenderState( D3DRS_POINTSCALEENABLE, FALSE );
+ SetSupportedRenderState( D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL );
+ SetSupportedRenderState( D3DRS_SPECULARMATERIALSOURCE, D3DMCS_COLOR2 );
+ SetSupportedRenderState( D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL );
+ SetSupportedRenderState( D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_MATERIAL );
+ SetSupportedRenderState( D3DRS_COLORVERTEX, TRUE ); // This defaults to true anyways. . .
+
+ // Set a default identity material.
+ SetDefaultMaterial();
+
+#if 0
+ float fBias = -1.0f;
+ SetTextureStageState( 0, D3DTSS_MIPMAPLODBIAS, *( ( LPDWORD ) (&fBias) ) );
+ SetTextureStageState( 1, D3DTSS_MIPMAPLODBIAS, *( ( LPDWORD ) (&fBias) ) );
+ SetTextureStageState( 2, D3DTSS_MIPMAPLODBIAS, *( ( LPDWORD ) (&fBias) ) );
+ SetTextureStageState( 3, D3DTSS_MIPMAPLODBIAS, *( ( LPDWORD ) (&fBias) ) );
+#endif
+
+ if ( bFullReset )
+ {
+ // Set the modelview matrix to identity too
+ for ( i = 0; i < NUM_MODEL_TRANSFORMS; ++i )
+ {
+ SetIdentityMatrix( m_boneMatrix[i] );
+ }
+ MatrixMode( MATERIAL_VIEW );
+ LoadIdentity();
+ MatrixMode( MATERIAL_PROJECTION );
+ LoadIdentity();
+ }
+
+#ifdef _X360
+ m_DynamicState.m_bBuffer2Frames = m_bBuffer2FramesAhead;
+ SetRenderState( D3DRS_BUFFER2FRAMES, m_DynamicState.m_bBuffer2Frames );
+#endif
+
+ m_DynamicState.m_Viewport.X = m_DynamicState.m_Viewport.Y =
+ m_DynamicState.m_Viewport.Width = m_DynamicState.m_Viewport.Height = 0xFFFFFFFF;
+ m_DynamicState.m_Viewport.MinZ = m_DynamicState.m_Viewport.MaxZ = 0.0;
+
+ // Be sure scissoring is off
+ m_DynamicState.m_RenderState[D3DRS_SCISSORTESTENABLE] = FALSE;
+ SetRenderState( D3DRS_SCISSORTESTENABLE, FALSE );
+ m_DynamicState.m_ScissorRect.left = -1;
+ m_DynamicState.m_ScissorRect.top = -1;
+ m_DynamicState.m_ScissorRect.right = -1;
+ m_DynamicState.m_ScissorRect.bottom = -1;
+
+ //SetHeightClipMode( MATERIAL_HEIGHTCLIPMODE_DISABLE );
+ EnableFastClip( false );
+ float fFakePlane[4];
+ unsigned int iFakePlaneVal = 0xFFFFFFFF;
+ fFakePlane[0] = fFakePlane[1] = fFakePlane[2] = fFakePlane[3] = *((float *)&iFakePlaneVal);
+ SetFastClipPlane( fFakePlane ); //doing this to better wire up plane change detection
+
+ float zero[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+
+ // Make sure that our state is dirty.
+ m_DynamicState.m_UserClipPlaneEnabled = 0;
+ m_DynamicState.m_UserClipPlaneChanged = 0;
+ m_DynamicState.m_UserClipLastUpdatedUsingFixedFunction = false;
+ for( i = 0; i < g_pHardwareConfig->MaxUserClipPlanes(); i++ )
+ {
+ // Make sure that our state is dirty.
+ m_DynamicState.m_UserClipPlaneWorld[i][0] = -1.0f;
+ m_DynamicState.m_UserClipPlaneProj[i][0] = -9999.0f;
+ m_DynamicState.m_UserClipPlaneEnabled |= ( 1 << i );
+ SetClipPlane( i, zero );
+ EnableClipPlane( i, false );
+ Assert( m_DynamicState.m_UserClipPlaneEnabled == 0 );
+ }
+ Assert( m_DynamicState.m_UserClipPlaneChanged == ((1 << g_pHardwareConfig->MaxUserClipPlanes()) - 1) );
+
+ m_DynamicState.m_FastClipEnabled = false;
+ m_DynamicState.m_bFastClipPlaneChanged = true;
+
+ // User clip override
+ m_DynamicState.m_bUserClipTransformOverride = false;
+ D3DXMatrixIdentity( &m_DynamicState.m_UserClipTransform );
+
+ // Viewport defaults to the window size
+ RECT windowRect;
+#if !defined( DX_TO_GL_ABSTRACTION )
+ GetClientRect( (HWND)m_hWnd, &windowRect );
+#else
+ toglGetClientRect( (VD3DHWND)m_hWnd, &windowRect );
+#endif
+
+ ShaderViewport_t viewport;
+ viewport.Init( windowRect.left, windowRect.top,
+ windowRect.right - windowRect.left, windowRect.bottom - windowRect.top );
+ SetViewports( 1, &viewport );
+
+ // No render mesh
+ m_pRenderMesh = 0;
+
+ // Reset cached vertex decl
+ m_DynamicState.m_pVertexDecl = NULL;
+
+ // Reset the render target to be the normal backbuffer
+ if ( IsX360() )
+ {
+ m_hCachedRenderTarget = INVALID_SHADERAPI_TEXTURE_HANDLE;
+ m_bUsingSRGBRenderTarget = false;
+ }
+ AcquireInternalRenderTargets();
+ SetRenderTarget();
+
+ // Maintain vertex + pixel shader constant buffers
+ Vector4D *pVectorPixelShaderConstants = m_DesiredState.m_pVectorPixelShaderConstant;
+ int *pBooleanPixelShaderConstants = m_DesiredState.m_pBooleanPixelShaderConstant;
+ IntVector4D *pIntegerPixelShaderConstants = m_DesiredState.m_pIntegerPixelShaderConstant;
+ Vector4D *pVectorVertexShaderConstants = m_DesiredState.m_pVectorVertexShaderConstant;
+ int *pBooleanVertexShaderConstants = m_DesiredState.m_pBooleanVertexShaderConstant;
+ IntVector4D *pIntegerVertexShaderConstants = m_DesiredState.m_pIntegerVertexShaderConstant;
+ m_DesiredState = m_DynamicState;
+ m_DesiredState.m_pVectorPixelShaderConstant = pVectorPixelShaderConstants;
+ m_DesiredState.m_pBooleanPixelShaderConstant = pBooleanPixelShaderConstants;
+ m_DesiredState.m_pIntegerPixelShaderConstant = pIntegerPixelShaderConstants;
+ m_DesiredState.m_pVectorVertexShaderConstant = pVectorVertexShaderConstants;
+ m_DesiredState.m_pBooleanVertexShaderConstant = pBooleanVertexShaderConstants;
+ m_DesiredState.m_pIntegerVertexShaderConstant = pIntegerVertexShaderConstants;
+ if ( g_pHardwareConfig->Caps().m_SupportsPixelShaders )
+ {
+ if ( !bFullReset )
+ {
+ //Full resets init the values to defaults. Normal resets just leave them dirty.
+ if( g_pHardwareConfig->Caps().m_NumVertexShaderConstants != 0 )
+ SetVertexShaderConstant( 0, m_DesiredState.m_pVectorVertexShaderConstant[0].Base(), IsX360() ? 217 : g_pHardwareConfig->Caps().m_NumVertexShaderConstants, true ); //217 on X360 to play nice with fast blatting code
+
+ if( g_pHardwareConfig->Caps().m_NumIntegerVertexShaderConstants != 0 )
+ SetIntegerVertexShaderConstant( 0, (int *)m_DesiredState.m_pIntegerVertexShaderConstant, g_pHardwareConfig->Caps().m_NumIntegerVertexShaderConstants, true );
+
+ if( g_pHardwareConfig->Caps().m_NumBooleanVertexShaderConstants != 0 )
+ SetBooleanVertexShaderConstant( 0, m_DesiredState.m_pBooleanVertexShaderConstant, g_pHardwareConfig->Caps().m_NumBooleanVertexShaderConstants, true );
+
+
+ if( g_pHardwareConfig->Caps().m_NumPixelShaderConstants != 0 )
+ SetPixelShaderConstant( 0, m_DesiredState.m_pVectorPixelShaderConstant[0].Base(), g_pHardwareConfig->Caps().m_NumPixelShaderConstants, true );
+
+ if( g_pHardwareConfig->Caps().m_NumIntegerPixelShaderConstants != 0 )
+ SetIntegerPixelShaderConstant( 0, (int *)m_DesiredState.m_pIntegerPixelShaderConstant, g_pHardwareConfig->Caps().m_NumIntegerPixelShaderConstants, true );
+
+ if( g_pHardwareConfig->Caps().m_NumBooleanPixelShaderConstants != 0 )
+ SetBooleanPixelShaderConstant( 0, m_DesiredState.m_pBooleanPixelShaderConstant, g_pHardwareConfig->Caps().m_NumBooleanPixelShaderConstants, true );
+ }
+ }
+
+ RECORD_DEBUG_STRING( "END ResetRenderState" );
+
+ m_bResettingRenderState = false;
+}
+
+//-----------------------------------------------------------------------------
+// Sets the default render state
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::SetDefaultState()
+{
+ LOCK_SHADERAPI();
+
+ // NOTE: This used to be in the material system, but I want to avoid all the per pass/batch
+ // virtual function calls.
+ int numTextureStages = g_pHardwareConfig->GetTextureStageCount();
+
+ // FIXME: This is a brutal hack. We only need to load these transforms for fixed-function
+ // hardware. Cap the max here to 4.
+ if ( IsPC() )
+ {
+ numTextureStages = min( numTextureStages, 4 );
+ int i;
+ for( i = 0; i < numTextureStages; i++ )
+ {
+ CShaderAPIDx8::DisableTextureTransform( (TextureStage_t)i );
+ CShaderAPIDx8::MatrixMode( (MaterialMatrixMode_t)(MATERIAL_TEXTURE0 + i) );
+ CShaderAPIDx8::LoadIdentity( );
+ }
+ }
+ CShaderAPIDx8::MatrixMode( MATERIAL_MODEL );
+
+ CShaderAPIDx8::Color4ub( 255, 255, 255, 255 );
+ CShaderAPIDx8::ShadeMode( SHADER_SMOOTH );
+ CShaderAPIDx8::SetVertexShaderIndex( );
+ CShaderAPIDx8::SetPixelShaderIndex( );
+
+ MeshMgr()->MarkUnusedVertexFields( 0, 0, NULL );
+}
+
+
+
+//-----------------------------------------------------------------------------
+//
+// Methods related to vertex format
+//
+//-----------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------
+// Sets the vertex
+//-----------------------------------------------------------------------------
+inline void CShaderAPIDx8::SetVertexDecl( VertexFormat_t vertexFormat, bool bHasColorMesh, bool bUsingFlex, bool bUsingMorph )
+{
+ VPROF("CShaderAPIDx8::SetVertexDecl");
+ IDirect3DVertexDeclaration9 *pDecl = FindOrCreateVertexDecl( vertexFormat, bHasColorMesh, bUsingFlex, bUsingMorph );
+ Assert( pDecl );
+
+ if ( ( pDecl != m_DynamicState.m_pVertexDecl ) && pDecl )
+ {
+ Dx9Device()->SetVertexDeclaration( pDecl );
+ m_DynamicState.m_pVertexDecl = pDecl;
+ }
+}
+
+
+
+//-----------------------------------------------------------------------------
+//
+// Methods related to vertex buffers
+//
+//-----------------------------------------------------------------------------
+
+IMesh *CShaderAPIDx8::GetFlexMesh()
+{
+ LOCK_SHADERAPI();
+ return MeshMgr()->GetFlexMesh();
+}
+
+//-----------------------------------------------------------------------------
+// Gets the dynamic mesh
+//-----------------------------------------------------------------------------
+IMesh* CShaderAPIDx8::GetDynamicMesh( IMaterial* pMaterial, int nHWSkinBoneCount, bool buffered,
+ IMesh* pVertexOverride, IMesh* pIndexOverride )
+{
+ Assert( (pMaterial == NULL) || ((IMaterialInternal *)pMaterial)->IsRealTimeVersion() );
+
+ LOCK_SHADERAPI();
+ return MeshMgr()->GetDynamicMesh( pMaterial, 0, nHWSkinBoneCount, buffered, pVertexOverride, pIndexOverride );
+}
+
+IMesh* CShaderAPIDx8::GetDynamicMeshEx( IMaterial* pMaterial, VertexFormat_t vertexFormat, int nHWSkinBoneCount,
+ bool bBuffered, IMesh* pVertexOverride, IMesh* pIndexOverride )
+{
+ Assert( (pMaterial == NULL) || ((IMaterialInternal *)pMaterial)->IsRealTimeVersion() );
+
+ LOCK_SHADERAPI();
+ return MeshMgr()->GetDynamicMesh( pMaterial, vertexFormat, nHWSkinBoneCount, bBuffered, pVertexOverride, pIndexOverride );
+}
+
+//-----------------------------------------------------------------------------
+// Returns the number of vertices we can render using the dynamic mesh
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::GetMaxToRender( IMesh *pMesh, bool bMaxUntilFlush, int *pMaxVerts, int *pMaxIndices )
+{
+ LOCK_SHADERAPI();
+ MeshMgr()->GetMaxToRender( pMesh, bMaxUntilFlush, pMaxVerts, pMaxIndices );
+}
+
+int CShaderAPIDx8::GetMaxVerticesToRender( IMaterial *pMaterial )
+{
+ pMaterial = ((IMaterialInternal *)pMaterial)->GetRealTimeVersion(); //always work with the realtime version internally
+
+ LOCK_SHADERAPI();
+ return MeshMgr()->GetMaxVerticesToRender( pMaterial );
+}
+
+int CShaderAPIDx8::GetMaxIndicesToRender( )
+{
+ LOCK_SHADERAPI();
+ return MeshMgr()->GetMaxIndicesToRender( );
+}
+
+void CShaderAPIDx8::MarkUnusedVertexFields( unsigned int nFlags, int nTexCoordCount, bool *pUnusedTexCoords )
+{
+ LOCK_SHADERAPI();
+ MeshMgr()->MarkUnusedVertexFields( nFlags, nTexCoordCount, pUnusedTexCoords );
+}
+
+//-----------------------------------------------------------------------------
+// Draws the mesh
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::DrawMesh( CMeshBase *pMesh )
+{
+ VPROF("CShaderAPIDx8::DrawMesh");
+ if ( ShaderUtil()->GetConfig().m_bSuppressRendering )
+ return;
+
+#if defined( PIX_INSTRUMENTATION ) || defined( NVPERFHUD )
+ PIXifyName( s_pPIXMaterialName, sizeof( s_pPIXMaterialName ), m_pMaterial->GetName() );
+ BeginPIXEvent( PIX_VALVE_ORANGE, s_pPIXMaterialName );
+#endif
+
+ m_pRenderMesh = pMesh;
+ VertexFormat_t vertexFormat = m_pRenderMesh->GetVertexFormat();
+ SetVertexDecl( vertexFormat, m_pRenderMesh->HasColorMesh(), m_pRenderMesh->HasFlexMesh(), m_pMaterial->IsUsingVertexID() );
+ CommitStateChanges();
+ Assert( m_pRenderMesh && m_pMaterial );
+ m_pMaterial->DrawMesh( CompressionType( vertexFormat ) );
+ m_pRenderMesh = NULL;
+
+#if defined( PIX_INSTRUMENTATION ) || defined( NVPERFHUD )
+ EndPIXEvent();
+#endif
+}
+
+void CShaderAPIDx8::DrawWithVertexAndIndexBuffers( void )
+{
+ VPROF("CShaderAPIDx8::DrawWithVertexAndIndexBuffers");
+ if ( ShaderUtil()->GetConfig().m_bSuppressRendering )
+ return;
+
+#if defined( PIX_INSTRUMENTATION ) || defined( NVPERFHUD )
+ PIXifyName( s_pPIXMaterialName, sizeof( s_pPIXMaterialName ), m_pMaterial->GetName());
+ BeginPIXEvent( PIX_VALVE_ORANGE, s_pPIXMaterialName );
+#endif
+
+// m_pRenderMesh = pMesh;
+ // FIXME: need to make this deal with multiple streams, etc.
+ VertexFormat_t vertexFormat = MeshMgr()->GetCurrentVertexFormat();
+ SetVertexDecl( vertexFormat, false /*m_pRenderMesh->HasColorMesh()*/,
+ false /*m_pRenderMesh->HasFlexMesh()*/, false /*m_pRenderMesh->IsUsingMorphData()*/ );
+ CommitStateChanges();
+ if ( m_pMaterial )
+ {
+ m_pMaterial->DrawMesh( CompressionType( vertexFormat ) );
+ }
+ else
+ {
+ MeshMgr()->RenderPassWithVertexAndIndexBuffers();
+ }
+// m_pRenderMesh = NULL;
+
+#if defined( PIX_INSTRUMENTATION ) || defined( NVPERFHUD )
+ EndPIXEvent();
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Discards the vertex buffers
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::DiscardVertexBuffers()
+{
+ MeshMgr()->DiscardVertexBuffers();
+}
+
+void CShaderAPIDx8::ForceHardwareSync_WithManagedTexture()
+{
+ if ( IsX360() || !m_pFrameSyncTexture )
+ return;
+
+ // Set the default state for everything so we don't get more than we ask for here!
+ SetDefaultState();
+
+ D3DLOCKED_RECT rect;
+
+ tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "%s", __FUNCTION__ );
+
+ HRESULT hr = m_pFrameSyncTexture->LockRect( 0, &rect, NULL, 0 );
+ if ( SUCCEEDED( hr ) )
+ {
+ // modify..
+ unsigned long *pData = (unsigned long*)rect.pBits;
+ (*pData)++;
+
+ m_pFrameSyncTexture->UnlockRect( 0 );
+
+ // Now draw something with this texture.
+ DWORD iStage = 0;
+ IDirect3DBaseTexture9 *pOldTexture;
+ hr = Dx9Device()->GetTexture( iStage, &pOldTexture );
+ if ( SUCCEEDED( hr ) )
+ {
+ Dx9Device()->SetTexture( iStage, m_pFrameSyncTexture );
+ // Remember the old FVF.
+ DWORD oldFVF;
+ hr = Dx9Device()->GetFVF( &oldFVF );
+ if ( SUCCEEDED( hr ) )
+ {
+ // Set the new FVF.
+ Dx9Device()->SetFVF( D3DFVF_XYZ );
+ // Now, draw the simplest primitive D3D has ever seen.
+ unsigned short indices[3] = { 0, 1, 2 };
+ Vector verts[3] = {vec3_origin, vec3_origin, vec3_origin};
+
+ tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "DrawIndexedPrimitiveUP" );
+
+ Dx9Device()->DrawIndexedPrimitiveUP(
+ D3DPT_TRIANGLELIST,
+ 0, // Min vertex index
+ 3, // Num vertices used
+ 1, // # primitives
+ indices, // indices
+ D3DFMT_INDEX16, // index format
+ verts, // Vertices
+ sizeof( Vector )// Vertex stride
+ );
+
+ Dx9Device()->SetFVF( oldFVF );
+ }
+ Dx9Device()->SetTexture( iStage, pOldTexture );
+ }
+ }
+ // If this assert fails, then we failed somewhere above.
+ AssertOnce( SUCCEEDED( hr ) );
+}
+
+void CShaderAPIDx8::UpdateFrameSyncQuery( int queryIndex, bool bIssue )
+{
+ Assert(queryIndex < NUM_FRAME_SYNC_QUERIES);
+ // wait if already issued
+ if ( m_bQueryIssued[queryIndex] )
+ {
+ tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "%s", __FUNCTION__ );
+
+ double flStartTime = Plat_FloatTime();
+ BOOL dummyData = 0;
+ HRESULT hr = S_OK;
+ // NOTE: This fix helps out motherboards that are a little freaky.
+ // On such boards, sometimes the driver has to reset itself (an event which takes several seconds)
+ // and when that happens, the frame sync query object gets lost
+ for (;;)
+ {
+ hr = m_pFrameSyncQueryObject[queryIndex]->GetData( &dummyData, sizeof( dummyData ), D3DGETDATA_FLUSH );
+ if ( hr != S_FALSE )
+ break;
+ double flCurrTime = Plat_FloatTime();
+ // don't wait more than 200ms (5fps) for these
+ if ( flCurrTime - flStartTime > 0.200f )
+ break;
+ // Avoid burning a full core while waiting for the query. Spinning can actually harm performance
+ // because there might be driver threads that are trying to do work that end up starved, and the
+ // power drawn by the CPU may take away from the power available to the integrated graphics chip.
+ // A sleep of one millisecond should never be long enough to affect performance, especially since
+ // this should only trigger when the CPU is already ahead of the GPU.
+ // On L4D2/TF2 in GL mode this spinning was causing slowdowns.
+ ThreadSleep( 1 );
+ }
+ m_bQueryIssued[queryIndex] = false;
+ Assert(hr == S_OK || hr == D3DERR_DEVICELOST);
+
+ if ( hr == D3DERR_DEVICELOST )
+ {
+ MarkDeviceLost( );
+ return;
+ }
+ }
+ if ( bIssue )
+ {
+ m_pFrameSyncQueryObject[queryIndex]->Issue( D3DISSUE_END );
+ m_bQueryIssued[queryIndex] = true;
+ }
+}
+
+void CShaderAPIDx8::ForceHardwareSync( void )
+{
+ LOCK_SHADERAPI();
+ VPROF( "CShaderAPIDx8::ForceHardwareSync" );
+
+#ifdef DX_TO_GL_ABSTRACTION
+ if ( true )
+#else
+ if ( !mat_frame_sync_enable.GetInt() )
+#endif
+ return;
+
+ // need to flush the dynamic buffer and make sure the entire image is there
+ FlushBufferedPrimitives();
+
+ RECORD_COMMAND( DX8_HARDWARE_SYNC, 0 );
+
+#if !defined( _X360 )
+ // How do you query dx9 for how many frames behind the hardware is or, alternatively, how do you tell the hardware to never be more than N frames behind?
+ // 1) The old QueryPendingFrameCount design was removed. It was
+ // a simple transaction with the driver through the
+ // GetDriverState, trivial for the drivers to lie. We came up
+ // with a much better scheme for tracking pending frames where
+ // the driver can not lie without a possible performance loss:
+ // use the asynchronous query system with D3DQUERYTYPE_EVENT and
+ // data size 0. When GetData returns S_OK for the query, you
+ // know that frame has finished.
+ if ( mat_frame_sync_force_texture.GetBool() )
+ {
+ ForceHardwareSync_WithManagedTexture();
+ }
+ else if ( m_pFrameSyncQueryObject[0] )
+ {
+ // FIXME: Could install a callback into the materialsystem to do something while waiting for
+ // the frame to finish (update sound, etc.)
+
+ // Disable VCR mode here or else it'll screw up (and we don't really care if this part plays back in exactly the same amount of time).
+ VCRSetEnabled( false );
+
+ m_currentSyncQuery ++;
+ if ( m_currentSyncQuery >= ARRAYSIZE(m_pFrameSyncQueryObject) )
+ {
+ m_currentSyncQuery = 0;
+ }
+ double fStart = Plat_FloatTime();
+ int waitIndex = ((m_currentSyncQuery + NUM_FRAME_SYNC_QUERIES) - (NUM_FRAME_SYNC_FRAMES_LATENCY+1)) % NUM_FRAME_SYNC_QUERIES;
+ UpdateFrameSyncQuery( waitIndex, false );
+ UpdateFrameSyncQuery( m_currentSyncQuery, true );
+ VCRSetEnabled( true );
+ }
+#else
+ DWORD hFence = Dx9Device()->InsertFence();
+ Dx9Device()->BlockOnFence( hFence );
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Needs render state
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::QueueResetRenderState()
+{
+ m_bResetRenderStateNeeded = true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Use this to begin and end the frame
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::BeginFrame()
+{
+ LOCK_SHADERAPI();
+
+ if ( m_bResetRenderStateNeeded )
+ {
+ ResetRenderState( false );
+ m_bResetRenderStateNeeded = false;
+ }
+
+#if ALLOW_SMP_ACCESS
+ Dx9Device()->SetASyncMode( mat_use_smp.GetInt() != 0 );
+#endif
+
+ ++m_CurrentFrame;
+ m_nTextureMemoryUsedLastFrame = 0;
+}
+
+void CShaderAPIDx8::EndFrame()
+{
+ LOCK_SHADERAPI();
+
+#if !defined( _X360 )
+ MEMCHECK;
+#endif
+
+ ExportTextureList();
+}
+
+
+void CShaderAPIDx8::AddBufferToTextureList( const char *pName, D3DSURFACE_DESC &desc )
+{
+// ImageFormat imageFormat;
+// imageFormat = ImageLoader::D3DFormatToImageFormat( desc.Format );
+// if( imageFormat < 0 )
+// {
+// Assert( 0 );
+// return;
+// }
+ KeyValues *pSubKey = m_pDebugTextureList->CreateNewKey();
+ pSubKey->SetString( "Name", pName );
+ pSubKey->SetString( "TexGroup", TEXTURE_GROUP_RENDER_TARGET );
+ pSubKey->SetInt( "Size",
+// ImageLoader::SizeInBytes( imageFormat ) * desc.Width * desc.Height );
+ 4 * desc.Width * desc.Height );
+ pSubKey->SetString( "Format", "32 bit buffer (hack)" );//ImageLoader::GetName( imageFormat ) );
+ pSubKey->SetInt( "Width", desc.Width );
+ pSubKey->SetInt( "Height", desc.Height );
+
+ pSubKey->SetInt( "BindsMax", 1 );
+ pSubKey->SetInt( "BindsFrame", 1 );
+}
+
+void CShaderAPIDx8::ExportTextureList()
+{
+ if ( !m_bEnableDebugTextureList )
+ return;
+
+ if ( !m_pBackBufferSurface || !m_pZBufferSurface )
+ // Device vanished...
+ return;
+
+ m_nDebugDataExportFrame = m_CurrentFrame;
+
+ if ( IsPC() || !IsX360() )
+ {
+ if ( m_pDebugTextureList )
+ m_pDebugTextureList->deleteThis();
+
+ m_pDebugTextureList = new KeyValues( "TextureList" );
+
+ m_nTextureMemoryUsedTotal = 0;
+ m_nTextureMemoryUsedPicMip1 = 0;
+ m_nTextureMemoryUsedPicMip2 = 0;
+ for ( ShaderAPITextureHandle_t hTexture = m_Textures.Head() ; hTexture != m_Textures.InvalidIndex(); hTexture = m_Textures.Next( hTexture ) )
+ {
+ Texture_t &tex = m_Textures[hTexture];
+
+ if ( !( tex.m_Flags & Texture_t::IS_ALLOCATED ) )
+ continue;
+
+ // Compute total texture memory usage
+ m_nTextureMemoryUsedTotal += tex.GetMemUsage();
+
+ // Compute picmip memory usage
+ {
+ int numBytes = tex.GetMemUsage();
+
+ if ( tex.m_NumLevels > 1 )
+ {
+ if ( tex.GetWidth() > 4 || tex.GetHeight() > 4 || tex.GetDepth() > 4 )
+ {
+ int topmipsize = ImageLoader::GetMemRequired( tex.GetWidth(), tex.GetHeight(), tex.GetDepth(), tex.GetImageFormat(), false );
+ numBytes -= topmipsize;
+
+ m_nTextureMemoryUsedPicMip1 += numBytes;
+
+ if ( tex.GetWidth() > 8 || tex.GetHeight() > 8 || tex.GetDepth() > 8 )
+ {
+ int othermipsizeRatio = ( ( tex.GetWidth() > 8 ) ? 2 : 1 ) * ( ( tex.GetHeight() > 8 ) ? 2 : 1 ) * ( ( tex.GetDepth() > 8 ) ? 2 : 1 );
+ int othermipsize = topmipsize / othermipsizeRatio;
+ numBytes -= othermipsize;
+ }
+
+ m_nTextureMemoryUsedPicMip1 += numBytes;
+ }
+ else
+ {
+ m_nTextureMemoryUsedPicMip1 += numBytes;
+ m_nTextureMemoryUsedPicMip2 += numBytes;
+ }
+ }
+ else
+ {
+ m_nTextureMemoryUsedPicMip1 += numBytes;
+ m_nTextureMemoryUsedPicMip2 += numBytes;
+ }
+ }
+
+ if ( !m_bDebugGetAllTextures &&
+ tex.m_LastBoundFrame != m_CurrentFrame )
+ continue;
+
+ if ( tex.m_LastBoundFrame != m_CurrentFrame )
+ tex.m_nTimesBoundThisFrame = 0;
+
+ KeyValues *pSubKey = m_pDebugTextureList->CreateNewKey();
+ pSubKey->SetString( "Name", tex.m_DebugName.String() );
+ pSubKey->SetString( "TexGroup", tex.m_TextureGroupName.String() );
+ pSubKey->SetInt( "Size", tex.GetMemUsage() );
+ if ( tex.GetCount() > 1 )
+ pSubKey->SetInt( "Count", tex.GetCount() );
+ pSubKey->SetString( "Format", ImageLoader::GetName( tex.GetImageFormat() ) );
+ pSubKey->SetInt( "Width", tex.GetWidth() );
+ pSubKey->SetInt( "Height", tex.GetHeight() );
+
+ pSubKey->SetInt( "BindsMax", tex.m_nTimesBoundMax );
+ pSubKey->SetInt( "BindsFrame", tex.m_nTimesBoundThisFrame );
+ }
+
+ D3DSURFACE_DESC desc;
+ m_pBackBufferSurface->GetDesc( &desc );
+ AddBufferToTextureList( "BACKBUFFER", desc );
+ AddBufferToTextureList( "FRONTBUFFER", desc );
+ // ImageFormat imageFormat = ImageLoader::D3DFormatToImageFormat( desc.Format );
+ // if( imageFormat >= 0 )
+ {
+ VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_frame_" TEXTURE_GROUP_RENDER_TARGET,
+ COUNTER_GROUP_TEXTURE_PER_FRAME,
+ // ImageLoader::SizeInBytes( imageFormat ) * desc.Width * desc.Height );
+ 2 * 4 * desc.Width * desc.Height ); // hack (times 2 for front and back buffer)
+ }
+
+ m_pZBufferSurface->GetDesc( &desc );
+ AddBufferToTextureList( "DEPTHBUFFER", desc );
+ // imageFormat = ImageLoader::D3DFormatToImageFormat( desc.Format );
+ // if( imageFormat >= 0 )
+ {
+ VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_frame_" TEXTURE_GROUP_RENDER_TARGET,
+ COUNTER_GROUP_TEXTURE_PER_FRAME,
+ // ImageLoader::SizeInBytes( imageFormat ) * desc.Width * desc.Height );
+ 4 * desc.Width * desc.Height ); // hack
+ }
+ }
+
+#if defined( _X360 )
+ // toggle to do one shot transmission
+ m_bEnableDebugTextureList = false;
+
+ int numTextures = m_Textures.Count() + 3;
+ xTextureList_t* pXTextureList = (xTextureList_t *)_alloca( numTextures * sizeof( xTextureList_t ) );
+ memset( pXTextureList, 0, numTextures * sizeof( xTextureList_t ) );
+
+ numTextures = 0;
+ for ( ShaderAPITextureHandle_t hTexture = m_Textures.Head() ; hTexture != m_Textures.InvalidIndex(); hTexture = m_Textures.Next( hTexture ) )
+ {
+ Texture_t &tex = m_Textures[hTexture];
+
+ if ( !m_bDebugGetAllTextures && tex.m_LastBoundFrame != m_CurrentFrame )
+ {
+ continue;
+ }
+ if ( !( tex.m_Flags & Texture_t::IS_ALLOCATED ) )
+ {
+ continue;
+ }
+
+ int refCount;
+ if ( tex.m_Flags & Texture_t::IS_DEPTH_STENCIL )
+ {
+ // interface forces us to ignore these
+ refCount = -1;
+ }
+ else
+ {
+ refCount = GetD3DTextureRefCount( CShaderAPIDx8::GetD3DTexture( hTexture ) );
+ }
+
+ pXTextureList[numTextures].pName = tex.m_DebugName.String();
+ pXTextureList[numTextures].size = tex.m_SizeBytes * tex.m_NumCopies;
+ pXTextureList[numTextures].pGroupName = tex.m_TextureGroupName.String();
+ pXTextureList[numTextures].pFormatName = D3DFormatName( ImageLoader::ImageFormatToD3DFormat( tex.GetImageFormat() ) );
+ pXTextureList[numTextures].width = tex.GetWidth();
+ pXTextureList[numTextures].height = tex.GetHeight();
+ pXTextureList[numTextures].depth = tex.GetDepth();
+ pXTextureList[numTextures].numLevels = tex.m_NumLevels;
+ pXTextureList[numTextures].binds = tex.m_nTimesBoundThisFrame;
+ pXTextureList[numTextures].refCount = refCount;
+ pXTextureList[numTextures].edram = ( tex.m_Flags & Texture_t::IS_RENDER_TARGET_SURFACE ) != 0;
+ pXTextureList[numTextures].procedural = tex.m_NumCopies > 1;
+ pXTextureList[numTextures].final = ( tex.m_Flags & Texture_t::IS_FINALIZED ) != 0;
+ pXTextureList[numTextures].failed = ( tex.m_Flags & Texture_t::IS_FAILED ) != 0;
+ numTextures++;
+ }
+
+ // build special entries for implicit surfaces/textures
+ D3DSURFACE_DESC desc;
+ m_pBackBufferSurface->GetDesc( &desc );
+ int size = ImageLoader::GetMemRequired(
+ desc.Width,
+ desc.Height,
+ 0,
+ ImageLoader::D3DFormatToImageFormat( desc.Format ),
+ false );
+ pXTextureList[numTextures].pName = "_rt_BackBuffer";
+ pXTextureList[numTextures].size = size;
+ pXTextureList[numTextures].pGroupName = TEXTURE_GROUP_RENDER_TARGET_SURFACE;
+ pXTextureList[numTextures].pFormatName = D3DFormatName( desc.Format );
+ pXTextureList[numTextures].width = desc.Width;
+ pXTextureList[numTextures].height = desc.Height;
+ pXTextureList[numTextures].depth = 1;
+ pXTextureList[numTextures].binds = 1;
+ pXTextureList[numTextures].refCount = 1;
+ pXTextureList[numTextures].sRGB = IS_D3DFORMAT_SRGB( desc.Format );
+ pXTextureList[numTextures].edram = true;
+ numTextures++;
+
+ m_pZBufferSurface->GetDesc( &desc );
+ pXTextureList[numTextures].pName = "_rt_DepthBuffer";
+ pXTextureList[numTextures].size = size;
+ pXTextureList[numTextures].pGroupName = TEXTURE_GROUP_RENDER_TARGET_SURFACE;
+ pXTextureList[numTextures].pFormatName = D3DFormatName( desc.Format );
+ pXTextureList[numTextures].width = desc.Width;
+ pXTextureList[numTextures].height = desc.Height;
+ pXTextureList[numTextures].depth = 1;
+ pXTextureList[numTextures].binds = 1;
+ pXTextureList[numTextures].refCount = 1;
+ pXTextureList[numTextures].sRGB = IS_D3DFORMAT_SRGB( desc.Format );
+ pXTextureList[numTextures].edram = true;
+ numTextures++;
+
+ // front buffer resides in DDR
+ pXTextureList[numTextures].pName = "_rt_FrontBuffer";
+ pXTextureList[numTextures].size = size;
+ pXTextureList[numTextures].pGroupName = TEXTURE_GROUP_RENDER_TARGET;
+ pXTextureList[numTextures].pFormatName = D3DFormatName( desc.Format );
+ pXTextureList[numTextures].width = desc.Width;
+ pXTextureList[numTextures].height = desc.Height;
+ pXTextureList[numTextures].depth = 1;
+ pXTextureList[numTextures].binds = 1;
+ pXTextureList[numTextures].refCount = 1;
+ pXTextureList[numTextures].sRGB = IS_D3DFORMAT_SRGB( desc.Format );
+ numTextures++;
+
+ int totalMemory = 0;
+ for ( int i = 0; i < numTextures; i++ )
+ {
+ if ( pXTextureList[i].edram )
+ {
+ // skip edram based items
+ continue;
+ }
+ totalMemory += pXTextureList[i].size;
+ }
+ Msg( "Total D3D Texture Memory: %.2f MB\n", (float)totalMemory/( 1024.0f * 1024.0f ) );
+
+ // transmit to console
+ XBX_rTextureList( numTextures, pXTextureList );
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Releases/reloads resources when other apps want some memory
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::ReleaseShaderObjects()
+{
+ ReleaseInternalRenderTargets();
+ EvictManagedResourcesInternal();
+
+ // FIXME: Move into shaderdevice when textures move over.
+
+#ifdef _DEBUG
+ // Helps to find the unreleased textures.
+ if ( TextureCount() > 0 )
+ {
+ ShaderAPITextureHandle_t hTexture;
+ for ( hTexture = m_Textures.Head(); hTexture != m_Textures.InvalidIndex(); hTexture = m_Textures.Next( hTexture ) )
+ {
+ if ( GetTexture( hTexture ).m_NumCopies == 1 )
+ {
+ if ( GetTexture( hTexture ).GetTexture() )
+ {
+ Warning( "Didn't correctly clean up texture 0x%8.8x (%s)\n", hTexture, GetTexture( hTexture ).m_DebugName.String() );
+ }
+ }
+ else
+ {
+ for ( int k = GetTexture( hTexture ).m_NumCopies; --k >= 0; )
+ {
+ if ( GetTexture( hTexture ).GetTexture( k ) != 0 )
+ {
+ Warning( "Didn't correctly clean up texture 0x%8.8x (%s)\n", hTexture, GetTexture( hTexture ).m_DebugName.String() );
+ break;
+ }
+ }
+ }
+ }
+ }
+#endif
+
+ Assert( TextureCount() == 0 );
+}
+
+void CShaderAPIDx8::RestoreShaderObjects()
+{
+ AcquireInternalRenderTargets();
+ SetRenderTarget();
+}
+
+
+//--------------------------------------------------------------------
+// PIX instrumentation routines
+// Windows only for now. Turn these on with PIX_INSTRUMENTATION above
+//--------------------------------------------------------------------
+
+#if 0 // hack versions for OSX to be able to PIX log even when not built debug...
+void CShaderAPIDx8::BeginPIXEvent( unsigned long color, const char* szName )
+ {
+ LOCK_SHADERAPI();
+ GLMBeginPIXEvent( szName ); // direct call no macro
+ return;
+ }
+
+ void CShaderAPIDx8::EndPIXEvent( void )
+ {
+ LOCK_SHADERAPI();
+ GLMEndPIXEvent(); // direct call no macro
+ return;
+ }
+
+#else
+
+#if defined( PIX_INSTRUMENTATION ) || defined( NVPERFHUD )
+ConVar pix_break_on_event( "pix_break_on_event", "" );
+#endif
+
+void CShaderAPIDx8::BeginPIXEvent( unsigned long color, const char* szName )
+{
+#if ( defined( PIX_INSTRUMENTATION ) || defined( NVPERFHUD ) )
+ //LOCK_SHADERAPI();
+
+ const char *p = pix_break_on_event.GetString();
+ if ( p && V_strlen( p ) )
+ {
+ if ( V_stristr( szName, p ) != NULL )
+ {
+ DebuggerBreak();
+ }
+ }
+
+#if defined ( DX_TO_GL_ABSTRACTION )
+ GLMBeginPIXEvent( szName );
+
+#if defined( _WIN32 )
+ // AMD PerfStudio integration: Call into D3D9.DLL's D3DPERF_BeginEvent() (this gets intercepted by PerfStudio even in GL mode).
+ if ( g_pShaderDeviceMgrDx8->m_pBeginEvent )
+ {
+ wchar_t wszName[128];
+ mbstowcs( wszName, szName, 128 );
+
+ g_pShaderDeviceMgrDx8->m_pBeginEvent( 0x2F2F2F2F, wszName );
+ }
+#endif
+#elif defined(_X360 )
+#ifndef _DEBUG
+ char szPIXEventName[32];
+ PIXifyName( szPIXEventName, szName );
+ PIXBeginNamedEvent( color, szPIXEventName );
+#endif
+#else // PC
+ if ( PIXError() )
+ return;
+
+ wchar_t wszName[128];
+ mbstowcs( wszName, szName, 128 );
+
+ // Fire the PIX event, trapping for errors...
+ if ( D3DPERF_BeginEvent( color, wszName ) < 0 )
+ {
+ Warning( "PIX error Beginning %s event\n", szName );
+ IncrementPIXError();
+ }
+#endif
+#endif // #if defined( PIX_INSTRUMENTATION )
+}
+
+void CShaderAPIDx8::EndPIXEvent( void )
+{
+#if ( defined( PIX_INSTRUMENTATION ) || defined( NVPERFHUD ) )
+ //LOCK_SHADERAPI();
+
+#if defined ( DX_TO_GL_ABSTRACTION )
+ GLMEndPIXEvent();
+
+#if defined( _WIN32 )
+ // AMD PerfStudio integration: Call into D3D9.DLL's D3DPERF_EndEvent() (this gets intercepted by PerfStudio even in GL mode).
+ if ( g_pShaderDeviceMgrDx8->m_pEndEvent )
+ {
+ g_pShaderDeviceMgrDx8->m_pEndEvent();
+ }
+#endif
+#elif defined( _X360 )
+#ifndef _DEBUG
+ PIXEndNamedEvent();
+#endif
+#else // PC
+ if ( PIXError() )
+ return;
+
+#if !defined( NVPERFHUD )
+ // Fire the PIX event, trapping for errors...
+ if ( D3DPERF_EndEvent() < 0 )
+ {
+ Warning("PIX error ending event\n");
+ IncrementPIXError();
+ }
+#endif
+#endif
+#endif // #if defined( PIX_INSTRUMENTATION )
+}
+
+#endif
+
+void CShaderAPIDx8::AdvancePIXFrame()
+{
+#if defined( PIX_INSTRUMENTATION )
+ // Ping PIX when this bool goes from false to true
+ if ( r_pix_start.GetBool() && (!m_bPixCapturing) )
+ {
+ StartPIXInstrumentation();
+ m_bPixCapturing = true;
+ }
+
+ // If we want to record frames...
+ if ( r_pix_recordframes.GetInt() )
+ {
+ if ( m_nPixFrame == 0 ) // First frame to record
+ {
+ StartPIXInstrumentation();
+ m_nPixFrame++;
+ }
+ else if( m_nPixFrame == r_pix_recordframes.GetInt() ) // Last frame to record
+ {
+ EndPIXInstrumentation();
+ r_pix_recordframes.SetValue(0);
+ m_nPixFrame = 0;
+ }
+ else
+ {
+ m_nPixFrame++; // Recording frames...
+ }
+ }
+#endif
+}
+
+// No begin-end for this...use this to put discrete markers in the PIX stream
+void CShaderAPIDx8::SetPIXMarker( unsigned long color, const char* szName )
+{
+#if defined( PIX_INSTRUMENTATION )
+ LOCK_SHADERAPI();
+
+#if defined( DX_TO_GL_ABSTRACTION )
+ if ( g_pShaderDeviceMgrDx8->m_pSetMarker )
+ {
+ wchar_t wszName[128];
+ mbstowcs(wszName, szName, 128 );
+ g_pShaderDeviceMgrDx8->m_pSetMarker( 0x2F2F2F2F, wszName );
+ }
+#elif defined( _X360 )
+#ifndef _DEBUG
+ char szPIXMarkerName[32];
+ PIXifyName( szPIXMarkerName, szName );
+ PIXSetMarker( color, szPIXMarkerName );
+#endif
+#else // PC
+ if ( PIXError() )
+ return;
+ wchar_t wszName[128];
+ mbstowcs(wszName, szName, 128 );
+ D3DPERF_SetMarker( color, wszName );
+#endif
+
+#endif // PIX_INSTRUMENTATION
+}
+
+void CShaderAPIDx8::StartPIXInstrumentation()
+{
+#if defined( PIX_INSTRUMENTATION )
+ SetPIXMarker( PIX_VALVE_ORANGE, "Valve_PIX_Capture_Start" );
+#endif
+}
+
+void CShaderAPIDx8::EndPIXInstrumentation()
+{
+#if defined( PIX_INSTRUMENTATION )
+ SetPIXMarker( PIX_VALVE_ORANGE, "Valve_PIX_Capture_End" );
+#endif
+}
+
+void CShaderAPIDx8::IncrementPIXError()
+{
+#if defined( PIX_INSTRUMENTATION ) && !defined( NVPERFHUD )
+ m_nPIXErrorCount++;
+ if ( m_nPIXErrorCount >= MAX_PIX_ERRORS )
+ {
+ Warning( "Source engine built with PIX instrumentation, but PIX doesn't seem to have been used to instantiate the game, which is necessary on PC.\n" );
+ }
+#endif
+}
+
+// Have we already hit several PIX errors?
+bool CShaderAPIDx8::PIXError()
+{
+#if defined( PIX_INSTRUMENTATION ) && !defined( NVPERFHUD )
+ return m_nPIXErrorCount >= MAX_PIX_ERRORS;
+#else
+ return false;
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Check for device lost
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::ChangeVideoMode( const ShaderDeviceInfo_t &info )
+{
+ if ( IsX360() )
+ return;
+
+ LOCK_SHADERAPI();
+
+ m_PendingVideoModeChangeConfig = info;
+ m_bPendingVideoModeChange = true;
+
+ if ( info.m_DisplayMode.m_nWidth != 0 && info.m_DisplayMode.m_nHeight != 0 )
+ {
+ m_nWindowWidth = info.m_DisplayMode.m_nWidth;
+ m_nWindowHeight = info.m_DisplayMode.m_nHeight;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Compute fill rate
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::ComputeFillRate()
+{
+ if ( IsX360() )
+ {
+ // not valid
+ return;
+ }
+
+ static unsigned char* pBuf = 0;
+
+ int width, height;
+ GetWindowSize( width, height );
+ // Snapshot; look at total # pixels drawn...
+ if ( !pBuf )
+ {
+ int memSize = ShaderUtil()->GetMemRequired(
+ width,
+ height,
+ 1,
+ IMAGE_FORMAT_RGB888,
+ false ) + 4;
+
+ pBuf = (unsigned char*)malloc( memSize );
+ }
+
+ ReadPixels(
+ 0,
+ 0,
+ width,
+ height,
+ pBuf,
+ IMAGE_FORMAT_RGB888 );
+
+ int mask = 0xFF;
+ int count = 0;
+ unsigned char* pRead = pBuf;
+ for (int i = 0; i < height; ++i)
+ {
+ for (int j = 0; j < width; ++j)
+ {
+ int val = *(int*)pRead;
+ count += (val & mask);
+ pRead += 3;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Use this to get the mesh builder that allows us to modify vertex data
+//-----------------------------------------------------------------------------
+CMeshBuilder* CShaderAPIDx8::GetVertexModifyBuilder()
+{
+ return &m_ModifyBuilder;
+}
+
+bool CShaderAPIDx8::InFlashlightMode() const
+{
+ return ShaderUtil()->InFlashlightMode();
+}
+
+bool CShaderAPIDx8::InEditorMode() const
+{
+ return ShaderUtil()->InEditorMode();
+}
+
+//-----------------------------------------------------------------------------
+// Gets the bound morph's vertex format; returns 0 if no morph is bound
+//-----------------------------------------------------------------------------
+MorphFormat_t CShaderAPIDx8::GetBoundMorphFormat()
+{
+ return ShaderUtil()->GetBoundMorphFormat();
+}
+
+//-----------------------------------------------------------------------------
+// returns the current time in seconds...
+//-----------------------------------------------------------------------------
+double CShaderAPIDx8::CurrentTime() const
+{
+ // FIXME: Return game time instead of real time!
+ // Or eliminate this altogether and put it into a material var
+ // (this is used by vertex modifiers in shader code at the moment)
+ return Plat_FloatTime();
+}
+
+
+//-----------------------------------------------------------------------------
+// Methods called by the transition table that use dynamic state...
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::ApplyZBias( const ShadowState_t& shaderState )
+{
+ MaterialSystem_Config_t &config = ShaderUtil()->GetConfig();
+ float a = (config.m_SlopeScaleDepthBias_Decal != 0.0f) ? 1.0f / config.m_SlopeScaleDepthBias_Decal : 0.0f;
+ float b = (config.m_SlopeScaleDepthBias_Normal != 0.0f) ? 1.0f / config.m_SlopeScaleDepthBias_Normal : 0.0f;
+ float c = (config.m_DepthBias_Decal != 0.0f) ? 1.0f / config.m_DepthBias_Decal : 0.0f;
+ float d = (config.m_DepthBias_Normal != 0.0f) ? 1.0f / config.m_DepthBias_Normal : 0.0f;
+
+ // FIXME: No longer necessary; may be necessary if you want to use cat 4.3 drivers?
+ // GR - hack for R200
+ bool bPS14Only = g_pHardwareConfig->Caps().m_SupportsPixelShaders_1_4 && !g_pHardwareConfig->Caps().m_SupportsPixelShaders_2_0;
+ if( ( g_pHardwareConfig->Caps().m_VendorID == 0x1002 ) && bPS14Only )
+ {
+ // Slam to m_SlopeScaleDepthBias_Decal = 0, m_DepthBias_Decal = -4096
+ // which empirically is what appears to look good on r200
+ // NOTE: Slamming to 0 instead of -1.0 / 4096 because on Cat 4.9, WinXP, 8500,
+ // this causes the z values to be more than 50 units away from the original z values
+
+ a = 0.0f;
+ c = -1.0/4096.0;
+ }
+
+ // bias = (s * D3DRS_SLOPESCALEDEPTHBIAS) + D3DRS_DEPTHBIAS, where s is the maximum depth slope of the triangle being rendered
+ if ( g_pHardwareConfig->Caps().m_ZBiasAndSlopeScaledDepthBiasSupported )
+ {
+ float fSlopeScaleDepthBias, fDepthBias;
+ if ( shaderState.m_ZBias == SHADER_POLYOFFSET_DECAL )
+ {
+ fSlopeScaleDepthBias = a;
+ fDepthBias = c;
+ }
+ else if ( shaderState.m_ZBias == SHADER_POLYOFFSET_SHADOW_BIAS )
+ {
+ fSlopeScaleDepthBias = m_fShadowSlopeScaleDepthBias;
+ fDepthBias = m_fShadowDepthBias;
+ }
+ else // assume SHADER_POLYOFFSET_DISABLE
+ {
+ fSlopeScaleDepthBias = b;
+ fDepthBias = d;
+ }
+
+ if( ReverseDepthOnX360() )
+ {
+ fSlopeScaleDepthBias = -fSlopeScaleDepthBias;
+ fDepthBias = -fDepthBias;
+ }
+
+ SetRenderStateConstMacro( this, D3DRS_SLOPESCALEDEPTHBIAS, *((DWORD*) (&fSlopeScaleDepthBias)) );
+ SetRenderStateConstMacro( this, D3DRS_DEPTHBIAS, *((DWORD*) (&fDepthBias)) );
+ }
+ else
+ {
+ MarkAllUserClipPlanesDirty();
+ m_DynamicState.m_TransformChanged[MATERIAL_PROJECTION] |=
+ STATE_CHANGED_VERTEX_SHADER | STATE_CHANGED_FIXED_FUNCTION;
+ }
+}
+
+void CShaderAPIDx8::ApplyTextureEnable( const ShadowState_t& state, int nSampler )
+{
+ if ( state.m_SamplerState[nSampler].m_TextureEnable == SamplerState(nSampler).m_TextureEnable )
+ return;
+
+ if ( state.m_SamplerState[nSampler].m_TextureEnable )
+ {
+ SamplerState( nSampler ).m_TextureEnable = true;
+
+ // Should not be necessary/possible (SetTextureState() calls D3D9/DXAbstract, so the calling thread must already own the device.
+ //LOCK_SHADERAPI();
+
+ // Don't do this here!! It ends up giving us extra texture sets.
+ // We'll Assert in debug mode if you enable a texture stage
+ // but don't bind a texture.
+ // see CShaderAPIDx8::RenderPass() for this check.
+ // NOTE: We aren't doing this optimization quite yet. There are situations
+ // where you want a texture stage enabled for its texture coordinates, but
+ // you don't actually bind a texture (texmvspec for example.)
+ SetTextureState( (Sampler_t)nSampler, SamplerState(nSampler).m_BoundTexture, true );
+ }
+ else
+ {
+ SamplerState( nSampler ).m_TextureEnable = false;
+ SetTextureState( (Sampler_t)nSampler, INVALID_SHADERAPI_TEXTURE_HANDLE );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Used to clear the transition table when we know it's become invalid.
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::ClearSnapshots()
+{
+ LOCK_SHADERAPI();
+ FlushBufferedPrimitives();
+ m_TransitionTable.Reset();
+ InitRenderState();
+}
+
+
+static void KillTranslation( D3DXMATRIX& mat )
+{
+ mat[3] = 0.0f;
+ mat[7] = 0.0f;
+ mat[11] = 0.0f;
+ mat[12] = 0.0f;
+ mat[13] = 0.0f;
+ mat[14] = 0.0f;
+ mat[15] = 1.0f;
+}
+
+static void PrintMatrix( const char *name, const D3DXMATRIX& mat )
+{
+ int row, col;
+ char buf[128];
+
+ Plat_DebugString( name );
+ Plat_DebugString( "\n" );
+ for( row = 0; row < 4; row++ )
+ {
+ Plat_DebugString( " " );
+ for( col = 0; col < 4; col++ )
+ {
+ sprintf( buf, "%f ", ( float )mat( row, col ) );
+ Plat_DebugString( buf );
+ }
+ Plat_DebugString( "\n" );
+ }
+ Plat_DebugString( "\n" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the vertex format for a particular snapshot id
+//-----------------------------------------------------------------------------
+VertexFormat_t CShaderAPIDx8::ComputeVertexUsage( int num, StateSnapshot_t* pIds ) const
+{
+ LOCK_SHADERAPI();
+ if (num == 0)
+ return 0;
+
+ // We don't have to all sorts of crazy stuff if there's only one snapshot
+ if ( num == 1 )
+ {
+ const ShadowShaderState_t& state = m_TransitionTable.GetSnapshotShader( pIds[0] );
+ return state.m_VertexUsage;
+ }
+
+ Assert( pIds );
+
+ // Aggregating vertex formats is a little tricky;
+ // For example, what do we do when two passes want user data?
+ // Can we assume they are the same? For now, I'm going to
+ // just print a warning in debug.
+
+ VertexCompressionType_t compression = VERTEX_COMPRESSION_INVALID;
+ int userDataSize = 0;
+ int numBones = 0;
+ int texCoordSize[VERTEX_MAX_TEXTURE_COORDINATES] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ int flags = 0;
+
+ for (int i = num; --i >= 0; )
+ {
+ const ShadowShaderState_t& state = m_TransitionTable.GetSnapshotShader( pIds[i] );
+ VertexFormat_t fmt = state.m_VertexUsage;
+ flags |= VertexFlags(fmt);
+
+ VertexCompressionType_t newCompression = CompressionType( fmt );
+ if ( ( compression != newCompression ) && ( compression != VERTEX_COMPRESSION_INVALID ) )
+ {
+ Warning("Encountered a material with two passes that specify different vertex compression types!\n");
+ compression = VERTEX_COMPRESSION_NONE; // Be safe, disable compression
+ }
+
+ int newNumBones = NumBoneWeights(fmt);
+ if ((numBones != newNumBones) && (newNumBones != 0))
+ {
+ if (numBones != 0)
+ {
+ Warning("Encountered a material with two passes that use different numbers of bones!\n");
+ }
+ numBones = newNumBones;
+ }
+
+ int newUserSize = UserDataSize(fmt);
+ if ((userDataSize != newUserSize) && (newUserSize != 0))
+ {
+ if (userDataSize != 0)
+ {
+ Warning("Encountered a material with two passes that use different user data sizes!\n");
+ }
+ userDataSize = newUserSize;
+ }
+
+ for ( int j = 0; j < VERTEX_MAX_TEXTURE_COORDINATES; ++j )
+ {
+ int newSize = TexCoordSize( (TextureStage_t)j, fmt );
+ if ( ( texCoordSize[j] != newSize ) && ( newSize != 0 ) )
+ {
+ if ( texCoordSize[j] != 0 )
+ {
+ Warning("Encountered a material with two passes that use different texture coord sizes!\n");
+ }
+ if ( texCoordSize[j] < newSize )
+ {
+ texCoordSize[j] = newSize;
+ }
+ }
+ }
+ }
+
+ return MeshMgr()->ComputeVertexFormat( flags, VERTEX_MAX_TEXTURE_COORDINATES,
+ texCoordSize, numBones, userDataSize );
+}
+
+VertexFormat_t CShaderAPIDx8::ComputeVertexFormat( int num, StateSnapshot_t* pIds ) const
+{
+ LOCK_SHADERAPI();
+ VertexFormat_t fmt = ComputeVertexUsage( num, pIds );
+ return fmt;
+}
+
+
+//-----------------------------------------------------------------------------
+// What fields in the morph do we actually use?
+//-----------------------------------------------------------------------------
+MorphFormat_t CShaderAPIDx8::ComputeMorphFormat( int numSnapshots, StateSnapshot_t* pIds ) const
+{
+ LOCK_SHADERAPI();
+ MorphFormat_t format = 0;
+ for ( int i = 0; i < numSnapshots; ++i )
+ {
+ MorphFormat_t fmt = m_TransitionTable.GetSnapshotShader( pIds[i] ).m_MorphUsage;
+ format |= VertexFlags(fmt);
+ }
+ return format;
+}
+
+//-----------------------------------------------------------------------------
+// Commits a range of vertex shader constants
+//-----------------------------------------------------------------------------
+static void CommitVertexShaderConstantRange( IDirect3DDevice9 *pDevice, const DynamicState_t &desiredState,
+ DynamicState_t &currentState, bool bForce, int nFirstConstant, int nCount )
+{
+ if ( IsX360() )
+ {
+ // invalid code path for 360, not coded for 360 GPU contant awareness
+ Assert( 0 );
+ return;
+ }
+
+ int nFirstCommit = nFirstConstant;
+ int nCommitCount = 0;
+
+ for ( int i = 0; i < nCount; ++i )
+ {
+ int nVar = nFirstConstant + i;
+
+ bool bDifferentValue = bForce || ( desiredState.m_pVectorVertexShaderConstant[nVar] != currentState.m_pVectorVertexShaderConstant[nVar] );
+ if ( !bDifferentValue )
+ {
+ if ( nCommitCount != 0 )
+ {
+ // flush the prior range
+ pDevice->SetVertexShaderConstantF( nFirstCommit, desiredState.m_pVectorVertexShaderConstant[nFirstCommit].Base(), nCommitCount );
+
+ memcpy( &currentState.m_pVectorVertexShaderConstant[nFirstCommit],
+ &desiredState.m_pVectorVertexShaderConstant[nFirstCommit], nCommitCount * 4 * sizeof(float) );
+ }
+
+ // start of new range
+ nFirstCommit = nVar + 1;
+ nCommitCount = 0;
+ }
+ else
+ {
+ ++nCommitCount;
+ }
+ }
+
+ if ( nCommitCount != 0 )
+ {
+ // flush range
+ pDevice->SetVertexShaderConstantF( nFirstCommit, desiredState.m_pVectorVertexShaderConstant[nFirstCommit].Base(), nCommitCount );
+
+ memcpy( &currentState.m_pVectorVertexShaderConstant[nFirstCommit],
+ &desiredState.m_pVectorVertexShaderConstant[nFirstCommit], nCommitCount * 4 * sizeof(float) );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the current buffered state... (debug only)
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::GetBufferedState( BufferedState_t& state )
+{
+ memcpy( &state.m_Transform[0], &GetTransform(MATERIAL_MODEL), sizeof(D3DXMATRIX) );
+ memcpy( &state.m_Transform[1], &GetTransform(MATERIAL_VIEW), sizeof(D3DXMATRIX) );
+ memcpy( &state.m_Transform[2], &GetTransform(MATERIAL_PROJECTION), sizeof(D3DXMATRIX) );
+ memcpy( &state.m_Viewport, &m_DynamicState.m_Viewport, sizeof(state.m_Viewport) );
+ state.m_PixelShader = ShaderManager()->GetCurrentPixelShader();
+ state.m_VertexShader = ShaderManager()->GetCurrentVertexShader();
+ for (int i = 0; i < g_pHardwareConfig->GetSamplerCount(); ++i)
+ {
+ state.m_BoundTexture[i] = m_DynamicState.m_SamplerState[i].m_BoundTexture;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// constant color methods
+//-----------------------------------------------------------------------------
+
+void CShaderAPIDx8::Color3f( float r, float g, float b )
+{
+ unsigned int color = D3DCOLOR_ARGB( 255, (int)(r * 255),
+ (int)(g * 255), (int)(b * 255) );
+ if (color != m_DynamicState.m_ConstantColor)
+ {
+ m_DynamicState.m_ConstantColor = color;
+ SetSupportedRenderState( D3DRS_TEXTUREFACTOR, color );
+ }
+}
+
+void CShaderAPIDx8::Color4f( float r, float g, float b, float a )
+{
+ unsigned int color = D3DCOLOR_ARGB( (int)(a * 255), (int)(r * 255),
+ (int)(g * 255), (int)(b * 255) );
+ if (color != m_DynamicState.m_ConstantColor)
+ {
+ m_DynamicState.m_ConstantColor = color;
+ SetSupportedRenderState( D3DRS_TEXTUREFACTOR, color );
+ }
+}
+
+void CShaderAPIDx8::Color3fv( float const *c )
+{
+ Assert( c );
+ unsigned int color = D3DCOLOR_ARGB( 255, (int)(c[0] * 255),
+ (int)(c[1] * 255), (int)(c[2] * 255) );
+ if (color != m_DynamicState.m_ConstantColor)
+ {
+ m_DynamicState.m_ConstantColor = color;
+ SetSupportedRenderState( D3DRS_TEXTUREFACTOR, color );
+ }
+}
+
+void CShaderAPIDx8::Color4fv( float const *c )
+{
+ Assert( c );
+ unsigned int color = D3DCOLOR_ARGB( (int)(c[3] * 255), (int)(c[0] * 255),
+ (int)(c[1] * 255), (int)(c[2] * 255) );
+ if (color != m_DynamicState.m_ConstantColor)
+ {
+ m_DynamicState.m_ConstantColor = color;
+ SetSupportedRenderState( D3DRS_TEXTUREFACTOR, color );
+ }
+}
+
+void CShaderAPIDx8::Color3ub( unsigned char r, unsigned char g, unsigned char b )
+{
+ unsigned int color = D3DCOLOR_ARGB( 255, r, g, b );
+ if (color != m_DynamicState.m_ConstantColor)
+ {
+ m_DynamicState.m_ConstantColor = color;
+ SetSupportedRenderState( D3DRS_TEXTUREFACTOR, color );
+ }
+}
+
+void CShaderAPIDx8::Color3ubv( unsigned char const* pColor )
+{
+ Assert( pColor );
+ unsigned int color = D3DCOLOR_ARGB( 255, pColor[0], pColor[1], pColor[2] );
+ if (color != m_DynamicState.m_ConstantColor)
+ {
+ m_DynamicState.m_ConstantColor = color;
+ SetSupportedRenderState( D3DRS_TEXTUREFACTOR, color );
+ }
+}
+
+void CShaderAPIDx8::Color4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a )
+{
+ unsigned int color = D3DCOLOR_ARGB( a, r, g, b );
+ if (color != m_DynamicState.m_ConstantColor)
+ {
+ m_DynamicState.m_ConstantColor = color;
+ SetSupportedRenderState( D3DRS_TEXTUREFACTOR, color );
+ }
+}
+
+void CShaderAPIDx8::Color4ubv( unsigned char const* pColor )
+{
+ Assert( pColor );
+ unsigned int color = D3DCOLOR_ARGB( pColor[3], pColor[0], pColor[1], pColor[2] );
+ if (color != m_DynamicState.m_ConstantColor)
+ {
+ m_DynamicState.m_ConstantColor = color;
+ SetSupportedRenderState( D3DRS_TEXTUREFACTOR, color );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// The shade mode
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::ShadeMode( ShaderShadeMode_t mode )
+{
+ LOCK_SHADERAPI();
+ D3DSHADEMODE shadeMode = (mode == SHADER_FLAT) ? D3DSHADE_FLAT : D3DSHADE_GOURAUD;
+ if (m_DynamicState.m_ShadeMode != shadeMode)
+ {
+ m_DynamicState.m_ShadeMode = shadeMode;
+ SetRenderStateConstMacro( this, D3DRS_SHADEMODE, shadeMode );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Buffering 2 frames ahead
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::EnableBuffer2FramesAhead( bool bEnable )
+{
+#ifdef _X360
+ m_bBuffer2FramesAhead = bEnable;
+ if ( bEnable != m_DynamicState.m_bBuffer2Frames )
+ {
+ SetRenderState( D3DRS_BUFFER2FRAMES, bEnable );
+ m_DynamicState.m_bBuffer2Frames = bEnable;
+ }
+#endif
+}
+
+void CShaderAPIDx8::SetDepthFeatheringPixelShaderConstant( int iConstant, float fDepthBlendScale )
+{
+ float fConstantValues[4];
+
+ if( IsX360() )
+ {
+ const D3DMATRIX &projMatrix = GetProjectionMatrix();
+
+ fConstantValues[0] = 50.0f / fDepthBlendScale;
+ fConstantValues[1] = 1.0f / projMatrix.m[2][2];
+ fConstantValues[2] = 1.0f / projMatrix.m[3][2];
+ fConstantValues[3] = projMatrix.m[2][2];
+
+ /*
+ D3DXMATRIX invProjMatrix;
+ D3DXMatrixInverse( &invProjMatrix, NULL, (D3DXMATRIX *)&projMatrix );
+ fConstantValues[1] = invProjMatrix.m[3][2];
+ fConstantValues[2] = invProjMatrix.m[3][3];
+ fConstantValues[3] = invProjMatrix.m[2][2];
+ */
+ }
+ else
+ {
+ fConstantValues[0] = m_DynamicState.m_DestAlphaDepthRange / fDepthBlendScale;
+ fConstantValues[1] = fConstantValues[2] = fConstantValues[3] = 0.0f; //empty
+ }
+
+ SetPixelShaderConstant( iConstant, fConstantValues );
+}
+
+
+//-----------------------------------------------------------------------------
+// Cull mode..
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::SetCullModeState( bool bEnable, D3DCULL nDesiredCullMode )
+{
+ D3DCULL nCullMode = bEnable ? nDesiredCullMode : D3DCULL_NONE;
+ if ( nCullMode != m_DynamicState.m_CullMode )
+ {
+ SetRenderStateConstMacro( this, D3DRS_CULLMODE, nCullMode );
+ m_DynamicState.m_CullMode = nCullMode;
+ }
+}
+
+void CShaderAPIDx8::ApplyCullEnable( bool bEnable )
+{
+ m_DynamicState.m_bCullEnabled = bEnable;
+ SetCullModeState( m_DynamicState.m_bCullEnabled, m_DynamicState.m_DesiredCullMode );
+}
+
+void CShaderAPIDx8::CullMode( MaterialCullMode_t nCullMode )
+{
+ LOCK_SHADERAPI();
+ D3DCULL nNewCullMode;
+ switch( nCullMode )
+ {
+ case MATERIAL_CULLMODE_CCW:
+ // Culls backfacing polys (normal)
+ nNewCullMode = D3DCULL_CCW;
+ break;
+
+ case MATERIAL_CULLMODE_CW:
+ // Culls frontfacing polys
+ nNewCullMode = D3DCULL_CW;
+ break;
+
+ default:
+ Warning( "CullMode: invalid cullMode\n" );
+ return;
+ }
+
+ if (m_DynamicState.m_DesiredCullMode != nNewCullMode)
+ {
+ FlushBufferedPrimitives();
+ m_DynamicState.m_DesiredCullMode = nNewCullMode;
+ SetCullModeState( m_DynamicState.m_bCullEnabled, m_DynamicState.m_DesiredCullMode );
+ }
+}
+
+static ConVar mat_alphacoverage( "mat_alphacoverage", "1" );
+void CShaderAPIDx8::ApplyAlphaToCoverage( bool bEnable )
+{
+ if ( mat_alphacoverage.GetBool() )
+ {
+ if ( bEnable )
+ EnableAlphaToCoverage();
+ else
+ DisableAlphaToCoverage();
+ }
+ else
+ {
+ DisableAlphaToCoverage();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Returns the current cull mode of the current material (for selection mode only)
+//-----------------------------------------------------------------------------
+D3DCULL CShaderAPIDx8::GetCullMode() const
+{
+ Assert( m_pMaterial );
+ if ( m_pMaterial->GetMaterialVarFlag( MATERIAL_VAR_NOCULL ) )
+ return D3DCULL_NONE;
+ return m_DynamicState.m_DesiredCullMode;
+}
+
+void CShaderAPIDx8::SetRasterState( const ShaderRasterState_t& state )
+{
+ // FIXME: Implement!
+}
+
+
+void CShaderAPIDx8::ForceDepthFuncEquals( bool bEnable )
+{
+ LOCK_SHADERAPI();
+ if ( !g_pShaderDeviceDx8->IsDeactivated() )
+ {
+ m_TransitionTable.ForceDepthFuncEquals( bEnable );
+ }
+}
+
+void CShaderAPIDx8::OverrideDepthEnable( bool bEnable, bool bDepthEnable )
+{
+ LOCK_SHADERAPI();
+ if ( !g_pShaderDeviceDx8->IsDeactivated() )
+ {
+ m_TransitionTable.OverrideDepthEnable( bEnable, bDepthEnable );
+ }
+}
+
+void CShaderAPIDx8::OverrideAlphaWriteEnable( bool bOverrideEnable, bool bAlphaWriteEnable )
+{
+ LOCK_SHADERAPI();
+ if ( !g_pShaderDeviceDx8->IsDeactivated() )
+ {
+ m_TransitionTable.OverrideAlphaWriteEnable( bOverrideEnable, bAlphaWriteEnable );
+ }
+}
+
+void CShaderAPIDx8::OverrideColorWriteEnable( bool bOverrideEnable, bool bColorWriteEnable )
+{
+ LOCK_SHADERAPI();
+ if ( !g_pShaderDeviceDx8->IsDeactivated() )
+ {
+ m_TransitionTable.OverrideColorWriteEnable( bOverrideEnable, bColorWriteEnable );
+ }
+}
+
+void CShaderAPIDx8::UpdateFastClipUserClipPlane( void )
+{
+ float plane[4];
+ switch( m_DynamicState.m_HeightClipMode )
+ {
+ case MATERIAL_HEIGHTCLIPMODE_DISABLE:
+ EnableFastClip( false );
+ break;
+ case MATERIAL_HEIGHTCLIPMODE_RENDER_ABOVE_HEIGHT:
+ plane[0] = 0.0f;
+ plane[1] = 0.0f;
+ plane[2] = 1.0f;
+ plane[3] = m_DynamicState.m_HeightClipZ;
+ EnableFastClip( true );
+ SetFastClipPlane(plane);
+ break;
+ case MATERIAL_HEIGHTCLIPMODE_RENDER_BELOW_HEIGHT:
+ plane[0] = 0.0f;
+ plane[1] = 0.0f;
+ plane[2] = -1.0f;
+ plane[3] = -m_DynamicState.m_HeightClipZ;
+ EnableFastClip( true );
+ SetFastClipPlane(plane);
+ break;
+ }
+}
+
+void CShaderAPIDx8::SetHeightClipZ( float z )
+{
+ LOCK_SHADERAPI();
+ if( z != m_DynamicState.m_HeightClipZ )
+ {
+ FlushBufferedPrimitives();
+ m_DynamicState.m_HeightClipZ = z;
+ UpdateVertexShaderFogParams();
+ UpdateFastClipUserClipPlane();
+ m_DynamicState.m_TransformChanged[MATERIAL_PROJECTION] |=
+ STATE_CHANGED_VERTEX_SHADER | STATE_CHANGED_FIXED_FUNCTION;
+ }
+}
+
+void CShaderAPIDx8::SetHeightClipMode( MaterialHeightClipMode_t heightClipMode )
+{
+ LOCK_SHADERAPI();
+ if( heightClipMode != m_DynamicState.m_HeightClipMode )
+ {
+ FlushBufferedPrimitives();
+ m_DynamicState.m_HeightClipMode = heightClipMode;
+ UpdateVertexShaderFogParams();
+ UpdateFastClipUserClipPlane();
+ m_DynamicState.m_TransformChanged[MATERIAL_PROJECTION] |=
+ STATE_CHANGED_VERTEX_SHADER | STATE_CHANGED_FIXED_FUNCTION;
+ }
+}
+
+void CShaderAPIDx8::SetClipPlane( int index, const float *pPlane )
+{
+ LOCK_SHADERAPI();
+ Assert( index < g_pHardwareConfig->MaxUserClipPlanes() && index >= 0 );
+
+ // NOTE: The plane here is specified in *world space*
+ // NOTE: This is done because they assume Ax+By+Cz+Dw = 0 (where w = 1 in real space)
+ // while we use Ax+By+Cz=D
+ D3DXPLANE plane;
+ plane.a = pPlane[0];
+ plane.b = pPlane[1];
+ plane.c = pPlane[2];
+ plane.d = -pPlane[3];
+
+ if ( plane != m_DynamicState.m_UserClipPlaneWorld[index] )
+ {
+ FlushBufferedPrimitives();
+
+ m_DynamicState.m_UserClipPlaneChanged |= ( 1 << index );
+ m_DynamicState.m_UserClipPlaneWorld[index] = plane;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Converts a D3DXMatrix to a VMatrix and back
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::D3DXMatrixToVMatrix( const D3DXMATRIX &in, VMatrix &out )
+{
+ MatrixTranspose( *(const VMatrix*)&in, out );
+}
+
+void CShaderAPIDx8::VMatrixToD3DXMatrix( const VMatrix &in, D3DXMATRIX &out )
+{
+ MatrixTranspose( in, *(VMatrix*)&out );
+}
+
+
+//-----------------------------------------------------------------------------
+// Mark all user clip planes as being dirty
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::MarkAllUserClipPlanesDirty()
+{
+ m_DynamicState.m_UserClipPlaneChanged |= ( 1 << g_pHardwareConfig->MaxUserClipPlanes() ) - 1;
+ m_DynamicState.m_bFastClipPlaneChanged = true;
+}
+
+
+//-----------------------------------------------------------------------------
+// User clip plane override
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::EnableUserClipTransformOverride( bool bEnable )
+{
+ LOCK_SHADERAPI();
+ if ( m_DynamicState.m_bUserClipTransformOverride != bEnable )
+ {
+ FlushBufferedPrimitives();
+ m_DynamicState.m_bUserClipTransformOverride = bEnable;
+ MarkAllUserClipPlanesDirty();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Specify user clip transform
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::UserClipTransform( const VMatrix &worldToProjection )
+{
+ LOCK_SHADERAPI();
+ D3DXMATRIX dxWorldToProjection;
+ VMatrixToD3DXMatrix( worldToProjection, dxWorldToProjection );
+
+ if ( m_DynamicState.m_UserClipTransform != dxWorldToProjection )
+ {
+ m_DynamicState.m_UserClipTransform = dxWorldToProjection;
+ if ( m_DynamicState.m_bUserClipTransformOverride )
+ {
+ FlushBufferedPrimitives();
+ MarkAllUserClipPlanesDirty();
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Enables a user clip plane
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::EnableClipPlane( int index, bool bEnable )
+{
+ LOCK_SHADERAPI();
+ Assert( index < g_pHardwareConfig->MaxUserClipPlanes() && index >= 0 );
+ if( ( m_DynamicState.m_UserClipPlaneEnabled & ( 1 << index ) ? true : false ) != bEnable )
+ {
+ FlushBufferedPrimitives();
+ if( bEnable )
+ {
+ m_DynamicState.m_UserClipPlaneEnabled |= ( 1 << index );
+ }
+ else
+ {
+ m_DynamicState.m_UserClipPlaneEnabled &= ~( 1 << index );
+ }
+ SetRenderStateConstMacro( this, D3DRS_CLIPPLANEENABLE, m_DynamicState.m_UserClipPlaneEnabled );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Recomputes the fast-clip plane matrices based on the current fast-clip plane
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::CommitFastClipPlane( )
+{
+ // Don't bother recomputing if unchanged or disabled
+ if ( !m_DynamicState.m_bFastClipPlaneChanged || !m_DynamicState.m_FastClipEnabled )
+ return;
+
+ m_DynamicState.m_bFastClipPlaneChanged = false;
+
+ D3DXMatrixIdentity( &m_CachedFastClipProjectionMatrix );
+
+ // Compute worldToProjection - need inv. transpose for transforming plane.
+ D3DXMATRIX viewToProjInvTrans, viewToProjInv, viewToProj = GetTransform(MATERIAL_PROJECTION);
+ viewToProj._43 *= 0.5f; // pull in zNear because the shear in effect
+ // moves it out: clipping artifacts when looking down at water
+ // could occur if this multiply is not done
+
+ D3DXMATRIX worldToViewInvTrans, worldToViewInv, worldToView = GetUserClipTransform();
+
+ D3DXMatrixInverse( &worldToViewInv, NULL, &worldToView );
+ D3DXMatrixTranspose( &worldToViewInvTrans, &worldToViewInv );
+
+ D3DXMatrixInverse( &viewToProjInv, NULL, &viewToProj );
+ D3DXMatrixTranspose( &viewToProjInvTrans, &viewToProjInv );
+
+ D3DXPLANE plane;
+ D3DXPlaneNormalize( &plane, &m_DynamicState.m_FastClipPlane );
+ D3DXVECTOR4 clipPlane( plane.a, plane.b, plane.c, plane.d );
+
+ // transform clip plane into view space
+ D3DXVec4Transform( &clipPlane, &clipPlane, &worldToViewInvTrans );
+
+ // transform clip plane into projection space
+ D3DXVec4Transform( &clipPlane, &clipPlane, &viewToProjInvTrans );
+
+#define ALLOW_FOR_FASTCLIPDUMPS 0
+
+#if (ALLOW_FOR_FASTCLIPDUMPS == 1)
+ static ConVar shader_dumpfastclipprojectioncoords( "shader_dumpfastclipprojectioncoords", "0", 0, "dump fast clip projected matrix" );
+ if( shader_dumpfastclipprojectioncoords.GetBool() )
+ DevMsg( "Fast clip plane projected coordinates: %f %f %f %f", clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w );
+#endif
+
+ if( (clipPlane.z * clipPlane.w) <= -0.4f ) // a plane with (z*w) > -0.4 at this point is behind the camera and will cause graphical glitches. Toss it. (0.4 found through experimentation)
+ {
+#if (ALLOW_FOR_FASTCLIPDUMPS == 1)
+ if( shader_dumpfastclipprojectioncoords.GetBool() )
+ DevMsg( " %f %f %f %f\n", clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w );
+#endif
+
+ D3DXVec4Normalize( &clipPlane, &clipPlane );
+
+ //if ((fabs(clipPlane.z) > 0.01) && (fabs(clipPlane.w) > 0.01f))
+ {
+ // put projection space clip plane in Z column
+ m_CachedFastClipProjectionMatrix._13 = clipPlane.x;
+ m_CachedFastClipProjectionMatrix._23 = clipPlane.y;
+ m_CachedFastClipProjectionMatrix._33 = clipPlane.z;
+ m_CachedFastClipProjectionMatrix._43 = clipPlane.w;
+ }
+ }
+#if (ALLOW_FOR_FASTCLIPDUMPS == 1)
+ else
+ {
+ if( shader_dumpfastclipprojectioncoords.GetBool() )
+ DevMsg( "\n" ); //finish off the line above
+ }
+#endif
+
+ m_CachedFastClipProjectionMatrix = viewToProj * m_CachedFastClipProjectionMatrix;
+
+ // Update the cached polyoffset matrix (with clip) too:
+ ComputePolyOffsetMatrix( m_CachedFastClipProjectionMatrix, m_CachedFastClipPolyOffsetProjectionMatrix );
+}
+
+//-----------------------------------------------------------------------------
+// Sets the fast-clip plane; but doesn't update the matrices
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::SetFastClipPlane( const float *pPlane )
+{
+ LOCK_SHADERAPI();
+ D3DXPLANE plane;
+ plane.a = pPlane[0];
+ plane.b = pPlane[1];
+ plane.c = pPlane[2];
+ plane.d = -pPlane[3];
+ if ( plane != m_DynamicState.m_FastClipPlane )
+ {
+ FlushBufferedPrimitives();
+ UpdateVertexShaderFogParams();
+
+ m_DynamicState.m_FastClipPlane = plane;
+
+ // Mark a dirty bit so when it comes time to commit view + projection transforms,
+ // we also update the fast clip matrices
+ m_DynamicState.m_bFastClipPlaneChanged = true;
+
+ m_DynamicState.m_TransformChanged[MATERIAL_PROJECTION] |=
+ STATE_CHANGED_VERTEX_SHADER | STATE_CHANGED_FIXED_FUNCTION;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Enables/disables fast-clip mode
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::EnableFastClip( bool bEnable )
+{
+ LOCK_SHADERAPI();
+ if( m_DynamicState.m_FastClipEnabled != bEnable )
+ {
+ FlushBufferedPrimitives();
+ UpdateVertexShaderFogParams();
+
+ m_DynamicState.m_FastClipEnabled = bEnable;
+
+ m_DynamicState.m_TransformChanged[MATERIAL_PROJECTION] |=
+ STATE_CHANGED_VERTEX_SHADER | STATE_CHANGED_FIXED_FUNCTION;
+ }
+}
+
+/*
+// -----------------------------------------------------------------------------
+// SetInvariantClipVolume - This routine takes six planes as input and sets the
+// appropriate Direct3D user clip plane state
+// What we mean by "invariant clipping" here is that certain devices implement
+// user clip planes at the raster level, which means that multi-pass rendering
+// where one pass is unclipped (such as base geometry) and another pass *IS*
+// clipped (such as flashlight geometry), there is no z-fighting since the
+// clipping is implemented at the raster level in an "invariant" way
+// -----------------------------------------------------------------------------
+void CShaderAPIDx8::SetInvariantClipVolume( Frustum_t *pFrustumPlanes )
+{
+ // Only do this on modern nVidia hardware, which does invariant clipping
+ if ( m_VendorID == VENDORID_NVIDIA )
+ {
+ if ( pFrustumPlanes )
+ {
+// if ()
+// {
+//
+// }
+
+ for (int i=0; i<6; i++)
+ {
+ const cplane_t *pPlane = pFrustumPlanes->GetPlane(i);
+
+ SetClipPlane( i, (float *) &pPlane->normal );
+ EnableClipPlane( i, true );
+
+// FRUSTUM_RIGHT = 0,
+// FRUSTUM_LEFT = 1,
+// FRUSTUM_TOP = 2,
+// FRUSTUM_BOTTOM = 3,
+// FRUSTUM_NEARZ = 4,
+// FRUSTUM_FARZ = 5,
+
+ }
+ }
+ else // NULL disables the invariant clip volume...
+ {
+ for (int i=0; i<6; i++)
+ {
+ EnableClipPlane( i, false );
+ }
+ }
+ }
+}
+*/
+
+//-----------------------------------------------------------------------------
+// Vertex blending
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::SetVertexBlendState( int numBones )
+{
+ if (numBones < 0)
+ {
+ numBones = m_DynamicState.m_NumBones;
+ }
+
+ // For fixed-function, the number of weights is actually one less than
+ // the number of bones
+ if (numBones > 0)
+ --numBones;
+
+ bool normalizeNormals = true;
+ D3DVERTEXBLENDFLAGS vertexBlend;
+ switch(numBones)
+ {
+ case 0:
+ vertexBlend = D3DVBF_DISABLE;
+ normalizeNormals = false;
+ break;
+
+ case 1:
+ vertexBlend = D3DVBF_1WEIGHTS;
+ break;
+
+ case 2:
+ vertexBlend = D3DVBF_2WEIGHTS;
+ break;
+
+ case 3:
+ vertexBlend = D3DVBF_3WEIGHTS;
+ break;
+
+ default:
+ vertexBlend = D3DVBF_DISABLE;
+ Assert(0);
+ break;
+ }
+
+ if (m_DynamicState.m_VertexBlend != vertexBlend)
+ {
+ m_DynamicState.m_VertexBlend = vertexBlend;
+ SetSupportedRenderState( D3DRS_VERTEXBLEND, vertexBlend );
+ }
+
+ // Activate normalize normals when skinning is on
+ if (m_DynamicState.m_NormalizeNormals != normalizeNormals)
+ {
+ m_DynamicState.m_NormalizeNormals = normalizeNormals;
+ SetSupportedRenderState( D3DRS_NORMALIZENORMALS, normalizeNormals );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Vertex blending
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::SetNumBoneWeights( int numBones )
+{
+ LOCK_SHADERAPI();
+ if (m_DynamicState.m_NumBones != numBones)
+ {
+ FlushBufferedPrimitives();
+ m_DynamicState.m_NumBones = numBones;
+
+ if ( m_TransitionTable.CurrentShadowState() )
+ {
+ SetVertexBlendState( m_TransitionTable.CurrentShadowState()->m_VertexBlendEnable ? -1 : 0 );
+ }
+ }
+}
+
+void CShaderAPIDx8::EnableHWMorphing( bool bEnable )
+{
+ LOCK_SHADERAPI();
+ if ( m_DynamicState.m_bHWMorphingEnabled != bEnable )
+ {
+ FlushBufferedPrimitives();
+ m_DynamicState.m_bHWMorphingEnabled = bEnable;
+ }
+}
+
+void CShaderAPIDx8::EnabledSRGBWrite( bool bEnabled )
+{
+ m_DynamicState.m_bSRGBWritesEnabled = bEnabled;
+
+ if ( g_pHardwareConfig->SupportsPixelShaders_2_b() )
+ {
+ UpdatePixelFogColorConstant();
+
+ if ( bEnabled && g_pHardwareConfig->NeedsShaderSRGBConversion() )
+ BindTexture( SHADER_SAMPLER15, m_hLinearToGammaTableTexture );
+ else
+ BindTexture( SHADER_SAMPLER15, m_hLinearToGammaTableIdentityTexture );
+ }
+}
+
+#if defined( _X360 )
+void CShaderAPIDx8::ApplySRGBReadState( int iTextureStage, bool bSRGBReadEnabled )
+{
+ Sampler_t sampler = (Sampler_t)iTextureStage;
+ SamplerState_t &samplerState = SamplerState( sampler );
+ samplerState.m_SRGBReadEnable = bSRGBReadEnabled;
+
+ if ( ( samplerState.m_BoundTexture == INVALID_SHADERAPI_TEXTURE_HANDLE ) || !samplerState.m_TextureEnable )
+ {
+ return;
+ }
+
+ IDirect3DBaseTexture *pBindTexture = CShaderAPIDx8::GetD3DTexture( samplerState.m_BoundTexture );
+ if ( !pBindTexture )
+ {
+ return;
+ }
+
+ DWORD linearFormatBackup = pBindTexture->Format.dword[0]; //if we convert to srgb format, we need the original format for reverting. We only need the first DWORD of GPUTEXTURE_FETCH_CONSTANT.
+ if ( bSRGBReadEnabled )
+ {
+ pBindTexture->Format.SignX = pBindTexture->Format.SignY = pBindTexture->Format.SignZ = 3; //convert to srgb format for the bind. This effectively emulates the old srgb read sampler state
+ }
+
+ Dx9Device()->SetTexture( sampler, pBindTexture );
+
+ // copy back the format in case we changed it
+ pBindTexture->Format.dword[0] = linearFormatBackup;
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// Fog methods...
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::UpdatePixelFogColorConstant( void )
+{
+ Assert( HardwareConfig()->SupportsPixelShaders_2_b() );
+ float fogColor[4];
+
+ switch( GetPixelFogMode() )
+ {
+ case MATERIAL_FOG_NONE:
+ {
+ for( int i = 0; i != 3; ++i )
+ fogColor[i] = 0.0f;
+ }
+ break;
+
+ case MATERIAL_FOG_LINEAR:
+ {
+ //setup the fog for mixing linear fog in the pixel shader so that it emulates ff range fog
+ for( int i = 0; i != 3; ++i )
+ fogColor[i] = m_DynamicState.m_PixelFogColor[i];
+
+ if( m_DynamicState.m_bSRGBWritesEnabled )
+ {
+ //since the fog color will assuredly get converted from linear to gamma, we should probably convert it from gamma to linear
+ for( int i = 0; i != 3; ++i )
+ fogColor[i] = GammaToLinear_HardwareSpecific( fogColor[i] );
+ }
+
+ if( (!m_DynamicState.m_bFogGammaCorrectionDisabled) && (g_pHardwareConfig->GetHDRType() == HDR_TYPE_INTEGER) )
+ {
+ for( int i = 0; i != 3; ++i )
+ fogColor[i] *= m_ToneMappingScale.x; // Linear
+ }
+ }
+ break;
+
+ case MATERIAL_FOG_LINEAR_BELOW_FOG_Z:
+ {
+ //water fog has been around a while and has never tonemap scaled, and has always been in linear space
+ if( g_pHardwareConfig->NeedsShaderSRGBConversion() )
+ {
+ //srgb in ps2b uses the 2.2 curve
+ for( int i = 0; i != 3; ++i )
+ fogColor[i] = pow( m_DynamicState.m_PixelFogColor[i], 2.2f );
+ }
+ else
+ {
+ for( int i = 0; i != 3; ++i )
+ fogColor[i] = GammaToLinear_HardwareSpecific( m_DynamicState.m_PixelFogColor[i] ); //this is how water fog color has always been setup in the past
+ }
+
+ if( (!m_DynamicState.m_bFogGammaCorrectionDisabled) && (g_pHardwareConfig->GetHDRType() == HDR_TYPE_INTEGER) )
+ {
+ for( int i = 0; i != 3; ++i )
+ fogColor[i] *= m_ToneMappingScale.x; // Linear
+ }
+ }
+ break;
+
+ NO_DEFAULT;
+ };
+
+ fogColor[3] = 1.0f / m_DynamicState.m_DestAlphaDepthRange;
+
+ SetPixelShaderConstant( LINEAR_FOG_COLOR, fogColor );
+}
+
+
+void CShaderAPIDx8::ApplyFogMode( ShaderFogMode_t fogMode, bool bSRGBWritesEnabled, bool bDisableFogGammaCorrection )
+{
+ HDRType_t hdrType = g_pHardwareConfig->GetHDRType();
+
+ if ( fogMode == SHADER_FOGMODE_DISABLED )
+ {
+ if( hdrType != HDR_TYPE_FLOAT )
+ {
+ FogMode( MATERIAL_FOG_NONE );
+ }
+
+ if( m_DelayedShaderConstants.iPixelShaderFogParams != -1 )
+ SetPixelShaderFogParams( m_DelayedShaderConstants.iPixelShaderFogParams, fogMode );
+
+ return;
+ }
+
+ bool bShouldGammaCorrect = true; // By default, we'll gamma correct.
+ unsigned char r = 0, g = 0, b = 0; // Black fog
+
+
+ if( hdrType != HDR_TYPE_FLOAT )
+ {
+ FogMode( m_SceneFogMode );
+ }
+
+ if( m_DelayedShaderConstants.iPixelShaderFogParams != -1 )
+ SetPixelShaderFogParams( m_DelayedShaderConstants.iPixelShaderFogParams, fogMode );
+
+ switch( fogMode )
+ {
+ case SHADER_FOGMODE_BLACK: // Additive decals
+ bShouldGammaCorrect = false;
+ break;
+ case SHADER_FOGMODE_OO_OVERBRIGHT:
+ case SHADER_FOGMODE_GREY: // Mod2x decals
+ r = g = b = 128;
+ break;
+ case SHADER_FOGMODE_WHITE: // Multiplicative decals
+ r = g = b = 255;
+ bShouldGammaCorrect = false;
+ break;
+ case SHADER_FOGMODE_FOGCOLOR:
+ GetSceneFogColor( &r, &g, &b ); // Scene fog color
+ break;
+ NO_DEFAULT
+ }
+
+ bShouldGammaCorrect &= !bDisableFogGammaCorrection;
+ m_DynamicState.m_bFogGammaCorrectionDisabled = !bShouldGammaCorrect;
+
+ D3DCOLOR color;
+ if ( bShouldGammaCorrect )
+ {
+ color = ComputeGammaCorrectedFogColor( r, g, b, bSRGBWritesEnabled );
+ }
+ else
+ {
+ color = D3DCOLOR_ARGB( 255, r, g, b );
+ }
+
+
+ const float fColorScale = 1.0f / 255.0f;
+ m_DynamicState.m_PixelFogColor[0] = (float)(r) * fColorScale;
+ m_DynamicState.m_PixelFogColor[1] = (float)(g) * fColorScale;
+ m_DynamicState.m_PixelFogColor[2] = (float)(b) * fColorScale;
+
+ if( g_pMaterialSystemHardwareConfig->SupportsPixelShaders_2_b() )
+ {
+ UpdatePixelFogColorConstant();
+ }
+
+ if ( color != m_DynamicState.m_FogColor )
+ {
+ if( hdrType != HDR_TYPE_FLOAT )
+ {
+ m_DynamicState.m_FogColor = color;
+ SetRenderStateConstMacro( this, D3DRS_FOGCOLOR, m_DynamicState.m_FogColor );
+ }
+ }
+}
+
+void CShaderAPIDx8::SceneFogMode( MaterialFogMode_t fogMode )
+{
+ LOCK_SHADERAPI();
+ if( m_SceneFogMode != fogMode )
+ {
+ FlushBufferedPrimitives();
+ m_SceneFogMode = fogMode;
+
+ if ( m_TransitionTable.CurrentShadowState() )
+ {
+ // Get the shadow state in sync since it depends on SceneFogMode.
+ ApplyFogMode( m_TransitionTable.CurrentShadowState()->m_FogMode, m_TransitionTable.CurrentShadowState()->m_SRGBWriteEnable, m_TransitionTable.CurrentShadowState()->m_bDisableFogGammaCorrection );
+ }
+ }
+}
+
+MaterialFogMode_t CShaderAPIDx8::GetSceneFogMode()
+{
+ return m_SceneFogMode;
+}
+
+MaterialFogMode_t CShaderAPIDx8::GetPixelFogMode()
+{
+ if( ShouldUsePixelFogForMode( m_SceneFogMode ) )
+ return m_SceneFogMode;
+ else
+ return MATERIAL_FOG_NONE;
+}
+
+int CShaderAPIDx8::GetPixelFogCombo( void )
+{
+ if( (m_SceneFogMode != MATERIAL_FOG_NONE) && ShouldUsePixelFogForMode( m_SceneFogMode ) )
+ return m_SceneFogMode - 1; //PIXELFOGTYPE dynamic combos are shifted down one. MATERIAL_FOG_NONE is simulated by range fog with rigged parameters. Gets rid of a dynamic combo across the ps2x set
+ else
+ return MATERIAL_FOG_NONE;
+}
+
+
+static ConVar r_pixelfog( "r_pixelfog", "1" );
+
+bool CShaderAPIDx8::ShouldUsePixelFogForMode( MaterialFogMode_t fogMode )
+{
+ if( fogMode == MATERIAL_FOG_NONE )
+ return false;
+
+ if( IsX360() || IsPosix() ) // Always use pixel fog on X360 and Posix
+ return true;
+
+ if( g_pHardwareConfig->Caps().m_nDXSupportLevel < 90 ) //pixel fog not available until at least ps2.0
+ return false;
+
+ switch( m_SceneFogMode )
+ {
+ case MATERIAL_FOG_LINEAR:
+ return (g_pHardwareConfig->SupportsPixelShaders_2_b() && //lightmappedgeneric_ps20.fxc can't handle the instruction count
+ r_pixelfog.GetBool()); //use pixel fog if preferred
+
+ case MATERIAL_FOG_LINEAR_BELOW_FOG_Z:
+ return true;
+ };
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Fog methods...
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::FogMode( MaterialFogMode_t fogMode )
+{
+ bool bFogEnable;
+
+ if ( IsX360() )
+ {
+ // FF fog not applicable on 360
+ return;
+ }
+
+ m_DynamicState.m_SceneFog = fogMode;
+ switch( fogMode )
+ {
+ default:
+ Assert( 0 );
+ // fall through
+
+ case MATERIAL_FOG_NONE:
+ bFogEnable = false;
+ break;
+
+ case MATERIAL_FOG_LINEAR:
+ // use vertex fog to achieve linear range fog
+ bFogEnable = true;
+ break;
+
+ case MATERIAL_FOG_LINEAR_BELOW_FOG_Z:
+ // use pixel fog on 9.0 and greater for height fog
+ bFogEnable = g_pHardwareConfig->Caps().m_nDXSupportLevel < 90;
+ break;
+ }
+
+ if( ShouldUsePixelFogForMode( fogMode ) )
+ {
+ bFogEnable = false; //disable FF fog when doing fog in the pixel shader
+ }
+
+#if 0
+ // HACK - do this to disable fog always
+ bFogEnable = false;
+ m_DynamicState.m_SceneFog = MATERIAL_FOG_NONE;
+#endif
+
+ // These two are always set to this, so don't bother setting them.
+ // We are always using vertex fog.
+// SetRenderState( D3DRS_FOGTABLEMODE, D3DFOG_NONE );
+// SetRenderState( D3DRS_RANGEFOGENABLE, false );
+
+ // Set fog enable if it's different than before.
+ if ( bFogEnable != m_DynamicState.m_FogEnable )
+ {
+ SetSupportedRenderState( D3DRS_FOGENABLE, bFogEnable );
+ m_DynamicState.m_FogEnable = bFogEnable;
+ }
+}
+
+
+void CShaderAPIDx8::FogStart( float fStart )
+{
+ LOCK_SHADERAPI();
+ if (fStart != m_DynamicState.m_FogStart)
+ {
+ // need to flush the dynamic buffer
+ FlushBufferedPrimitives();
+
+ SetRenderStateConstMacro( this, D3DRS_FOGSTART, *((DWORD*)(&fStart)));
+ m_VertexShaderFogParams[0] = fStart;
+ UpdateVertexShaderFogParams();
+ m_DynamicState.m_FogStart = fStart;
+ }
+}
+
+void CShaderAPIDx8::FogEnd( float fEnd )
+{
+ LOCK_SHADERAPI();
+ if (fEnd != m_DynamicState.m_FogEnd)
+ {
+ // need to flush the dynamic buffer
+ FlushBufferedPrimitives();
+
+ SetRenderStateConstMacro( this, D3DRS_FOGEND, *((DWORD*)(&fEnd)));
+ m_VertexShaderFogParams[1] = fEnd;
+ UpdateVertexShaderFogParams();
+ m_DynamicState.m_FogEnd = fEnd;
+ }
+}
+
+void CShaderAPIDx8::SetFogZ( float fogZ )
+{
+ LOCK_SHADERAPI();
+ if (fogZ != m_DynamicState.m_FogZ)
+ {
+ // need to flush the dynamic buffer
+ FlushBufferedPrimitives();
+ m_DynamicState.m_FogZ = fogZ;
+ UpdateVertexShaderFogParams();
+ }
+}
+
+void CShaderAPIDx8::FogMaxDensity( float flMaxDensity )
+{
+ LOCK_SHADERAPI();
+ if (flMaxDensity != m_DynamicState.m_FogMaxDensity)
+ {
+ // need to flush the dynamic buffer
+ FlushBufferedPrimitives();
+
+// SetRenderState(D3DRS_FOGDENSITY, *((DWORD*)(&flMaxDensity))); // ??? do I need to to this ???
+ m_flFogMaxDensity = flMaxDensity;
+ UpdateVertexShaderFogParams();
+ m_DynamicState.m_FogMaxDensity = flMaxDensity;
+ }
+}
+
+void CShaderAPIDx8::GetFogDistances( float *fStart, float *fEnd, float *fFogZ )
+{
+ LOCK_SHADERAPI();
+ if( fStart )
+ *fStart = m_DynamicState.m_FogStart;
+
+ if( fEnd )
+ *fEnd = m_DynamicState.m_FogEnd;
+
+ if( fFogZ )
+ *fFogZ = m_DynamicState.m_FogZ;
+}
+
+void CShaderAPIDx8::SceneFogColor3ub( unsigned char r, unsigned char g, unsigned char b )
+{
+ LOCK_SHADERAPI();
+ if( m_SceneFogColor[0] != r || m_SceneFogColor[1] != g || m_SceneFogColor[2] != b )
+ {
+ FlushBufferedPrimitives();
+ m_SceneFogColor[0] = r;
+ m_SceneFogColor[1] = g;
+ m_SceneFogColor[2] = b;
+
+ if ( m_TransitionTable.CurrentShadowState() )
+ {
+ ApplyFogMode( m_TransitionTable.CurrentShadowState()->m_FogMode, m_TransitionTable.CurrentShadowState()->m_SRGBWriteEnable, m_TransitionTable.CurrentShadowState()->m_bDisableFogGammaCorrection );
+ }
+ }
+}
+
+void CShaderAPIDx8::GetSceneFogColor( unsigned char *rgb )
+{
+ LOCK_SHADERAPI();
+ rgb[0] = m_SceneFogColor[0];
+ rgb[1] = m_SceneFogColor[1];
+ rgb[2] = m_SceneFogColor[2];
+}
+
+void CShaderAPIDx8::GetSceneFogColor( unsigned char *r, unsigned char *g, unsigned char *b )
+{
+ *r = m_SceneFogColor[0];
+ *g = m_SceneFogColor[1];
+ *b = m_SceneFogColor[2];
+}
+
+
+//-----------------------------------------------------------------------------
+// Gamma correction of fog color, or not...
+//-----------------------------------------------------------------------------
+D3DCOLOR CShaderAPIDx8::ComputeGammaCorrectedFogColor( unsigned char r, unsigned char g, unsigned char b, bool bSRGBWritesEnabled )
+{
+#ifdef _DEBUG
+ if( g_pHardwareConfig->GetHDRType() == HDR_TYPE_FLOAT && !bSRGBWritesEnabled )
+ {
+// Assert( 0 );
+ }
+#endif
+ bool bLinearSpace = g_pHardwareConfig->Caps().m_bFogColorAlwaysLinearSpace ||
+ ( bSRGBWritesEnabled && ( g_pHardwareConfig->Caps().m_bFogColorSpecifiedInLinearSpace || g_pHardwareConfig->GetHDRType() == HDR_TYPE_FLOAT ) );
+
+ bool bScaleFogByToneMappingScale = g_pHardwareConfig->GetHDRType() == HDR_TYPE_INTEGER;
+
+ float fr = ( r / 255.0f );
+ float fg = ( g / 255.0f );
+ float fb = ( b / 255.0f );
+ if ( bLinearSpace )
+ {
+ fr = GammaToLinear( fr );
+ fg = GammaToLinear( fg );
+ fb = GammaToLinear( fb );
+ if ( bScaleFogByToneMappingScale )
+ {
+ fr *= m_ToneMappingScale.x; //
+ fg *= m_ToneMappingScale.x; // Linear
+ fb *= m_ToneMappingScale.x; //
+ }
+ }
+ else if ( bScaleFogByToneMappingScale )
+ {
+ fr *= m_ToneMappingScale.w; //
+ fg *= m_ToneMappingScale.w; // Gamma
+ fb *= m_ToneMappingScale.w; //
+ }
+
+ fr = min( fr, 1.0f );
+ fg = min( fg, 1.0f );
+ fb = min( fb, 1.0f );
+ r = (int)( fr * 255 );
+ g = (int)( fg * 255 );
+ b = (int)( fb * 255 );
+ return D3DCOLOR_ARGB( 255, r, g, b );
+}
+
+
+//-----------------------------------------------------------------------------
+// Some methods chaining vertex + pixel shaders through to the shader manager
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::SetVertexShaderIndex( int vshIndex )
+{
+ ShaderManager()->SetVertexShaderIndex( vshIndex );
+}
+
+void CShaderAPIDx8::SetPixelShaderIndex( int pshIndex )
+{
+ ShaderManager()->SetPixelShaderIndex( pshIndex );
+}
+
+void CShaderAPIDx8::SyncToken( const char *pToken )
+{
+ LOCK_SHADERAPI();
+ RECORD_COMMAND( DX8_SYNC_TOKEN, 1 );
+ RECORD_STRING( pToken );
+}
+
+
+//-----------------------------------------------------------------------------
+// Deals with vertex buffers
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::DestroyVertexBuffers( bool bExitingLevel )
+{
+ LOCK_SHADERAPI();
+ MeshMgr()->DestroyVertexBuffers( );
+ // After a map is shut down, we switch to using smaller dynamic VBs
+ // (VGUI shouldn't need much), so that we have more memory free during map loading
+ m_nDynamicVBSize = bExitingLevel ? DYNAMIC_VERTEX_BUFFER_MEMORY_SMALL : DYNAMIC_VERTEX_BUFFER_MEMORY;
+}
+
+int CShaderAPIDx8::GetCurrentDynamicVBSize( void )
+{
+ return m_nDynamicVBSize;
+}
+
+FORCEINLINE void CShaderAPIDx8::SetVertexShaderConstantInternal( int var, float const* pVec, int numVecs, bool bForce )
+{
+ Assert( pVec );
+
+ // DX8 asm shaders use a constant mapping which has transforms and vertex shader
+ // specific constants shifted down by 10 constants (two 5-constant light structures)
+ if ( IsPC() )
+ {
+ if ( (g_pHardwareConfig->Caps().m_nDXSupportLevel < 90) && (var >= VERTEX_SHADER_MODULATION_COLOR) )
+ {
+ var -= 10;
+ }
+ Assert( var + numVecs <= g_pHardwareConfig->NumVertexShaderConstants() );
+
+ if ( !bForce )
+ {
+ int skip = 0;
+ numVecs = AdjustUpdateRange( pVec, &m_DesiredState.m_pVectorVertexShaderConstant[var], numVecs, &skip );
+ if ( !numVecs )
+ return;
+ var += skip;
+ pVec += skip * 4;
+ }
+ Dx9Device()->SetVertexShaderConstantF( var, pVec, numVecs );
+ memcpy( &m_DynamicState.m_pVectorVertexShaderConstant[var], pVec, numVecs * 4 * sizeof(float) );
+ }
+ else
+ {
+ Assert( var + numVecs <= g_pHardwareConfig->NumVertexShaderConstants() );
+ }
+
+ memcpy( &m_DesiredState.m_pVectorVertexShaderConstant[var], pVec, numVecs * 4 * sizeof(float) );
+
+ if ( IsX360() )
+ {
+ m_MaxVectorVertexShaderConstant = max( m_MaxVectorVertexShaderConstant, var + numVecs );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the constant register for vertex and pixel shaders
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::SetVertexShaderConstant( int var, float const* pVec, int numVecs, bool bForce )
+{
+ SetVertexShaderConstantInternal( var, pVec, numVecs, bForce );
+}
+
+//-----------------------------------------------------------------------------
+// Sets the boolean registers for vertex shader control flow
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::SetBooleanVertexShaderConstant( int var, int const* pVec, int numBools, bool bForce )
+{
+ Assert( pVec );
+ Assert( var + numBools <= g_pHardwareConfig->NumBooleanVertexShaderConstants() );
+
+ if ( IsPC() && g_pHardwareConfig->GetDXSupportLevel() < 90 )
+ {
+ return;
+ }
+
+ if ( IsPC() && !bForce && memcmp( pVec, &m_DesiredState.m_pBooleanVertexShaderConstant[var], numBools * sizeof( BOOL ) ) == 0 )
+ {
+ return;
+ }
+
+ if ( IsPC() )
+ {
+ Dx9Device()->SetVertexShaderConstantB( var, pVec, numBools );
+ memcpy( &m_DynamicState.m_pBooleanVertexShaderConstant[var], pVec, numBools * sizeof(BOOL) );
+ }
+
+ memcpy( &m_DesiredState.m_pBooleanVertexShaderConstant[var], pVec, numBools * sizeof(BOOL) );
+
+ if ( IsX360() && var + numBools > m_MaxBooleanVertexShaderConstant )
+ {
+ m_MaxBooleanVertexShaderConstant = var + numBools;
+ Assert( m_MaxBooleanVertexShaderConstant <= 16 );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the integer registers for vertex shader control flow
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::SetIntegerVertexShaderConstant( int var, int const* pVec, int numIntVecs, bool bForce )
+{
+ Assert( pVec );
+ Assert( var + numIntVecs <= g_pHardwareConfig->NumIntegerVertexShaderConstants() );
+
+ if ( IsPC() && g_pHardwareConfig->GetDXSupportLevel() < 90 )
+ {
+ return;
+ }
+
+ if ( IsPC() && !bForce && memcmp( pVec, &m_DesiredState.m_pIntegerVertexShaderConstant[var], numIntVecs * sizeof( IntVector4D ) ) == 0 )
+ {
+ return;
+ }
+
+ if ( IsPC() )
+ {
+ Dx9Device()->SetVertexShaderConstantI( var, pVec, numIntVecs );
+ memcpy( &m_DynamicState.m_pIntegerVertexShaderConstant[var], pVec, numIntVecs * sizeof(IntVector4D) );
+ }
+ memcpy( &m_DesiredState.m_pIntegerVertexShaderConstant[var], pVec, numIntVecs * sizeof(IntVector4D) );
+
+ if ( IsX360() && var + numIntVecs > m_MaxIntegerVertexShaderConstant )
+ {
+ m_MaxIntegerVertexShaderConstant = var + numIntVecs;
+ Assert( m_MaxIntegerVertexShaderConstant <= 16 );
+ }
+}
+
+FORCEINLINE void CShaderAPIDx8::SetPixelShaderConstantInternal( int nStartConst, float const* pValues, int nNumConsts, bool bForce )
+{
+ Assert( nStartConst + nNumConsts <= g_pHardwareConfig->NumPixelShaderConstants() );
+
+ if ( IsPC() )
+ {
+ if ( ! bForce )
+ {
+ int skip = 0;
+ nNumConsts = AdjustUpdateRange( pValues, &m_DesiredState.m_pVectorPixelShaderConstant[nStartConst], nNumConsts, &skip );
+ if ( !nNumConsts )
+ return;
+ nStartConst += skip;
+ pValues += skip * 4;
+ }
+
+ Dx9Device()->SetPixelShaderConstantF( nStartConst, pValues, nNumConsts );
+ memcpy( &m_DynamicState.m_pVectorPixelShaderConstant[nStartConst], pValues, nNumConsts * 4 * sizeof(float) );
+ }
+
+ memcpy( &m_DesiredState.m_pVectorPixelShaderConstant[nStartConst], pValues, nNumConsts * 4 * sizeof(float) );
+
+ if ( IsX360() )
+ {
+ m_MaxVectorPixelShaderConstant = max( m_MaxVectorPixelShaderConstant, nStartConst + nNumConsts );
+ Assert( m_MaxVectorPixelShaderConstant <= 32 );
+ }
+}
+
+void CShaderAPIDx8::SetPixelShaderConstant( int var, float const* pVec, int numVecs, bool bForce )
+{
+ SetPixelShaderConstantInternal( var, pVec, numVecs, bForce );
+}
+
+template<class T> FORCEINLINE T GetData( uint8 const *pData )
+{
+ return * ( reinterpret_cast< T const *>( pData ) );
+}
+
+
+
+void CShaderAPIDx8::SetStandardTextureHandle( StandardTextureId_t nId, ShaderAPITextureHandle_t nHandle )
+{
+ Assert( nId < ARRAYSIZE( m_StdTextureHandles ) );
+ m_StdTextureHandles[nId] = nHandle;
+}
+
+void CShaderAPIDx8::ExecuteCommandBuffer( uint8 *pCmdBuf )
+{
+ uint8 *pReturnStack[20];
+ uint8 **pSP = &pReturnStack[ARRAYSIZE(pReturnStack)];
+ uint8 *pLastCmd;
+ for(;;)
+ {
+ uint8 *pCmd=pCmdBuf;
+ int nCmd = GetData<int>( pCmdBuf );
+ switch( nCmd )
+ {
+ case CBCMD_END:
+ {
+ if ( pSP == &pReturnStack[ARRAYSIZE(pReturnStack)] )
+ return;
+ else
+ {
+ // pop pc
+ pCmdBuf = *( pSP ++ );
+ break;
+ }
+ }
+
+ case CBCMD_JUMP:
+ pCmdBuf = GetData<uint8 *>( pCmdBuf + sizeof( int ) );
+ break;
+
+ case CBCMD_JSR:
+ {
+ Assert( pSP > &(pReturnStack[0] ) );
+// *(--pSP ) = pCmdBuf + sizeof( int ) + sizeof( uint8 *);
+// pCmdBuf = GetData<uint8 *>( pCmdBuf + sizeof( int ) );
+ ExecuteCommandBuffer( GetData<uint8 *>( pCmdBuf + sizeof( int ) ) );
+ pCmdBuf = pCmdBuf + sizeof( int ) + sizeof( uint8 *);
+ break;
+ }
+
+ case CBCMD_SET_PIXEL_SHADER_FLOAT_CONST:
+ {
+ int nStartConst = GetData<int>( pCmdBuf + sizeof( int ) );
+ int nNumConsts = GetData<int>( pCmdBuf + 2 * sizeof( int ) );
+ float const *pValues = reinterpret_cast< float const *> ( pCmdBuf + 3 * sizeof( int ) );
+ pCmdBuf += nNumConsts * 4 * sizeof( float ) + 3 * sizeof( int );
+ SetPixelShaderConstantInternal( nStartConst, pValues, nNumConsts, false );
+ break;
+ }
+
+ case CBCMD_SETPIXELSHADERFOGPARAMS:
+ {
+ int nReg = GetData<int>( pCmdBuf + sizeof( int ) );
+ pCmdBuf += 2 * sizeof( int );
+ SetPixelShaderFogParams( nReg ); // !! speed fixme
+ break;
+ }
+ case CBCMD_STORE_EYE_POS_IN_PSCONST:
+ {
+ int nReg = GetData<int>( pCmdBuf + sizeof( int ) );
+ pCmdBuf += 2 * sizeof( int );
+ SetPixelShaderConstantInternal( nReg, m_WorldSpaceCameraPositon.Base(), 1, false );
+ break;
+ }
+
+ case CBCMD_COMMITPIXELSHADERLIGHTING:
+ {
+ int nReg = GetData<int>( pCmdBuf + sizeof( int ) );
+ pCmdBuf += 2 * sizeof( int );
+ CommitPixelShaderLighting( nReg );
+ break;
+ }
+
+ case CBCMD_SETPIXELSHADERSTATEAMBIENTLIGHTCUBE:
+ {
+ int nReg = GetData<int>( pCmdBuf + sizeof( int ) );
+ pCmdBuf += 2 * sizeof( int );
+ float *pCubeBase = m_DynamicState.m_AmbientLightCube[0].Base();
+ SetPixelShaderConstantInternal( nReg, pCubeBase, 6, false );
+ break;
+ }
+
+ case CBCMD_SETAMBIENTCUBEDYNAMICSTATEVERTEXSHADER:
+ {
+ pCmdBuf +=sizeof( int );
+ SetVertexShaderStateAmbientLightCube();
+ break;
+ }
+
+ case CBCMD_SET_DEPTH_FEATHERING_CONST:
+ {
+ int nConst = GetData<int>( pCmdBuf + sizeof( int ) );
+ float fDepthBlendScale = GetData<float>( pCmdBuf + 2 * sizeof( int ) );
+ pCmdBuf += 2 * sizeof( int ) + sizeof( float );
+ SetDepthFeatheringPixelShaderConstant( nConst, fDepthBlendScale );
+ break;
+ }
+
+ case CBCMD_SET_VERTEX_SHADER_FLOAT_CONST:
+ {
+ int nStartConst = GetData<int>( pCmdBuf + sizeof( int ) );
+ int nNumConsts = GetData<int>( pCmdBuf + 2 * sizeof( int ) );
+ float const *pValues = reinterpret_cast< float const *> ( pCmdBuf + 3 * sizeof( int ) );
+ pCmdBuf += nNumConsts * 4 * sizeof( float ) + 3 * sizeof( int );
+ SetVertexShaderConstantInternal( nStartConst, pValues, nNumConsts, false );
+ break;
+ }
+
+ case CBCMD_BIND_STANDARD_TEXTURE:
+ {
+ int nSampler = GetData<int>( pCmdBuf + sizeof( int ) );
+ int nTextureID = GetData<int>( pCmdBuf + 2 * sizeof( int ) );
+ pCmdBuf += 3 * sizeof( int );
+ if ( m_StdTextureHandles[nTextureID] != INVALID_SHADERAPI_TEXTURE_HANDLE )
+ {
+ BindTexture( (Sampler_t) nSampler, m_StdTextureHandles[nTextureID] );
+ }
+ else
+ {
+ ShaderUtil()->BindStandardTexture( (Sampler_t) nSampler, (StandardTextureId_t ) nTextureID );
+ }
+ break;
+ }
+
+ case CBCMD_BIND_SHADERAPI_TEXTURE_HANDLE:
+ {
+ int nSampler = GetData<int>( pCmdBuf + sizeof( int ) );
+ ShaderAPITextureHandle_t hTexture = GetData<ShaderAPITextureHandle_t>( pCmdBuf + 2 * sizeof( int ) );
+ Assert( hTexture != INVALID_SHADERAPI_TEXTURE_HANDLE );
+ pCmdBuf += 2 * sizeof( int ) + sizeof( ShaderAPITextureHandle_t );
+ BindTexture( (Sampler_t) nSampler, hTexture );
+ break;
+ }
+
+ case CBCMD_SET_PSHINDEX:
+ {
+ int nIdx = GetData<int>( pCmdBuf + sizeof( int ) );
+ ShaderManager()->SetPixelShaderIndex( nIdx );
+ pCmdBuf += 2 * sizeof( int );
+ break;
+ }
+
+ case CBCMD_SET_VSHINDEX:
+ {
+ int nIdx = GetData<int>( pCmdBuf + sizeof( int ) );
+ ShaderManager()->SetVertexShaderIndex( nIdx );
+ pCmdBuf += 2 * sizeof( int );
+ break;
+ }
+
+
+
+#ifndef NDEBUG
+ default:
+ {
+ Assert(0);
+ }
+#endif
+
+
+ }
+ pLastCmd = pCmd;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the boolean registers for pixel shader control flow
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::SetBooleanPixelShaderConstant( int var, int const* pVec, int numBools, bool bForce )
+{
+ Assert( pVec );
+ Assert( var + numBools <= g_pHardwareConfig->NumBooleanPixelShaderConstants() );
+
+ if ( IsPC() && !bForce && memcmp( pVec, &m_DesiredState.m_pBooleanPixelShaderConstant[var], numBools * sizeof( BOOL ) ) == 0 )
+ {
+ return;
+ }
+
+ if ( IsPC() )
+ {
+ Dx9Device()->SetPixelShaderConstantB( var, pVec, numBools );
+ memcpy( &m_DynamicState.m_pBooleanPixelShaderConstant[var], pVec, numBools * sizeof(BOOL) );
+ }
+
+ memcpy( &m_DesiredState.m_pBooleanPixelShaderConstant[var], pVec, numBools * sizeof(BOOL) );
+
+ if ( IsX360() && var + numBools > m_MaxBooleanPixelShaderConstant )
+ {
+ m_MaxBooleanPixelShaderConstant = var + numBools;
+ Assert( m_MaxBooleanPixelShaderConstant <= 16 );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the integer registers for pixel shader control flow
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::SetIntegerPixelShaderConstant( int var, int const* pVec, int numIntVecs, bool bForce )
+{
+ Assert( pVec );
+ Assert( var + numIntVecs <= g_pHardwareConfig->NumIntegerPixelShaderConstants() );
+
+ if ( IsPC() && !bForce && memcmp( pVec, &m_DesiredState.m_pIntegerPixelShaderConstant[var], numIntVecs * sizeof( IntVector4D ) ) == 0 )
+ {
+ return;
+ }
+
+ if ( IsPC() )
+ {
+ Dx9Device()->SetPixelShaderConstantI( var, pVec, numIntVecs );
+ memcpy( &m_DynamicState.m_pIntegerPixelShaderConstant[var], pVec, numIntVecs * sizeof(IntVector4D) );
+ }
+
+ memcpy( &m_DesiredState.m_pIntegerPixelShaderConstant[var], pVec, numIntVecs * sizeof(IntVector4D) );
+
+ if ( IsX360() && var + numIntVecs > m_MaxIntegerPixelShaderConstant )
+ {
+ m_MaxIntegerPixelShaderConstant = var + numIntVecs;
+ Assert( m_MaxBooleanPixelShaderConstant <= 16 );
+ }
+}
+
+
+void CShaderAPIDx8::InvalidateDelayedShaderConstants( void )
+{
+ m_DelayedShaderConstants.Invalidate();
+}
+
+//-----------------------------------------------------------------------------
+//
+// Methods dealing with texture stage state
+//
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// Gets the texture associated with a texture state...
+//-----------------------------------------------------------------------------
+
+inline IDirect3DBaseTexture* CShaderAPIDx8::GetD3DTexture( ShaderAPITextureHandle_t hTexture )
+{
+ if ( hTexture == INVALID_SHADERAPI_TEXTURE_HANDLE )
+ {
+ return NULL;
+ }
+
+ AssertValidTextureHandle( hTexture );
+
+ Texture_t& tex = GetTexture( hTexture );
+ if ( tex.m_NumCopies == 1 )
+ {
+ return tex.GetTexture();
+ }
+ else
+ {
+ return tex.GetTexture( tex.m_CurrentCopy );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Inline methods
+//-----------------------------------------------------------------------------
+inline ShaderAPITextureHandle_t CShaderAPIDx8::GetModifyTextureHandle() const
+{
+ return m_ModifyTextureHandle;
+}
+
+inline IDirect3DBaseTexture* CShaderAPIDx8::GetModifyTexture()
+{
+ return CShaderAPIDx8::GetD3DTexture( m_ModifyTextureHandle );
+}
+
+void CShaderAPIDx8::SetModifyTexture( IDirect3DBaseTexture* pTex )
+{
+ if ( m_ModifyTextureHandle == INVALID_SHADERAPI_TEXTURE_HANDLE )
+ return;
+
+ Texture_t& tex = GetTexture( m_ModifyTextureHandle );
+ if ( tex.m_NumCopies == 1 )
+ {
+ tex.SetTexture( pTex );
+ }
+ else
+ {
+ tex.SetTexture( tex.m_CurrentCopy, pTex );
+ }
+}
+
+inline ShaderAPITextureHandle_t CShaderAPIDx8::GetBoundTextureBindId( Sampler_t sampler ) const
+{
+ return SamplerState( sampler ).m_BoundTexture;
+}
+
+inline bool CShaderAPIDx8::WouldBeOverTextureLimit( ShaderAPITextureHandle_t hTexture )
+{
+ if ( IsPC() )
+ {
+ if ( mat_texture_limit.GetInt() < 0 )
+ return false;
+
+ Texture_t &tex = GetTexture( hTexture );
+ if ( tex.m_LastBoundFrame == m_CurrentFrame )
+ return false;
+
+ return m_nTextureMemoryUsedLastFrame + tex.GetMemUsage() > (mat_texture_limit.GetInt() * 1024);
+ }
+ return false;
+}
+
+
+#define SETSAMPLESTATEANDMIRROR( sampler, samplerState, state_type, mirror_field, value ) \
+ if ( samplerState.mirror_field != value ) \
+ { \
+ samplerState.mirror_field = value; \
+ ::SetSamplerState( g_pD3DDevice, sampler, state_type, value ); \
+ }
+
+#define SETSAMPLESTATEANDMIRROR_FLOAT( sampler, samplerState, state_type, mirror_field, value ) \
+ if ( samplerState.mirror_field != value ) \
+ { \
+ samplerState.mirror_field = value; \
+ ::SetSamplerState( g_pD3DDevice, sampler, state_type, *(DWORD*)&value ); \
+ }
+
+
+//-----------------------------------------------------------------------------
+// Sets state on the board related to the texture state
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::SetTextureState( Sampler_t sampler, ShaderAPITextureHandle_t hTexture, bool force )
+{
+ // Get the dynamic texture info
+ SamplerState_t &samplerState = SamplerState( sampler );
+
+ // Set the texture state, but only if it changes
+ if ( ( samplerState.m_BoundTexture == hTexture ) && !force )
+ return;
+
+ // Disabling texturing
+ if ( hTexture == INVALID_SHADERAPI_TEXTURE_HANDLE || WouldBeOverTextureLimit( hTexture ) )
+ {
+ Dx9Device()->SetTexture( sampler, 0 );
+ return;
+ }
+
+ samplerState.m_BoundTexture = hTexture;
+
+ // Don't set this if we're disabled
+ if ( !samplerState.m_TextureEnable )
+ return;
+
+ RECORD_COMMAND( DX8_SET_TEXTURE, 3 );
+ RECORD_INT( stage );
+ RECORD_INT( hTexture );
+ RECORD_INT( GetTexture( hTexture).m_CurrentCopy );
+
+ IDirect3DBaseTexture *pTexture = CShaderAPIDx8::GetD3DTexture( hTexture );
+
+#if defined( _X360 )
+ DWORD linearFormatBackup = pTexture->Format.dword[0];
+ if ( samplerState.m_SRGBReadEnable )
+ {
+ // convert to srgb format for the bind. This effectively emulates the old srgb read sampler state
+ pTexture->Format.SignX =
+ pTexture->Format.SignY =
+ pTexture->Format.SignZ = 3;
+ }
+#endif
+
+ Dx9Device()->SetTexture( sampler, pTexture );
+
+#if defined( _X360 )
+ // put the format back in linear space
+ pTexture->Format.dword[0] = linearFormatBackup;
+#endif
+
+ Texture_t &tex = GetTexture( hTexture );
+ if ( tex.m_LastBoundFrame != m_CurrentFrame )
+ {
+ tex.m_LastBoundFrame = m_CurrentFrame;
+ tex.m_nTimesBoundThisFrame = 0;
+
+ if ( tex.m_pTextureGroupCounterFrame )
+ {
+ // Update the per-frame texture group counter.
+ *tex.m_pTextureGroupCounterFrame += tex.GetMemUsage();
+ }
+
+ // Track memory usage.
+ m_nTextureMemoryUsedLastFrame += tex.GetMemUsage();
+ }
+
+ if ( !m_bDebugTexturesRendering )
+ ++tex.m_nTimesBoundThisFrame;
+
+ tex.m_nTimesBoundMax = MAX( tex.m_nTimesBoundMax, tex.m_nTimesBoundThisFrame );
+
+ static MaterialSystem_Config_t &materialSystemConfig = ShaderUtil()->GetConfig();
+
+ D3DTEXTUREFILTERTYPE minFilter = tex.m_MinFilter;
+ D3DTEXTUREFILTERTYPE magFilter = tex.m_MagFilter;
+ D3DTEXTUREFILTERTYPE mipFilter = tex.m_MipFilter;
+ int finestMipmapLevel = tex.m_FinestMipmapLevel;
+ float lodBias = tex.m_LodBias;
+
+ if ( materialSystemConfig.bMipMapTextures == 0 )
+ {
+ mipFilter = D3DTEXF_NONE;
+ }
+
+ if ( materialSystemConfig.bFilterTextures == 0 && tex.m_NumLevels > 1 )
+ {
+ minFilter = D3DTEXF_NONE;
+ magFilter = D3DTEXF_NONE;
+ mipFilter = D3DTEXF_POINT;
+ }
+
+ D3DTEXTUREADDRESS uTexWrap = tex.m_UTexWrap;
+ D3DTEXTUREADDRESS vTexWrap = tex.m_VTexWrap;
+ D3DTEXTUREADDRESS wTexWrap = tex.m_WTexWrap;
+
+ // For now do this the old way on OSX since the dxabstract layer doesn't support SetSamplerStates
+ // ###OSX### punting on OSX for now
+#if DX_TO_GL_ABSTRACTION && !OSX
+ if ( ( samplerState.m_MinFilter != minFilter ) || ( samplerState.m_MagFilter != magFilter ) || ( samplerState.m_MipFilter != mipFilter ) ||
+ ( samplerState.m_UTexWrap != uTexWrap ) || ( samplerState.m_VTexWrap != vTexWrap ) || ( samplerState.m_WTexWrap != wTexWrap ) ||
+ ( samplerState.m_FinestMipmapLevel != finestMipmapLevel ) || ( samplerState.m_LodBias != lodBias ) )
+ {
+ samplerState.m_UTexWrap = uTexWrap;
+ samplerState.m_VTexWrap = vTexWrap;
+ samplerState.m_WTexWrap = wTexWrap;
+ samplerState.m_MinFilter = minFilter;
+ samplerState.m_MagFilter = magFilter;
+ samplerState.m_MipFilter = mipFilter;
+ samplerState.m_FinestMipmapLevel = finestMipmapLevel;
+ samplerState.m_LodBias = lodBias;
+ Dx9Device()->SetSamplerStates( sampler, uTexWrap, vTexWrap, wTexWrap, minFilter, magFilter, mipFilter, finestMipmapLevel, lodBias );
+ }
+#else
+ SETSAMPLESTATEANDMIRROR( sampler, samplerState, D3DSAMP_ADDRESSU, m_UTexWrap, uTexWrap );
+ SETSAMPLESTATEANDMIRROR( sampler, samplerState, D3DSAMP_ADDRESSV, m_VTexWrap, vTexWrap );
+ SETSAMPLESTATEANDMIRROR( sampler, samplerState, D3DSAMP_ADDRESSW, m_WTexWrap, wTexWrap );
+ SETSAMPLESTATEANDMIRROR( sampler, samplerState, D3DSAMP_MINFILTER, m_MinFilter, minFilter );
+ SETSAMPLESTATEANDMIRROR( sampler, samplerState, D3DSAMP_MAGFILTER, m_MagFilter, magFilter );
+ SETSAMPLESTATEANDMIRROR( sampler, samplerState, D3DSAMP_MIPFILTER, m_MipFilter, mipFilter );
+ SETSAMPLESTATEANDMIRROR( sampler, samplerState, D3DSAMP_MAXMIPLEVEL, m_FinestMipmapLevel, finestMipmapLevel );
+ SETSAMPLESTATEANDMIRROR_FLOAT( sampler, samplerState, D3DSAMP_MIPMAPLODBIAS, m_LodBias, lodBias );
+
+#endif
+}
+
+void CShaderAPIDx8::BindTexture( Sampler_t sampler, ShaderAPITextureHandle_t textureHandle )
+{
+ LOCK_SHADERAPI();
+ SetTextureState( sampler, textureHandle );
+}
+
+void CShaderAPIDx8::BindVertexTexture( VertexTextureSampler_t nStage, ShaderAPITextureHandle_t textureHandle )
+{
+ Assert( g_pMaterialSystemHardwareConfig->GetVertexTextureCount() != 0 );
+ LOCK_SHADERAPI();
+ ADD_VERTEX_TEXTURE_FUNC( COMMIT_PER_PASS, COMMIT_VERTEX_SHADER,
+ CommitVertexTextures, nStage, m_BoundTexture, textureHandle );
+}
+
+
+//-----------------------------------------------------------------------------
+// Texture allocation/deallocation
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// Computes stats info for a texture
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::ComputeStatsInfo( ShaderAPITextureHandle_t hTexture, bool isCubeMap, bool isVolumeTexture )
+{
+ Texture_t &textureData = GetTexture( hTexture );
+
+ textureData.m_SizeBytes = 0;
+ textureData.m_SizeTexels = 0;
+ textureData.m_LastBoundFrame = -1;
+ if ( IsX360() )
+ {
+ textureData.m_nTimesBoundThisFrame = 0;
+ }
+
+ IDirect3DBaseTexture* pD3DTex = CShaderAPIDx8::GetD3DTexture( hTexture );
+
+ if ( IsPC() || !IsX360() )
+ {
+ if ( isCubeMap )
+ {
+ IDirect3DCubeTexture* pTex = static_cast<IDirect3DCubeTexture*>(pD3DTex);
+ if ( !pTex )
+ {
+ Assert( 0 );
+ return;
+ }
+
+ int numLevels = pTex->GetLevelCount();
+ for (int i = 0; i < numLevels; ++i)
+ {
+ D3DSURFACE_DESC desc;
+ HRESULT hr = pTex->GetLevelDesc( i, &desc );
+ Assert( !FAILED(hr) );
+ textureData.m_SizeBytes += 6 * ImageLoader::GetMemRequired( desc.Width, desc.Height, 1, textureData.GetImageFormat(), false );
+ textureData.m_SizeTexels += 6 * desc.Width * desc.Height;
+ }
+ }
+ else if ( isVolumeTexture )
+ {
+ IDirect3DVolumeTexture9* pTex = static_cast<IDirect3DVolumeTexture9*>(pD3DTex);
+ if ( !pTex )
+ {
+ Assert( 0 );
+ return;
+ }
+ int numLevels = pTex->GetLevelCount();
+ for (int i = 0; i < numLevels; ++i)
+ {
+ D3DVOLUME_DESC desc;
+ HRESULT hr = pTex->GetLevelDesc( i, &desc );
+ Assert( !FAILED( hr ) );
+ textureData.m_SizeBytes += ImageLoader::GetMemRequired( desc.Width, desc.Height, desc.Depth, textureData.GetImageFormat(), false );
+ textureData.m_SizeTexels += desc.Width * desc.Height;
+ }
+ }
+ else
+ {
+ IDirect3DTexture* pTex = static_cast<IDirect3DTexture*>(pD3DTex);
+ if ( !pTex )
+ {
+ Assert( 0 );
+ return;
+ }
+
+ int numLevels = pTex->GetLevelCount();
+ for (int i = 0; i < numLevels; ++i)
+ {
+ D3DSURFACE_DESC desc;
+ HRESULT hr = pTex->GetLevelDesc( i, &desc );
+ Assert( !FAILED( hr ) );
+ textureData.m_SizeBytes += ImageLoader::GetMemRequired( desc.Width, desc.Height, 1, textureData.GetImageFormat(), false );
+ textureData.m_SizeTexels += desc.Width * desc.Height;
+ }
+ }
+ }
+
+#if defined( _X360 )
+ // 360 uses gpu storage size (which accounts for page alignment bloat), not format size
+ textureData.m_SizeBytes = g_TextureHeap.GetSize( pD3DTex );
+#endif
+}
+
+static D3DFORMAT ComputeFormat( IDirect3DBaseTexture* pTexture, bool isCubeMap )
+{
+ Assert( pTexture );
+ D3DSURFACE_DESC desc;
+ if (isCubeMap)
+ {
+ IDirect3DCubeTexture* pTex = static_cast<IDirect3DCubeTexture*>(pTexture);
+ HRESULT hr = pTex->GetLevelDesc( 0, &desc );
+ Assert( !FAILED(hr) );
+ }
+ else
+ {
+ IDirect3DTexture* pTex = static_cast<IDirect3DTexture*>(pTexture);
+ HRESULT hr = pTex->GetLevelDesc( 0, &desc );
+ Assert( !FAILED(hr) );
+ }
+ return desc.Format;
+}
+
+ShaderAPITextureHandle_t CShaderAPIDx8::CreateDepthTexture(
+ ImageFormat renderTargetFormat,
+ int width,
+ int height,
+ const char *pDebugName,
+ bool bTexture )
+{
+ LOCK_SHADERAPI();
+
+ ShaderAPITextureHandle_t i = CreateTextureHandle();
+ Texture_t *pTexture = &GetTexture( i );
+
+ pTexture->m_Flags = Texture_t::IS_ALLOCATED;
+ if( bTexture )
+ {
+ pTexture->m_Flags |= Texture_t::IS_DEPTH_STENCIL_TEXTURE;
+ }
+ else
+ {
+ pTexture->m_Flags |= Texture_t::IS_DEPTH_STENCIL;
+ }
+
+ pTexture->m_DebugName = pDebugName;
+ pTexture->m_Width = width;
+ pTexture->m_Height = height;
+ pTexture->m_Depth = 1; // fake
+ pTexture->m_Count = 1; // created single texture
+ pTexture->m_CountIndex = 0; // created single texture
+ pTexture->m_CreationFlags = 0; // fake
+ pTexture->m_NumCopies = 1;
+ pTexture->m_CurrentCopy = 0;
+
+ ImageFormat renderFormat = FindNearestSupportedFormat( renderTargetFormat, false, true, false );
+#if defined( _X360 )
+ D3DFORMAT nDepthFormat = ReverseDepthOnX360() ? D3DFMT_D24FS8 : D3DFMT_D24S8;
+#else
+ D3DFORMAT nDepthFormat = m_bUsingStencil ? D3DFMT_D24S8 : D3DFMT_D24X8;
+#endif
+ D3DFORMAT format = FindNearestSupportedDepthFormat( m_nAdapter, m_AdapterFormat, renderFormat, nDepthFormat );
+ D3DMULTISAMPLE_TYPE multisampleType = D3DMULTISAMPLE_NONE;
+
+ pTexture->m_NumLevels = 1;
+ pTexture->m_SizeTexels = width * height;
+ pTexture->m_SizeBytes = ImageLoader::GetMemRequired( width, height, 1, renderFormat, false );
+
+ RECORD_COMMAND( DX8_CREATE_DEPTH_TEXTURE, 5 );
+ RECORD_INT( i );
+ RECORD_INT( width );
+ RECORD_INT( height );
+ RECORD_INT( format );
+ RECORD_INT( multisampleType );
+
+ HRESULT hr;
+ if ( !bTexture )
+ {
+#if defined( _X360 )
+ int backWidth, backHeight;
+ ShaderAPI()->GetBackBufferDimensions( backWidth, backHeight );
+ D3DFORMAT backBufferFormat = ImageLoader::ImageFormatToD3DFormat( g_pShaderDevice->GetBackBufferFormat() );
+ // immediately follows back buffer in EDRAM
+ D3DSURFACE_PARAMETERS surfParameters;
+ surfParameters.Base = 2*XGSurfaceSize( backWidth, backHeight, backBufferFormat, D3DMULTISAMPLE_NONE );
+ surfParameters.ColorExpBias = 0;
+ surfParameters.HierarchicalZBase = 0;
+ hr = Dx9Device()->CreateDepthStencilSurface(
+ width, height, format, multisampleType, 0, TRUE, &pTexture->GetDepthStencilSurface(), &surfParameters );
+#else
+ hr = Dx9Device()->CreateDepthStencilSurface(
+ width, height, format, multisampleType, 0, TRUE, &pTexture->GetDepthStencilSurface(), NULL );
+#endif
+ }
+ else
+ {
+ IDirect3DTexture9 *pTex;
+ hr = Dx9Device()->CreateTexture( width, height, 1, D3DUSAGE_DEPTHSTENCIL, format, D3DPOOL_DEFAULT, &pTex, NULL );
+ pTexture->SetTexture( pTex );
+ }
+
+ if ( FAILED( hr ) )
+ {
+ switch( hr )
+ {
+ case D3DERR_INVALIDCALL:
+ Warning( "ShaderAPIDX8::CreateDepthStencilSurface: D3DERR_INVALIDCALL\n" );
+ break;
+ case D3DERR_OUTOFVIDEOMEMORY:
+ Warning( "ShaderAPIDX8::CreateDepthStencilSurface: D3DERR_OUTOFVIDEOMEMORY\n" );
+ break;
+ default:
+ break;
+ }
+ Assert( 0 );
+ }
+
+#ifdef _XBOX
+ D3DSURFACE_DESC desc;
+ hr = pTexture->GetDepthStencilSurface()->GetDesc( &desc );
+ Assert( !FAILED( hr ) );
+
+ pTexture->m_nTimesBoundThisFrame = 0;
+ pTexture->m_StaticSizeBytes = desc.Size;
+ pTexture->m_DynamicSizeBytes = 0;
+ pTexture->m_DebugName = pDebugName;
+ pTexture->m_TextureGroupName = TEXTURE_GROUP_RENDER_TARGET;
+ pTexture->SetImageFormat( IMAGE_FORMAT_UNKNOWN );
+#endif
+
+ return i;
+}
+
+
+// FIXME!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// Could keep a free-list for this instead of linearly searching. We
+// don't create textures all the time, so this is probably fine for now.
+// FIXME!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ShaderAPITextureHandle_t CShaderAPIDx8::CreateTextureHandle( void )
+{
+ ShaderAPITextureHandle_t handle;
+ CreateTextureHandles( &handle, 1 );
+ return handle;
+}
+
+void CShaderAPIDx8::CreateTextureHandles( ShaderAPITextureHandle_t *handles, int count )
+{
+ TM_ZONE_DEFAULT( TELEMETRY_LEVEL0 );
+
+ if ( count <= 0 )
+ return;
+
+ MEM_ALLOC_CREDIT();
+
+ int idxCreating = 0;
+ ShaderAPITextureHandle_t hTexture;
+
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - Search", __FUNCTION__ );
+
+ for ( hTexture = m_Textures.Head(); hTexture != m_Textures.InvalidIndex(); hTexture = m_Textures.Next( hTexture ) )
+ {
+ if ( !( m_Textures[hTexture].m_Flags & Texture_t::IS_ALLOCATED ) )
+ {
+ handles[ idxCreating ++ ] = hTexture;
+ if ( idxCreating >= count )
+ return;
+ }
+ }
+ }
+
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - Add", __FUNCTION__ );
+ while ( idxCreating < count )
+ handles[ idxCreating ++ ] = m_Textures.AddToTail();
+}
+
+//-----------------------------------------------------------------------------
+// Creates a lovely texture
+//-----------------------------------------------------------------------------
+
+ShaderAPITextureHandle_t CShaderAPIDx8::CreateTexture(
+ int width,
+ int height,
+ int depth,
+ ImageFormat dstImageFormat,
+ int numMipLevels,
+ int numCopies,
+ int creationFlags,
+ const char *pDebugName,
+ const char *pTextureGroupName )
+{
+ ShaderAPITextureHandle_t handle = 0;
+ CreateTextures( &handle, 1, width, height, depth, dstImageFormat, numMipLevels, numCopies, creationFlags, pDebugName, pTextureGroupName );
+ return handle;
+}
+
+void CShaderAPIDx8::CreateTextures(
+ ShaderAPITextureHandle_t *pHandles,
+ int count,
+ int width,
+ int height,
+ int depth,
+ ImageFormat dstImageFormat,
+ int numMipLevels,
+ int numCopies,
+ int creationFlags,
+ const char *pDebugName,
+ const char *pTextureGroupName )
+{
+ TM_ZONE_DEFAULT( TELEMETRY_LEVEL0 );
+
+ LOCK_SHADERAPI();
+
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - PostLock", __FUNCTION__ );
+
+ Assert( this == g_pShaderAPI );
+
+ if ( depth == 0 )
+ {
+ depth = 1;
+ }
+
+ bool isCubeMap = (creationFlags & TEXTURE_CREATE_CUBEMAP) != 0;
+ bool isRenderTarget = (creationFlags & TEXTURE_CREATE_RENDERTARGET) != 0;
+ bool managed = (creationFlags & TEXTURE_CREATE_MANAGED) != 0;
+ bool isDepthBuffer = (creationFlags & TEXTURE_CREATE_DEPTHBUFFER) != 0;
+ bool isDynamic = (creationFlags & TEXTURE_CREATE_DYNAMIC) != 0;
+ bool isSRGB = (creationFlags & TEXTURE_CREATE_SRGB) != 0; // for Posix/GL only... not used here ?
+
+#if defined(IS_WINDOWS_PC) && defined(SHADERAPIDX9)
+ extern bool g_ShaderDeviceUsingD3D9Ex;
+ if ( g_ShaderDeviceUsingD3D9Ex && managed )
+ {
+ // Managed textures aren't available under D3D9Ex, but we never lose
+ // texture data, so it's ok to use the default pool. Really. We can't
+ // lock default-pool textures like we normally would to upload, but we
+ // have special logic to blit full updates via D3DX helper functions
+ // in D3D9Ex mode (see texturedx8.cpp)
+ managed = false;
+ creationFlags &= ~TEXTURE_CREATE_MANAGED;
+ }
+#endif
+
+ // Can't be both managed + dynamic. Dynamic is an optimization, but
+ // if it's not managed, then we gotta do special client-specific stuff
+ // So, managed wins out!
+ if ( managed )
+ {
+ creationFlags &= ~TEXTURE_CREATE_DYNAMIC;
+ isDynamic = false;
+ }
+
+
+
+ // Create a set of texture handles
+ CreateTextureHandles( pHandles, count );
+ Texture_t **arrTxp = ( Texture_t ** ) stackalloc( count * sizeof( Texture_t * ) );
+
+ unsigned short usSetFlags = 0;
+ usSetFlags |= ( IsPosix() || ( creationFlags & (TEXTURE_CREATE_DYNAMIC | TEXTURE_CREATE_MANAGED) ) ) ? Texture_t::IS_LOCKABLE : 0;
+ usSetFlags |= ( creationFlags & TEXTURE_CREATE_VERTEXTEXTURE) ? Texture_t::IS_VERTEX_TEXTURE : 0;
+#if defined( _X360 )
+ usSetFlags |= ( creationFlags & TEXTURE_CREATE_RENDERTARGET ) ? Texture_t::IS_RENDER_TARGET : 0;
+ usSetFlags |= ( creationFlags & TEXTURE_CREATE_CANCONVERTFORMAT ) ? Texture_t::CAN_CONVERT_FORMAT : 0;
+#endif
+
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - CreateFrames", __FUNCTION__ );
+
+ for ( int idxFrame = 0; idxFrame < count; ++ idxFrame )
+ {
+ arrTxp[ idxFrame ] = &GetTexture( pHandles[ idxFrame ] );
+ Texture_t *pTexture = arrTxp[ idxFrame ];
+ pTexture->m_Flags = Texture_t::IS_ALLOCATED;
+ pTexture->m_DebugName = pDebugName;
+ pTexture->m_Width = width;
+ pTexture->m_Height = height;
+ pTexture->m_Depth = depth;
+ pTexture->m_Count = count;
+ pTexture->m_CountIndex = idxFrame;
+
+ pTexture->m_CreationFlags = creationFlags;
+ pTexture->m_Flags |= usSetFlags;
+
+ RECORD_COMMAND( DX8_CREATE_TEXTURE, 12 );
+ RECORD_INT( textureHandle );
+ RECORD_INT( width );
+ RECORD_INT( height );
+ RECORD_INT( depth ); // depth for volume textures
+ RECORD_INT( ImageLoader::ImageFormatToD3DFormat( FindNearestSupportedFormat(dstImageFormat)) );
+ RECORD_INT( numMipLevels );
+ RECORD_INT( isCubeMap );
+ RECORD_INT( numCopies <= 1 ? 1 : numCopies );
+ RECORD_INT( isRenderTarget ? 1 : 0 );
+ RECORD_INT( managed );
+ RECORD_INT( isDepthBuffer ? 1 : 0 );
+ RECORD_INT( isDynamic ? 1 : 0 );
+
+ IDirect3DBaseTexture* pD3DTex;
+
+ // Set the initial texture state
+ if ( numCopies <= 1 )
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - CreateD3DTexture", __FUNCTION__ );
+
+ pTexture->m_NumCopies = 1;
+ pD3DTex = CreateD3DTexture( width, height, depth, dstImageFormat, numMipLevels, creationFlags, (char*)pDebugName );
+ pTexture->SetTexture( pD3DTex );
+ }
+ else
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - CreateD3DTexture", __FUNCTION__ );
+
+ pTexture->m_NumCopies = numCopies;
+ {
+// X360TEMP
+// MEM_ALLOC_CREDIT();
+ pTexture->GetTextureArray() = new IDirect3DBaseTexture* [numCopies];
+ }
+ for (int k = 0; k < numCopies; ++k)
+ {
+ pD3DTex = CreateD3DTexture( width, height, depth, dstImageFormat, numMipLevels, creationFlags, (char*)pDebugName );
+ pTexture->SetTexture( k, pD3DTex );
+ }
+ }
+ pTexture->m_CurrentCopy = 0;
+
+ pD3DTex = CShaderAPIDx8::GetD3DTexture( pHandles[ idxFrame ] );
+
+#if defined( _X360 )
+ if ( pD3DTex )
+ {
+ D3DSURFACE_DESC desc;
+ HRESULT hr;
+ if ( creationFlags & TEXTURE_CREATE_CUBEMAP )
+ {
+ hr = ((IDirect3DCubeTexture *)pD3DTex)->GetLevelDesc( 0, &desc );
+ }
+ else
+ {
+ hr = ((IDirect3DTexture *)pD3DTex)->GetLevelDesc( 0, &desc );
+ }
+ Assert( !FAILED( hr ) );
+
+ // for proper info get the actual format because the input format may have been redirected
+ dstImageFormat = ImageLoader::D3DFormatToImageFormat( desc.Format );
+ Assert( dstImageFormat != IMAGE_FORMAT_UNKNOWN );
+
+ // track linear or tiled
+ if ( !XGIsTiledFormat( desc.Format ) )
+ {
+ pTexture->m_Flags |= Texture_t::IS_LINEAR;
+ }
+ }
+#endif
+
+ pTexture->SetImageFormat( dstImageFormat );
+ pTexture->m_UTexWrap = D3DTADDRESS_CLAMP;
+ pTexture->m_VTexWrap = D3DTADDRESS_CLAMP;
+ pTexture->m_WTexWrap = D3DTADDRESS_CLAMP;
+
+ if ( isRenderTarget )
+ {
+#if !defined( _X360 )
+ if ( ( dstImageFormat == IMAGE_FORMAT_NV_INTZ ) || ( dstImageFormat == IMAGE_FORMAT_NV_RAWZ ) ||
+ ( dstImageFormat == IMAGE_FORMAT_ATI_DST16 ) || ( dstImageFormat == IMAGE_FORMAT_ATI_DST24 ) )
+ {
+ pTexture->m_MinFilter = pTexture->m_MagFilter = D3DTEXF_POINT;
+ }
+ else
+#endif
+ {
+ pTexture->m_MinFilter = pTexture->m_MagFilter = D3DTEXF_LINEAR;
+ }
+
+ pTexture->m_NumLevels = 1;
+ pTexture->m_MipFilter = D3DTEXF_NONE;
+ }
+ else
+ {
+ pTexture->m_NumLevels = pD3DTex ? pD3DTex->GetLevelCount() : 1;
+ pTexture->m_MipFilter = (pTexture->m_NumLevels != 1) ? D3DTEXF_LINEAR : D3DTEXF_NONE;
+ pTexture->m_MinFilter = pTexture->m_MagFilter = D3DTEXF_LINEAR;
+ }
+ pTexture->m_SwitchNeeded = false;
+
+ ComputeStatsInfo( pHandles[idxFrame], isCubeMap, (depth > 1) );
+ SetupTextureGroup( pHandles[idxFrame], pTextureGroupName );
+ }
+}
+
+void CShaderAPIDx8::SetupTextureGroup( ShaderAPITextureHandle_t hTexture, const char *pTextureGroupName )
+{
+ Texture_t *pTexture = &GetTexture( hTexture );
+
+ Assert( !pTexture->m_pTextureGroupCounterGlobal );
+
+ // Setup the texture group stuff.
+ if ( pTextureGroupName && pTextureGroupName[0] != 0 )
+ {
+ pTexture->m_TextureGroupName = pTextureGroupName;
+ }
+ else
+ {
+ pTexture->m_TextureGroupName = TEXTURE_GROUP_UNACCOUNTED;
+ }
+
+ // 360 cannot vprof due to multicore loading until vprof is reentrant and these counters are real.
+#if defined( VPROF_ENABLED ) && !defined( _X360 )
+ char counterName[256];
+ Q_snprintf( counterName, sizeof( counterName ), "TexGroup_global_%s", pTexture->m_TextureGroupName.String() );
+ pTexture->m_pTextureGroupCounterGlobal = g_VProfCurrentProfile.FindOrCreateCounter( counterName, COUNTER_GROUP_TEXTURE_GLOBAL );
+
+ Q_snprintf( counterName, sizeof( counterName ), "TexGroup_frame_%s", pTexture->m_TextureGroupName.String() );
+ pTexture->m_pTextureGroupCounterFrame = g_VProfCurrentProfile.FindOrCreateCounter( counterName, COUNTER_GROUP_TEXTURE_PER_FRAME );
+#else
+ pTexture->m_pTextureGroupCounterGlobal = NULL;
+ pTexture->m_pTextureGroupCounterFrame = NULL;
+#endif
+
+ if ( pTexture->m_pTextureGroupCounterGlobal )
+ {
+ *pTexture->m_pTextureGroupCounterGlobal += pTexture->GetMemUsage();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Deletes a texture...
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::DeleteD3DTexture( ShaderAPITextureHandle_t hTexture )
+{
+ int numDeallocated = 0;
+ Texture_t &texture = GetTexture( hTexture );
+
+ if ( texture.m_Flags & Texture_t::IS_DEPTH_STENCIL )
+ {
+ // garymcthack - need to make sure that playback knows how to deal with these.
+ RECORD_COMMAND( DX8_DESTROY_DEPTH_TEXTURE, 1 );
+ RECORD_INT( hTexture );
+
+ if ( texture.GetDepthStencilSurface() )
+ {
+ int nRetVal = texture.GetDepthStencilSurface()->Release();
+ Assert( nRetVal == 0 );
+ texture.GetDepthStencilSurface() = 0;
+ numDeallocated = 1;
+ }
+ else
+ {
+ // FIXME: we hit this on shutdown of HLMV on some machines
+ Assert( 0 );
+ }
+ }
+ else if ( texture.m_NumCopies == 1 )
+ {
+ if ( texture.GetTexture() )
+ {
+ RECORD_COMMAND( DX8_DESTROY_TEXTURE, 1 );
+ RECORD_INT( hTexture );
+
+ DestroyD3DTexture( texture.GetTexture() );
+ texture.SetTexture( 0 );
+ numDeallocated = 1;
+ }
+ }
+ else
+ {
+ if ( texture.GetTextureArray() )
+ {
+ RECORD_COMMAND( DX8_DESTROY_TEXTURE, 1 );
+ RECORD_INT( hTexture );
+
+ // Multiple copy texture
+ for (int j = 0; j < texture.m_NumCopies; ++j)
+ {
+ if (texture.GetTexture( j ))
+ {
+ DestroyD3DTexture( texture.GetTexture( j ) );
+ texture.SetTexture( j, 0 );
+ ++numDeallocated;
+ }
+ }
+
+ delete [] texture.GetTextureArray();
+ texture.GetTextureArray() = 0;
+ }
+ }
+
+ texture.m_NumCopies = 0;
+
+ // Remove this texture from its global texture group counter.
+ if ( texture.m_pTextureGroupCounterGlobal )
+ {
+ *texture.m_pTextureGroupCounterGlobal -= texture.GetMemUsage();
+ Assert( *texture.m_pTextureGroupCounterGlobal >= 0 );
+ texture.m_pTextureGroupCounterGlobal = NULL;
+ }
+
+ // remove this texture from std textures
+ for( int i=0 ; i < ARRAYSIZE( m_StdTextureHandles ) ; i++ )
+ {
+ if ( m_StdTextureHandles[i] == hTexture )
+ m_StdTextureHandles[i] = INVALID_SHADERAPI_TEXTURE_HANDLE;
+ }
+
+}
+
+
+//-----------------------------------------------------------------------------
+// Unbinds a texture from all texture stages
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::UnbindTexture( ShaderAPITextureHandle_t hTexture )
+{
+ // Make sure no texture units are currently bound to it...
+ for ( int unit = 0; unit < g_pHardwareConfig->GetSamplerCount(); ++unit )
+ {
+ if ( hTexture == SamplerState( unit ).m_BoundTexture )
+ {
+ // Gotta set this here because INVALID_SHADERAPI_TEXTURE_HANDLE means don't actually
+ // set bound texture (it's used for disabling texturemapping)
+ SamplerState( unit ).m_BoundTexture = INVALID_SHADERAPI_TEXTURE_HANDLE;
+ SetTextureState( (Sampler_t)unit, INVALID_SHADERAPI_TEXTURE_HANDLE );
+ }
+ }
+
+ int nVertexTextureCount = g_pHardwareConfig->GetVertexTextureCount();
+ for ( int nSampler = 0; nSampler < nVertexTextureCount; ++nSampler )
+ {
+ if ( hTexture == m_DynamicState.m_VertexTextureState[ nSampler ].m_BoundTexture )
+ {
+ // Gotta set this here because INVALID_SHADERAPI_TEXTURE_HANDLE means don't actually
+ // set bound texture (it's used for disabling texturemapping)
+ BindVertexTexture( (VertexTextureSampler_t)nSampler, INVALID_SHADERAPI_TEXTURE_HANDLE );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Deletes a texture...
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::DeleteTexture( ShaderAPITextureHandle_t textureHandle )
+{
+ LOCK_SHADERAPI();
+ AssertValidTextureHandle( textureHandle );
+
+ if ( !TextureIsAllocated( textureHandle ) )
+ {
+ // already deallocated
+ return;
+ }
+
+ // Unbind it!
+ UnbindTexture( textureHandle );
+
+ // Delete it baby
+ DeleteD3DTexture( textureHandle );
+
+ // Now remove the texture from the list
+ // Mark as deallocated so that it can be reused.
+ GetTexture( textureHandle ).m_Flags = 0;
+}
+
+
+void CShaderAPIDx8::WriteTextureToFile( ShaderAPITextureHandle_t hTexture, const char *szFileName )
+{
+ Texture_t *pTexInt = &GetTexture( hTexture );
+ //Assert( pTexInt->IsCubeMap() == false );
+ //Assert( pTexInt->IsVolumeTexture() == false );
+ IDirect3DTexture *pD3DTexture = (IDirect3DTexture *)pTexInt->GetTexture();
+
+ // Get the level of the texture we want to read from
+ IDirect3DSurface* pTextureLevel;
+ HRESULT hr = pD3DTexture ->GetSurfaceLevel( 0, &pTextureLevel );
+ if ( FAILED( hr ) )
+ return;
+
+ D3DSURFACE_DESC surfaceDesc;
+ pD3DTexture->GetLevelDesc( 0, &surfaceDesc );
+
+ D3DLOCKED_RECT lockedRect;
+
+
+ //if( pTexInt->m_Flags & Texture_t::IS_RENDER_TARGET )
+#if !defined( _X360 ) //TODO: x360 version
+ {
+ //render targets can't be locked, luckily we can copy the surface to system memory and lock that.
+ IDirect3DSurface *pSystemSurface;
+
+ Assert( !IsX360() );
+
+ hr = Dx9Device()->CreateOffscreenPlainSurface( surfaceDesc.Width, surfaceDesc.Height, surfaceDesc.Format, D3DPOOL_SYSTEMMEM, &pSystemSurface, NULL );
+ Assert( SUCCEEDED( hr ) );
+
+ pSystemSurface->GetDesc( &surfaceDesc );
+
+ hr = Dx9Device()->GetRenderTargetData( pTextureLevel, pSystemSurface );
+ Assert( SUCCEEDED( hr ) );
+
+ //pretend this is the texture level we originally grabbed with GetSurfaceLevel() and continue on
+ pTextureLevel->Release();
+ pTextureLevel = pSystemSurface;
+ }
+#endif
+
+ // lock the region
+ if ( FAILED( pTextureLevel->LockRect( &lockedRect, NULL, D3DLOCK_READONLY ) ) )
+ {
+ Assert( 0 );
+ pTextureLevel->Release();
+ return;
+ }
+
+ TGAWriter::WriteTGAFile( szFileName, surfaceDesc.Width, surfaceDesc.Height, pTexInt->GetImageFormat(), (const uint8 *)lockedRect.pBits, lockedRect.Pitch );
+
+ if ( FAILED( pTextureLevel->UnlockRect() ) )
+ {
+ Assert( 0 );
+ pTextureLevel->Release();
+ return;
+ }
+
+ pTextureLevel->Release();
+}
+
+
+//-----------------------------------------------------------------------------
+// Releases all textures
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::ReleaseAllTextures()
+{
+ ClearStdTextureHandles();
+ ShaderAPITextureHandle_t hTexture;
+ for ( hTexture = m_Textures.Head(); hTexture != m_Textures.InvalidIndex(); hTexture = m_Textures.Next( hTexture ) )
+ {
+ if ( TextureIsAllocated( hTexture ) )
+ {
+ // Delete it baby
+ DeleteD3DTexture( hTexture );
+ }
+ }
+
+ // Make sure all texture units are pointing to nothing
+ for (int unit = 0; unit < g_pHardwareConfig->GetSamplerCount(); ++unit )
+ {
+ SamplerState( unit ).m_BoundTexture = INVALID_SHADERAPI_TEXTURE_HANDLE;
+ SetTextureState( (Sampler_t)unit, INVALID_SHADERAPI_TEXTURE_HANDLE );
+ }
+}
+
+void CShaderAPIDx8::DeleteAllTextures()
+{
+ ReleaseAllTextures();
+ m_Textures.Purge();
+}
+
+bool CShaderAPIDx8::IsTexture( ShaderAPITextureHandle_t textureHandle )
+{
+ LOCK_SHADERAPI();
+
+ if ( !TextureIsAllocated( textureHandle ) )
+ {
+ return false;
+ }
+
+#if !defined( _X360 )
+ if ( GetTexture( textureHandle ).m_Flags & Texture_t::IS_DEPTH_STENCIL )
+ {
+ return GetTexture( textureHandle ).GetDepthStencilSurface() != 0;
+ }
+ else if ( ( GetTexture( textureHandle ).m_NumCopies == 1 && GetTexture( textureHandle ).GetTexture() != 0 ) ||
+ ( GetTexture( textureHandle ).m_NumCopies > 1 && GetTexture( textureHandle ).GetTexture( 0 ) != 0 ) )
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+#else
+ // query is about texture handle validity, not presence
+ // texture handle is allocated, texture may or may not be present
+ return true;
+#endif
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Gets the surface associated with a texture (refcount of surface is increased)
+//-----------------------------------------------------------------------------
+IDirect3DSurface* CShaderAPIDx8::GetTextureSurface( ShaderAPITextureHandle_t textureHandle )
+{
+ MEM_ALLOC_D3D_CREDIT();
+
+ IDirect3DSurface* pSurface;
+
+ // We'll be modifying this sucka
+ AssertValidTextureHandle( textureHandle );
+ Texture_t &tex = GetTexture( textureHandle );
+ if ( !( tex.m_Flags & Texture_t::IS_ALLOCATED ) )
+ {
+ return NULL;
+ }
+
+ if ( IsX360() && ( tex.m_Flags & Texture_t::IS_RENDER_TARGET_SURFACE ) )
+ {
+ pSurface = tex.GetRenderTargetSurface( false );
+
+#if POSIX
+ // dxabstract's AddRef/Release have optional args to help track usage
+ pSurface->AddRef( 0, "CShaderAPIDx8::GetTextureSurface public addref");
+#else
+ pSurface->AddRef();
+#endif
+
+ return pSurface;
+ }
+
+ IDirect3DBaseTexture* pD3DTex = CShaderAPIDx8::GetD3DTexture( textureHandle );
+ IDirect3DTexture* pTex = static_cast<IDirect3DTexture*>( pD3DTex );
+ Assert( pTex );
+ if ( !pTex )
+ {
+ return NULL;
+ }
+
+ HRESULT hr = pTex->GetSurfaceLevel( 0, &pSurface );
+ Assert( hr == D3D_OK );
+
+ return pSurface;
+}
+
+//-----------------------------------------------------------------------------
+// Gets the surface associated with a texture (refcount of surface is increased)
+//-----------------------------------------------------------------------------
+IDirect3DSurface* CShaderAPIDx8::GetDepthTextureSurface( ShaderAPITextureHandle_t textureHandle )
+{
+ AssertValidTextureHandle( textureHandle );
+ if ( !TextureIsAllocated( textureHandle ) )
+ {
+ return NULL;
+ }
+ return GetTexture( textureHandle ).GetDepthStencilSurface();
+}
+
+//-----------------------------------------------------------------------------
+// Changes the render target
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::SetRenderTargetEx( int nRenderTargetID, ShaderAPITextureHandle_t colorTextureHandle, ShaderAPITextureHandle_t depthTextureHandle )
+{
+ LOCK_SHADERAPI();
+ if ( IsDeactivated( ) )
+ {
+ return;
+ }
+
+ // GR - need to flush batched geometry
+ FlushBufferedPrimitives();
+
+#if defined( PIX_INSTRUMENTATION )
+ {
+ const char *pRT = "Backbuffer";
+ const char *pDS = "DefaultDepthStencil";
+
+ if ( colorTextureHandle == SHADER_RENDERTARGET_NONE )
+ {
+ pRT = "None";
+ }
+ else if ( colorTextureHandle != SHADER_RENDERTARGET_BACKBUFFER )
+ {
+ Texture_t &tex = GetTexture( colorTextureHandle );
+ pRT = tex.m_DebugName.String();
+ }
+
+ if ( depthTextureHandle == SHADER_RENDERTARGET_NONE )
+ {
+ pDS = "None";
+ }
+ else if ( depthTextureHandle != SHADER_RENDERTARGET_DEPTHBUFFER )
+ {
+ Texture_t &tex = GetTexture( depthTextureHandle );
+ pDS = tex.m_DebugName.String();
+ }
+
+ char buf[256];
+ sprintf( buf, "SRT:%s %s", pRT ? pRT : "?", pDS ? pDS : "?" );
+ BeginPIXEvent( 0xFFFFFFFF, buf );
+ EndPIXEvent();
+ }
+#endif
+
+#if !defined( _X360 )
+ RECORD_COMMAND( DX8_TEST_COOPERATIVE_LEVEL, 0 );
+ HRESULT hr = Dx9Device()->TestCooperativeLevel();
+ if ( hr != D3D_OK )
+ {
+ MarkDeviceLost();
+ return;
+ }
+#endif
+
+ IDirect3DSurface* pColorSurface = NULL;
+ IDirect3DSurface* pZSurface = NULL;
+
+ RECORD_COMMAND( DX8_SET_RENDER_TARGET, 3 );
+ RECORD_INT( nRenderTargetID );
+ RECORD_INT( colorTextureHandle );
+ RECORD_INT( depthTextureHandle );
+
+ // The 0th render target defines which depth buffer we are using, so
+ // don't bother if we are another render target
+ if ( nRenderTargetID > 0 )
+ {
+ depthTextureHandle = SHADER_RENDERTARGET_NONE;
+ }
+
+ // NOTE!!!! If this code changes, also change Dx8SetRenderTarget in playback.cpp
+ bool usingTextureTarget = false;
+ if ( colorTextureHandle == SHADER_RENDERTARGET_BACKBUFFER )
+ {
+ pColorSurface = m_pBackBufferSurface;
+
+#ifdef ENABLE_NULLREF_DEVICE_SUPPORT
+ if( pColorSurface )
+#endif
+ {
+ // This is just to make the code a little simpler...
+ // (simplifies the release logic)
+#if POSIX
+ // dxabstract's AddRef/Release have optional args to help track usage
+ pColorSurface->AddRef( 0, "+C CShaderAPIDx8::SetRenderTargetEx public addref 1");
+#else
+ pColorSurface->AddRef();
+#endif
+ }
+ }
+ else
+ {
+ // get the texture (Refcount increases)
+ UnbindTexture( colorTextureHandle );
+ pColorSurface = GetTextureSurface( colorTextureHandle );
+ if ( !pColorSurface )
+ {
+ return;
+ }
+
+ usingTextureTarget = true;
+ }
+
+ if ( depthTextureHandle == SHADER_RENDERTARGET_DEPTHBUFFER )
+ {
+ // using the default depth buffer
+ pZSurface = m_pZBufferSurface;
+
+#ifdef ENABLE_NULLREF_DEVICE_SUPPORT
+ if( pZSurface )
+#endif
+ {
+ // simplify the prologue logic
+#if POSIX
+ // dxabstract's AddRef/Release have optional args to help track usage
+ pZSurface->AddRef( 0, "+D CShaderAPIDx8::SetRenderTargetEx public addref 1");
+#else
+ pZSurface->AddRef();
+#endif
+ }
+ }
+ else if ( depthTextureHandle == SHADER_RENDERTARGET_NONE )
+ {
+ // GR - disable depth buffer
+ pZSurface = NULL;
+ }
+ else
+ {
+ UnbindTexture( depthTextureHandle );
+
+ Texture_t &tex = GetTexture( depthTextureHandle );
+
+ //Cannot use a depth/stencil surface derived from a texture.
+ //Asserting helps get the whole call stack instead of letting the 360 report an error with a partial stack
+ Assert( !( IsX360() && (tex.m_Flags & Texture_t::IS_DEPTH_STENCIL_TEXTURE) ) );
+
+ if ( tex.m_Flags & Texture_t::IS_DEPTH_STENCIL )
+ {
+ pZSurface = GetDepthTextureSurface( depthTextureHandle );
+ if ( pZSurface )
+ {
+#if POSIX
+ // dxabstract's AddRef/Release have optional args to help track usage
+ pZSurface->AddRef( 0, "+D CShaderAPIDx8::SetRenderTargetEx public addref 2");
+#else
+ pZSurface->AddRef();
+#endif
+ }
+ }
+ else
+ {
+ HRESULT hr = ((IDirect3DTexture9*)tex.GetTexture())->GetSurfaceLevel( 0, &pZSurface );
+ }
+
+ if ( !pZSurface )
+ {
+ // Refcount of color surface was increased above
+#if POSIX
+ // dxabstract's AddRef/Release have optional args to help track usage
+ pColorSurface->Release( 0, "-C CShaderAPIDx8::SetRenderTargetEx public release 1" );
+#else
+ pColorSurface->Release();
+#endif
+ return;
+ }
+ usingTextureTarget = true;
+ }
+
+#ifdef _DEBUG
+ if ( pZSurface )
+ {
+ D3DSURFACE_DESC zSurfaceDesc, colorSurfaceDesc;
+ pZSurface->GetDesc( &zSurfaceDesc );
+ pColorSurface->GetDesc( &colorSurfaceDesc );
+
+ if ( !HushAsserts() )
+ {
+ Assert( colorSurfaceDesc.Width <= zSurfaceDesc.Width );
+ Assert( colorSurfaceDesc.Height <= zSurfaceDesc.Height );
+ }
+ }
+#endif
+
+ // we only set this flag for the 0th render target so that NULL
+ // render targets 1-3 don't mess with the viewport on the main RT
+ if( nRenderTargetID == 0 )
+ m_UsingTextureRenderTarget = usingTextureTarget;
+
+ // NOTE: The documentation says that SetRenderTarget increases the refcount
+ // but it doesn't appear to in practice. If this somehow changes (perhaps
+ // in a device-specific manner, we're in trouble).
+ if ( IsPC() || !IsX360() )
+ {
+ if ( pColorSurface == m_pBackBufferSurface && nRenderTargetID > 0 )
+ {
+ // SetRenderTargetEx is overloaded so that if you pass NULL in for anything that
+ // isn't the zeroth render target, you effectively disable that MRT index.
+ // (Passing in NULL for the zeroth render target means that you want to use the backbuffer
+ // as the render target.)
+ // hack hack hack!!!!! If the render target id > 0 and the user passed in NULL, disable the render target
+ Dx9Device()->SetRenderTarget( nRenderTargetID, NULL );
+ }
+ else
+ {
+ Dx9Device()->SetRenderTarget( nRenderTargetID, pColorSurface );
+ }
+ }
+ else
+ {
+ Assert( nRenderTargetID == 0 );
+ SetRenderTargetInternalXbox( colorTextureHandle );
+ }
+
+ // The 0th render target defines which depth buffer we are using, so
+ // don't bother if we are another render target
+ if ( nRenderTargetID == 0 )
+ {
+ Dx9Device()->SetDepthStencilSurface( pZSurface );
+ }
+
+ // The 0th render target defines the viewport, therefore it also defines
+ // the viewport limits.
+ if ( m_UsingTextureRenderTarget && nRenderTargetID == 0 )
+ {
+ D3DSURFACE_DESC desc;
+ HRESULT hr;
+ if ( !pZSurface )
+ {
+ hr = pColorSurface->GetDesc( &desc );
+ }
+ else
+ {
+ hr = pZSurface->GetDesc( &desc );
+ }
+ Assert( !FAILED(hr) );
+ m_ViewportMaxWidth = desc.Width;
+ m_ViewportMaxHeight = desc.Height;
+ }
+
+ static bool assert_on_refzero = false;
+ int ref;
+ if ( pZSurface )
+ {
+#if POSIX
+ ref = pZSurface->Release( 0, "-D CShaderAPIDx8::SetRenderTargetEx public release (z surface)");
+#else
+ ref = pZSurface->Release();
+#endif
+
+ if(assert_on_refzero)
+ {
+ Assert( ref != 0 );
+ }
+ }
+
+#ifdef ENABLE_NULLREF_DEVICE_SUPPORT
+ if( pColorSurface )
+#endif
+ {
+#if POSIX
+ ref = pColorSurface->Release( 0, "-C CShaderAPIDx8::SetRenderTargetEx public release (color surface)");
+#else
+ ref = pColorSurface->Release();
+#endif
+ if(assert_on_refzero)
+ {
+ Assert( ref != 0 );
+ }
+ }
+
+ // Changing the render target sets a default viewport. Force rewrite to preserve the current desired state.
+ m_DynamicState.m_Viewport.X = 0;
+ m_DynamicState.m_Viewport.Y = 0;
+ m_DynamicState.m_Viewport.Width = (DWORD)-1;
+ m_DynamicState.m_Viewport.Height = (DWORD)-1;
+
+ ADD_COMMIT_FUNC( COMMIT_PER_DRAW, COMMIT_ALWAYS, CommitSetViewports );
+}
+
+
+//-----------------------------------------------------------------------------
+// Changes the render target
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::SetRenderTarget( ShaderAPITextureHandle_t colorTextureHandle, ShaderAPITextureHandle_t depthTextureHandle )
+{
+ LOCK_SHADERAPI();
+ SetRenderTargetEx( 0, colorTextureHandle, depthTextureHandle );
+}
+
+//-----------------------------------------------------------------------------
+// Returns the nearest supported format
+//-----------------------------------------------------------------------------
+ImageFormat CShaderAPIDx8::GetNearestSupportedFormat( ImageFormat fmt, bool bFilteringRequired /* = true */ ) const
+{
+ return FindNearestSupportedFormat( fmt, false, false, bFilteringRequired );
+}
+
+
+ImageFormat CShaderAPIDx8::GetNearestRenderTargetFormat( ImageFormat fmt ) const
+{
+ return FindNearestSupportedFormat( fmt, false, true, false );
+}
+
+
+bool CShaderAPIDx8::DoRenderTargetsNeedSeparateDepthBuffer() const
+{
+ LOCK_SHADERAPI();
+ return m_PresentParameters.MultiSampleType != D3DMULTISAMPLE_NONE;
+}
+
+
+//-----------------------------------------------------------------------------
+// Indicates we're modifying a texture
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::ModifyTexture( ShaderAPITextureHandle_t textureHandle )
+{
+ tmZone( TELEMETRY_LEVEL2, TMZF_NONE, "%s", __FUNCTION__ );
+
+ LOCK_SHADERAPI();
+ // Can't do this if we're locked!
+ Assert( m_ModifyTextureLockedLevel < 0 );
+
+ AssertValidTextureHandle( textureHandle );
+ m_ModifyTextureHandle = textureHandle;
+
+ // If we're got a multi-copy texture, we need to up the current copy count
+ Texture_t& tex = GetTexture( textureHandle );
+ if (tex.m_NumCopies > 1)
+ {
+ // Each time we modify a texture, we'll want to switch texture
+ // as soon as a TexImage2D call is made...
+ tex.m_SwitchNeeded = true;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Advances the current copy of a texture...
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::AdvanceCurrentCopy( ShaderAPITextureHandle_t hTexture )
+{
+ // May need to switch textures....
+ Texture_t& tex = GetTexture( hTexture );
+ if (tex.m_NumCopies > 1)
+ {
+ if (++tex.m_CurrentCopy >= tex.m_NumCopies)
+ tex.m_CurrentCopy = 0;
+
+ // When the current copy changes, we need to make sure this texture
+ // isn't bound to any stages any more; thereby guaranteeing the new
+ // copy will be re-bound.
+ UnbindTexture( hTexture );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Locks, unlocks the current texture
+//-----------------------------------------------------------------------------
+
+bool CShaderAPIDx8::TexLock( int level, int cubeFaceID, int xOffset, int yOffset,
+ int width, int height, CPixelWriter& writer )
+{
+ tmZone( TELEMETRY_LEVEL2, TMZF_NONE, "%s", __FUNCTION__ );
+
+ LOCK_SHADERAPI();
+
+ Assert( m_ModifyTextureLockedLevel < 0 );
+
+ ShaderAPITextureHandle_t hTexture = GetModifyTextureHandle();
+ if ( !m_Textures.IsValidIndex( hTexture ) )
+ return false;
+
+ // Blow off mip levels if we don't support mipmapping
+ if ( !g_pHardwareConfig->SupportsMipmapping() && ( level > 0 ) )
+ return false;
+
+ // This test here just makes sure we don't try to download mipmap levels
+ // if we weren't able to create them in the first place
+ Texture_t& tex = GetTexture( hTexture );
+ if ( level >= tex.m_NumLevels )
+ {
+ return false;
+ }
+
+ // May need to switch textures....
+ if ( tex.m_SwitchNeeded )
+ {
+ AdvanceCurrentCopy( hTexture );
+ tex.m_SwitchNeeded = false;
+ }
+
+ IDirect3DBaseTexture *pTexture = GetModifyTexture();
+#if defined( _X360 )
+ // 360 can't lock a bound texture
+ if ( pTexture->IsSet( Dx9Device() ) )
+ {
+ UnbindTexture( hTexture );
+ }
+#endif
+
+ bool bOK = LockTexture( hTexture, tex.m_CurrentCopy, pTexture,
+ level, (D3DCUBEMAP_FACES)cubeFaceID, xOffset, yOffset, width, height, false, writer );
+ if ( bOK )
+ {
+ m_ModifyTextureLockedLevel = level;
+ m_ModifyTextureLockedFace = cubeFaceID;
+ }
+ return bOK;
+}
+
+void CShaderAPIDx8::TexUnlock( )
+{
+ tmZone( TELEMETRY_LEVEL2, TMZF_NONE, "%s", __FUNCTION__ );
+
+ LOCK_SHADERAPI();
+ if ( m_ModifyTextureLockedLevel >= 0 )
+ {
+ Texture_t& tex = GetTexture( GetModifyTextureHandle() );
+ UnlockTexture( GetModifyTextureHandle(), tex.m_CurrentCopy, GetModifyTexture(),
+ m_ModifyTextureLockedLevel, (D3DCUBEMAP_FACES)m_ModifyTextureLockedFace );
+
+ m_ModifyTextureLockedLevel = -1;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Texture image upload
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::TexImage2D(
+ int level,
+ int cubeFaceID,
+ ImageFormat dstFormat,
+ int z,
+ int width,
+ int height,
+ ImageFormat srcFormat,
+ bool bSrcIsTiled,
+ void *pSrcData )
+{
+ LOCK_SHADERAPI();
+
+ Assert( pSrcData );
+ AssertValidTextureHandle( GetModifyTextureHandle() );
+
+ if ( !m_Textures.IsValidIndex( GetModifyTextureHandle() ) )
+ {
+ return;
+ }
+
+ Assert( (width <= g_pHardwareConfig->Caps().m_MaxTextureWidth) && (height <= g_pHardwareConfig->Caps().m_MaxTextureHeight) );
+
+ // Blow off mip levels if we don't support mipmapping
+ if ( !g_pHardwareConfig->SupportsMipmapping() && (level > 0))
+ {
+ return;
+ }
+
+ // This test here just makes sure we don't try to download mipmap levels
+ // if we weren't able to create them in the first place
+ Texture_t& tex = GetTexture( GetModifyTextureHandle() );
+ if ( level >= tex.m_NumLevels )
+ {
+ return;
+ }
+
+ // May need to switch textures....
+ if (tex.m_SwitchNeeded)
+ {
+ AdvanceCurrentCopy( GetModifyTextureHandle() );
+ tex.m_SwitchNeeded = false;
+ }
+
+ TextureLoadInfo_t info;
+ info.m_TextureHandle = GetModifyTextureHandle();
+ info.m_pTexture = GetModifyTexture();
+ info.m_nLevel = level;
+ info.m_nCopy = tex.m_CurrentCopy;
+ info.m_CubeFaceID = (D3DCUBEMAP_FACES)cubeFaceID;
+ info.m_nWidth = width;
+ info.m_nHeight = height;
+ info.m_nZOffset = z;
+ info.m_SrcFormat = srcFormat;
+ info.m_pSrcData = (unsigned char *)pSrcData;
+#if defined( _X360 )
+ info.m_bSrcIsTiled = bSrcIsTiled;
+ info.m_bCanConvertFormat = ( tex.m_Flags & Texture_t::CAN_CONVERT_FORMAT ) != 0;
+#else
+ info.m_bTextureIsLockable = ( tex.m_Flags & Texture_t::IS_LOCKABLE ) != 0;
+#endif
+ LoadTexture( info );
+ SetModifyTexture( info.m_pTexture );
+}
+
+//-----------------------------------------------------------------------------
+// Upload to a sub-piece of a texture
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::TexSubImage2D(
+ int level,
+ int cubeFaceID,
+ int xOffset,
+ int yOffset,
+ int zOffset,
+ int width,
+ int height,
+ ImageFormat srcFormat,
+ int srcStride,
+ bool bSrcIsTiled,
+ void *pSrcData )
+{
+ LOCK_SHADERAPI();
+
+ Assert( pSrcData );
+ AssertValidTextureHandle( GetModifyTextureHandle() );
+
+ if ( !m_Textures.IsValidIndex( GetModifyTextureHandle() ) )
+ {
+ return;
+ }
+
+ // Blow off mip levels if we don't support mipmapping
+ if ( !g_pHardwareConfig->SupportsMipmapping() && ( level > 0 ) )
+ {
+ return;
+ }
+
+ // NOTE: This can only be done with procedural textures if this method is
+ // being used to download the entire texture, cause last frame's partial update
+ // may be in a completely different texture! Sadly, I don't have all of the
+ // information I need, but I can at least check a couple things....
+#ifdef _DEBUG
+ if ( GetTexture( GetModifyTextureHandle() ).m_NumCopies > 1 )
+ {
+ Assert( (xOffset == 0) && (yOffset == 0) );
+ }
+#endif
+
+ // This test here just makes sure we don't try to download mipmap levels
+ // if we weren't able to create them in the first place
+ Texture_t& tex = GetTexture( GetModifyTextureHandle() );
+ if ( level >= tex.m_NumLevels )
+ {
+ return;
+ }
+
+ // May need to switch textures....
+ if ( tex.m_SwitchNeeded )
+ {
+ AdvanceCurrentCopy( GetModifyTextureHandle() );
+ tex.m_SwitchNeeded = false;
+ }
+
+ TextureLoadInfo_t info;
+ info.m_TextureHandle = GetModifyTextureHandle();
+ info.m_pTexture = GetModifyTexture();
+ info.m_nLevel = level;
+ info.m_nCopy = tex.m_CurrentCopy;
+ info.m_CubeFaceID = (D3DCUBEMAP_FACES)cubeFaceID;
+ info.m_nWidth = width;
+ info.m_nHeight = height;
+ info.m_nZOffset = zOffset;
+ info.m_SrcFormat = srcFormat;
+ info.m_pSrcData = (unsigned char *)pSrcData;
+#if defined( _X360 )
+ info.m_bSrcIsTiled = bSrcIsTiled;
+ info.m_bCanConvertFormat = ( tex.m_Flags & Texture_t::CAN_CONVERT_FORMAT ) != 0;
+#else
+ info.m_bTextureIsLockable = ( tex.m_Flags & Texture_t::IS_LOCKABLE ) != 0;
+#endif
+ LoadSubTexture( info, xOffset, yOffset, srcStride );
+}
+
+//-----------------------------------------------------------------------------
+// Volume texture upload
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::TexImageFromVTF( IVTFTexture *pVTF, int iVTFFrame )
+{
+ LOCK_SHADERAPI();
+ Assert( pVTF );
+ AssertValidTextureHandle( GetModifyTextureHandle() );
+ if ( !m_Textures.IsValidIndex( GetModifyTextureHandle() ) )
+ {
+ return;
+ }
+ Texture_t& tex = GetTexture( GetModifyTextureHandle() );
+
+ // May need to switch textures....
+ if (tex.m_SwitchNeeded)
+ {
+ AdvanceCurrentCopy( GetModifyTextureHandle() );
+ tex.m_SwitchNeeded = false;
+ }
+
+ TextureLoadInfo_t info;
+ info.m_TextureHandle = GetModifyTextureHandle();
+ info.m_pTexture = GetModifyTexture();
+ info.m_nLevel = 0;
+ info.m_nCopy = tex.m_CurrentCopy;
+ info.m_CubeFaceID = (D3DCUBEMAP_FACES)0;
+ info.m_nWidth = 0;
+ info.m_nHeight = 0;
+ info.m_nZOffset = 0;
+ info.m_SrcFormat = pVTF->Format();
+ info.m_pSrcData = NULL;
+#if defined( _X360 )
+ info.m_bSrcIsTiled = pVTF->IsPreTiled();
+ info.m_bCanConvertFormat = ( tex.m_Flags & Texture_t::CAN_CONVERT_FORMAT ) != 0;
+#else
+ info.m_bTextureIsLockable = ( tex.m_Flags & Texture_t::IS_LOCKABLE ) != 0;
+#endif
+ if ( pVTF->Depth() > 1 )
+ {
+ LoadVolumeTextureFromVTF( info, pVTF, iVTFFrame );
+ }
+ else if ( pVTF->IsCubeMap() )
+ {
+ if ( HardwareConfig()->SupportsCubeMaps() )
+ {
+ LoadCubeTextureFromVTF( info, pVTF, iVTFFrame );
+ }
+ else
+ {
+ info.m_CubeFaceID = (D3DCUBEMAP_FACES)6;
+ LoadTextureFromVTF( info, pVTF, iVTFFrame );
+ }
+ }
+ else
+ {
+ LoadTextureFromVTF( info, pVTF, iVTFFrame );
+ }
+ SetModifyTexture( info.m_pTexture );
+}
+
+
+//-----------------------------------------------------------------------------
+// Is the texture resident?
+//-----------------------------------------------------------------------------
+bool CShaderAPIDx8::IsTextureResident( ShaderAPITextureHandle_t textureHandle )
+{
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Level of anisotropic filtering
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::SetAnisotropicLevel( int nAnisotropyLevel )
+{
+ LOCK_SHADERAPI();
+
+ // NOTE: This must be called before the rest of the code in this function so
+ // anisotropic can be set per-texture to force it on! This will also avoid
+ // a possible infinite loop that existed before.
+ g_pShaderUtil->NoteAnisotropicLevel( nAnisotropyLevel );
+
+ // Never set this to 1. In the case we want it set to 1, we will use this to override
+ // aniso per-texture, so set it to something reasonable
+ if ( nAnisotropyLevel > g_pHardwareConfig->Caps().m_nMaxAnisotropy || nAnisotropyLevel <= 1 )
+ {
+ // Set it to 1/4 the max but between 2-8
+ nAnisotropyLevel = max( 2, min( 8, ( g_pHardwareConfig->Caps().m_nMaxAnisotropy / 4 ) ) );
+ }
+
+ // Set the D3D max insotropy state for all samplers
+ for ( int i = 0; i < g_pHardwareConfig->Caps().m_NumSamplers; ++i)
+ {
+ SamplerState(i).m_nAnisotropicLevel = nAnisotropyLevel;
+ SetSamplerState( i, D3DSAMP_MAXANISOTROPY, SamplerState(i).m_nAnisotropicLevel );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the priority
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::TexSetPriority( int priority )
+{
+#if !defined( _X360 )
+ LOCK_SHADERAPI();
+
+ // A hint to the cacher...
+ ShaderAPITextureHandle_t hModifyTexture = GetModifyTextureHandle();
+ if ( hModifyTexture == INVALID_SHADERAPI_TEXTURE_HANDLE )
+ return;
+
+ Texture_t& tex = GetTexture( hModifyTexture );
+ if ( tex.m_NumCopies > 1 )
+ {
+ for (int i = 0; i < tex.m_NumCopies; ++i)
+ tex.GetTexture( i )->SetPriority( priority );
+ }
+ else
+ {
+ tex.GetTexture()->SetPriority( priority );
+ }
+#endif
+}
+
+void CShaderAPIDx8::TexLodClamp( int finest )
+{
+ LOCK_SHADERAPI();
+
+ ShaderAPITextureHandle_t hModifyTexture = GetModifyTextureHandle();
+ if ( hModifyTexture == INVALID_SHADERAPI_TEXTURE_HANDLE )
+ return;
+
+ Texture_t& tex = GetTexture( hModifyTexture );
+ tex.m_FinestMipmapLevel = finest;
+}
+
+void CShaderAPIDx8::TexLodBias( float bias )
+{
+ LOCK_SHADERAPI();
+
+ ShaderAPITextureHandle_t hModifyTexture = GetModifyTextureHandle();
+ if ( hModifyTexture == INVALID_SHADERAPI_TEXTURE_HANDLE )
+ return;
+
+ Texture_t& tex = GetTexture( hModifyTexture );
+ tex.m_LodBias = bias;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Texturemapping state
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::TexWrap( ShaderTexCoordComponent_t coord, ShaderTexWrapMode_t wrapMode )
+{
+ LOCK_SHADERAPI();
+
+ ShaderAPITextureHandle_t hModifyTexture = GetModifyTextureHandle();
+ if ( hModifyTexture == INVALID_SHADERAPI_TEXTURE_HANDLE )
+ return;
+
+ D3DTEXTUREADDRESS address;
+ switch( wrapMode )
+ {
+ case SHADER_TEXWRAPMODE_CLAMP:
+ address = D3DTADDRESS_CLAMP;
+ break;
+ case SHADER_TEXWRAPMODE_REPEAT:
+ address = D3DTADDRESS_WRAP;
+ break;
+ case SHADER_TEXWRAPMODE_BORDER:
+ address = D3DTADDRESS_BORDER;
+ break;
+ default:
+ address = D3DTADDRESS_CLAMP;
+ Warning( "CShaderAPIDx8::TexWrap: unknown wrapMode\n" );
+ break;
+ }
+
+ switch( coord )
+ {
+ case SHADER_TEXCOORD_S:
+ GetTexture( hModifyTexture ).m_UTexWrap = address;
+ break;
+ case SHADER_TEXCOORD_T:
+ GetTexture( hModifyTexture ).m_VTexWrap = address;
+ break;
+ case SHADER_TEXCOORD_U:
+ GetTexture( hModifyTexture ).m_WTexWrap = address;
+ break;
+ default:
+ Warning( "CShaderAPIDx8::TexWrap: unknown coord\n" );
+ break;
+ }
+}
+
+void CShaderAPIDx8::TexMinFilter( ShaderTexFilterMode_t texFilterMode )
+{
+ LOCK_SHADERAPI();
+
+ ShaderAPITextureHandle_t hModifyTexture = GetModifyTextureHandle();
+ if ( hModifyTexture == INVALID_SHADERAPI_TEXTURE_HANDLE )
+ return;
+
+ switch( texFilterMode )
+ {
+ case SHADER_TEXFILTERMODE_NEAREST:
+ GetTexture( hModifyTexture ).m_MinFilter = D3DTEXF_POINT;
+ GetTexture( hModifyTexture ).m_MipFilter = D3DTEXF_NONE;
+ break;
+ case SHADER_TEXFILTERMODE_LINEAR:
+ GetTexture( hModifyTexture ).m_MinFilter = D3DTEXF_LINEAR;
+ GetTexture( hModifyTexture ).m_MipFilter = D3DTEXF_NONE;
+ break;
+ case SHADER_TEXFILTERMODE_NEAREST_MIPMAP_NEAREST:
+ GetTexture( hModifyTexture ).m_MinFilter = D3DTEXF_POINT;
+ GetTexture( hModifyTexture ).m_MipFilter =
+ GetTexture( hModifyTexture ).m_NumLevels != 1 ? D3DTEXF_POINT : D3DTEXF_NONE;
+ break;
+ case SHADER_TEXFILTERMODE_LINEAR_MIPMAP_NEAREST:
+ GetTexture( hModifyTexture ).m_MinFilter = D3DTEXF_LINEAR;
+ GetTexture( hModifyTexture ).m_MipFilter =
+ GetTexture( hModifyTexture ).m_NumLevels != 1 ? D3DTEXF_POINT : D3DTEXF_NONE;
+ break;
+ case SHADER_TEXFILTERMODE_NEAREST_MIPMAP_LINEAR:
+ GetTexture( hModifyTexture ).m_MinFilter = D3DTEXF_POINT;
+ GetTexture( hModifyTexture ).m_MipFilter =
+ GetTexture( hModifyTexture ).m_NumLevels != 1 ? D3DTEXF_LINEAR : D3DTEXF_NONE;
+ break;
+ case SHADER_TEXFILTERMODE_LINEAR_MIPMAP_LINEAR:
+ GetTexture( hModifyTexture ).m_MinFilter = D3DTEXF_LINEAR;
+ GetTexture( hModifyTexture ).m_MipFilter =
+ GetTexture( hModifyTexture ).m_NumLevels != 1 ? D3DTEXF_LINEAR : D3DTEXF_NONE;
+ break;
+ case SHADER_TEXFILTERMODE_ANISOTROPIC:
+ GetTexture( hModifyTexture ).m_MinFilter = D3DTEXF_ANISOTROPIC;
+ GetTexture( hModifyTexture ).m_MipFilter =
+ GetTexture( hModifyTexture ).m_NumLevels != 1 ? D3DTEXF_LINEAR : D3DTEXF_NONE;
+ break;
+ default:
+ Warning( "CShaderAPIDx8::TexMinFilter: Unknown texFilterMode\n" );
+ break;
+ }
+}
+
+void CShaderAPIDx8::TexMagFilter( ShaderTexFilterMode_t texFilterMode )
+{
+ LOCK_SHADERAPI();
+
+ ShaderAPITextureHandle_t hModifyTexture = GetModifyTextureHandle();
+ if ( hModifyTexture == INVALID_SHADERAPI_TEXTURE_HANDLE )
+ return;
+
+ switch( texFilterMode )
+ {
+ case SHADER_TEXFILTERMODE_NEAREST:
+ GetTexture( hModifyTexture ).m_MagFilter = D3DTEXF_POINT;
+ break;
+ case SHADER_TEXFILTERMODE_LINEAR:
+ GetTexture( hModifyTexture ).m_MagFilter = D3DTEXF_LINEAR;
+ break;
+ case SHADER_TEXFILTERMODE_NEAREST_MIPMAP_NEAREST:
+ Warning( "CShaderAPIDx8::TexMagFilter: SHADER_TEXFILTERMODE_NEAREST_MIPMAP_NEAREST is invalid\n" );
+ break;
+ case SHADER_TEXFILTERMODE_LINEAR_MIPMAP_NEAREST:
+ Warning( "CShaderAPIDx8::TexMagFilter: SHADER_TEXFILTERMODE_LINEAR_MIPMAP_NEAREST is invalid\n" );
+ break;
+ case SHADER_TEXFILTERMODE_NEAREST_MIPMAP_LINEAR:
+ Warning( "CShaderAPIDx8::TexMagFilter: SHADER_TEXFILTERMODE_NEAREST_MIPMAP_LINEAR is invalid\n" );
+ break;
+ case SHADER_TEXFILTERMODE_LINEAR_MIPMAP_LINEAR:
+ Warning( "CShaderAPIDx8::TexMagFilter: SHADER_TEXFILTERMODE_LINEAR_MIPMAP_LINEAR is invalid\n" );
+ break;
+ case SHADER_TEXFILTERMODE_ANISOTROPIC:
+ GetTexture( hModifyTexture ).m_MagFilter = g_pHardwareConfig->Caps().m_bSupportsMagAnisotropicFiltering ? D3DTEXF_ANISOTROPIC : D3DTEXF_LINEAR;
+ break;
+ default:
+ Warning( "CShaderAPIDx8::TexMAGFilter: Unknown texFilterMode\n" );
+ break;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the matrix stack from the matrix mode
+//-----------------------------------------------------------------------------
+
+int CShaderAPIDx8::GetMatrixStack( MaterialMatrixMode_t mode ) const
+{
+ Assert( mode >= 0 && mode < NUM_MATRIX_MODES );
+ return mode;
+}
+
+//-----------------------------------------------------------------------------
+// Returns true if we're modulating constant color into the vertex color
+//-----------------------------------------------------------------------------
+bool CShaderAPIDx8::IsModulatingVertexColor() const
+{
+ return m_TransitionTable.CurrentShadowShaderState()->m_ModulateConstantColor;
+}
+
+
+//-----------------------------------------------------------------------------
+// Material property (used to deal with overbright for lights)
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::SetDefaultMaterial()
+{
+#if !defined( _X360 )
+ D3DMATERIAL mat;
+ mat.Diffuse.r = mat.Diffuse.g = mat.Diffuse.b = mat.Diffuse.a = 1.0f;
+ mat.Ambient.r = mat.Ambient.g = mat.Ambient.b = mat.Ambient.a = 0.0f;
+ mat.Specular.r = mat.Specular.g = mat.Specular.b = mat.Specular.a = 0.0f;
+ mat.Emissive.r = mat.Emissive.g = mat.Emissive.b = mat.Emissive.a = 0.0f;
+ mat.Power = 1.0f;
+ Dx9Device()->SetMaterial( &mat );
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// lighting related methods
+//-----------------------------------------------------------------------------
+
+void CShaderAPIDx8::SetAmbientLight( float r, float g, float b )
+{
+ LOCK_SHADERAPI();
+ unsigned int ambient = D3DCOLOR_ARGB( 255, (int)(r * 255),
+ (int)(g * 255), (int)(b * 255) );
+ if (ambient != m_DynamicState.m_Ambient)
+ {
+ m_DynamicState.m_Ambient = ambient;
+ SetSupportedRenderState( D3DRS_AMBIENT, ambient );
+ }
+}
+
+void CShaderAPIDx8::SetLightingOrigin( Vector vLightingOrigin )
+{
+ if ( vLightingOrigin != m_DynamicState.m_vLightingOrigin )
+ {
+ FlushBufferedPrimitives();
+ m_DynamicState.m_vLightingOrigin = vLightingOrigin;
+ }
+}
+
+//#define NO_LOCAL_LIGHTS
+void CShaderAPIDx8::SetLight( int lightNum, const LightDesc_t& desc_ )
+{
+ LOCK_SHADERAPI();
+#ifdef NO_LOCAL_LIGHTS
+ LightDesc_t desc = desc_;
+ desc.m_Type = MATERIAL_LIGHT_DISABLE;
+#else
+ LightDesc_t &desc = const_cast<LightDesc_t &>(desc_); // to permit '&'
+#endif
+ Assert( lightNum < g_pHardwareConfig->Caps().m_MaxNumLights && lightNum >= 0 );
+
+ if( lightNum >= g_pHardwareConfig->Caps().m_MaxNumLights || lightNum < 0 )
+ return;
+
+ m_DynamicState.m_LightDescs[lightNum] = desc;
+
+ FlushBufferedPrimitives();
+
+ if (desc.m_Type == MATERIAL_LIGHT_DISABLE)
+ {
+ if (m_DynamicState.m_LightEnable[lightNum])
+ {
+ m_DynamicState.m_LightEnableChanged[lightNum] = STATE_CHANGED;
+ m_DynamicState.m_LightEnable[lightNum] = false;
+ }
+ return;
+ }
+
+ if (!m_DynamicState.m_LightEnable[lightNum])
+ {
+ m_DynamicState.m_LightEnableChanged[lightNum] = STATE_CHANGED;
+ m_DynamicState.m_LightEnable[lightNum] = true;
+ }
+
+ D3DLIGHT light;
+ switch( desc.m_Type )
+ {
+ case MATERIAL_LIGHT_POINT:
+ light.Type = D3DLIGHT_POINT;
+ light.Range = desc.m_Range;
+ break;
+
+ case MATERIAL_LIGHT_DIRECTIONAL:
+ light.Type = D3DLIGHT_DIRECTIONAL;
+ light.Range = 1e12; // This is supposed to be ignored
+ break;
+
+ case MATERIAL_LIGHT_SPOT:
+ light.Type = D3DLIGHT_SPOT;
+ light.Range = desc.m_Range;
+ break;
+
+ default:
+ m_DynamicState.m_LightEnable[lightNum] = false;
+ return;
+ }
+
+ // This is a D3D limitation
+ Assert( (light.Range >= 0) && (light.Range <= sqrt(FLT_MAX)) );
+
+ memcpy( &light.Diffuse, &desc.m_Color[0], 3*sizeof(float) );
+ memcpy( &light.Specular, &desc.m_Color[0], 3*sizeof(float) );
+ light.Diffuse.a = 1.0f;
+ light.Specular.a = 1.0f;
+ light.Ambient.a = light.Ambient.b = light.Ambient.g = light.Ambient.r = 0;
+ memcpy( &light.Position, &desc.m_Position[0], 3 * sizeof(float) );
+ memcpy( &light.Direction, &desc.m_Direction[0], 3 * sizeof(float) );
+ light.Falloff = desc.m_Falloff;
+ light.Attenuation0 = desc.m_Attenuation0;
+ light.Attenuation1 = desc.m_Attenuation1;
+ light.Attenuation2 = desc.m_Attenuation2;
+
+ // normalize light color...
+ light.Theta = desc.m_Theta;
+ light.Phi = desc.m_Phi;
+ if (light.Phi > M_PI)
+ light.Phi = M_PI;
+
+ // This piece of crap line of code is because if theta gets too close to phi,
+ // we get no light at all.
+ if (light.Theta - light.Phi > -1e-3)
+ light.Theta = light.Phi - 1e-3;
+
+ m_DynamicState.m_LightChanged[lightNum] = STATE_CHANGED;
+ memcpy( &m_DynamicState.m_Lights[lightNum], &light, sizeof(light) );
+}
+
+void CShaderAPIDx8::DisableAllLocalLights()
+{
+ LOCK_SHADERAPI();
+ bool bFlushed = false;
+ for ( int lightNum = 0; lightNum < MAX_NUM_LIGHTS; lightNum++ )
+ {
+ if (m_DynamicState.m_LightEnable[lightNum])
+ {
+ if ( !bFlushed )
+ {
+ FlushBufferedPrimitives();
+ bFlushed = true;
+ }
+ m_DynamicState.m_LightDescs[lightNum].m_Type = MATERIAL_LIGHT_DISABLE;
+ m_DynamicState.m_LightEnableChanged[lightNum] = STATE_CHANGED;
+ m_DynamicState.m_LightEnable[lightNum] = false;
+ }
+ }
+}
+
+int CShaderAPIDx8::GetMaxLights( void ) const
+{
+ return g_pHardwareConfig->Caps().m_MaxNumLights;
+}
+
+const LightDesc_t& CShaderAPIDx8::GetLight( int lightNum ) const
+{
+ Assert( lightNum < g_pHardwareConfig->Caps().m_MaxNumLights && lightNum >= 0 );
+ return m_DynamicState.m_LightDescs[lightNum];
+}
+
+//-----------------------------------------------------------------------------
+// Ambient cube
+//-----------------------------------------------------------------------------
+
+//#define NO_AMBIENT_CUBE 1
+void CShaderAPIDx8::SetAmbientLightCube( Vector4D cube[6] )
+{
+ LOCK_SHADERAPI();
+/*
+ int i;
+ for( i = 0; i < 6; i++ )
+ {
+ ColorClamp( cube[i].AsVector3D() );
+// if( i == 0 )
+// {
+// Warning( "%d: %f %f %f\n", i, cube[i][0], cube[i][1], cube[i][2] );
+// }
+ }
+*/
+ if (memcmp(&m_DynamicState.m_AmbientLightCube[0][0], cube, 6 * sizeof(Vector4D)))
+ {
+ memcpy( &m_DynamicState.m_AmbientLightCube[0][0], cube, 6 * sizeof(Vector4D) );
+
+#ifdef NO_AMBIENT_CUBE
+ memset( &m_DynamicState.m_AmbientLightCube[0][0], 0, 6 * sizeof(Vector4D) );
+#endif
+
+//#define DEBUG_AMBIENT_CUBE
+
+#ifdef DEBUG_AMBIENT_CUBE
+ m_DynamicState.m_AmbientLightCube[0][0] = 1.0f;
+ m_DynamicState.m_AmbientLightCube[0][1] = 0.0f;
+ m_DynamicState.m_AmbientLightCube[0][2] = 0.0f;
+
+ m_DynamicState.m_AmbientLightCube[1][0] = 0.0f;
+ m_DynamicState.m_AmbientLightCube[1][1] = 1.0f;
+ m_DynamicState.m_AmbientLightCube[1][2] = 0.0f;
+
+ m_DynamicState.m_AmbientLightCube[2][0] = 0.0f;
+ m_DynamicState.m_AmbientLightCube[2][1] = 0.0f;
+ m_DynamicState.m_AmbientLightCube[2][2] = 1.0f;
+
+ m_DynamicState.m_AmbientLightCube[3][0] = 1.0f;
+ m_DynamicState.m_AmbientLightCube[3][1] = 0.0f;
+ m_DynamicState.m_AmbientLightCube[3][2] = 1.0f;
+
+ m_DynamicState.m_AmbientLightCube[4][0] = 1.0f;
+ m_DynamicState.m_AmbientLightCube[4][1] = 1.0f;
+ m_DynamicState.m_AmbientLightCube[4][2] = 0.0f;
+
+ m_DynamicState.m_AmbientLightCube[5][0] = 0.0f;
+ m_DynamicState.m_AmbientLightCube[5][1] = 1.0f;
+ m_DynamicState.m_AmbientLightCube[5][2] = 1.0f;
+#endif
+
+ m_CachedAmbientLightCube = STATE_CHANGED;
+ }
+}
+
+void CShaderAPIDx8::SetVertexShaderStateAmbientLightCube()
+{
+ if (m_CachedAmbientLightCube & STATE_CHANGED_VERTEX_SHADER)
+ {
+ SetVertexShaderConstant( VERTEX_SHADER_AMBIENT_LIGHT, m_DynamicState.m_AmbientLightCube[0].Base(), 6 );
+ m_CachedAmbientLightCube &= ~STATE_CHANGED_VERTEX_SHADER;
+ }
+}
+
+
+void CShaderAPIDx8::SetPixelShaderStateAmbientLightCube( int pshReg, bool bForceToBlack )
+{
+ float *pCubeBase;
+ Vector4D tempCube[6];
+
+ if( bForceToBlack )
+ {
+ for ( int i=0; i<6 ; i++ )
+ tempCube[i].Init();
+
+ pCubeBase = tempCube[0].Base();
+ }
+ else
+ {
+ pCubeBase = m_DynamicState.m_AmbientLightCube[0].Base();
+ }
+
+ SetPixelShaderConstant( pshReg, pCubeBase, 6 );
+}
+
+float CShaderAPIDx8::GetAmbientLightCubeLuminance( void )
+{
+ Vector4D vLuminance( 0.3f, 0.59f, 0.11f, 0.0f );
+ float fLuminance = 0.0f;
+
+ for (int i=0; i<6; i++)
+ {
+ fLuminance += vLuminance.Dot( m_DynamicState.m_AmbientLightCube[i] );
+ }
+
+ return fLuminance / 6.0f;
+}
+
+static inline RECT* RectToRECT( Rect_t *pSrcRect, RECT &dstRect )
+{
+ if ( !pSrcRect )
+ return NULL;
+
+ dstRect.left = pSrcRect->x;
+ dstRect.top = pSrcRect->y;
+ dstRect.right = pSrcRect->x + pSrcRect->width;
+ dstRect.bottom = pSrcRect->y + pSrcRect->height;
+ return &dstRect;
+}
+
+void CShaderAPIDx8::CopyRenderTargetToTextureEx( ShaderAPITextureHandle_t textureHandle, int nRenderTargetID, Rect_t *pSrcRect, Rect_t *pDstRect )
+{
+ LOCK_SHADERAPI();
+ VPROF_BUDGET( "CShaderAPIDx8::CopyRenderTargetToTexture", "Refraction overhead" );
+
+ if ( !TextureIsAllocated( textureHandle ) )
+ return;
+
+#if defined( PIX_INSTRUMENTATION )
+ {
+ const char *pRT = ( nRenderTargetID < 0 ) ? "DS" : "RT";
+
+ if ( textureHandle == SHADER_RENDERTARGET_NONE )
+ {
+ pRT = "None";
+ }
+ else if ( textureHandle != SHADER_RENDERTARGET_BACKBUFFER )
+ {
+ Texture_t &tex = GetTexture( textureHandle );
+ pRT = tex.m_DebugName.String();
+ }
+
+ char buf[256];
+ sprintf( buf, "CopyRTToTexture:%s", pRT ? pRT : "?" );
+ BeginPIXEvent( 0xFFFFFFFF, buf );
+ EndPIXEvent();
+ }
+#endif
+
+ // Don't flush here!! If you have to flush here, then there is a driver bug.
+ // FlushHardware( );
+
+ AssertValidTextureHandle( textureHandle );
+ Texture_t *pTexture = &GetTexture( textureHandle );
+ Assert( pTexture );
+ IDirect3DTexture *pD3DTexture = (IDirect3DTexture *)pTexture->GetTexture();
+ Assert( pD3DTexture );
+
+#if !defined( _X360 )
+ IDirect3DSurface* pRenderTargetSurface;
+ HRESULT hr = Dx9Device()->GetRenderTarget( nRenderTargetID, &pRenderTargetSurface );
+ if ( FAILED( hr ) )
+ {
+ Assert( 0 );
+ return;
+ }
+
+ IDirect3DSurface *pDstSurf;
+ hr = pD3DTexture->GetSurfaceLevel( 0, &pDstSurf );
+ Assert( !FAILED( hr ) );
+ if ( FAILED( hr ) )
+ {
+ pRenderTargetSurface->Release();
+ return;
+ }
+
+ bool tryblit = true;
+ if ( tryblit )
+ {
+ RECORD_COMMAND( DX8_COPY_FRAMEBUFFER_TO_TEXTURE, 1 );
+ RECORD_INT( textureHandle );
+
+ RECT srcRect, dstRect;
+ hr = Dx9Device()->StretchRect( pRenderTargetSurface, RectToRECT( pSrcRect, srcRect ),
+ pDstSurf, RectToRECT( pDstRect, dstRect ), D3DTEXF_LINEAR );
+ Assert( !FAILED( hr ) );
+ }
+
+ pDstSurf->Release();
+ pRenderTargetSurface->Release();
+#else
+ DWORD flags = 0;
+ switch( nRenderTargetID )
+ {
+ case -1:
+ flags = D3DRESOLVE_DEPTHSTENCIL | D3DRESOLVE_FRAGMENT0;
+ break;
+ case 0:
+ flags = D3DRESOLVE_RENDERTARGET0;
+ break;
+ case 1:
+ case 2:
+ case 3:
+ // not supporting MRT
+ Assert( 0 );
+ return;
+ NO_DEFAULT
+ };
+
+ // not prepared to handle mip mapping yet
+ Assert( pD3DTexture->GetLevelCount() == 1 );
+
+ D3DPOINT dstPoint = { 0 };
+ if ( pDstRect )
+ {
+ dstPoint.x = pDstRect->x;
+ dstPoint.y = pDstRect->y;
+ }
+
+ int destWidth, destHeight;
+ if( pDstRect )
+ {
+ destWidth = pDstRect->width;
+ destHeight = pDstRect->height;
+
+ Assert( (destWidth <= pTexture->GetWidth()) && (destHeight <= pTexture->GetHeight()) );
+ }
+ else
+ {
+ destWidth = pTexture->GetWidth();
+ destHeight = pTexture->GetHeight();
+ }
+
+ RECT srcRect;
+ RECT *pResolveRect = NULL;
+ int srcWidth, srcHeight;
+ if ( pSrcRect )
+ {
+ RectToRECT( pSrcRect, srcRect );
+ pResolveRect = &srcRect;
+
+ // resolve has no stretching ability, and we can only compensate when doing a resolve to a whole texture larger than the source
+ Assert( !pDstRect || ( pSrcRect->width <= pDstRect->width && pSrcRect->height <= pDstRect->height ) );
+
+ srcWidth = pSrcRect->width;
+ srcHeight = pSrcRect->height;
+ }
+ else
+ {
+ srcRect.left = srcRect.top = 0;
+ srcRect.right = m_DynamicState.m_Viewport.Width;
+ srcRect.bottom = m_DynamicState.m_Viewport.Height;
+ if( (srcRect.right < 0) || (srcRect.bottom < 0) )
+ {
+ if( m_UsingTextureRenderTarget )
+ {
+ srcRect.right = m_ViewportMaxWidth;
+ srcRect.bottom = m_ViewportMaxHeight;
+ }
+ else
+ {
+ int w,h;
+ GetBackBufferDimensions( w, h );
+ srcRect.right = w;
+ srcRect.bottom = h;
+ }
+ }
+ srcWidth = srcRect.right;
+ srcHeight = srcRect.bottom;
+ }
+
+ if( (srcWidth != destWidth) || (srcHeight != destHeight) )
+ {
+ //Not a 1:1 resolve, we should only have gotten this far if we can downsize the target texture to compensate
+ Assert( (destWidth > srcWidth) && (destHeight > srcHeight) && (dstPoint.x == 0) && (dstPoint.y == 0) );
+
+ //What we're doing is telling D3D that this texture is smaller than it is so the resolve is 1:1.
+ //We leave the texture in this state until it resolves from something bigger.
+ //All outside code still thinks this texture is it's original size. And it still owns enough memory to go back to it's original size.
+ pD3DTexture->Format.Size.TwoD.Width = srcWidth - 1;
+ pD3DTexture->Format.Size.TwoD.Height = srcHeight - 1; //no idea why they store it as size-1, but they do
+ pResolveRect = NULL;
+ }
+ else
+ {
+ //restore D3D texture to full size in case it was previously downsized
+ pD3DTexture->Format.Size.TwoD.Width = pTexture->GetWidth() - 1;
+ pD3DTexture->Format.Size.TwoD.Height = pTexture->GetHeight() - 1; //no idea why they store it as size-1, but they do
+ }
+
+ // if we convert to srgb format, we need the original format for reverting. We only need the first DWORD of GPUTEXTURE_FETCH_CONSTANT.
+ DWORD linearFormatBackup = pD3DTexture->Format.dword[0];
+ if ( !( flags & D3DRESOLVE_DEPTHSTENCIL ) && ( m_DynamicState.m_bSRGBWritesEnabled ) )
+ {
+ // we need a matched resolve regarding sRGB to get values transfered as-is
+ // when the surface is sRGB, use the corresponding sRGB texture
+ pD3DTexture->Format.SignX = pD3DTexture->Format.SignY = pD3DTexture->Format.SignZ = 3;
+ }
+
+ HRESULT hr = Dx9Device()->Resolve( flags, (D3DRECT*)pResolveRect, pD3DTexture, &dstPoint, 0, 0, NULL, 0, 0, NULL );
+ Assert( !FAILED( hr ) );
+
+ pD3DTexture->Format.dword[0] = linearFormatBackup;
+#endif
+}
+
+void CShaderAPIDx8::CopyRenderTargetToScratchTexture( ShaderAPITextureHandle_t srcRt, ShaderAPITextureHandle_t dstTex, Rect_t *pSrcRect, Rect_t *pDstRect )
+{
+ LOCK_SHADERAPI();
+
+ if ( !TextureIsAllocated( srcRt ) || !TextureIsAllocated( dstTex ) )
+ {
+ Assert( !"Fix that render target or dest texture aren't allocated." );
+ return;
+ }
+
+ HRESULT hr = D3D_OK;
+
+ IDirect3DSurface9* srcSurf = NULL;
+ AssertValidTextureHandle( srcRt );
+ Texture_t *pSrcRt = &GetTexture( srcRt );
+ Assert( pSrcRt );
+ IDirect3DTexture *pD3DSrcRt = ( IDirect3DTexture * ) pSrcRt->GetTexture();
+ Assert( pD3DSrcRt );
+ hr = pD3DSrcRt->GetSurfaceLevel( 0, &srcSurf );
+ Assert( SUCCEEDED( hr ) && srcSurf );
+
+ IDirect3DSurface9* dstSurf = NULL;
+ AssertValidTextureHandle( dstTex );
+ Texture_t *pDstTex = &GetTexture( dstTex );
+ Assert( pDstTex );
+ IDirect3DTexture *pD3DDstTex = ( IDirect3DTexture * ) pDstTex->GetTexture();
+ Assert( pD3DDstTex );
+ hr = pD3DDstTex->GetSurfaceLevel( 0, &dstSurf );
+ Assert( SUCCEEDED( hr ) && dstSurf );
+
+ // This does it.
+ hr = Dx9Device()->GetRenderTargetData( srcSurf, dstSurf );
+ Assert( SUCCEEDED( hr ) );
+
+ srcSurf->Release();
+ dstSurf->Release();
+}
+
+//-------------------------------------------------------------------------
+// Allows locking and unlocking of very specific surface types. pOutBits and pOutPitch will not be touched if
+// the lock fails.
+//-------------------------------------------------------------------------
+void CShaderAPIDx8::LockRect( void** pOutBits, int* pOutPitch, ShaderAPITextureHandle_t texHandle, int mipmap, int x, int y, int w, int h, bool bWrite, bool bRead )
+{
+ LOCK_SHADERAPI();
+
+ Assert( pOutBits );
+ Assert( pOutPitch );
+
+ if ( !TextureIsAllocated( texHandle ) )
+ {
+ Assert( !"Fix that texture isn't allocated." );
+ return;
+ }
+
+ HRESULT hr = D3D_OK;
+ IDirect3DSurface9* surf = NULL;
+ AssertValidTextureHandle( texHandle );
+ Texture_t *pTex = &GetTexture( texHandle );
+ Assert( pTex );
+ IDirect3DTexture *pD3DTex = ( IDirect3DTexture * ) pTex->GetTexture();
+ Assert( pD3DTex );
+
+ hr = pD3DTex->GetSurfaceLevel( mipmap, &surf );
+ Assert( SUCCEEDED( hr ) && surf );
+
+ D3DLOCKED_RECT lockRect = { 0 };
+ RECT srcRect = { x, y, w, h };
+ DWORD flags = 0;
+
+ if ( !bRead && !bWrite )
+ {
+ Assert( !"Asking to neither read nor write? Probably a caller bug." );
+ goto cleanup;
+ }
+
+ if ( bRead && !bWrite )
+ flags = D3DLOCK_READONLY;
+
+ hr = surf->LockRect( &lockRect, &srcRect, flags );
+ if ( FAILED( hr ) )
+ {
+ Assert( !"Lock failed, look into why." );
+ goto cleanup;
+ }
+
+ (*pOutBits) = lockRect.pBits;
+ (*pOutPitch) = lockRect.Pitch;
+
+cleanup:
+ surf->Release();
+}
+
+void CShaderAPIDx8::UnlockRect( ShaderAPITextureHandle_t texHandle, int mipmap )
+{
+ LOCK_SHADERAPI();
+
+ if ( !TextureIsAllocated( texHandle ) )
+ {
+ Assert( !"Fix that texture isn't allocated." );
+ return;
+ }
+
+ HRESULT hr = D3D_OK;
+ IDirect3DSurface9* surf = NULL;
+ AssertValidTextureHandle( texHandle );
+ Texture_t *pTex = &GetTexture( texHandle );
+ Assert( pTex );
+ IDirect3DTexture *pD3DTex = ( IDirect3DTexture * ) pTex->GetTexture();
+ Assert( pD3DTex );
+
+ hr = pD3DTex->GetSurfaceLevel( mipmap, &surf );
+ Assert( SUCCEEDED( hr ) && surf );
+
+ hr = surf->UnlockRect();
+ Assert( SUCCEEDED( hr ) );
+
+ surf->Release();
+}
+
+static float GetAspectRatio( const Texture_t* pTex )
+{
+ Assert( pTex );
+ if ( pTex->m_Height != 0 )
+ return float( pTex->m_Width ) / float( pTex->m_Height );
+
+ Assert( !"Height of texture is 0, that seems like a bug." );
+ return 0.0f;
+}
+
+struct TextureExtents_t
+{
+ int width;
+ int height;
+ int depth;
+ int mipmaps;
+
+ int fine;
+ int coarse;
+
+ TextureExtents_t() : width( 0 ), height( 0 ), depth( 0 ), mipmaps( 0 ), fine( 0 ), coarse( 0 ) { }
+};
+
+// Returns positive integer on success, 0 or <0 on failure.
+static int FindCommonMipmapRange( int *pOutSrcFine, int *pOutDstFine, Texture_t *pSrcTex, Texture_t *pDstTex )
+{
+ Assert( pOutSrcFine && pOutDstFine );
+ Assert( pSrcTex && pDstTex );
+
+ if ( GetAspectRatio( pSrcTex ) != GetAspectRatio( pDstTex ) )
+ return 0;
+
+ TextureExtents_t src,
+ dst;
+
+ // LOD Clamp indicates that there's no actual data in the finer mipmap levels yet, so respect it when determining
+ // the source and destination levels that could have data.
+ const int srcLodClamp = pSrcTex->GetLodClamp();
+ src.width = Max( 1, pSrcTex->GetWidth() >> srcLodClamp );
+ src.height = Max( 1, pSrcTex->GetHeight() >> srcLodClamp );
+ src.depth = Max( 1, pSrcTex->GetDepth() >> srcLodClamp );
+ src.mipmaps = pSrcTex->m_NumLevels - srcLodClamp;
+ Assert( src.mipmaps >= 1 );
+
+
+ const int dstLodClamp = pDstTex->GetLodClamp();
+ dst.width = Max( 1, pDstTex->GetWidth() >> dstLodClamp );
+ dst.height = Max( 1, pDstTex->GetHeight() >> dstLodClamp );
+ dst.depth = Max( 1, pDstTex->GetDepth() >> dstLodClamp );
+ dst.mipmaps = pDstTex->m_NumLevels - dstLodClamp;
+ Assert( dst.mipmaps >= 1 );
+
+ TextureExtents_t *pLarger = NULL,
+ *pSmaller = NULL;
+
+ if ( src.width >= dst.width && src.height >= dst.height && src.depth >= dst.depth )
+ {
+ pLarger = &src;
+ pSmaller = &dst;
+ }
+ else
+ {
+ pLarger = &dst;
+ pSmaller = &src;
+ }
+
+ // Since we are same aspect ratio, only need to test one dimension
+ while ( ( pLarger->width >> pLarger->fine ) > pSmaller->width )
+ {
+ ++pLarger->fine;
+ --pLarger->mipmaps;
+ }
+
+ ( *pOutSrcFine ) = src.fine;
+ ( *pOutDstFine ) = dst.fine;
+
+ return Min( src.mipmaps, dst.mipmaps );
+}
+
+void CShaderAPIDx8::CopyTextureToTexture( ShaderAPITextureHandle_t srcTex, ShaderAPITextureHandle_t dstTex )
+{
+ LOCK_SHADERAPI();
+
+ AssertValidTextureHandle( srcTex );
+ AssertValidTextureHandle( dstTex );
+
+ Assert( TextureIsAllocated( srcTex ) && TextureIsAllocated( dstTex ) );
+
+ Texture_t *pSrcTex = &GetTexture( srcTex );
+ Texture_t *pDstTex = &GetTexture( dstTex );
+
+ Assert( pSrcTex && pDstTex );
+
+ // Must have same image format
+ Assert( pSrcTex->GetImageFormat() == pDstTex->GetImageFormat() );
+
+ int srcFine = 0,
+ dstFine = 0;
+
+ int mipmapCount = FindCommonMipmapRange( &srcFine, &dstFine, pSrcTex, pDstTex );
+
+ if ( mipmapCount <= 0 )
+ {
+ // This is legit for things that are streamed in that are very small (near the 32x32 cutoff we do at the
+ // tip of the mipmap pyramid). But leaving it here because it's useful if you're tracking a specific bug.
+ // Warning( "Attempted to copy textures that had non-overlapping mipmap pyramids. This has failed and no copy has taken place.\n" );
+ return;
+ }
+
+ IDirect3DTexture* pSrcD3DTex = ( IDirect3DTexture * ) pSrcTex->GetTexture();
+ IDirect3DTexture* pDstD3DTex = ( IDirect3DTexture * ) pDstTex->GetTexture();
+
+ HRESULT hr = S_OK;
+ for ( int i = 0; i < mipmapCount; ++i )
+ {
+ int srcMipmap = srcFine + i;
+ int dstMipmap = dstFine + i;
+
+ IDirect3DSurface9* pSrcSurf = NULL;
+ IDirect3DSurface9* pDstSurf = NULL;
+
+ hr = pSrcD3DTex->GetSurfaceLevel( srcMipmap, &pSrcSurf );
+ Assert( SUCCEEDED( hr ) && pSrcSurf );
+
+ hr = pDstD3DTex->GetSurfaceLevel( dstMipmap, &pDstSurf );
+ Assert( SUCCEEDED( hr ) && pDstSurf );
+
+ hr = g_pD3DDevice->StretchRect( pSrcSurf, NULL, pDstSurf, NULL, D3DTEXF_NONE );
+ Assert( SUCCEEDED( hr ) );
+
+ pSrcSurf->Release();
+ pDstSurf->Release();
+ }
+}
+
+
+
+void CShaderAPIDx8::CopyRenderTargetToTexture( ShaderAPITextureHandle_t textureHandle )
+{
+ LOCK_SHADERAPI();
+ CopyRenderTargetToTextureEx( textureHandle, 0 );
+}
+
+
+void CShaderAPIDx8::CopyTextureToRenderTargetEx( int nRenderTargetID, ShaderAPITextureHandle_t textureHandle, Rect_t *pSrcRect, Rect_t *pDstRect )
+{
+ LOCK_SHADERAPI();
+ VPROF( "CShaderAPIDx8::CopyRenderTargetToTexture" );
+
+ if ( !TextureIsAllocated( textureHandle ) )
+ return;
+
+ // Don't flush here!! If you have to flush here, then there is a driver bug.
+ // FlushHardware( );
+
+ AssertValidTextureHandle( textureHandle );
+ Texture_t *pTexture = &GetTexture( textureHandle );
+ Assert( pTexture );
+ IDirect3DTexture *pD3DTexture = (IDirect3DTexture *)pTexture->GetTexture();
+ Assert( pD3DTexture );
+
+#if !defined( _X360 )
+ IDirect3DSurface* pRenderTargetSurface;
+ HRESULT hr = Dx9Device()->GetRenderTarget( nRenderTargetID, &pRenderTargetSurface );
+ if ( FAILED( hr ) )
+ {
+ Assert( 0 );
+ return;
+ }
+
+ IDirect3DSurface *pDstSurf;
+ hr = pD3DTexture->GetSurfaceLevel( 0, &pDstSurf );
+ Assert( !FAILED( hr ) );
+ if ( FAILED( hr ) )
+ {
+ pRenderTargetSurface->Release();
+ return;
+ }
+
+ bool tryblit = true;
+ if ( tryblit )
+ {
+ RECORD_COMMAND( DX8_COPY_FRAMEBUFFER_TO_TEXTURE, 1 );
+ RECORD_INT( textureHandle );
+
+ RECT srcRect, dstRect;
+ hr = Dx9Device()->StretchRect( pDstSurf, RectToRECT( pSrcRect, srcRect ),
+ pRenderTargetSurface, RectToRECT( pDstRect, dstRect ), D3DTEXF_LINEAR );
+ Assert( !FAILED( hr ) );
+ }
+
+ pDstSurf->Release();
+ pRenderTargetSurface->Release();
+#else
+ Assert( 0 );
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// modifies the vertex data when necessary
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::ModifyVertexData( )
+{
+ // this should be a dead code path
+ Assert( 0 );
+#if 0
+ // We have to modulate the vertex color by the constant color sometimes
+ if (IsModulatingVertexColor())
+ {
+ m_ModifyBuilder.Reset();
+
+ float factor[4];
+ unsigned char* pColor = (unsigned char*)&m_DynamicState.m_ConstantColor;
+ factor[0] = pColor[0] / 255.0f;
+ factor[1] = pColor[1] / 255.0f;
+ factor[2] = pColor[2] / 255.0f;
+ factor[3] = pColor[3] / 255.0f;
+
+ for ( int i = 0; i < m_ModifyBuilder.VertexCount(); ++i )
+ {
+ unsigned int color = m_ModifyBuilder.Color();
+ unsigned char* pVertexColor = (unsigned char*)&color;
+
+ pVertexColor[0] = (unsigned char)((float)pVertexColor[0] * factor[0]);
+ pVertexColor[1] = (unsigned char)((float)pVertexColor[1] * factor[1]);
+ pVertexColor[2] = (unsigned char)((float)pVertexColor[2] * factor[2]);
+ pVertexColor[3] = (unsigned char)((float)pVertexColor[3] * factor[3]);
+ m_ModifyBuilder.Color4ubv( pVertexColor );
+
+ m_ModifyBuilder.AdvanceVertex();
+ }
+ }
+#endif
+}
+
+static const char *TextureArgToString( int arg )
+{
+ static char buf[128];
+ switch( arg & D3DTA_SELECTMASK )
+ {
+ case D3DTA_DIFFUSE:
+ strcpy( buf, "D3DTA_DIFFUSE" );
+ break;
+ case D3DTA_CURRENT:
+ strcpy( buf, "D3DTA_CURRENT" );
+ break;
+ case D3DTA_TEXTURE:
+ strcpy( buf, "D3DTA_TEXTURE" );
+ break;
+ case D3DTA_TFACTOR:
+ strcpy( buf, "D3DTA_TFACTOR" );
+ break;
+ case D3DTA_SPECULAR:
+ strcpy( buf, "D3DTA_SPECULAR" );
+ break;
+ case D3DTA_TEMP:
+ strcpy( buf, "D3DTA_TEMP" );
+ break;
+ default:
+ strcpy( buf, "<ERROR>" );
+ break;
+ }
+
+ if( arg & D3DTA_COMPLEMENT )
+ {
+ strcat( buf, "|D3DTA_COMPLEMENT" );
+ }
+ if( arg & D3DTA_ALPHAREPLICATE )
+ {
+ strcat( buf, "|D3DTA_ALPHAREPLICATE" );
+ }
+ return buf;
+}
+
+static const char *TextureOpToString( D3DTEXTUREOP op )
+{
+ switch( op )
+ {
+ case D3DTOP_DISABLE:
+ return "D3DTOP_DISABLE";
+ case D3DTOP_SELECTARG1:
+ return "D3DTOP_SELECTARG1";
+ case D3DTOP_SELECTARG2:
+ return "D3DTOP_SELECTARG2";
+ case D3DTOP_MODULATE:
+ return "D3DTOP_MODULATE";
+ case D3DTOP_MODULATE2X:
+ return "D3DTOP_MODULATE2X";
+ case D3DTOP_MODULATE4X:
+ return "D3DTOP_MODULATE4X";
+ case D3DTOP_ADD:
+ return "D3DTOP_ADD";
+ case D3DTOP_ADDSIGNED:
+ return "D3DTOP_ADDSIGNED";
+ case D3DTOP_ADDSIGNED2X:
+ return "D3DTOP_ADDSIGNED2X";
+ case D3DTOP_SUBTRACT:
+ return "D3DTOP_SUBTRACT";
+ case D3DTOP_ADDSMOOTH:
+ return "D3DTOP_ADDSMOOTH";
+ case D3DTOP_BLENDDIFFUSEALPHA:
+ return "D3DTOP_BLENDDIFFUSEALPHA";
+ case D3DTOP_BLENDTEXTUREALPHA:
+ return "D3DTOP_BLENDTEXTUREALPHA";
+ case D3DTOP_BLENDFACTORALPHA:
+ return "D3DTOP_BLENDFACTORALPHA";
+ case D3DTOP_BLENDTEXTUREALPHAPM:
+ return "D3DTOP_BLENDTEXTUREALPHAPM";
+ case D3DTOP_BLENDCURRENTALPHA:
+ return "D3DTOP_BLENDCURRENTALPHA";
+ case D3DTOP_PREMODULATE:
+ return "D3DTOP_PREMODULATE";
+ case D3DTOP_MODULATEALPHA_ADDCOLOR:
+ return "D3DTOP_MODULATEALPHA_ADDCOLOR";
+ case D3DTOP_MODULATECOLOR_ADDALPHA:
+ return "D3DTOP_MODULATECOLOR_ADDALPHA";
+ case D3DTOP_MODULATEINVALPHA_ADDCOLOR:
+ return "D3DTOP_MODULATEINVALPHA_ADDCOLOR";
+ case D3DTOP_MODULATEINVCOLOR_ADDALPHA:
+ return "D3DTOP_MODULATEINVCOLOR_ADDALPHA";
+ case D3DTOP_BUMPENVMAP:
+ return "D3DTOP_BUMPENVMAP";
+ case D3DTOP_BUMPENVMAPLUMINANCE:
+ return "D3DTOP_BUMPENVMAPLUMINANCE";
+ case D3DTOP_DOTPRODUCT3:
+ return "D3DTOP_DOTPRODUCT3";
+ case D3DTOP_MULTIPLYADD:
+ return "D3DTOP_MULTIPLYADD";
+ case D3DTOP_LERP:
+ return "D3DTOP_LERP";
+ default:
+ return "<ERROR>";
+ }
+}
+
+static const char *BlendModeToString( int blendMode )
+{
+ switch( blendMode )
+ {
+ case D3DBLEND_ZERO:
+ return "D3DBLEND_ZERO";
+ case D3DBLEND_ONE:
+ return "D3DBLEND_ONE";
+ case D3DBLEND_SRCCOLOR:
+ return "D3DBLEND_SRCCOLOR";
+ case D3DBLEND_INVSRCCOLOR:
+ return "D3DBLEND_INVSRCCOLOR";
+ case D3DBLEND_SRCALPHA:
+ return "D3DBLEND_SRCALPHA";
+ case D3DBLEND_INVSRCALPHA:
+ return "D3DBLEND_INVSRCALPHA";
+ case D3DBLEND_DESTALPHA:
+ return "D3DBLEND_DESTALPHA";
+ case D3DBLEND_INVDESTALPHA:
+ return "D3DBLEND_INVDESTALPHA";
+ case D3DBLEND_DESTCOLOR:
+ return "D3DBLEND_DESTCOLOR";
+ case D3DBLEND_INVDESTCOLOR:
+ return "D3DBLEND_INVDESTCOLOR";
+ case D3DBLEND_SRCALPHASAT:
+ return "D3DBLEND_SRCALPHASAT";
+#if !defined( _X360 )
+ case D3DBLEND_BOTHSRCALPHA:
+ return "D3DBLEND_BOTHSRCALPHA";
+ case D3DBLEND_BOTHINVSRCALPHA:
+ return "D3DBLEND_BOTHINVSRCALPHA";
+#endif
+ default:
+ return "<ERROR>";
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Spew Board State
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::SpewBoardState()
+{
+ // FIXME: This has regressed
+ return;
+#ifdef DEBUG_BOARD_STATE
+/*
+ {
+ static ID3DXFont* pFont = 0;
+ if (!pFont)
+ {
+ HFONT hFont = CreateFont( 0, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE,
+ ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
+ DEFAULT_PITCH | FF_MODERN, 0 );
+ Assert( hFont != 0 );
+
+ HRESULT hr = D3DXCreateFont( Dx9Device(), hFont, &pFont );
+ }
+
+ static char buf[1024];
+ static RECT r = { 0, 0, 640, 480 };
+
+ if (m_DynamicState.m_VertexBlend == 0)
+ return;
+
+#if 1
+ D3DXMATRIX* m = &GetTransform(MATERIAL_MODEL);
+ D3DXMATRIX* m2 = &GetTransform(MATERIAL_MODEL + 1);
+ sprintf(buf,"FVF %x\n"
+ "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n"
+ "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n\n",
+ "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n",
+ "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n",
+ ShaderManager()->GetCurrentVertexShader(),
+ m->m[0][0], m->m[0][1], m->m[0][2], m->m[0][3],
+ m->m[1][0], m->m[1][1], m->m[1][2], m->m[1][3],
+ m->m[2][0], m->m[2][1], m->m[2][2], m->m[2][3],
+ m->m[3][0], m->m[3][1], m->m[3][2], m->m[3][3],
+ m2->m[0][0], m2->m[0][1], m2->m[0][2], m2->m[0][3],
+ m2->m[1][0], m2->m[1][1], m2->m[1][2], m2->m[1][3],
+ m2->m[2][0], m2->m[2][1], m2->m[2][2], m2->m[2][3],
+ m2->m[3][0], m2->m[3][1], m2->m[3][2], m2->m[3][3]
+ );
+#else
+ Vector4D *pVec2 = &m_DynamicState.m_pVectorVertexShaderConstant[VERTEX_SHADER_MODELVIEWPROJ];
+ Vector4D *pVec3 = &m_DynamicState.m_pVectorVertexShaderConstant[VERTEX_SHADER_VIEWPROJ];
+ Vector4D *pVec4 = &m_DynamicState.m_pVectorVertexShaderConstant[VERTEX_SHADER_MODEL];
+
+ sprintf(buf,"\n"
+ "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n"
+ "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n\n"
+
+ "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n"
+ "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n\n"
+
+ "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n"
+ "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n\n"
+
+ "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n"
+ "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n",
+
+ pVec1[0][0], pVec1[0][1], pVec1[0][2], pVec1[0][3],
+ pVec1[1][0], pVec1[1][1], pVec1[1][2], pVec1[1][3],
+ pVec1[2][0], pVec1[2][1], pVec1[2][2], pVec1[2][3],
+ pVec1[3][0], pVec1[3][1], pVec1[3][2], pVec1[3][3],
+
+ pVec2[0][0], pVec2[0][1], pVec2[0][2], pVec2[0][3],
+ pVec2[1][0], pVec2[1][1], pVec2[1][2], pVec2[1][3],
+ pVec2[2][0], pVec2[2][1], pVec2[2][2], pVec2[2][3],
+ pVec2[3][0], pVec2[3][1], pVec2[3][2], pVec2[3][3],
+
+ pVec3[0][0], pVec3[0][1], pVec3[0][2], pVec3[0][3],
+ pVec3[1][0], pVec3[1][1], pVec3[1][2], pVec3[1][3],
+ pVec3[2][0], pVec3[2][1], pVec3[2][2], pVec3[2][3],
+ pVec3[3][0], pVec3[3][1], pVec3[3][2], pVec3[3][3],
+
+ pVec4[0][0], pVec4[0][1], pVec4[0][2], pVec4[0][3],
+ pVec4[1][0], pVec4[1][1], pVec4[1][2], pVec4[1][3],
+ pVec4[2][0], pVec4[2][1], pVec4[2][2], pVec4[2][3],
+ 0, 0, 0, 1
+ );
+#endif
+ pFont->Begin();
+ pFont->DrawText( buf, -1, &r, DT_LEFT | DT_TOP,
+ D3DCOLOR_RGBA( 255, 255, 255, 255 ) );
+ pFont->End();
+
+ return;
+ }
+
+#if 0
+ Vector4D *pVec2 = &m_DynamicState.m_pVectorVertexShaderConstant[VERTEX_SHADER_MODELVIEWPROJ];
+ Vector4D *pVec3 = &m_DynamicState.m_pVectorVertexShaderConstant[VERTEX_SHADER_VIEWPROJ];
+ Vector4D *pVec4 = &m_DynamicState.m_pVectorVertexShaderConstant[VERTEX_SHADER_MODEL];
+
+ static char buf2[1024];
+ sprintf(buf2,"\n"
+ "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n"
+ "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n\n"
+
+ "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n"
+ "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n\n"
+
+ "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n"
+ "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n\n"
+
+ "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n"
+ "[%6.3f %6.3f %6.3f %6.3f]\n[%6.3f %6.3f %6.3f %6.3f]\n",
+
+ pVec1[0][0], pVec1[0][1], pVec1[0][2], pVec1[0][3],
+ pVec1[1][0], pVec1[1][1], pVec1[1][2], pVec1[1][3],
+ pVec1[2][0], pVec1[2][1], pVec1[2][2], pVec1[2][3],
+ pVec1[3][0], pVec1[3][1], pVec1[3][2], pVec1[3][3],
+
+ pVec2[0][0], pVec2[0][1], pVec2[0][2], pVec2[0][3],
+ pVec2[1][0], pVec2[1][1], pVec2[1][2], pVec2[1][3],
+ pVec2[2][0], pVec2[2][1], pVec2[2][2], pVec2[2][3],
+ pVec2[3][0], pVec2[3][1], pVec2[3][2], pVec2[3][3],
+
+ pVec3[0][0], pVec3[0][1], pVec3[0][2], pVec3[0][3],
+ pVec3[1][0], pVec3[1][1], pVec3[1][2], pVec3[1][3],
+ pVec3[2][0], pVec3[2][1], pVec3[2][2], pVec3[2][3],
+ pVec3[3][0], pVec3[3][1], pVec3[3][2], pVec3[3][3],
+
+ pVec4[0][0], pVec4[0][1], pVec4[0][2], pVec4[0][3],
+ pVec4[1][0], pVec4[1][1], pVec4[1][2], pVec4[1][3],
+ pVec4[2][0], pVec4[2][1], pVec4[2][2], pVec4[2][3],
+ 0, 0, 0, 1.0f
+ );
+ Plat_DebugString(buf2);
+ return;
+#endif
+*/
+
+ char buf[256];
+ sprintf(buf, "\nSnapshot id %d : \n", m_TransitionTable.CurrentSnapshot() );
+ Plat_DebugString(buf);
+
+ ShadowState_t &boardState = m_TransitionTable.BoardState();
+ ShadowShaderState_t &boardShaderState = m_TransitionTable.BoardShaderState();
+
+ sprintf(buf,"Depth States: ZFunc %d, ZWrite %d, ZEnable %d, ZBias %d\n",
+ boardState.m_ZFunc, boardState.m_ZWriteEnable,
+ boardState.m_ZEnable, boardState.m_ZBias );
+ Plat_DebugString(buf);
+ sprintf(buf,"Cull Enable %d Cull Mode %d Color Write %d Fill %d Const Color Mod %d sRGBWriteEnable %d\n",
+ boardState.m_CullEnable, m_DynamicState.m_CullMode, boardState.m_ColorWriteEnable,
+ boardState.m_FillMode, boardShaderState.m_ModulateConstantColor, boardState.m_SRGBWriteEnable );
+ Plat_DebugString(buf);
+ sprintf(buf,"Blend States: Blend Enable %d Test Enable %d Func %d SrcBlend %d (%s) DstBlend %d (%s)\n",
+ boardState.m_AlphaBlendEnable, boardState.m_AlphaTestEnable,
+ boardState.m_AlphaFunc, boardState.m_SrcBlend, BlendModeToString( boardState.m_SrcBlend ),
+ boardState.m_DestBlend, BlendModeToString( boardState.m_DestBlend ) );
+ Plat_DebugString(buf);
+ int len = sprintf(buf,"Alpha Ref %d, Lighting: %d, Ambient Color %x, LightsEnabled ",
+ boardState.m_AlphaRef, boardState.m_Lighting, m_DynamicState.m_Ambient);
+
+ int i;
+ for ( i = 0; i < g_pHardwareConfig->Caps().m_MaxNumLights; ++i)
+ {
+ len += sprintf(buf+len,"%d ", m_DynamicState.m_LightEnable[i] );
+ }
+ sprintf(buf+len,"\n");
+ Plat_DebugString(buf);
+ sprintf(buf,"Fixed Function: %d, VertexBlend %d\n",
+ boardState.m_UsingFixedFunction, m_DynamicState.m_VertexBlend );
+ Plat_DebugString(buf);
+
+ sprintf(buf,"Pass Vertex Usage: %llx Pixel Shader %p Vertex Shader %p\n",
+ boardShaderState.m_VertexUsage, ShaderManager()->GetCurrentPixelShader(),
+ ShaderManager()->GetCurrentVertexShader() );
+ Plat_DebugString(buf);
+
+ // REGRESSED!!!!
+ /*
+ D3DXMATRIX* m = &GetTransform(MATERIAL_MODEL);
+ sprintf(buf,"WorldMat [%4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f]\n",
+ m->m[0][0], m->m[0][1], m->m[0][2], m->m[0][3],
+ m->m[1][0], m->m[1][1], m->m[1][2], m->m[1][3],
+ m->m[2][0], m->m[2][1], m->m[2][2], m->m[2][3],
+ m->m[3][0], m->m[3][1], m->m[3][2], m->m[3][3] );
+ Plat_DebugString(buf);
+
+ m = &GetTransform(MATERIAL_MODEL + 1);
+ sprintf(buf,"WorldMat2 [%4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f]\n",
+ m->m[0][0], m->m[0][1], m->m[0][2], m->m[0][3],
+ m->m[1][0], m->m[1][1], m->m[1][2], m->m[1][3],
+ m->m[2][0], m->m[2][1], m->m[2][2], m->m[2][3],
+ m->m[3][0], m->m[3][1], m->m[3][2], m->m[3][3] );
+ Plat_DebugString(buf);
+
+ m = &GetTransform(MATERIAL_VIEW);
+ sprintf(buf,"ViewMat [%4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f]\n",
+ m->m[0][0], m->m[0][1], m->m[0][2],
+ m->m[1][0], m->m[1][1], m->m[1][2],
+ m->m[2][0], m->m[2][1], m->m[2][2],
+ m->m[3][0], m->m[3][1], m->m[3][2] );
+ Plat_DebugString(buf);
+
+ m = &GetTransform(MATERIAL_PROJECTION);
+ sprintf(buf,"ProjMat [%4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f]\n",
+ m->m[0][0], m->m[0][1], m->m[0][2],
+ m->m[1][0], m->m[1][1], m->m[1][2],
+ m->m[2][0], m->m[2][1], m->m[2][2],
+ m->m[3][0], m->m[3][1], m->m[3][2] );
+ Plat_DebugString(buf);
+
+ for (i = 0; i < GetTextureStageCount(); ++i)
+ {
+ m = &GetTransform(MATERIAL_TEXTURE0 + i);
+ sprintf(buf,"TexMat%d [%4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f %4.3f]\n",
+ i, m->m[0][0], m->m[0][1], m->m[0][2],
+ m->m[1][0], m->m[1][1], m->m[1][2],
+ m->m[2][0], m->m[2][1], m->m[2][2],
+ m->m[3][0], m->m[3][1], m->m[3][2] );
+ Plat_DebugString(buf);
+ }
+ */
+
+ sprintf(buf,"Viewport (%d %d) [%d %d] %4.3f %4.3f\n",
+ m_DynamicState.m_Viewport.X, m_DynamicState.m_Viewport.Y,
+ m_DynamicState.m_Viewport.Width, m_DynamicState.m_Viewport.Height,
+ m_DynamicState.m_Viewport.MinZ, m_DynamicState.m_Viewport.MaxZ);
+ Plat_DebugString(buf);
+
+ for (i = 0; i < MAX_TEXTURE_STAGES; ++i)
+ {
+ sprintf(buf,"Stage %d :\n", i);
+ Plat_DebugString(buf);
+ sprintf(buf," Color Op: %d (%s) Color Arg1: %d (%s)",
+ boardState.m_TextureStage[i].m_ColorOp,
+ TextureOpToString( boardState.m_TextureStage[i].m_ColorOp ),
+ boardState.m_TextureStage[i].m_ColorArg1,
+ TextureArgToString( boardState.m_TextureStage[i].m_ColorArg1 ) );
+ Plat_DebugString(buf);
+ sprintf( buf, " Color Arg2: %d (%s)\n",
+ boardState.m_TextureStage[i].m_ColorArg2,
+ TextureArgToString( boardState.m_TextureStage[i].m_ColorArg2 ) );
+ Plat_DebugString(buf);
+ sprintf(buf," Alpha Op: %d (%s) Alpha Arg1: %d (%s)",
+ boardState.m_TextureStage[i].m_AlphaOp,
+ TextureOpToString( boardState.m_TextureStage[i].m_AlphaOp ),
+ boardState.m_TextureStage[i].m_AlphaArg1,
+ TextureArgToString( boardState.m_TextureStage[i].m_AlphaArg1 ) );
+ Plat_DebugString(buf);
+ sprintf(buf," Alpha Arg2: %d (%s)\n",
+ boardState.m_TextureStage[i].m_AlphaArg2,
+ TextureArgToString( boardState.m_TextureStage[i].m_AlphaArg2 ) );
+ Plat_DebugString(buf);
+ }
+
+ for ( int i = 0; i < MAX_SAMPLERS; ++i )
+ {
+ sprintf(buf," Texture Enabled: %d Bound Texture: %d UWrap: %d VWrap: %d\n",
+ SamplerState(i).m_TextureEnable, GetBoundTextureBindId( (Sampler_t)i ),
+ SamplerState(i).m_UTexWrap, SamplerState(i).m_VTexWrap );
+ Plat_DebugString(buf);
+ sprintf(buf," Mag Filter: %d Min Filter: %d Mip Filter: %d\n",
+ SamplerState(i).m_MagFilter, SamplerState(i).m_MinFilter,
+ SamplerState(i).m_MipFilter );
+ sprintf(buf," MaxMipLevel: %d\n", SamplerState(i).m_FinestMipmapLevel );
+ Plat_DebugString(buf);
+ }
+#else
+ Plat_DebugString("::SpewBoardState() Not Implemented Yet");
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Begin a render pass
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::BeginPass( StateSnapshot_t snapshot )
+{
+ LOCK_SHADERAPI();
+ VPROF("CShaderAPIDx8::BeginPass");
+ if (IsDeactivated())
+ return;
+
+ m_nCurrentSnapshot = snapshot;
+// Assert( m_pRenderMesh );
+ // FIXME: This only does anything with temp meshes, so don't bother yet for the new code.
+ if( m_pRenderMesh )
+ {
+ m_pRenderMesh->BeginPass( );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Render da polygon!
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::RenderPass( int nPass, int nPassCount )
+{
+ if ( IsDeactivated() )
+ return;
+
+ Assert( m_nCurrentSnapshot != -1 );
+// Assert( m_pRenderMesh ); MESHFIXME
+
+ m_TransitionTable.UseSnapshot( m_nCurrentSnapshot );
+ CommitPerPassStateChanges( m_nCurrentSnapshot );
+
+ // Make sure that we bound a texture for every stage that is enabled
+ // NOTE: not enabled/finished yet... see comment in CShaderAPIDx8::ApplyTextureEnable
+// int nSampler;
+// for ( nSampler = 0; nSampler < g_pHardwareConfig->GetSamplerCount(); nSampler++ )
+// {
+// if ( SamplerState( nSampler ).m_TextureEnable )
+// {
+// }
+// }
+
+#ifdef DEBUG_BOARD_STATE
+ // Spew out render state...
+ if ( m_pMaterial->PerformDebugTrace() )
+ {
+ SpewBoardState();
+ }
+#endif
+
+#ifdef TEST_CACHE_LOCKS
+ g_pDataCache->Flush();
+#endif
+
+// Assert( m_pRenderMesh ); MESHFIXME
+ if ( m_pRenderMesh )
+ {
+ m_pRenderMesh->RenderPass();
+ }
+ else
+ {
+ MeshMgr()->RenderPassWithVertexAndIndexBuffers();
+ }
+ m_nCurrentSnapshot = -1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Matrix mode
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::MatrixMode( MaterialMatrixMode_t matrixMode )
+{
+ // NOTE!!!!!!
+ // The only time that m_MatrixMode is used is for texture matrices. Do not use
+ // it for anything else unless you change this code!
+ if ( matrixMode >= MATERIAL_TEXTURE0 && matrixMode <= MATERIAL_TEXTURE7 )
+ {
+ m_MatrixMode = ( D3DTRANSFORMSTATETYPE )( matrixMode - MATERIAL_TEXTURE0 + D3DTS_TEXTURE0 );
+ }
+ else
+ {
+ m_MatrixMode = (D3DTRANSFORMSTATETYPE)-1;
+ }
+
+ m_CurrStack = GetMatrixStack( matrixMode );
+}
+
+//-----------------------------------------------------------------------------
+// the current camera position in world space.
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::GetWorldSpaceCameraPosition( float* pPos ) const
+{
+ memcpy( pPos, m_WorldSpaceCameraPositon.Base(), sizeof( float[3] ) );
+}
+
+void CShaderAPIDx8::CacheWorldSpaceCameraPosition()
+{
+ D3DXMATRIX& view = GetTransform(MATERIAL_VIEW);
+ m_WorldSpaceCameraPositon[0] =
+ -( view( 3, 0 ) * view( 0, 0 ) +
+ view( 3, 1 ) * view( 0, 1 ) +
+ view( 3, 2 ) * view( 0, 2 ) );
+ m_WorldSpaceCameraPositon[1] =
+ -( view( 3, 0 ) * view( 1, 0 ) +
+ view( 3, 1 ) * view( 1, 1 ) +
+ view( 3, 2 ) * view( 1, 2 ) );
+ m_WorldSpaceCameraPositon[2] =
+ -( view( 3, 0 ) * view( 2, 0 ) +
+ view( 3, 1 ) * view( 2, 1 ) +
+ view( 3, 2 ) * view( 2, 2 ) );
+ m_WorldSpaceCameraPositon[3] = 1.0f;
+
+ // Protect against zero, as some pixel shaders will divide by this in CalcWaterFogAlpha() in common_ps_fxc.h
+ if ( fabs( m_WorldSpaceCameraPositon[2] ) <= 0.00001f )
+ {
+ m_WorldSpaceCameraPositon[2] = 0.01f;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Computes a matrix which includes the poly offset given an initial projection matrix
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::ComputePolyOffsetMatrix( const D3DXMATRIX& matProjection, D3DXMATRIX &matProjectionOffset )
+{
+ // We never need to do this on hardware that can handle zbias
+ if ( g_pHardwareConfig->Caps().m_ZBiasAndSlopeScaledDepthBiasSupported )
+ return;
+
+ float offsetVal =
+ -1.0f * (m_DesiredState.m_Viewport.MaxZ - m_DesiredState.m_Viewport.MinZ) /
+ 16384.0f;
+
+ D3DXMATRIX offset;
+ D3DXMatrixTranslation( &offset, 0.0f, 0.0f, offsetVal );
+ D3DXMatrixMultiply( &matProjectionOffset, &matProjection, &offset );
+}
+
+
+//-----------------------------------------------------------------------------
+// Caches off the poly-offset projection matrix
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::CachePolyOffsetProjectionMatrix()
+{
+ ComputePolyOffsetMatrix( GetTransform(MATERIAL_PROJECTION), m_CachedPolyOffsetProjectionMatrix );
+}
+
+
+//-----------------------------------------------------------------------------
+// Performs a flush on the matrix state if necessary
+//-----------------------------------------------------------------------------
+bool CShaderAPIDx8::MatrixIsChanging( TransformType_t type )
+{
+ if ( IsDeactivated() )
+ {
+ return false;
+ }
+
+ // early out if the transform is already one of our standard types
+ if ((type != TRANSFORM_IS_GENERAL) && (type == m_DynamicState.m_TransformType[m_CurrStack]))
+ return false;
+
+ // Only flush state if we're changing something other than a texture transform
+ int textureMatrix = m_CurrStack - MATERIAL_TEXTURE0;
+ if (( textureMatrix < 0 ) || (textureMatrix >= NUM_TEXTURE_TRANSFORMS))
+ FlushBufferedPrimitivesInternal();
+
+ return true;
+}
+
+void CShaderAPIDx8::SetTextureTransformDimension( TextureStage_t textureMatrix, int dimension, bool projected )
+{
+ D3DTEXTURETRANSFORMFLAGS textureTransformFlags = ( D3DTEXTURETRANSFORMFLAGS )dimension;
+ if( projected )
+ {
+ Assert( sizeof( int ) == sizeof( D3DTEXTURETRANSFORMFLAGS ) );
+ ( *( int * )&textureTransformFlags ) |= D3DTTFF_PROJECTED;
+ }
+
+ if (TextureStage(textureMatrix).m_TextureTransformFlags != textureTransformFlags )
+ {
+ SetTextureStageState( textureMatrix, D3DTSS_TEXTURETRANSFORMFLAGS, textureTransformFlags );
+ TextureStage(textureMatrix).m_TextureTransformFlags = textureTransformFlags;
+ }
+}
+
+void CShaderAPIDx8::DisableTextureTransform( TextureStage_t textureMatrix )
+{
+ if (TextureStage(textureMatrix).m_TextureTransformFlags != D3DTTFF_DISABLE )
+ {
+ SetTextureStageState( textureMatrix, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
+ TextureStage(textureMatrix).m_TextureTransformFlags = D3DTTFF_DISABLE;
+ }
+}
+
+void CShaderAPIDx8::SetBumpEnvMatrix( TextureStage_t textureStage, float m00, float m01, float m10, float m11 )
+{
+ TextureStageState_t &textureStageState = TextureStage( textureStage );
+
+ if( textureStageState.m_BumpEnvMat00 != m00 ||
+ textureStageState.m_BumpEnvMat01 != m01 ||
+ textureStageState.m_BumpEnvMat10 != m10 ||
+ textureStageState.m_BumpEnvMat11 != m11 )
+ {
+ SetTextureStageState( textureStage, D3DTSS_BUMPENVMAT00, *( ( LPDWORD ) (&m00) ) );
+ SetTextureStageState( textureStage, D3DTSS_BUMPENVMAT01, *( ( LPDWORD ) (&m01) ) );
+ SetTextureStageState( textureStage, D3DTSS_BUMPENVMAT10, *( ( LPDWORD ) (&m10) ) );
+ SetTextureStageState( textureStage, D3DTSS_BUMPENVMAT11, *( ( LPDWORD ) (&m11) ) );
+ textureStageState.m_BumpEnvMat00 = m00;
+ textureStageState.m_BumpEnvMat01 = m01;
+ textureStageState.m_BumpEnvMat10 = m10;
+ textureStageState.m_BumpEnvMat11 = m11;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Sets the actual matrix state
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::UpdateMatrixTransform( TransformType_t type )
+{
+ int textureMatrix = m_CurrStack - MATERIAL_TEXTURE0;
+ if (( textureMatrix >= 0 ) && (textureMatrix < NUM_TEXTURE_TRANSFORMS))
+ {
+ // NOTE: Flush shouldn't happen here because we
+ // expect that texture transforms will be set within the shader
+
+ // FIXME: We only want to use D3DTTFF_COUNT3 for cubemaps
+ // D3DTFF_COUNT2 is used for non-cubemaps. Of course, if there's
+ // no performance penalty for COUNT3, we should just use that.
+ D3DTEXTURETRANSFORMFLAGS transformFlags;
+ transformFlags = (type == TRANSFORM_IS_IDENTITY) ? D3DTTFF_DISABLE : D3DTTFF_COUNT3;
+
+ if (TextureStage(textureMatrix).m_TextureTransformFlags != transformFlags )
+ {
+ SetTextureStageState( textureMatrix, D3DTSS_TEXTURETRANSFORMFLAGS, transformFlags );
+ TextureStage(textureMatrix).m_TextureTransformFlags = transformFlags;
+ }
+ }
+
+ m_DynamicState.m_TransformType[m_CurrStack] = type;
+ m_DynamicState.m_TransformChanged[m_CurrStack] = STATE_CHANGED;
+
+#ifdef _DEBUG
+ // Store off the board state
+ D3DXMATRIX *pSrc = &GetTransform(m_CurrStack);
+ D3DXMATRIX *pDst = &m_DynamicState.m_Transform[m_CurrStack];
+// Assert( *pSrc != *pDst );
+ memcpy( pDst, pSrc, sizeof(D3DXMATRIX) );
+#endif
+
+ if ( m_CurrStack == MATERIAL_VIEW )
+ {
+ CacheWorldSpaceCameraPosition();
+ }
+
+ if ( !IsX360() && m_CurrStack == MATERIAL_PROJECTION )
+ {
+ CachePolyOffsetProjectionMatrix();
+ }
+
+ // Any time the view or projection matrix changes, the user clip planes need recomputing....
+ // Assuming we're not overriding the user clip transform
+ if ( ( m_CurrStack == MATERIAL_PROJECTION ) ||
+ ( ( m_CurrStack == MATERIAL_VIEW ) && ( !m_DynamicState.m_bUserClipTransformOverride ) ) )
+ {
+ MarkAllUserClipPlanesDirty();
+ }
+
+ // Set the state if it's a texture transform
+ if ( (m_CurrStack >= MATERIAL_TEXTURE0) && (m_CurrStack <= MATERIAL_TEXTURE7) )
+ {
+ SetTransform( m_MatrixMode, &GetTransform(m_CurrStack) );
+ }
+}
+
+
+//--------------------------------------------------------------------------------
+// deformations
+//--------------------------------------------------------------------------------
+void CShaderAPIDx8::PushDeformation( DeformationBase_t const *pDef )
+{
+ Assert( m_pDeformationStackPtr > m_DeformationStack );
+ --m_pDeformationStackPtr;
+ m_pDeformationStackPtr->m_nDeformationType = pDef->m_eType;
+
+ switch( pDef->m_eType )
+ {
+ case DEFORMATION_CLAMP_TO_BOX_IN_WORLDSPACE:
+ {
+ BoxDeformation_t const *pBox = reinterpret_cast< const BoxDeformation_t *>( pDef );
+ m_pDeformationStackPtr->m_nNumParameters = 16;
+ memcpy( m_pDeformationStackPtr->m_flDeformationParameters, &( pBox->m_SourceMins.x ), 16 * sizeof( float ) );
+ break;
+ }
+ break;
+
+ default:
+ Assert( 0 );
+ }
+}
+
+
+void CShaderAPIDx8::PopDeformation( )
+{
+ Assert( m_pDeformationStackPtr != m_DeformationStack + DEFORMATION_STACK_DEPTH );
+ ++m_pDeformationStackPtr;
+}
+
+int CShaderAPIDx8::GetNumActiveDeformations( void ) const
+{
+ return ( m_DeformationStack + DEFORMATION_STACK_DEPTH ) - m_pDeformationStackPtr;
+}
+
+
+// for shaders to set vertex shader constants. returns a packed state which can be used to set the dynamic combo
+int CShaderAPIDx8::GetPackedDeformationInformation( int nMaskOfUnderstoodDeformations,
+ float *pConstantValuesOut,
+ int nBufferSize,
+ int nMaximumDeformations,
+ int *pDefCombosOut ) const
+{
+ int nCombosFound = 0;
+ memset( pDefCombosOut, 0, sizeof( pDefCombosOut[0] ) * nMaximumDeformations );
+ size_t nRemainingBufferSize = nBufferSize;
+
+ for( const Deformation_t *i = m_DeformationStack + DEFORMATION_STACK_DEPTH -1; i >= m_pDeformationStackPtr; i-- )
+ {
+ int nFloatsOut = 4 * ( ( i->m_nNumParameters + 3 )>> 2 );
+ if (
+ ( ( 1 << i->m_nDeformationType ) & nMaskOfUnderstoodDeformations ) &&
+ ( nRemainingBufferSize >= ( nFloatsOut * sizeof( float ) ) ) )
+ {
+ memcpy( pConstantValuesOut, i->m_flDeformationParameters, nFloatsOut * sizeof( float ) );
+ pConstantValuesOut += nFloatsOut;
+ nRemainingBufferSize -= nFloatsOut * sizeof( float );
+ ( *pDefCombosOut++ ) = i->m_nDeformationType;
+ nCombosFound++;
+ }
+ }
+ return nCombosFound;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Matrix stack operations
+//-----------------------------------------------------------------------------
+
+void CShaderAPIDx8::PushMatrix()
+{
+ // NOTE: No matrix transform update needed here.
+ m_pMatrixStack[m_CurrStack]->Push();
+}
+
+void CShaderAPIDx8::PopMatrix()
+{
+ if (MatrixIsChanging())
+ {
+ m_pMatrixStack[m_CurrStack]->Pop();
+ UpdateMatrixTransform();
+ }
+}
+
+void CShaderAPIDx8::LoadIdentity( )
+{
+ if (MatrixIsChanging(TRANSFORM_IS_IDENTITY))
+ {
+ m_pMatrixStack[m_CurrStack]->LoadIdentity( );
+ UpdateMatrixTransform( TRANSFORM_IS_IDENTITY );
+ }
+}
+
+void CShaderAPIDx8::LoadCameraToWorld( )
+{
+ if (MatrixIsChanging(TRANSFORM_IS_CAMERA_TO_WORLD))
+ {
+ // could just use the transpose instead, if we know there's no scale
+ float det;
+ D3DXMATRIX inv;
+ D3DXMatrixInverse( &inv, &det, &GetTransform(MATERIAL_VIEW) );
+
+ // Kill translation
+ inv.m[3][0] = inv.m[3][1] = inv.m[3][2] = 0.0f;
+
+ m_pMatrixStack[m_CurrStack]->LoadMatrix( &inv );
+ UpdateMatrixTransform( TRANSFORM_IS_CAMERA_TO_WORLD );
+ }
+}
+
+void CShaderAPIDx8::LoadMatrix( float *m )
+{
+ // Check for identity...
+ if ( (fabs(m[0] - 1.0f) < 1e-3) && (fabs(m[5] - 1.0f) < 1e-3) && (fabs(m[10] - 1.0f) < 1e-3) && (fabs(m[15] - 1.0f) < 1e-3) &&
+ (fabs(m[1]) < 1e-3) && (fabs(m[2]) < 1e-3) && (fabs(m[3]) < 1e-3) &&
+ (fabs(m[4]) < 1e-3) && (fabs(m[6]) < 1e-3) && (fabs(m[7]) < 1e-3) &&
+ (fabs(m[8]) < 1e-3) && (fabs(m[9]) < 1e-3) && (fabs(m[11]) < 1e-3) &&
+ (fabs(m[12]) < 1e-3) && (fabs(m[13]) < 1e-3) && (fabs(m[14]) < 1e-3) )
+ {
+ LoadIdentity();
+ return;
+ }
+
+ if (MatrixIsChanging())
+ {
+ m_pMatrixStack[m_CurrStack]->LoadMatrix( (D3DXMATRIX*)m );
+ UpdateMatrixTransform();
+ }
+}
+
+void CShaderAPIDx8::LoadBoneMatrix( int boneIndex, const float *m )
+{
+ if ( IsDeactivated() )
+ return;
+
+ memcpy( m_boneMatrix[boneIndex].Base(), m, sizeof(float)*12 );
+ if ( boneIndex > m_maxBoneLoaded )
+ {
+ m_maxBoneLoaded = boneIndex;
+ }
+ if ( boneIndex == 0 )
+ {
+ MatrixMode( MATERIAL_MODEL );
+ VMatrix transposeMatrix;
+ transposeMatrix.Init( *(matrix3x4_t *)m );
+ MatrixTranspose( transposeMatrix, transposeMatrix );
+ LoadMatrix( (float*)transposeMatrix.m );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Commits morph target factors
+//-----------------------------------------------------------------------------
+static void CommitFlexWeights( IDirect3DDevice9 *pDevice, const DynamicState_t &desiredState,
+ DynamicState_t &currentState, bool bForce )
+{
+ if ( IsX360() )
+ {
+ // not supporting for 360
+ return;
+ }
+
+ CommitVertexShaderConstantRange( pDevice, desiredState, currentState, bForce,
+ VERTEX_SHADER_FLEX_WEIGHTS, VERTEX_SHADER_MAX_FLEX_WEIGHT_COUNT );
+}
+
+void CShaderAPIDx8::SetFlexWeights( int nFirstWeight, int nCount, const MorphWeight_t* pWeights )
+{
+ if ( IsX360() )
+ {
+ // not supported for 360
+ return;
+ }
+
+ LOCK_SHADERAPI();
+ if ( g_pHardwareConfig->Caps().m_NumVertexShaderConstants < VERTEX_SHADER_FLEX_WEIGHTS + VERTEX_SHADER_MAX_FLEX_WEIGHT_COUNT )
+ return;
+
+ if ( nFirstWeight + nCount > VERTEX_SHADER_MAX_FLEX_WEIGHT_COUNT )
+ {
+ Warning( "Attempted to set too many flex weights! Max is %d\n", VERTEX_SHADER_MAX_FLEX_WEIGHT_COUNT );
+ nCount = VERTEX_SHADER_MAX_FLEX_WEIGHT_COUNT - nFirstWeight;
+ }
+
+ if ( nCount <= 0 )
+ return;
+
+ float *pDest = m_DesiredState.m_pVectorVertexShaderConstant[ VERTEX_SHADER_FLEX_WEIGHTS + nFirstWeight ].Base();
+ memcpy( pDest, pWeights, nCount * sizeof(MorphWeight_t) );
+
+ ADD_COMMIT_FUNC( COMMIT_PER_DRAW, COMMIT_VERTEX_SHADER, CommitFlexWeights );
+}
+
+void CShaderAPIDx8::MultMatrix( float *m )
+{
+ if (MatrixIsChanging())
+ {
+ m_pMatrixStack[m_CurrStack]->MultMatrix( (D3DXMATRIX*)m );
+ UpdateMatrixTransform();
+ }
+}
+
+void CShaderAPIDx8::MultMatrixLocal( float *m )
+{
+ if (MatrixIsChanging())
+ {
+ m_pMatrixStack[m_CurrStack]->MultMatrixLocal( (D3DXMATRIX*)m );
+ UpdateMatrixTransform();
+ }
+}
+
+void CShaderAPIDx8::Rotate( float angle, float x, float y, float z )
+{
+ if (MatrixIsChanging())
+ {
+ D3DXVECTOR3 axis( x, y, z );
+ m_pMatrixStack[m_CurrStack]->RotateAxisLocal( &axis, M_PI * angle / 180.0f );
+ UpdateMatrixTransform();
+ }
+}
+
+void CShaderAPIDx8::Translate( float x, float y, float z )
+{
+ if (MatrixIsChanging())
+ {
+ m_pMatrixStack[m_CurrStack]->TranslateLocal( x, y, z );
+ UpdateMatrixTransform();
+ }
+}
+
+void CShaderAPIDx8::Scale( float x, float y, float z )
+{
+ if (MatrixIsChanging())
+ {
+ m_pMatrixStack[m_CurrStack]->ScaleLocal( x, y, z );
+ UpdateMatrixTransform();
+ }
+}
+
+void CShaderAPIDx8::ScaleXY( float x, float y )
+{
+ if (MatrixIsChanging())
+ {
+ m_pMatrixStack[m_CurrStack]->ScaleLocal( x, y, 1.0f );
+ UpdateMatrixTransform();
+ }
+}
+
+void CShaderAPIDx8::Ortho( double left, double top, double right, double bottom, double zNear, double zFar )
+{
+ if (MatrixIsChanging())
+ {
+ D3DXMATRIX matrix;
+
+ // FIXME: This is being used incorrectly! Should read:
+ // D3DXMatrixOrthoOffCenterRH( &matrix, left, right, bottom, top, zNear, zFar );
+ // Which is certainly why we need these extra -1 scales in y. Bleah
+
+ // NOTE: The camera can be imagined as the following diagram:
+ // /z
+ // /
+ // /____ x Z is going into the screen
+ // |
+ // |
+ // |y
+ //
+ // (0,0,z) represents the upper-left corner of the screen.
+ // Our projection transform needs to transform from this space to a LH coordinate
+ // system that looks thusly:
+ //
+ // y| /z
+ // | /
+ // |/____ x Z is going into the screen
+ //
+ // Where x,y lies between -1 and 1, and z lies from 0 to 1
+ // This is because the viewport transformation from projection space to pixels
+ // introduces a -1 scale in the y coordinates
+// D3DXMatrixOrthoOffCenterLH( &matrix, left, right, bottom, top, zNear, zFar );
+
+ D3DXMatrixOrthoOffCenterRH( &matrix, left, right, top, bottom, zNear, zFar );
+ m_pMatrixStack[m_CurrStack]->MultMatrixLocal(&matrix);
+ Assert( m_CurrStack == MATERIAL_PROJECTION );
+ UpdateMatrixTransform();
+ }
+}
+
+void CShaderAPIDx8::PerspectiveX( double fovx, double aspect, double zNear, double zFar )
+{
+ if (MatrixIsChanging())
+ {
+ float width = 2 * zNear * tan( fovx * M_PI / 360.0 );
+ float height = width / aspect;
+ Assert( m_CurrStack == MATERIAL_PROJECTION );
+ D3DXMATRIX rh;
+ D3DXMatrixPerspectiveRH( &rh, width, height, zNear, zFar );
+ m_pMatrixStack[m_CurrStack]->MultMatrixLocal(&rh);
+ UpdateMatrixTransform();
+ }
+}
+
+void CShaderAPIDx8::PerspectiveOffCenterX( double fovx, double aspect, double zNear, double zFar, double bottom, double top, double left, double right )
+{
+ if (MatrixIsChanging())
+ {
+ float width = 2 * zNear * tan( fovx * M_PI / 360.0 );
+ float height = width / aspect;
+
+ // bottom, top, left, right are 0..1 so convert to -1..1
+ float flFrontPlaneLeft = -(width/2.0f) * (1.0f - left) + left * (width/2.0f);
+ float flFrontPlaneRight = -(width/2.0f) * (1.0f - right) + right * (width/2.0f);
+ float flFrontPlaneBottom = -(height/2.0f) * (1.0f - bottom) + bottom * (height/2.0f);
+ float flFrontPlaneTop = -(height/2.0f) * (1.0f - top) + top * (height/2.0f);
+
+ Assert( m_CurrStack == MATERIAL_PROJECTION );
+ D3DXMATRIX rh;
+ D3DXMatrixPerspectiveOffCenterRH( &rh, flFrontPlaneLeft, flFrontPlaneRight, flFrontPlaneBottom, flFrontPlaneTop, zNear, zFar );
+ m_pMatrixStack[m_CurrStack]->MultMatrixLocal(&rh);
+ UpdateMatrixTransform();
+ }
+}
+
+void CShaderAPIDx8::PickMatrix( int x, int y, int width, int height )
+{
+ if (MatrixIsChanging())
+ {
+ Assert( m_CurrStack == MATERIAL_PROJECTION );
+
+ // This is going to create a matrix to append to the standard projection.
+ // Projection space goes from -1 to 1 in x and y. This matrix we append
+ // will transform the pick region to -1 to 1 in projection space
+ ShaderViewport_t viewport;
+ GetViewports( &viewport, 1 );
+
+ int vx = viewport.m_nTopLeftX;
+ int vy = viewport.m_nTopLeftX;
+ int vwidth = viewport.m_nWidth;
+ int vheight = viewport.m_nHeight;
+
+ // Compute the location of the pick region in projection space...
+ float px = 2.0 * (float)(x - vx) / (float)vwidth - 1;
+ float py = 2.0 * (float)(y - vy)/ (float)vheight - 1;
+ float pw = 2.0 * (float)width / (float)vwidth;
+ float ph = 2.0 * (float)height / (float)vheight;
+
+ // we need to translate (px, py) to the origin
+ // and scale so (pw,ph) -> (2, 2)
+ D3DXMATRIX matrix;
+ D3DXMatrixIdentity( &matrix );
+ matrix.m[0][0] = 2.0 / pw;
+ matrix.m[1][1] = 2.0 / ph;
+ matrix.m[3][0] = -2.0 * px / pw;
+ matrix.m[3][1] = -2.0 * py / ph;
+
+ m_pMatrixStack[m_CurrStack]->MultMatrixLocal(&matrix);
+ UpdateMatrixTransform();
+ }
+}
+
+void CShaderAPIDx8::GetMatrix( MaterialMatrixMode_t matrixMode, float *dst )
+{
+ memcpy( dst, (void*)(FLOAT*)GetTransform(matrixMode), sizeof(D3DXMATRIX) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Did a transform change?
+//-----------------------------------------------------------------------------
+inline bool CShaderAPIDx8::VertexShaderTransformChanged( int i )
+{
+ return (m_DynamicState.m_TransformChanged[i] & STATE_CHANGED_VERTEX_SHADER) != 0;
+}
+
+inline bool CShaderAPIDx8::FixedFunctionTransformChanged( int i )
+{
+ return (m_DynamicState.m_TransformChanged[i] & STATE_CHANGED_FIXED_FUNCTION) != 0;
+}
+
+
+const D3DXMATRIX &CShaderAPIDx8::GetProjectionMatrix( void )
+{
+ bool bUsingZBiasProjectionMatrix =
+ !g_pHardwareConfig->Caps().m_ZBiasAndSlopeScaledDepthBiasSupported &&
+ ( m_TransitionTable.CurrentSnapshot() != -1 ) &&
+ m_TransitionTable.CurrentShadowState() &&
+ m_TransitionTable.CurrentShadowState()->m_ZBias;
+
+ if ( !m_DynamicState.m_FastClipEnabled )
+ {
+ if ( bUsingZBiasProjectionMatrix )
+ return m_CachedPolyOffsetProjectionMatrix;
+
+ return GetTransform( MATERIAL_PROJECTION );
+ }
+
+ if ( bUsingZBiasProjectionMatrix )
+ return m_CachedFastClipPolyOffsetProjectionMatrix;
+
+ return m_CachedFastClipProjectionMatrix;
+}
+
+
+//-----------------------------------------------------------------------------
+// Workaround hack for visualization of selection mode
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::SetupSelectionModeVisualizationState()
+{
+ Dx9Device()->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
+
+ D3DXMATRIX ident;
+ D3DXMatrixIdentity( &ident );
+ SetTransform( D3DTS_WORLD, &ident );
+ SetTransform( D3DTS_VIEW, &ident );
+ SetTransform( D3DTS_PROJECTION, &ident );
+
+ if ( g_pHardwareConfig->Caps().m_SupportsPixelShaders )
+ {
+ SetVertexShaderConstant( VERTEX_SHADER_VIEWPROJ, ident, 4 );
+ SetVertexShaderConstant( VERTEX_SHADER_MODELVIEWPROJ, ident, 4 );
+ float *pRowTwo = (float *)ident + 8;
+ SetVertexShaderConstant( VERTEX_SHADER_MODELVIEWPROJ_THIRD_ROW, pRowTwo, 1 ); // Row two of an identity matrix
+ SetVertexShaderConstant( VERTEX_SHADER_MODEL, ident, 3 * NUM_MODEL_TRANSFORMS );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Set view transforms
+//-----------------------------------------------------------------------------
+
+static void printmat4x4( char *label, float *m00 )
+{
+ // print label..
+ // fetch 4 from row, print as a row
+ // fetch 4 from column, print as a row
+
+#ifdef DX_TO_GL_ABSTRACTION
+ float row[4];
+ float col[4];
+
+ GLMPRINTF(("-M- -- %s --", label ));
+ for( int n=0; n<4; n++ )
+ {
+ // extract row and column floats
+ for( int i=0; i<4;i++)
+ {
+ row[i] = m00[(n*4)+i];
+ col[i] = m00[(i*4)+n];
+ }
+ GLMPRINTF(( "-M- [ %7.4f %7.4f %7.4f %7.4f ] T=> [ %7.4f %7.4f %7.4f %7.4f ]",
+ row[0],row[1],row[2],row[3],
+ col[0],col[1],col[2],col[3]
+ ));
+ }
+ GLMPRINTF(("-M-"));
+#endif
+}
+
+void CShaderAPIDx8::SetVertexShaderViewProj()
+{
+ //GLM_FUNC;
+ //GLMPRINTF(( ">-M- SetVertexShaderViewProj" ));
+
+ if (g_pHardwareConfig->Caps().m_SupportsPixelShaders)
+ {
+ D3DXMATRIX transpose;
+ if(0)
+ {
+ transpose = GetTransform(MATERIAL_VIEW) * GetProjectionMatrix();
+ D3DXMatrixTranspose( &transpose, &transpose );
+ }
+ else
+ {
+ // show work
+ D3DXMATRIX matView,matProj;
+
+ matView = GetTransform(MATERIAL_VIEW);
+ matProj = GetProjectionMatrix();
+ transpose = matView * matProj;
+
+ //printmat4x4( "matView", (float*)&matView );
+ //printmat4x4( "matProj", (float*)&matProj );
+ //printmat4x4( "result (view * proj) pre-transpose", (float*)&transpose );
+
+ D3DXMatrixTranspose( &transpose, &transpose );
+
+ #if 0 // turned off while we try to do fixup-Y in shader translate
+ if (IsPosix()) // flip all shader projection matrices for Y on GL since you can't have an upside-down viewport specification
+ {
+ // flip Y
+ transpose._21 *= -1.0f;
+ transpose._22 *= -1.0f;
+ transpose._23 *= -1.0f;
+ transpose._24 *= -1.0f;
+ }
+ #endif
+
+ //printmat4x4( "result (view * proj) post-transpose", (float*)&transpose );
+ }
+
+
+ SetVertexShaderConstant( VERTEX_SHADER_VIEWPROJ, transpose, 4 );
+
+ // If we're doing FastClip, the above viewproj matrix won't work well for
+ // vertex shaders which compute projPos.z, hence we'll compute a more useful
+ // viewproj and put the third row of it in another constant
+ transpose = GetTransform( MATERIAL_VIEW ) * GetTransform( MATERIAL_PROJECTION ); // Get the non-FastClip projection matrix
+ D3DXMatrixTranspose( &transpose, &transpose );
+
+ float *pRowTwo = (float *)transpose + 8;
+ SetVertexShaderConstant( VERTEX_SHADER_VIEWPROJ_THIRD_ROW, pRowTwo, 1 );
+ }
+ //GLMPRINTF(( "<-M- SetVertexShaderViewProj" ));
+}
+
+void CShaderAPIDx8::SetVertexShaderModelViewProjAndModelView( void )
+{
+ //GLM_FUNC;
+ //GLMPRINTF(( ">-M- SetVertexShaderModelViewProjAndModelView" ));
+
+ if (g_pHardwareConfig->Caps().m_SupportsPixelShaders)
+ {
+ D3DXMATRIX modelView, transpose;
+
+ if (0)
+ {
+ D3DXMatrixMultiply( &modelView, &GetTransform(MATERIAL_MODEL), &GetTransform(MATERIAL_VIEW) );
+ D3DXMatrixMultiply( &transpose, &modelView, &GetProjectionMatrix() );
+ }
+ else
+ {
+ // show work
+ D3DXMATRIX matView,matProj,matModel;
+
+ matModel = GetTransform(MATERIAL_MODEL);
+ matView = GetTransform(MATERIAL_VIEW);
+ matProj = GetProjectionMatrix();
+
+ D3DXMatrixMultiply( &modelView, &matModel, &matView );
+ D3DXMatrixMultiply( &transpose, &modelView, &matProj );
+
+ //printmat4x4( "matModel", (float*)&matModel );
+ //printmat4x4( "matView", (float*)&matView );
+ //printmat4x4( "matProj", (float*)&matProj );
+ //printmat4x4( "result (model * view * proj) pre-transpose", (float*)&transpose );
+ }
+
+ D3DXMatrixTranspose( &transpose, &transpose );
+
+ #if 0 // turned off while we try to do fixup-Y in shader translate
+ if (IsPosix()) // flip all shader projection matrices for Y on GL since you can't have an upside-down viewport specification
+ {
+ // flip Y
+ transpose._21 *= -1.0f;
+ transpose._22 *= -1.0f;
+ transpose._23 *= -1.0f;
+ transpose._24 *= -1.0f;
+ }
+ #endif
+
+ SetVertexShaderConstant( VERTEX_SHADER_MODELVIEWPROJ, transpose, 4 );
+
+ // If we're doing FastClip, the above modelviewproj matrix won't work well for
+ // vertex shaders which compute projPos.z, hence we'll compute a more useful
+ // modelviewproj and put the third row of it in another constant
+ D3DXMatrixMultiply( &transpose, &modelView, &GetTransform( MATERIAL_PROJECTION ) ); // Get the non-FastClip projection matrix
+ D3DXMatrixTranspose( &transpose, &transpose );
+
+ float *pRowTwo = (float *)transpose + 8;
+ SetVertexShaderConstant( VERTEX_SHADER_MODELVIEWPROJ_THIRD_ROW, pRowTwo, 1 );
+ }
+
+ //GLMPRINTF(( "<-M- SetVertexShaderModelViewProjAndModelView" ));
+}
+
+void CShaderAPIDx8::UpdateVertexShaderMatrix( int iMatrix )
+{
+ //GLM_FUNC;
+ if ( iMatrix == 0 )
+ {
+ int matrix = MATERIAL_MODEL;
+ if (VertexShaderTransformChanged(matrix))
+ {
+ int vertexShaderConstant = VERTEX_SHADER_MODEL + iMatrix * 3;
+
+ // Put the transform into the vertex shader constants...
+ D3DXMATRIX transpose;
+ D3DXMatrixTranspose( &transpose, &GetTransform(matrix) );
+ SetVertexShaderConstant( vertexShaderConstant, transpose, 3 );
+
+ // clear the change flag
+ m_DynamicState.m_TransformChanged[matrix] &= ~STATE_CHANGED_VERTEX_SHADER;
+ }
+ }
+ else
+ {
+ SetVertexShaderConstant( VERTEX_SHADER_MODEL + iMatrix, m_boneMatrix[iMatrix].Base(), 3 );
+ }
+}
+
+
+void CShaderAPIDx8::SetVertexShaderStateSkinningMatrices()
+{
+ //GLM_FUNC;
+ // casting from 4x3 matrices to a 4x4 D3DXMATRIX, need 4 floats of overflow
+ float results[12+4];
+
+ // get the first one from the MATERIAL_MODEL matrix stack
+ D3DXMatrixTranspose( (D3DXMATRIX *)&results[0], &GetTransform( MATERIAL_MODEL ) );
+ memcpy( m_boneMatrix[0].Base(), results, 12 * sizeof(float) );
+
+ m_maxBoneLoaded++;
+ int matricesLoaded = max( 1, m_maxBoneLoaded );
+ m_maxBoneLoaded = 0;
+
+ m_DynamicState.m_TransformChanged[MATERIAL_MODEL] &= ~STATE_CHANGED_VERTEX_SHADER;
+ SetVertexShaderConstant( VERTEX_SHADER_MODEL, m_boneMatrix[0].Base(), matricesLoaded * 3, true );
+
+ // ###OSX### punting on OSX for now
+#if defined( DX_TO_GL_ABSTRACTION ) && !defined( OSX )
+ Dx9Device()->SetMaxUsedVertexShaderConstantsHint( VERTEX_SHADER_MODEL + ( matricesLoaded * 3 ) );
+#endif
+
+}
+
+//-----------------------------------------------------------------------------
+// Commits vertex shader transforms that can change on a per pass basis
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::CommitPerPassVertexShaderTransforms()
+{
+ //GLMPRINTF(( ">-M- CommitPerPassVertexShaderTransforms" ));
+ Assert( g_pHardwareConfig->Caps().m_SupportsPixelShaders );
+
+ bool projChanged = VertexShaderTransformChanged( MATERIAL_PROJECTION );
+ //projChanged = true; //only for debug
+ if ( projChanged )
+ {
+ //GLMPRINTF(( "-M- projChanged=true in CommitPerPassVertexShaderTransforms" ));
+ SetVertexShaderViewProj();
+ SetVertexShaderModelViewProjAndModelView();
+
+ // Clear change flags
+ m_DynamicState.m_TransformChanged[MATERIAL_PROJECTION] &= ~STATE_CHANGED_VERTEX_SHADER;
+ }
+ else
+ {
+ //GLMPRINTF(( "-M- projChanged=false in CommitPerPassVertexShaderTransforms" ));
+ }
+
+ //GLMPRINTF(( "<-M- CommitPerPassVertexShaderTransforms" ));
+}
+
+//-----------------------------------------------------------------------------
+// Commits vertex shader transforms
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::CommitVertexShaderTransforms()
+{
+ //GLMPRINTF(( ">-M- CommitVertexShaderTransforms" ));
+
+ Assert( g_pHardwareConfig->Caps().m_SupportsPixelShaders );
+
+ bool viewChanged = VertexShaderTransformChanged(MATERIAL_VIEW);
+ bool projChanged = VertexShaderTransformChanged(MATERIAL_PROJECTION);
+ bool modelChanged = VertexShaderTransformChanged(MATERIAL_MODEL) && (m_DynamicState.m_NumBones < 1);
+
+ //GLMPRINTF(( "-M- viewChanged=%s projChanged=%s modelChanged = %s in CommitVertexShaderTransforms", viewChanged?"Y":"N",projChanged?"Y":"N",modelChanged?"Y":"N" ));
+ if (viewChanged)
+ {
+ //GLMPRINTF(( "-M- viewChanged --> UpdateVertexShaderFogParams" ));
+ UpdateVertexShaderFogParams();
+ }
+
+ if( viewChanged || projChanged )
+ {
+ // NOTE: We have to deal with fast-clip *before*
+ //GLMPRINTF(( "-M- viewChanged||projChanged --> SetVertexShaderViewProj" ));
+ SetVertexShaderViewProj();
+ }
+
+ if( viewChanged || modelChanged || projChanged )
+ {
+ //GLMPRINTF(( "-M- viewChanged||projChanged||modelChanged --> SetVertexShaderModelViewProjAndModelView" ));
+ SetVertexShaderModelViewProjAndModelView();
+ }
+
+ if( modelChanged && m_DynamicState.m_NumBones < 1 )
+ {
+ UpdateVertexShaderMatrix( 0 );
+ }
+
+ // Clear change flags
+ m_DynamicState.m_TransformChanged[MATERIAL_MODEL] &= ~STATE_CHANGED_VERTEX_SHADER;
+ m_DynamicState.m_TransformChanged[MATERIAL_VIEW] &= ~STATE_CHANGED_VERTEX_SHADER;
+ m_DynamicState.m_TransformChanged[MATERIAL_PROJECTION] &= ~STATE_CHANGED_VERTEX_SHADER;
+
+ //GLMPRINTF(( "<-M- CommitVertexShaderTransforms" ));
+}
+
+
+void CShaderAPIDx8::UpdateFixedFunctionMatrix( int iMatrix )
+{
+ if ( IsX360() )
+ return;
+
+ int matrix = MATERIAL_MODEL + iMatrix;
+ if ( FixedFunctionTransformChanged( matrix ) )
+ {
+ SetTransform( D3DTS_WORLDMATRIX(iMatrix), &GetTransform(matrix) );
+
+ // clear the change flag
+ m_DynamicState.m_TransformChanged[matrix] &= ~STATE_CHANGED_FIXED_FUNCTION;
+ }
+}
+
+
+void CShaderAPIDx8::SetFixedFunctionStateSkinningMatrices()
+{
+ if ( IsX360() )
+ return;
+
+ for( int i=1; i < g_pHardwareConfig->MaxBlendMatrices(); i++ )
+ {
+ UpdateFixedFunctionMatrix( i );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Commits transforms for the fixed function pipeline that can happen on a per pass basis
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::CommitPerPassFixedFunctionTransforms()
+{
+ if ( IsX360() )
+ return;
+
+ // Update projection
+ if ( FixedFunctionTransformChanged( MATERIAL_PROJECTION ) )
+ {
+ D3DTRANSFORMSTATETYPE matrix = D3DTS_PROJECTION;
+
+ SetTransform( matrix, &GetProjectionMatrix() );
+ // clear the change flag
+ m_DynamicState.m_TransformChanged[MATERIAL_PROJECTION] &= ~STATE_CHANGED_FIXED_FUNCTION;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Commits transforms for the fixed function pipeline
+//-----------------------------------------------------------------------------
+
+void CShaderAPIDx8::CommitFixedFunctionTransforms()
+{
+ if ( IsX360() )
+ return;
+
+ // Update view + projection
+ int i;
+ for ( i = MATERIAL_VIEW; i <= MATERIAL_PROJECTION; ++i)
+ {
+ if (FixedFunctionTransformChanged( i ))
+ {
+ D3DTRANSFORMSTATETYPE matrix = (i == MATERIAL_VIEW) ? D3DTS_VIEW : D3DTS_PROJECTION;
+ if ( i == MATERIAL_PROJECTION )
+ {
+ SetTransform( matrix, &GetProjectionMatrix() );
+ }
+ else
+ {
+ SetTransform( matrix, &GetTransform(i) );
+ }
+
+ // clear the change flag
+ m_DynamicState.m_TransformChanged[i] &= ~STATE_CHANGED_FIXED_FUNCTION;
+ }
+ }
+
+ UpdateFixedFunctionMatrix( 0 );
+}
+
+
+void CShaderAPIDx8::SetSkinningMatrices()
+{
+ LOCK_SHADERAPI();
+ Assert( m_pMaterial );
+
+ if ( m_DynamicState.m_NumBones == 0 )
+ {
+ // ###OSX### punting on OSX for now
+#if defined( DX_TO_GL_ABSTRACTION ) && !defined( OSX)
+ Dx9Device()->SetMaxUsedVertexShaderConstantsHint( VERTEX_SHADER_BONE_TRANSFORM( 0 ) + 3 );
+#endif
+ return;
+ }
+
+ uint nMaxVertexConstantIndex = 0;
+
+ if ( IsX360() || UsesVertexShader(m_pMaterial->GetVertexFormat()) )
+ {
+ SetVertexShaderStateSkinningMatrices();
+ }
+ else if ( IsPC() )
+ {
+#if defined( DX_TO_GL_ABSTRACTION ) && !defined( OSX)
+ Assert( 0 );
+#else
+ SetFixedFunctionStateSkinningMatrices();
+#endif
+ }
+ else
+ {
+ Assert( 0 );
+ }
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Commits vertex shader lighting
+//-----------------------------------------------------------------------------
+
+inline bool CShaderAPIDx8::VertexShaderLightingChanged( int i )
+{
+ return (m_DynamicState.m_LightChanged[i] & STATE_CHANGED_VERTEX_SHADER) != 0;
+}
+
+inline bool CShaderAPIDx8::VertexShaderLightingEnableChanged( int i )
+{
+ return (m_DynamicState.m_LightEnableChanged[i] & STATE_CHANGED_VERTEX_SHADER) != 0;
+}
+
+inline bool CShaderAPIDx8::FixedFunctionLightingChanged( int i )
+{
+ return (m_DynamicState.m_LightChanged[i] & STATE_CHANGED_FIXED_FUNCTION) != 0;
+}
+
+inline bool CShaderAPIDx8::FixedFunctionLightingEnableChanged( int i )
+{
+ return (m_DynamicState.m_LightEnableChanged[i] & STATE_CHANGED_FIXED_FUNCTION) != 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Computes the light type
+//-----------------------------------------------------------------------------
+
+VertexShaderLightTypes_t CShaderAPIDx8::ComputeLightType( int i ) const
+{
+ if (!m_DynamicState.m_LightEnable[i])
+ return LIGHT_NONE;
+
+ switch( m_DynamicState.m_Lights[i].Type )
+ {
+ case D3DLIGHT_POINT:
+ return LIGHT_POINT;
+
+ case D3DLIGHT_DIRECTIONAL:
+ return LIGHT_DIRECTIONAL;
+
+ case D3DLIGHT_SPOT:
+ return LIGHT_SPOT;
+ }
+
+ Assert(0);
+ return LIGHT_NONE;
+}
+
+
+//-----------------------------------------------------------------------------
+// Sort the lights by type
+//-----------------------------------------------------------------------------
+
+void CShaderAPIDx8::SortLights( int* index )
+{
+ m_DynamicState.m_NumLights = 0;
+
+ for (int i = 0; i < MAX_NUM_LIGHTS; ++i)
+ {
+ VertexShaderLightTypes_t type = ComputeLightType(i); // returns LIGHT_NONE if the light is disabled
+ int j = m_DynamicState.m_NumLights;
+ if (type != LIGHT_NONE)
+ {
+ while ( --j >= 0 )
+ {
+ if (m_DynamicState.m_LightType[j] <= type)
+ break;
+
+ // shift...
+ m_DynamicState.m_LightType[j+1] = m_DynamicState.m_LightType[j];
+ index[j+1] = index[j];
+ }
+ ++j;
+
+ m_DynamicState.m_LightType[j] = type;
+ index[j] = i;
+
+ ++m_DynamicState.m_NumLights;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Vertex Shader lighting
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::CommitVertexShaderLighting()
+{
+ // If nothing changed, then don't bother. Otherwise, reload...
+ int i;
+ for ( i = 0; i < MAX_NUM_LIGHTS; ++i )
+ {
+ if (VertexShaderLightingChanged(i) || VertexShaderLightingEnableChanged(i))
+ break;
+ }
+
+ // Yeah baby
+ if ( i == MAX_NUM_LIGHTS )
+ return;
+
+ // First, gotta sort the lights by their type
+ int lightIndex[MAX_NUM_LIGHTS];
+ memset( lightIndex, 0, sizeof( lightIndex ) );
+ SortLights( lightIndex );
+
+ // Clear the lighting enable flags
+ for ( i = 0; i < MAX_NUM_LIGHTS; ++i )
+ {
+ m_DynamicState.m_LightEnableChanged[i] &= ~STATE_CHANGED_VERTEX_SHADER;
+ m_DynamicState.m_LightChanged[i] &= ~STATE_CHANGED_VERTEX_SHADER;
+ }
+
+ bool bAtLeastDX90 = g_pHardwareConfig->GetDXSupportLevel() >= 90;
+
+ // Set the lighting state
+ for ( i = 0; i < m_DynamicState.m_NumLights; ++i )
+ {
+ D3DLIGHT& light = m_DynamicState.m_Lights[lightIndex[i]];
+
+ Vector4D lightState[5];
+
+ // The first one is the light color (and light type code on DX9)
+ float w = (light.Type == D3DLIGHT_DIRECTIONAL) && bAtLeastDX90 ? 1.0f : 0.0f;
+ lightState[0].Init( light.Diffuse.r, light.Diffuse.g, light.Diffuse.b, w);
+
+ // The next constant holds the light direction (and light type code on DX9)
+ w = (light.Type == D3DLIGHT_SPOT) && bAtLeastDX90 ? 1.0f : 0.0f;
+ lightState[1].Init( light.Direction.x, light.Direction.y, light.Direction.z, w );
+
+ // The next constant holds the light position
+ lightState[2].Init( light.Position.x, light.Position.y, light.Position.z, 1.0f );
+
+ // The next constant holds exponent, stopdot, stopdot2, 1 / (stopdot - stopdot2)
+ if (light.Type == D3DLIGHT_SPOT)
+ {
+ float stopdot = cos( light.Theta * 0.5f );
+ float stopdot2 = cos( light.Phi * 0.5f );
+ float oodot = (stopdot > stopdot2) ? 1.0f / (stopdot - stopdot2) : 0.0f;
+ lightState[3].Init( light.Falloff, stopdot, stopdot2, oodot );
+ }
+ else
+ {
+ lightState[3].Init( 0, 1, 1, 1 );
+ }
+
+ // The last constant holds attenuation0, attenuation1, attenuation2
+ lightState[4].Init( light.Attenuation0, light.Attenuation1, light.Attenuation2, 0.0f );
+
+ // Set the state
+ SetVertexShaderConstant( VERTEX_SHADER_LIGHTS + i * 5, lightState[0].Base(), 5 );
+ }
+
+ if ( g_pHardwareConfig->NumIntegerVertexShaderConstants() > 0 && g_pHardwareConfig->NumBooleanVertexShaderConstants() > 0 )
+ {
+ // Vertex Shader loop counter for number of lights (Only the .x component is used by our shaders)
+ // .x is the iteration count, .y is the initial value and .z is the increment step
+ int nLoopControl[4] = {m_DynamicState.m_NumLights, 0, 1, 0};
+ SetIntegerVertexShaderConstant( 0, nLoopControl, 1 );
+
+ // Enable lights using vertex shader static flow control
+ int nLightEnable[VERTEX_SHADER_LIGHT_ENABLE_BOOL_CONST_COUNT] = {0, 0, 0, 0};
+ for ( i = 0; i < m_DynamicState.m_NumLights; ++i )
+ {
+ nLightEnable[i] = 1;
+ }
+
+ SetBooleanVertexShaderConstant( VERTEX_SHADER_LIGHT_ENABLE_BOOL_CONST, nLightEnable, VERTEX_SHADER_LIGHT_ENABLE_BOOL_CONST_COUNT );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Set the pixel shader constants for lights
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::CommitPixelShaderLighting( int pshReg )
+{
+#ifndef NDEBUG
+ char const *materialName = m_pMaterial->GetName();
+#endif
+
+ // First, gotta sort the lights by their type
+ int lightIndex[MAX_NUM_LIGHTS];
+ SortLights( lightIndex );
+
+ // Offset to create a point light from directional
+ const float fFarAway = 10000.0f;
+
+ // Total pixel shader lighting state for four lights
+ Vector4D lightState[6];
+ for ( int i = 0; i < 6; i++ )
+ lightState[i].Init();
+
+ int nNumLights = m_DynamicState.m_NumLights;
+ if ( nNumLights > 0 )
+ {
+ D3DLIGHT *light = &m_DynamicState.m_Lights[lightIndex[0]];
+ lightState[0].Init( light->Diffuse.r, light->Diffuse.g, light->Diffuse.b, 0.0f );
+
+ if ( light->Type == D3DLIGHT_DIRECTIONAL )
+ {
+ Vector vDir(light->Direction.x, light->Direction.y, light->Direction.z );
+ Vector vPos = m_DynamicState.m_vLightingOrigin - vDir * fFarAway;
+ lightState[1].Init( vPos.x, vPos.y, vPos.z, 0.0f );
+ }
+ else
+ {
+ lightState[1].Init( light->Position.x, light->Position.y, light->Position.z, 0.0f );
+ }
+
+ if ( nNumLights > 1 ) // At least two lights
+ {
+ light = &m_DynamicState.m_Lights[lightIndex[1]];
+ lightState[2].Init( light->Diffuse.r, light->Diffuse.g, light->Diffuse.b, 0.0f );
+
+ if ( light->Type == D3DLIGHT_DIRECTIONAL )
+ {
+ Vector vDir(light->Direction.x, light->Direction.y, light->Direction.z );
+ Vector vPos = m_DynamicState.m_vLightingOrigin - vDir * fFarAway;
+ lightState[3].Init( vPos.x, vPos.y, vPos.z, 0.0f );
+ }
+ else
+ {
+ lightState[3].Init( light->Position.x, light->Position.y, light->Position.z, 0.0f );
+ }
+
+ if ( nNumLights > 2 ) // At least three lights
+ {
+ light = &m_DynamicState.m_Lights[lightIndex[2]];
+ lightState[4].Init( light->Diffuse.r, light->Diffuse.g, light->Diffuse.b, 0.0f );
+
+ if ( light->Type == D3DLIGHT_DIRECTIONAL )
+ {
+ Vector vDir(light->Direction.x, light->Direction.y, light->Direction.z );
+ Vector vPos = m_DynamicState.m_vLightingOrigin - vDir * fFarAway;
+ lightState[5].Init( vPos.x, vPos.y, vPos.z, 0.0f );
+ }
+ else
+ {
+ lightState[5].Init( light->Position.x, light->Position.y, light->Position.z, 0.0f );
+ }
+
+ if ( nNumLights > 3 ) // At least four lights (our current max)
+ {
+ light = &m_DynamicState.m_Lights[lightIndex[3]]; // Spread 4th light's constants across w components
+ lightState[0].w = light->Diffuse.r;
+ lightState[1].w = light->Diffuse.g;
+ lightState[2].w = light->Diffuse.b;
+
+ if ( light->Type == D3DLIGHT_DIRECTIONAL )
+ {
+ Vector vDir(light->Direction.x, light->Direction.y, light->Direction.z );
+ Vector vPos = m_DynamicState.m_vLightingOrigin - vDir * fFarAway;
+ lightState[3].w = vPos.x;
+ lightState[4].w = vPos.y;
+ lightState[5].w = vPos.z;
+ }
+ else
+ {
+ lightState[3].w = light->Position.x;
+ lightState[4].w = light->Position.y;
+ lightState[5].w = light->Position.z;
+ }
+ }
+ }
+ }
+ }
+ SetPixelShaderConstant( pshReg, lightState[0].Base(), 6 );
+}
+
+//-----------------------------------------------------------------------------
+// Fixed function lighting
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::CommitFixedFunctionLighting()
+{
+ if ( IsX360() )
+ {
+ return;
+ }
+
+ // Commit each light
+ for (int i = 0; i < g_pHardwareConfig->MaxNumLights(); ++i)
+ {
+ // Change light enable
+ if ( FixedFunctionLightingEnableChanged( i ) )
+ {
+ LightEnable( i, m_DynamicState.m_LightEnable[i] );
+
+ // Clear change flag
+ m_DynamicState.m_LightEnableChanged[i] &= ~STATE_CHANGED_FIXED_FUNCTION;
+ }
+
+ // Change lighting state...
+ if ( m_DynamicState.m_LightEnable[i] )
+ {
+ if ( FixedFunctionLightingChanged( i ) )
+ {
+ // Store off the "correct" falloff...
+ D3DLIGHT& light = m_DynamicState.m_Lights[i];
+
+ float falloff = light.Falloff;
+
+ SetLight( i, &light );
+
+ // Clear change flag
+ m_DynamicState.m_LightChanged[i] &= ~STATE_CHANGED_FIXED_FUNCTION;
+
+ // restore the correct falloff
+ light.Falloff = falloff;
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Commits user clip planes
+//-----------------------------------------------------------------------------
+D3DXMATRIX& CShaderAPIDx8::GetUserClipTransform( )
+{
+ if ( !m_DynamicState.m_bUserClipTransformOverride )
+ return GetTransform(MATERIAL_VIEW);
+
+ return m_DynamicState.m_UserClipTransform;
+}
+
+
+//-----------------------------------------------------------------------------
+// Commits user clip planes
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::CommitUserClipPlanes( bool bUsingFixedFunction )
+{
+ // We need to transform the clip planes, specified in world space,
+ // to be in projection space.. To transform the plane, we must transform
+ // the intercept and then transform the normal.
+
+ if( bUsingFixedFunction != m_DynamicState.m_UserClipLastUpdatedUsingFixedFunction )
+ {
+ //fixed function clip planes are in world space, vertex shader clip planes are in clip space, so we need to update every clip plane whenever there's a flip
+ m_DynamicState.m_UserClipPlaneChanged = (1 << g_pHardwareConfig->MaxUserClipPlanes()) - 1;
+ m_DynamicState.m_UserClipLastUpdatedUsingFixedFunction = bUsingFixedFunction;
+ }
+
+ D3DXMATRIX worldToProjectionInvTrans;
+#ifndef _DEBUG
+ if( m_DynamicState.m_UserClipPlaneChanged & m_DynamicState.m_UserClipPlaneEnabled & ((1 << g_pHardwareConfig->MaxUserClipPlanes()) - 1) )
+#endif
+ {
+ //we're going to need the transformation matrix at least once this call
+ if( bUsingFixedFunction )
+ {
+ if( m_DynamicState.m_bUserClipTransformOverride )
+ {
+ //D3DXMatrixIdentity( &worldToProjectionInvTrans ); //TODO: Test user clip transforms with this
+ //Since GetUserClipTransform() returns the view matrix if a user supplied transform doesn't exist, the general solution to this should be to transform the user transform by the inverse view matrix
+ //Since we don't know if the user clip is invertable, we'll premultiply by inverse view and cross our fingers that it's right more often than wrong
+ D3DXMATRIX viewInverse = GetTransform( MATERIAL_VIEW );
+ D3DXMatrixInverse(&viewInverse, NULL, &viewInverse);
+ worldToProjectionInvTrans = viewInverse * GetUserClipTransform(); //taking a cue from the multiplication below, multiplication goes left into right
+
+ D3DXMatrixInverse(&worldToProjectionInvTrans, NULL, &worldToProjectionInvTrans);
+ D3DXMatrixTranspose(&worldToProjectionInvTrans, &worldToProjectionInvTrans);
+ }
+ else
+ {
+ D3DXMatrixIdentity( &worldToProjectionInvTrans );
+ }
+ }
+ else
+ {
+ worldToProjectionInvTrans = GetUserClipTransform( ) * GetTransform( MATERIAL_PROJECTION );
+ D3DXMatrixInverse(&worldToProjectionInvTrans, NULL, &worldToProjectionInvTrans);
+ D3DXMatrixTranspose(&worldToProjectionInvTrans, &worldToProjectionInvTrans);
+ }
+ }
+
+ for (int i = 0; i < g_pHardwareConfig->MaxUserClipPlanes(); ++i)
+ {
+ // Don't bother with the plane if it's not enabled
+ if ( (m_DynamicState.m_UserClipPlaneEnabled & (1 << i)) == 0 )
+ continue;
+
+ // Don't bother if it didn't change...
+ if ( (m_DynamicState.m_UserClipPlaneChanged & (1 << i)) == 0 )
+ {
+#ifdef _DEBUG
+ //verify that the plane has not actually changed
+ D3DXPLANE clipPlaneProj;
+ D3DXPlaneTransform( &clipPlaneProj, &m_DynamicState.m_UserClipPlaneWorld[i], &worldToProjectionInvTrans );
+ Assert ( clipPlaneProj == m_DynamicState.m_UserClipPlaneProj[i] );
+#endif
+ continue;
+ }
+
+ m_DynamicState.m_UserClipPlaneChanged &= ~(1 << i);
+
+ D3DXPLANE clipPlaneProj;
+ D3DXPlaneTransform( &clipPlaneProj, &m_DynamicState.m_UserClipPlaneWorld[i], &worldToProjectionInvTrans );
+
+ if ( clipPlaneProj != m_DynamicState.m_UserClipPlaneProj[i] )
+ {
+ Dx9Device()->SetClipPlane( i, (float*)clipPlaneProj );
+ m_DynamicState.m_UserClipPlaneProj[i] = clipPlaneProj;
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Need to handle fog mode on a per-pass basis
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::CommitPerPassFogMode( bool bUsingVertexAndPixelShaders )
+{
+ if ( IsX360() )
+ {
+ // FF fog not applicable on 360
+ return;
+ }
+
+ D3DFOGMODE dxFogMode = D3DFOG_NONE;
+ if ( m_DynamicState.m_FogEnable )
+ {
+ dxFogMode = bUsingVertexAndPixelShaders ? D3DFOG_NONE : D3DFOG_LINEAR;
+ }
+
+ // Set fog mode if it's different than before.
+ if( m_DynamicState.m_FogMode != dxFogMode )
+ {
+ SetRenderStateConstMacro( this, D3DRS_FOGVERTEXMODE, dxFogMode );
+ m_DynamicState.m_FogMode = dxFogMode;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Handle Xbox GPU/DX API fixups necessary before actual draw.
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::CommitPerPassXboxFixups()
+{
+#if defined( _X360 )
+ // send updated shader constants to gpu
+ WriteShaderConstantsToGPU();
+
+ // sRGB write state may have changed after RT set, have to re-set correct RT
+ SetRenderTargetInternalXbox( m_hCachedRenderTarget );
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// These states can change between each pass
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::CommitPerPassStateChanges( StateSnapshot_t id )
+{
+ if ( IsX360() || UsesVertexAndPixelShaders(id) )
+ {
+ CommitPerPassVertexShaderTransforms();
+ CommitPerPassFogMode( true );
+ CommitPerPassXboxFixups();
+ CallCommitFuncs( COMMIT_PER_PASS, false );
+ }
+ else if ( IsPC() )
+ {
+ CommitPerPassFixedFunctionTransforms();
+ CommitPerPassFogMode( false );
+ CallCommitFuncs( COMMIT_PER_PASS, true );
+ }
+ else
+ {
+ Assert( 0 );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Commits transforms and lighting
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::CommitStateChanges()
+{
+ VPROF("CShaderAPIDx8::CommitStateChanges");
+ CommitFastClipPlane();
+
+ bool bUsingFixedFunction = !IsX360() && m_pMaterial && !UsesVertexShader( m_pMaterial->GetVertexFormat() );
+
+ // xboxissue - cannot support ff pipeline
+ Assert ( IsPC() || ( IsX360() && !bUsingFixedFunction ) );
+
+ if ( IsX360() || !bUsingFixedFunction )
+ {
+ CommitVertexShaderTransforms();
+
+ if ( m_pMaterial && m_pMaterial->IsVertexLit() )
+ {
+ CommitVertexShaderLighting();
+ }
+ }
+ else if ( IsPC() )
+ {
+ CommitFixedFunctionTransforms();
+
+ if ( m_pMaterial && ( m_pMaterial->IsVertexLit() || m_pMaterial->NeedsFixedFunctionFlashlight() ) )
+ {
+ CommitFixedFunctionLighting();
+ }
+ }
+ else
+ {
+ Assert( 0 );
+ }
+
+ if ( m_DynamicState.m_UserClipPlaneEnabled )
+ {
+ CommitUserClipPlanes( bUsingFixedFunction );
+ }
+
+ CallCommitFuncs( COMMIT_PER_DRAW, bUsingFixedFunction );
+}
+
+//-----------------------------------------------------------------------------
+// Commits viewports
+//-----------------------------------------------------------------------------
+static void CommitSetViewports( IDirect3DDevice9 *pDevice, const DynamicState_t &desiredState, DynamicState_t &currentState, bool bForce )
+{
+ bool bChanged = bForce || memcmp( &desiredState.m_Viewport, &currentState.m_Viewport, sizeof(D3DVIEWPORT9) );
+
+ // The width + height can be zero at startup sometimes.
+ if ( bChanged && ( desiredState.m_Viewport.Width != 0 ) && ( desiredState.m_Viewport.Height != 0 ) )
+ {
+ if( ReverseDepthOnX360() ) //reverse depth on 360 for better perf through hierarchical z
+ {
+ D3DVIEWPORT9 reverseDepthViewport;
+ reverseDepthViewport = desiredState.m_Viewport;
+ reverseDepthViewport.MinZ = 1.0f - desiredState.m_Viewport.MinZ;
+ reverseDepthViewport.MaxZ = 1.0f - desiredState.m_Viewport.MaxZ;
+ Dx9Device()->SetViewport( &reverseDepthViewport );
+ }
+ else
+ {
+ Dx9Device()->SetViewport( &desiredState.m_Viewport );
+ }
+ memcpy( &currentState.m_Viewport, &desiredState.m_Viewport, sizeof( D3DVIEWPORT9 ) );
+ }
+}
+
+
+void CShaderAPIDx8::SetViewports( int nCount, const ShaderViewport_t* pViewports )
+{
+ Assert( nCount == 1 && pViewports[0].m_nVersion == SHADER_VIEWPORT_VERSION );
+ if ( nCount != 1 )
+ return;
+
+ LOCK_SHADERAPI();
+
+ D3DVIEWPORT9 viewport;
+ viewport.X = pViewports[0].m_nTopLeftX;
+ viewport.Y = pViewports[0].m_nTopLeftY;
+ viewport.Width = pViewports[0].m_nWidth;
+ viewport.Height = pViewports[0].m_nHeight;
+ viewport.MinZ = pViewports[0].m_flMinZ;
+ viewport.MaxZ = pViewports[0].m_flMaxZ;
+
+ // Clamp the viewport to the current render target...
+ if ( !m_UsingTextureRenderTarget )
+ {
+ // Clamp to both the back buffer and the window, if it is resizing
+ int nMaxWidth = 0, nMaxHeight = 0;
+ GetBackBufferDimensions( nMaxWidth, nMaxHeight );
+ if ( IsPC() && m_IsResizing )
+ {
+ RECT viewRect;
+#if !defined( DX_TO_GL_ABSTRACTION )
+ GetClientRect( ( HWND )m_ViewHWnd, &viewRect );
+#else
+ toglGetClientRect( (VD3DHWND)m_ViewHWnd, &viewRect );
+#endif
+ m_nWindowWidth = viewRect.right - viewRect.left;
+ m_nWindowHeight = viewRect.bottom - viewRect.top;
+ nMaxWidth = min( m_nWindowWidth, nMaxWidth );
+ nMaxHeight = min( m_nWindowHeight, nMaxHeight );
+ }
+
+ // Dimensions can freak out on app exit, so at least make sure the viewport is positive
+ if ( (viewport.Width > (unsigned int)nMaxWidth ) && (nMaxWidth > 0) )
+ {
+ viewport.Width = nMaxWidth;
+ }
+
+ // Dimensions can freak out on app exit, so at least make sure the viewport is positive
+ if ( ( viewport.Height > (unsigned int)nMaxHeight ) && (nMaxHeight > 0) )
+ {
+ viewport.Height = nMaxHeight;
+ }
+ }
+ else
+ {
+ if ( viewport.Width > (unsigned int)m_ViewportMaxWidth )
+ {
+ viewport.Width = m_ViewportMaxWidth;
+ }
+ if ( viewport.Height > (unsigned int)m_ViewportMaxHeight )
+ {
+ viewport.Height = m_ViewportMaxHeight;
+ }
+ }
+
+ // FIXME: Once we extract buffered primitives out, we can directly fill in desired state
+ // and avoid the memcmp and copy
+ if ( memcmp( &m_DesiredState.m_Viewport, &viewport, sizeof(D3DVIEWPORT9) ) )
+ {
+ if ( !IsDeactivated() )
+ {
+ // State changed... need to flush the dynamic buffer
+ FlushBufferedPrimitives();
+ }
+
+ memcpy( &m_DesiredState.m_Viewport, &viewport, sizeof(D3DVIEWPORT9) );
+ }
+
+ ADD_COMMIT_FUNC( COMMIT_PER_DRAW, COMMIT_ALWAYS, CommitSetViewports );
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the current viewport size
+//-----------------------------------------------------------------------------
+int CShaderAPIDx8::GetViewports( ShaderViewport_t* pViewports, int nMax ) const
+{
+ if ( !pViewports || nMax == 0 )
+ return 1;
+
+ LOCK_SHADERAPI();
+
+ pViewports[0].m_nTopLeftX = m_DesiredState.m_Viewport.X;
+ pViewports[0].m_nTopLeftY = m_DesiredState.m_Viewport.Y;
+ pViewports[0].m_nWidth = m_DesiredState.m_Viewport.Width;
+ pViewports[0].m_nHeight = m_DesiredState.m_Viewport.Height;
+ pViewports[0].m_flMinZ = m_DesiredState.m_Viewport.MinZ;
+ pViewports[0].m_flMaxZ = m_DesiredState.m_Viewport.MaxZ;
+ return 1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Flushes buffered primitives
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::FlushBufferedPrimitives( )
+{
+ if ( ShaderUtil() )
+ {
+ if ( !ShaderUtil()->OnFlushBufferedPrimitives() )
+ {
+ return;
+ }
+ }
+ FlushBufferedPrimitivesInternal();
+}
+
+void CShaderAPIDx8::FlushBufferedPrimitivesInternal( )
+{
+ LOCK_SHADERAPI();
+ // This shouldn't happen in the inner rendering loop!
+ Assert( m_pRenderMesh == 0 );
+
+ // NOTE: We've gotta store off the matrix mode because
+ // it'll get reset by the default state application caused by the flush
+ int tempStack = m_CurrStack;
+ D3DTRANSFORMSTATETYPE tempMatrixMode = m_MatrixMode;
+
+ MeshMgr()->Flush();
+
+ m_CurrStack = tempStack;
+ m_MatrixMode = tempMatrixMode;
+}
+
+
+//-----------------------------------------------------------------------------
+// Flush the hardware
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::FlushHardware( )
+{
+ LOCK_SHADERAPI();
+ FlushBufferedPrimitives();
+
+ Dx9Device()->EndScene();
+
+ DiscardVertexBuffers();
+
+ Dx9Device()->BeginScene();
+
+ ForceHardwareSync();
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Deal with device lost (alt-tab)
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::HandleDeviceLost()
+{
+ if ( IsX360() )
+ {
+ return;
+ }
+
+ LOCK_SHADERAPI();
+
+ if ( !IsActive() )
+ return;
+
+ // need to flush the dynamic buffer
+ FlushBufferedPrimitives();
+
+ if ( !IsDeactivated() )
+ {
+ Dx9Device()->EndScene();
+ }
+
+ CheckDeviceLost( m_bOtherAppInitializing );
+
+ if ( !IsDeactivated() )
+ {
+ Dx9Device()->BeginScene();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Buffer clear color
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::ClearColor3ub( unsigned char r, unsigned char g, unsigned char b )
+{
+ LOCK_SHADERAPI();
+ float a = 255;//(r * 0.30f + g * 0.59f + b * 0.11f) / MAX_HDR_OVERBRIGHT;
+
+ // GR - need to force alpha to black for HDR
+ m_DynamicState.m_ClearColor = D3DCOLOR_ARGB((unsigned char)a,r,g,b);
+}
+
+void CShaderAPIDx8::ClearColor4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a )
+{
+ LOCK_SHADERAPI();
+ m_DynamicState.m_ClearColor = D3DCOLOR_ARGB(a,r,g,b);
+}
+
+// Converts the clear color to be appropriate for HDR
+D3DCOLOR CShaderAPIDx8::GetActualClearColor( D3DCOLOR clearColor )
+{
+ bool bConvert = !IsX360() && m_TransitionTable.CurrentState().m_bLinearColorSpaceFrameBufferEnable;
+
+#if defined( _X360 )
+ // The PC disables SRGBWrite when clearing so that the clear color won't get gamma converted
+ // The 360 cannot disable that state, and thus compensates for the sRGB conversion
+ // the desired result is the clear color written to the RT as-is
+ if ( clearColor & D3DCOLOR_ARGB( 0, 255, 255, 255 ) )
+ {
+ IDirect3DSurface *pRTSurface = NULL;
+ Dx9Device()->GetRenderTarget( 0, &pRTSurface );
+ if ( pRTSurface )
+ {
+ D3DSURFACE_DESC desc;
+ HRESULT hr = pRTSurface->GetDesc( &desc );
+ if ( !FAILED( hr ) && IS_D3DFORMAT_SRGB( desc.Format ) )
+ {
+ bConvert = true;
+ }
+ pRTSurface->Release();
+ }
+ }
+#endif
+
+ if ( bConvert )
+ {
+ // HDRFIXME: need to make sure this works this way.
+ // HDRFIXME: Is there a helper function that'll do this easier?
+ // convert clearColor from gamma to linear since our frame buffer is linear.
+ Vector vecGammaColor;
+ vecGammaColor.x = ( 1.0f / 255.0f ) * ( ( clearColor >> 16 ) & 0xff );
+ vecGammaColor.y = ( 1.0f / 255.0f ) * ( ( clearColor >> 8 ) & 0xff );
+ vecGammaColor.z = ( 1.0f / 255.0f ) * ( clearColor & 0xff );
+ Vector vecLinearColor;
+ vecLinearColor.x = GammaToLinear( vecGammaColor.x );
+ vecLinearColor.y = GammaToLinear( vecGammaColor.y );
+ vecLinearColor.z = GammaToLinear( vecGammaColor.z );
+ clearColor &= D3DCOLOR_RGBA( 0, 0, 0, 255 );
+ clearColor |= D3DCOLOR_COLORVALUE( vecLinearColor.x, vecLinearColor.y, vecLinearColor.z, 0.0f );
+ }
+
+ return clearColor;
+}
+
+
+//-----------------------------------------------------------------------------
+// Clear buffers while obeying stencil
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::ClearBuffersObeyStencil( bool bClearColor, bool bClearDepth )
+{
+ //copy the clear color bool into the clear alpha bool
+ ClearBuffersObeyStencilEx( bClearColor, bClearColor, bClearDepth );
+}
+
+void CShaderAPIDx8::ClearBuffersObeyStencilEx( bool bClearColor, bool bClearAlpha, bool bClearDepth )
+{
+ LOCK_SHADERAPI();
+
+ if ( !bClearColor && !bClearAlpha && !bClearDepth )
+ return;
+
+ FlushBufferedPrimitives();
+
+ // Before clearing can happen, user clip planes must be disabled
+ SetRenderState( D3DRS_CLIPPLANEENABLE, 0 );
+
+ D3DCOLOR clearColor = GetActualClearColor( m_DynamicState.m_ClearColor );
+
+ unsigned char r, g, b, a;
+ b = clearColor& 0xFF;
+ g = ( clearColor >> 8 ) & 0xFF;
+ r = ( clearColor >> 16 ) & 0xFF;
+ a = ( clearColor >> 24 ) & 0xFF;
+
+ ShaderUtil()->DrawClearBufferQuad( r, g, b, a, bClearColor, bClearAlpha, bClearDepth );
+
+ // Reset user clip plane state
+ FlushBufferedPrimitives();
+ SetRenderState( D3DRS_CLIPPLANEENABLE, m_DynamicState.m_UserClipPlaneEnabled );
+}
+
+//-------------------------------------------------------------------------
+//Perform stencil operations to every pixel on the screen
+//-------------------------------------------------------------------------
+void CShaderAPIDx8::PerformFullScreenStencilOperation( void )
+{
+ LOCK_SHADERAPI();
+
+ FlushBufferedPrimitives();
+
+ // We'll be drawing a large quad in altered worldspace, user clip planes must be disabled
+ SetRenderStateConstMacro( this, D3DRS_CLIPPLANEENABLE, 0 );
+
+ ShaderUtil()->DrawClearBufferQuad( 0, 0, 0, 0, false, false, false );
+
+ // Reset user clip plane state
+ FlushBufferedPrimitives();
+ SetRenderStateConstMacro( this, D3DRS_CLIPPLANEENABLE, m_DynamicState.m_UserClipPlaneEnabled );
+}
+
+
+//-----------------------------------------------------------------------------
+// Buffer clear
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::ClearBuffers( bool bClearColor, bool bClearDepth, bool bClearStencil, int renderTargetWidth, int renderTargetHeight )
+{
+ LOCK_SHADERAPI();
+ if ( ShaderUtil()->GetConfig().m_bSuppressRendering )
+ return;
+
+ if ( IsDeactivated() )
+ return;
+
+ // State changed... need to flush the dynamic buffer
+ FlushBufferedPrimitives();
+ CallCommitFuncs( COMMIT_PER_DRAW, true );
+
+ float depth = (ShaderUtil()->GetConfig().bReverseDepth ^ ReverseDepthOnX360()) ? 0.0f : 1.0f;
+ DWORD mask = 0;
+
+ if ( bClearColor )
+ {
+ mask |= D3DCLEAR_TARGET;
+ }
+
+ if ( bClearDepth )
+ {
+ mask |= D3DCLEAR_ZBUFFER;
+ }
+
+ if ( bClearStencil && m_bUsingStencil )
+ {
+ mask |= D3DCLEAR_STENCIL;
+ }
+
+ // Only clear the current view... right!??!
+ D3DRECT clear;
+ clear.x1 = m_DesiredState.m_Viewport.X;
+ clear.y1 = m_DesiredState.m_Viewport.Y;
+ clear.x2 = clear.x1 + m_DesiredState.m_Viewport.Width;
+ clear.y2 = clear.y1 + m_DesiredState.m_Viewport.Height;
+
+ // SRGBWrite is disabled when clearing so that the clear color won't get gamma converted
+ bool bSRGBWriteEnable = false;
+ if ( !IsX360() && bClearColor && m_TransitionTable.CurrentShadowState() )
+ {
+ bSRGBWriteEnable = m_TransitionTable.CurrentShadowState()->m_SRGBWriteEnable;
+ }
+
+#if !defined( _X360 )
+ if ( bSRGBWriteEnable )
+ {
+ // This path used to be !IsPosix(), but this makes no sense and causes the clear color to differ in D3D9 vs. GL.
+ Dx9Device()->SetRenderState( D3DRS_SRGBWRITEENABLE, 0 );
+ }
+#endif
+
+ D3DCOLOR clearColor = GetActualClearColor( m_DynamicState.m_ClearColor );
+
+ if ( mask != 0 )
+ {
+ bool bRenderTargetMatchesViewport =
+ ( renderTargetWidth == -1 && renderTargetHeight == -1 ) ||
+ ( m_DesiredState.m_Viewport.Width == -1 && m_DesiredState.m_Viewport.Height == -1 ) ||
+ ( renderTargetWidth == ( int )m_DesiredState.m_Viewport.Width &&
+ renderTargetHeight == ( int )m_DesiredState.m_Viewport.Height );
+
+ if ( bRenderTargetMatchesViewport )
+ {
+ RECORD_COMMAND( DX8_CLEAR, 6 );
+ RECORD_INT( 0 );
+ RECORD_STRUCT( &clear, sizeof(clear) );
+ RECORD_INT( mask );
+ RECORD_INT( clearColor );
+ RECORD_FLOAT( depth );
+ RECORD_INT( 0 );
+
+ Dx9Device()->Clear( 0, NULL, mask, clearColor, depth, 0L );
+ }
+ else
+ {
+ RECORD_COMMAND( DX8_CLEAR, 6 );
+ RECORD_INT( 0 );
+ RECORD_STRUCT( &clear, sizeof(clear) );
+ RECORD_INT( mask );
+ RECORD_INT( clearColor );
+ RECORD_FLOAT( depth );
+ RECORD_INT( 0 );
+
+ Dx9Device()->Clear( 1, &clear, mask, clearColor, depth, 0L );
+ }
+ }
+
+ // Restore state
+ if ( bSRGBWriteEnable )
+ {
+ // sRGBWriteEnable shouldn't be true if we have no shadow state. . . Assert just in case.
+ Assert( m_TransitionTable.CurrentShadowState() );
+ m_TransitionTable.ApplySRGBWriteEnable( *m_TransitionTable.CurrentShadowState() );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Bind
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::BindVertexShader( VertexShaderHandle_t hVertexShader )
+{
+ ShaderManager()->BindVertexShader( hVertexShader );
+}
+
+void CShaderAPIDx8::BindGeometryShader( GeometryShaderHandle_t hGeometryShader )
+{
+ Assert( hGeometryShader == GEOMETRY_SHADER_HANDLE_INVALID );
+}
+
+void CShaderAPIDx8::BindPixelShader( PixelShaderHandle_t hPixelShader )
+{
+ ShaderManager()->BindPixelShader( hPixelShader );
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns a copy of the front buffer
+//-----------------------------------------------------------------------------
+IDirect3DSurface* CShaderAPIDx8::GetFrontBufferImage( ImageFormat& format )
+{
+#if !defined( _X360 )
+ // need to flush the dynamic buffer and make sure the entire image is there
+ FlushBufferedPrimitives();
+
+ int w, h;
+ GetBackBufferDimensions( w, h );
+
+ HRESULT hr;
+ IDirect3DSurface *pFullScreenSurfaceBits = 0;
+ hr = Dx9Device()->CreateOffscreenPlainSurface( w, h,
+ D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &pFullScreenSurfaceBits, NULL );
+ if (FAILED(hr))
+ return 0;
+
+ hr = Dx9Device()->GetFrontBufferData( 0, pFullScreenSurfaceBits );
+ if (FAILED(hr))
+ return 0;
+
+ int windowWidth, windowHeight;
+ GetWindowSize( windowWidth, windowHeight );
+
+ IDirect3DSurface *pSurfaceBits = 0;
+ hr = Dx9Device()->CreateOffscreenPlainSurface( windowWidth, windowHeight,
+ D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &pSurfaceBits, NULL );
+ Assert( hr == D3D_OK );
+
+ POINT pnt;
+ pnt.x = pnt.y = 0;
+#ifdef _WIN32
+ BOOL result = ClientToScreen( ( HWND )m_hWnd, &pnt );
+#else
+ BOOL result = ClientToScreen( (VD3DHWND)m_hWnd, &pnt );
+#endif
+ Assert( result );
+
+ RECT srcRect;
+ srcRect.left = pnt.x;
+ srcRect.top = pnt.y;
+ srcRect.right = pnt.x + windowWidth;
+ srcRect.bottom = pnt.y + windowHeight;
+
+ POINT dstPnt;
+ dstPnt.x = dstPnt.y = 0;
+
+ D3DLOCKED_RECT lockedSrcRect;
+ hr = pFullScreenSurfaceBits->LockRect( &lockedSrcRect, &srcRect, D3DLOCK_READONLY );
+ Assert( hr == D3D_OK );
+
+ D3DLOCKED_RECT lockedDstRect;
+ hr = pSurfaceBits->LockRect( &lockedDstRect, NULL, 0 );
+ Assert( hr == D3D_OK );
+
+ int i;
+ for( i = 0; i < windowHeight; i++ )
+ {
+ memcpy( ( unsigned char * )lockedDstRect.pBits + ( i * lockedDstRect.Pitch ),
+ ( unsigned char * )lockedSrcRect.pBits + ( i * lockedSrcRect.Pitch ),
+ windowWidth * 4 ); // hack . . what if this is a different format?
+ }
+ hr = pSurfaceBits->UnlockRect();
+ Assert( hr == D3D_OK );
+ hr = pFullScreenSurfaceBits->UnlockRect();
+ Assert( hr == D3D_OK );
+
+ pFullScreenSurfaceBits->Release();
+
+ format = ImageLoader::D3DFormatToImageFormat( D3DFMT_A8R8G8B8 );
+ return pSurfaceBits;
+#else
+ Assert( 0 );
+ return NULL;
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Lets the shader know about the full-screen texture so it can
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::SetFullScreenTextureHandle( ShaderAPITextureHandle_t h )
+{
+ LOCK_SHADERAPI();
+ m_hFullScreenTexture = h;
+}
+
+
+//-----------------------------------------------------------------------------
+// Lets the shader know about the full-screen texture so it can
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::SetLinearToGammaConversionTextures( ShaderAPITextureHandle_t hSRGBWriteEnabledTexture, ShaderAPITextureHandle_t hIdentityTexture )
+{
+ LOCK_SHADERAPI();
+
+ m_hLinearToGammaTableTexture = hSRGBWriteEnabledTexture;
+ m_hLinearToGammaTableIdentityTexture = hIdentityTexture;
+}
+
+//-----------------------------------------------------------------------------
+// Returns a copy of the back buffer
+//-----------------------------------------------------------------------------
+IDirect3DSurface* CShaderAPIDx8::GetBackBufferImageHDR( Rect_t *pSrcRect, Rect_t *pDstRect, ImageFormat& format )
+{
+#if !defined( _X360 )
+ HRESULT hr;
+ IDirect3DSurface *pSurfaceBits = 0;
+ IDirect3DSurface *pTmpSurface = NULL;
+
+ // Get the back buffer
+ IDirect3DSurface* pBackBuffer;
+ hr = Dx9Device()->GetRenderTarget( 0, &pBackBuffer );
+ if (FAILED(hr))
+ return 0;
+
+ // Find about its size and format
+ D3DSURFACE_DESC desc;
+ D3DTEXTUREFILTERTYPE filter;
+
+ hr = pBackBuffer->GetDesc( &desc );
+ if (FAILED(hr))
+ goto CleanUp;
+
+ filter = ((pDstRect->width != pSrcRect->width) || (pDstRect->height != pSrcRect->height)) ? D3DTEXF_LINEAR : D3DTEXF_NONE;
+
+ if ( ( pDstRect->x + pDstRect->width <= SMALL_BACK_BUFFER_SURFACE_WIDTH ) &&
+ ( pDstRect->y + pDstRect->height <= SMALL_BACK_BUFFER_SURFACE_HEIGHT ) )
+ {
+ if (!m_pSmallBackBufferFP16TempSurface)
+ {
+ hr = Dx9Device()->CreateRenderTarget(
+ SMALL_BACK_BUFFER_SURFACE_WIDTH, SMALL_BACK_BUFFER_SURFACE_HEIGHT,
+ desc.Format, D3DMULTISAMPLE_NONE, 0, TRUE, &m_pSmallBackBufferFP16TempSurface,
+ NULL );
+ }
+ pTmpSurface = m_pSmallBackBufferFP16TempSurface;
+#if POSIX
+ pTmpSurface->AddRef( 0, "CShaderAPIDx8::GetBackBufferImageHDR public addref");
+#else
+ pTmpSurface->AddRef();
+#endif
+
+ desc.Width = SMALL_BACK_BUFFER_SURFACE_WIDTH;
+ desc.Height = SMALL_BACK_BUFFER_SURFACE_HEIGHT;
+
+ RECT srcRect, destRect;
+ RectToRECT( pSrcRect, srcRect );
+ RectToRECT( pDstRect, destRect );
+ hr = Dx9Device()->StretchRect( pBackBuffer, &srcRect, pTmpSurface, &destRect, filter );
+ if ( FAILED(hr) )
+ goto CleanUp;
+ }
+ else
+ {
+ // Normally we would only have to create a separate render target here and StretchBlt to it first
+ // if AA was enabled, but certain machines/drivers get reboots if we do GetRenderTargetData
+ // straight off the backbuffer.
+ hr = Dx9Device()->CreateRenderTarget( desc.Width, desc.Height, desc.Format,
+ D3DMULTISAMPLE_NONE, 0, TRUE, &pTmpSurface, NULL );
+ if ( FAILED(hr) )
+ goto CleanUp;
+
+ hr = Dx9Device()->StretchRect( pBackBuffer, NULL, pTmpSurface, NULL, filter );
+ if ( FAILED(hr) )
+ goto CleanUp;
+ }
+
+ // Create a buffer the same size and format
+ hr = Dx9Device()->CreateOffscreenPlainSurface( desc.Width, desc.Height,
+ desc.Format, D3DPOOL_SYSTEMMEM, &pSurfaceBits, NULL );
+ if (FAILED(hr))
+ goto CleanUp;
+
+ // Blit from the back buffer to our scratch buffer
+ hr = Dx9Device()->GetRenderTargetData( pTmpSurface ? pTmpSurface : pBackBuffer, pSurfaceBits );
+ if (FAILED(hr))
+ goto CleanUp2;
+
+ format = ImageLoader::D3DFormatToImageFormat(desc.Format);
+ if ( pTmpSurface )
+ {
+ pTmpSurface->Release();
+ }
+ pBackBuffer->Release();
+ return pSurfaceBits;
+
+CleanUp2:
+ pSurfaceBits->Release();
+
+CleanUp:
+ if ( pTmpSurface )
+ {
+ pTmpSurface->Release();
+ }
+
+ pBackBuffer->Release();
+#else
+ Assert( 0 );
+#endif
+ return 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns a copy of the back buffer
+//-----------------------------------------------------------------------------
+IDirect3DSurface* CShaderAPIDx8::GetBackBufferImage( Rect_t *pSrcRect, Rect_t *pDstRect, ImageFormat& format )
+{
+#if !defined( _X360 )
+ if ( !m_pBackBufferSurface || ( m_hFullScreenTexture == INVALID_SHADERAPI_TEXTURE_HANDLE ) )
+ return NULL;
+
+ HRESULT hr;
+ D3DSURFACE_DESC desc;
+
+ FlushBufferedPrimitives();
+
+ // Get the current render target
+ IDirect3DSurface* pRenderTarget;
+ hr = Dx9Device()->GetRenderTarget( 0, &pRenderTarget );
+ if (FAILED(hr))
+ return 0;
+
+ // Find about its size and format
+ hr = pRenderTarget->GetDesc( &desc );
+
+ if ( desc.Format == D3DFMT_A16B16G16R16F || desc.Format == D3DFMT_A32B32G32R32F )
+ return GetBackBufferImageHDR( pSrcRect, pDstRect, format );
+
+ IDirect3DSurface *pSurfaceBits = NULL;
+ IDirect3DSurface *pTmpSurface = NULL;
+ int nRenderTargetRefCount;
+ nRenderTargetRefCount = 0;
+
+ if ( (desc.MultiSampleType == D3DMULTISAMPLE_NONE) && (pRenderTarget != m_pBackBufferSurface) &&
+ (pSrcRect->width == pDstRect->width) && (pSrcRect->height == pDstRect->height) )
+ {
+ // Don't bother to blit through the full-screen texture if we don't
+ // have to stretch, we're not coming from the backbuffer, and we don't have to do AA resolve
+ pTmpSurface = pRenderTarget;
+#if POSIX
+ pTmpSurface->AddRef( 0, "CShaderAPIDx8::GetBackBufferImage public addref");
+#else
+ pTmpSurface->AddRef();
+#endif
+ }
+ else
+ {
+ Texture_t *pTex = &GetTexture( m_hFullScreenTexture );
+ IDirect3DTexture* pFullScreenTexture = (IDirect3DTexture*)pTex->GetTexture();
+
+ D3DTEXTUREFILTERTYPE filter = ((pDstRect->width != pSrcRect->width) || (pDstRect->height != pSrcRect->height)) ? D3DTEXF_LINEAR : D3DTEXF_NONE;
+
+ hr = pFullScreenTexture->GetSurfaceLevel( 0, &pTmpSurface );
+ if ( FAILED(hr) )
+ goto CleanUp;
+
+ if ( pTmpSurface == pRenderTarget )
+ {
+ Warning( "Can't blit from full-sized offscreen buffer!\n" );
+ goto CleanUp;
+ }
+
+ RECT srcRect, destRect;
+ srcRect.left = pSrcRect->x; srcRect.right = pSrcRect->x + pSrcRect->width;
+ srcRect.top = pSrcRect->y; srcRect.bottom = pSrcRect->y + pSrcRect->height;
+ srcRect.left = clamp( srcRect.left, 0, (int)desc.Width );
+ srcRect.right = clamp( srcRect.right, 0, (int)desc.Width );
+ srcRect.top = clamp( srcRect.top, 0, (int)desc.Height );
+ srcRect.bottom = clamp( srcRect.bottom, 0, (int)desc.Height );
+
+ destRect.left = pDstRect->x ; destRect.right = pDstRect->x + pDstRect->width;
+ destRect.top = pDstRect->y; destRect.bottom = pDstRect->y + pDstRect->height;
+ destRect.left = clamp( destRect.left, 0, (int)desc.Width );
+ destRect.right = clamp( destRect.right, 0, (int)desc.Width );
+ destRect.top = clamp( destRect.top, 0, (int)desc.Height );
+ destRect.bottom = clamp( destRect.bottom, 0, (int)desc.Height );
+
+ hr = Dx9Device()->StretchRect( pRenderTarget, &srcRect, pTmpSurface, &destRect, filter );
+ if ( FAILED(hr) )
+ {
+ AssertOnce( "Error resizing pixels!\n" );
+ goto CleanUp;
+ }
+ }
+
+ D3DSURFACE_DESC tmpDesc;
+ hr = pTmpSurface->GetDesc( &tmpDesc );
+ Assert( !FAILED(hr) );
+
+ // Create a buffer the same size and format
+ hr = Dx9Device()->CreateOffscreenPlainSurface( tmpDesc.Width, tmpDesc.Height,
+ desc.Format, D3DPOOL_SYSTEMMEM, &pSurfaceBits, NULL );
+ if ( FAILED(hr) )
+ {
+ AssertOnce( "Error creating offscreen surface!\n" );
+ goto CleanUp;
+ }
+
+ // Blit from the back buffer to our scratch buffer
+ hr = Dx9Device()->GetRenderTargetData( pTmpSurface, pSurfaceBits );
+ if ( FAILED(hr) )
+ {
+ AssertOnce( "Error copying bits into the offscreen surface!\n" );
+ goto CleanUp;
+ }
+
+ format = ImageLoader::D3DFormatToImageFormat( desc.Format );
+
+ pTmpSurface->Release();
+#ifdef _DEBUG
+ nRenderTargetRefCount =
+#endif
+ pRenderTarget->Release();
+ AssertOnce( nRenderTargetRefCount == 1 );
+ return pSurfaceBits;
+
+CleanUp:
+ if ( pSurfaceBits )
+ {
+ pSurfaceBits->Release();
+ }
+
+ if ( pTmpSurface )
+ {
+ pTmpSurface->Release();
+ }
+#else
+ Assert( 0 );
+#endif
+
+ return 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Copy bits from a host-memory surface
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::CopyBitsFromHostSurface( IDirect3DSurface* pSurfaceBits,
+ const Rect_t &dstRect, unsigned char *pData, ImageFormat srcFormat, ImageFormat dstFormat, int nDstStride )
+{
+ // Copy out the bits...
+ RECT rect;
+ rect.left = dstRect.x;
+ rect.right = dstRect.x + dstRect.width;
+ rect.top = dstRect.y;
+ rect.bottom = dstRect.y + dstRect.height;
+
+ D3DLOCKED_RECT lockedRect;
+ HRESULT hr;
+ int flags = D3DLOCK_READONLY | D3DLOCK_NOSYSLOCK;
+
+ tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "%s", __FUNCTION__ );
+
+ hr = pSurfaceBits->LockRect( &lockedRect, &rect, flags );
+ if ( !FAILED( hr ) )
+ {
+ unsigned char *pImage = (unsigned char *)lockedRect.pBits;
+ ShaderUtil()->ConvertImageFormat( (unsigned char *)pImage, srcFormat,
+ pData, dstFormat, dstRect.width, dstRect.height, lockedRect.Pitch, nDstStride );
+
+ hr = pSurfaceBits->UnlockRect( );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Reads from the current read buffer + stretches
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::ReadPixels( Rect_t *pSrcRect, Rect_t *pDstRect, unsigned char *pData, ImageFormat dstFormat, int nDstStride )
+{
+ LOCK_SHADERAPI();
+ Assert( pDstRect );
+
+ if ( IsPC() || !IsX360() )
+ {
+ Rect_t srcRect;
+ if ( !pSrcRect )
+ {
+ srcRect.x = srcRect.y = 0;
+ srcRect.width = m_nWindowWidth;
+ srcRect.height = m_nWindowHeight;
+ pSrcRect = &srcRect;
+ }
+
+ ImageFormat format;
+ IDirect3DSurface* pSurfaceBits = GetBackBufferImage( pSrcRect, pDstRect, format );
+ if ( pSurfaceBits )
+ {
+ CopyBitsFromHostSurface( pSurfaceBits, *pDstRect, pData, format, dstFormat, nDstStride );
+
+ // Release the temporary surface
+ pSurfaceBits->Release();
+ }
+ }
+ else
+ {
+#if defined( _X360 )
+ // 360 requires material system to handle due to RT complexities
+ ShaderUtil()->ReadBackBuffer( pSrcRect, pDstRect, pData, dstFormat, nDstStride );
+#endif
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Reads from the current read buffer
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::ReadPixels( int x, int y, int width, int height, unsigned char *pData, ImageFormat dstFormat )
+{
+ Rect_t rect;
+ rect.x = x;
+ rect.y = y;
+ rect.width = width;
+ rect.height = height;
+
+ if ( IsPC() || !IsX360() )
+ {
+ ImageFormat format;
+ IDirect3DSurface* pSurfaceBits = GetBackBufferImage( &rect, &rect, format );
+ if (pSurfaceBits)
+ {
+ CopyBitsFromHostSurface( pSurfaceBits, rect, pData, format, dstFormat, 0 );
+
+ // Release the temporary surface
+ pSurfaceBits->Release();
+ }
+ }
+ else
+ {
+#if defined( _X360 )
+ // 360 requires material system to handle due to RT complexities
+ ShaderUtil()->ReadBackBuffer( &rect, &rect, pData, dstFormat, 0 );
+#endif
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Binds a particular material to render with
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::Bind( IMaterial* pMaterial )
+{
+ LOCK_SHADERAPI();
+ IMaterialInternal* pMatInt = static_cast<IMaterialInternal*>( pMaterial );
+
+ bool bMaterialChanged;
+ if ( m_pMaterial && pMatInt && m_pMaterial->InMaterialPage() && pMatInt->InMaterialPage() )
+ {
+ bMaterialChanged = ( m_pMaterial->GetMaterialPage() != pMatInt->GetMaterialPage() );
+ }
+ else
+ {
+ bMaterialChanged = ( m_pMaterial != pMatInt ) || ( m_pMaterial && m_pMaterial->InMaterialPage() ) || ( pMatInt && pMatInt->InMaterialPage() );
+ }
+
+ if ( bMaterialChanged )
+ {
+ FlushBufferedPrimitives();
+#ifdef RECORDING
+ RECORD_DEBUG_STRING( ( char * )pMaterial->GetName() );
+ IShader *pShader = pMatInt->GetShader();
+ if( pShader && pShader->GetName() )
+ {
+ RECORD_DEBUG_STRING( pShader->GetName() );
+ }
+ else
+ {
+ RECORD_DEBUG_STRING( "<NULL SHADER>" );
+ }
+#endif
+ m_pMaterial = pMatInt;
+
+#if ( defined( PIX_INSTRUMENTATION ) || defined( NVPERFHUD ) )
+ PIXifyName( s_pPIXMaterialName, sizeof( s_pPIXMaterialName ), m_pMaterial->GetName() );
+#endif
+ }
+}
+
+// Get the currently bound material
+IMaterialInternal* CShaderAPIDx8::GetBoundMaterial()
+{
+ return m_pMaterial;
+}
+
+
+//-----------------------------------------------------------------------------
+// Binds a standard texture
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::BindStandardTexture( Sampler_t sampler, StandardTextureId_t id )
+{
+ if ( m_StdTextureHandles[id] != INVALID_SHADERAPI_TEXTURE_HANDLE )
+ {
+ BindTexture( sampler, m_StdTextureHandles[id] );
+ }
+ else
+ {
+ ShaderUtil()->BindStandardTexture( sampler, id );
+ }
+}
+
+void CShaderAPIDx8::BindStandardVertexTexture( VertexTextureSampler_t sampler, StandardTextureId_t id )
+{
+ ShaderUtil()->BindStandardVertexTexture( sampler, id );
+}
+
+void CShaderAPIDx8::GetStandardTextureDimensions( int *pWidth, int *pHeight, StandardTextureId_t id )
+{
+ ShaderUtil()->GetStandardTextureDimensions( pWidth, pHeight, id );
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the lightmap dimensions
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::GetLightmapDimensions( int *w, int *h )
+{
+ ShaderUtil()->GetLightmapDimensions( w, h );
+}
+
+
+//-----------------------------------------------------------------------------
+// Selection mode methods
+//-----------------------------------------------------------------------------
+int CShaderAPIDx8::SelectionMode( bool selectionMode )
+{
+ LOCK_SHADERAPI();
+ int numHits = m_NumHits;
+ if (m_InSelectionMode)
+ {
+ WriteHitRecord();
+ }
+ m_InSelectionMode = selectionMode;
+ m_pCurrSelectionRecord = m_pSelectionBuffer;
+ m_NumHits = 0;
+ return numHits;
+}
+
+bool CShaderAPIDx8::IsInSelectionMode() const
+{
+ return m_InSelectionMode;
+}
+
+void CShaderAPIDx8::SelectionBuffer( unsigned int* pBuffer, int size )
+{
+ LOCK_SHADERAPI();
+ Assert( !m_InSelectionMode );
+ Assert( pBuffer && size );
+ m_pSelectionBufferEnd = pBuffer + size;
+ m_pSelectionBuffer = pBuffer;
+ m_pCurrSelectionRecord = pBuffer;
+}
+
+void CShaderAPIDx8::ClearSelectionNames( )
+{
+ LOCK_SHADERAPI();
+ if (m_InSelectionMode)
+ {
+ WriteHitRecord();
+ }
+ m_SelectionNames.Clear();
+}
+
+void CShaderAPIDx8::LoadSelectionName( int name )
+{
+ LOCK_SHADERAPI();
+ if (m_InSelectionMode)
+ {
+ WriteHitRecord();
+ Assert( m_SelectionNames.Count() > 0 );
+ m_SelectionNames.Top() = name;
+ }
+}
+
+void CShaderAPIDx8::PushSelectionName( int name )
+{
+ LOCK_SHADERAPI();
+ if (m_InSelectionMode)
+ {
+ WriteHitRecord();
+ m_SelectionNames.Push(name);
+ }
+}
+
+void CShaderAPIDx8::PopSelectionName()
+{
+ LOCK_SHADERAPI();
+ if (m_InSelectionMode)
+ {
+ WriteHitRecord();
+ m_SelectionNames.Pop();
+ }
+}
+
+void CShaderAPIDx8::WriteHitRecord( )
+{
+ FlushBufferedPrimitives();
+
+ if (m_SelectionNames.Count() && (m_SelectionMinZ != FLT_MAX))
+ {
+ Assert( m_pCurrSelectionRecord + m_SelectionNames.Count() + 3 < m_pSelectionBufferEnd );
+ *m_pCurrSelectionRecord++ = m_SelectionNames.Count();
+ // NOTE: because of rounding, "(uint32)(float)UINT32_MAX" yields zero(!), hence the use of doubles.
+ // [ ALSO: As of Nov 2011, VS2010 exhibits a debug build code-gen bug if we cast the result to int32 instead of uint32 ]
+ *m_pCurrSelectionRecord++ = (uint32)( 0.5 + m_SelectionMinZ*(double)((uint32)~0) );
+ *m_pCurrSelectionRecord++ = (uint32)( 0.5 + m_SelectionMaxZ*(double)((uint32)~0) );
+ for (int i = 0; i < m_SelectionNames.Count(); ++i)
+ {
+ *m_pCurrSelectionRecord++ = m_SelectionNames[i];
+ }
+
+ ++m_NumHits;
+ }
+
+ m_SelectionMinZ = FLT_MAX;
+ m_SelectionMaxZ = FLT_MIN;
+}
+
+// We hit somefin in selection mode
+void CShaderAPIDx8::RegisterSelectionHit( float minz, float maxz )
+{
+ if (minz < 0)
+ minz = 0;
+ if (maxz > 1)
+ maxz = 1;
+ if (m_SelectionMinZ > minz)
+ m_SelectionMinZ = minz;
+ if (m_SelectionMaxZ < maxz)
+ m_SelectionMaxZ = maxz;
+}
+
+int CShaderAPIDx8::GetCurrentNumBones( void ) const
+{
+ return m_DynamicState.m_NumBones;
+}
+
+bool CShaderAPIDx8::IsHWMorphingEnabled( ) const
+{
+ return m_DynamicState.m_bHWMorphingEnabled;
+}
+
+
+//-----------------------------------------------------------------------------
+// Inserts the lighting block into the code
+//-----------------------------------------------------------------------------
+
+// If you change the number of lighting combinations, change this enum
+enum
+{
+ DX8_LIGHTING_COMBINATION_COUNT = 22,
+ DX9_LIGHTING_COMBINATION_COUNT = 35
+};
+
+#define MAX_LIGHTS 4
+
+
+// NOTE: These should match g_lightType* in vsh_prep.pl!
+static int g_DX8LightCombinations[][4] =
+{
+ // static ambient local1 local2
+
+ // This is a special case for no lighting at all.
+ { LIGHT_NONE, LIGHT_NONE, LIGHT_NONE, LIGHT_NONE },
+
+ // This is a special case so that we don't have to do the ambient cube
+ // when we only have static lighting
+ { LIGHT_STATIC, LIGHT_NONE, LIGHT_NONE, LIGHT_NONE },
+
+ { LIGHT_NONE, LIGHT_AMBIENTCUBE, LIGHT_NONE, LIGHT_NONE },
+ { LIGHT_NONE, LIGHT_AMBIENTCUBE, LIGHT_SPOT, LIGHT_NONE },
+ { LIGHT_NONE, LIGHT_AMBIENTCUBE, LIGHT_POINT, LIGHT_NONE },
+ { LIGHT_NONE, LIGHT_AMBIENTCUBE, LIGHT_DIRECTIONAL, LIGHT_NONE },
+ { LIGHT_NONE, LIGHT_AMBIENTCUBE, LIGHT_SPOT, LIGHT_SPOT },
+ { LIGHT_NONE, LIGHT_AMBIENTCUBE, LIGHT_SPOT, LIGHT_POINT, },
+ { LIGHT_NONE, LIGHT_AMBIENTCUBE, LIGHT_SPOT, LIGHT_DIRECTIONAL, },
+ { LIGHT_NONE, LIGHT_AMBIENTCUBE, LIGHT_POINT, LIGHT_POINT, },
+ { LIGHT_NONE, LIGHT_AMBIENTCUBE, LIGHT_POINT, LIGHT_DIRECTIONAL, },
+ { LIGHT_NONE, LIGHT_AMBIENTCUBE, LIGHT_DIRECTIONAL, LIGHT_DIRECTIONAL, },
+
+ { LIGHT_STATIC, LIGHT_AMBIENTCUBE, LIGHT_NONE, LIGHT_NONE },
+ { LIGHT_STATIC, LIGHT_AMBIENTCUBE, LIGHT_SPOT, LIGHT_NONE },
+ { LIGHT_STATIC, LIGHT_AMBIENTCUBE, LIGHT_POINT, LIGHT_NONE },
+ { LIGHT_STATIC, LIGHT_AMBIENTCUBE, LIGHT_DIRECTIONAL, LIGHT_NONE },
+ { LIGHT_STATIC, LIGHT_AMBIENTCUBE, LIGHT_SPOT, LIGHT_SPOT },
+ { LIGHT_STATIC, LIGHT_AMBIENTCUBE, LIGHT_SPOT, LIGHT_POINT, },
+ { LIGHT_STATIC, LIGHT_AMBIENTCUBE, LIGHT_SPOT, LIGHT_DIRECTIONAL, },
+ { LIGHT_STATIC, LIGHT_AMBIENTCUBE, LIGHT_POINT, LIGHT_POINT, },
+ { LIGHT_STATIC, LIGHT_AMBIENTCUBE, LIGHT_POINT, LIGHT_DIRECTIONAL, },
+ { LIGHT_STATIC, LIGHT_AMBIENTCUBE, LIGHT_DIRECTIONAL, LIGHT_DIRECTIONAL, }
+};
+
+// NOTE: These should match g_lightType* in vsh_prep.pl!
+// They also correspond to the parallel g_LocalLightTypeXArray[] arrays in common_vs_fxc.h
+static int g_DX9LightCombinations[][MAX_LIGHTS] =
+{
+ // local0 local1 local2 local3
+ { LIGHT_NONE, LIGHT_NONE, LIGHT_NONE, LIGHT_NONE }, // Zero lights [ Combo 0]
+
+ { LIGHT_SPOT, LIGHT_NONE, LIGHT_NONE, LIGHT_NONE }, // One light [ Combo 1]
+ { LIGHT_POINT, LIGHT_NONE, LIGHT_NONE, LIGHT_NONE },
+ { LIGHT_DIRECTIONAL, LIGHT_NONE, LIGHT_NONE, LIGHT_NONE },
+
+ { LIGHT_SPOT, LIGHT_SPOT, LIGHT_NONE, LIGHT_NONE }, // Two lights [ Combo 4]
+ { LIGHT_SPOT, LIGHT_POINT, LIGHT_NONE, LIGHT_NONE },
+ { LIGHT_SPOT, LIGHT_DIRECTIONAL, LIGHT_NONE, LIGHT_NONE },
+ { LIGHT_POINT, LIGHT_POINT, LIGHT_NONE, LIGHT_NONE },
+ { LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_NONE, LIGHT_NONE },
+ { LIGHT_DIRECTIONAL, LIGHT_DIRECTIONAL, LIGHT_NONE, LIGHT_NONE },
+
+ { LIGHT_SPOT, LIGHT_SPOT, LIGHT_SPOT, LIGHT_NONE }, // Three lights [ Combo 10]
+ { LIGHT_SPOT, LIGHT_SPOT, LIGHT_POINT, LIGHT_NONE },
+ { LIGHT_SPOT, LIGHT_SPOT, LIGHT_DIRECTIONAL, LIGHT_NONE },
+ { LIGHT_SPOT, LIGHT_POINT, LIGHT_POINT, LIGHT_NONE },
+ { LIGHT_SPOT, LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_NONE },
+ { LIGHT_SPOT, LIGHT_DIRECTIONAL, LIGHT_DIRECTIONAL, LIGHT_NONE },
+ { LIGHT_POINT, LIGHT_POINT, LIGHT_POINT, LIGHT_NONE },
+ { LIGHT_POINT, LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_NONE },
+ { LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_DIRECTIONAL, LIGHT_NONE },
+ { LIGHT_DIRECTIONAL, LIGHT_DIRECTIONAL, LIGHT_DIRECTIONAL, LIGHT_NONE },
+
+ { LIGHT_SPOT, LIGHT_SPOT, LIGHT_SPOT, LIGHT_SPOT }, // Four lights [ Combo 20]
+ { LIGHT_SPOT, LIGHT_SPOT, LIGHT_SPOT, LIGHT_POINT },
+ { LIGHT_SPOT, LIGHT_SPOT, LIGHT_SPOT, LIGHT_DIRECTIONAL },
+ { LIGHT_SPOT, LIGHT_SPOT, LIGHT_POINT, LIGHT_POINT },
+ { LIGHT_SPOT, LIGHT_SPOT, LIGHT_POINT, LIGHT_DIRECTIONAL },
+ { LIGHT_SPOT, LIGHT_SPOT, LIGHT_DIRECTIONAL, LIGHT_DIRECTIONAL },
+ { LIGHT_SPOT, LIGHT_POINT, LIGHT_POINT, LIGHT_POINT },
+ { LIGHT_SPOT, LIGHT_POINT, LIGHT_POINT, LIGHT_DIRECTIONAL },
+ { LIGHT_SPOT, LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_DIRECTIONAL },
+ { LIGHT_SPOT, LIGHT_DIRECTIONAL, LIGHT_DIRECTIONAL, LIGHT_DIRECTIONAL },
+ { LIGHT_POINT, LIGHT_POINT, LIGHT_POINT, LIGHT_POINT },
+ { LIGHT_POINT, LIGHT_POINT, LIGHT_POINT, LIGHT_DIRECTIONAL },
+ { LIGHT_POINT, LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_DIRECTIONAL },
+ { LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_DIRECTIONAL, LIGHT_DIRECTIONAL },
+ { LIGHT_DIRECTIONAL, LIGHT_DIRECTIONAL, LIGHT_DIRECTIONAL, LIGHT_DIRECTIONAL }
+};
+
+// This is just for getting light combos for DX8
+// For DX9, use GetDX9LightState()
+// It is up to the shader cpp files to use the right method
+int CShaderAPIDx8::GetCurrentLightCombo( void ) const
+{
+ Assert( g_pHardwareConfig->Caps().m_nDXSupportLevel <= 81 );
+
+ Assert( m_DynamicState.m_NumLights <= 2 );
+
+ COMPILE_TIME_ASSERT( DX8_LIGHTING_COMBINATION_COUNT ==
+ sizeof( g_DX8LightCombinations ) / sizeof( g_DX8LightCombinations[0] ) );
+
+ // hack . . do this a cheaper way.
+ bool bUseAmbientCube;
+ if( m_DynamicState.m_AmbientLightCube[0][0] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[0][1] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[0][2] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[1][0] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[1][1] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[1][2] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[2][0] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[2][1] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[2][2] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[3][0] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[3][1] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[3][2] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[4][0] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[4][1] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[4][2] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[5][0] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[5][1] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[5][2] == 0.0f )
+ {
+ bUseAmbientCube = false;
+ }
+ else
+ {
+ bUseAmbientCube = true;
+ }
+
+ Assert( m_pRenderMesh );
+
+ const VertexShaderLightTypes_t *pLightType = m_DynamicState.m_LightType;
+
+ if( m_DynamicState.m_NumLights == 0 && !bUseAmbientCube )
+ {
+ if( m_pRenderMesh->HasColorMesh() )
+ return 1; // special case for static lighting only
+ else
+ return 0; // special case for no lighting at all.
+ }
+
+ int i;
+ // hack - skip the first two for now since we don't know if the ambient cube is needed or not.
+ for( i = 2; i < DX9_LIGHTING_COMBINATION_COUNT; ++i )
+ {
+ int j;
+ for( j = 0; j < m_DynamicState.m_NumLights; ++j )
+ {
+ if( pLightType[j] != g_DX8LightCombinations[i][j+2] )
+ break;
+ }
+ if( j == m_DynamicState.m_NumLights )
+ {
+ while( j < 2 )
+ {
+ if (g_DX8LightCombinations[i][j+2] != LIGHT_NONE)
+ break;
+ ++j;
+ }
+ if( j == 2 )
+ {
+ if( m_pRenderMesh->HasColorMesh() )
+ {
+ return i + 10;
+ }
+ else
+ {
+ return i;
+ }
+ }
+ }
+ }
+
+ // should never get here!
+ Assert( 0 );
+ return 0;
+}
+
+void CShaderAPIDx8::GetDX9LightState( LightState_t *state ) const
+{
+ // hack . . do this a cheaper way.
+ if( m_DynamicState.m_AmbientLightCube[0][0] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[0][1] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[0][2] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[1][0] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[1][1] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[1][2] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[2][0] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[2][1] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[2][2] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[3][0] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[3][1] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[3][2] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[4][0] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[4][1] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[4][2] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[5][0] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[5][1] == 0.0f &&
+ m_DynamicState.m_AmbientLightCube[5][2] == 0.0f )
+ {
+ state->m_bAmbientLight = false;
+ }
+ else
+ {
+ state->m_bAmbientLight = true;
+ }
+
+ Assert( m_pRenderMesh );
+ Assert( m_DynamicState.m_NumLights <= 4 );
+
+ if ( g_pHardwareConfig->SupportsPixelShaders_2_b() )
+ {
+ Assert( m_DynamicState.m_NumLights <= MAX_LIGHTS ); // 2b hardware gets four lights
+ }
+ else
+ {
+ Assert( m_DynamicState.m_NumLights <= (MAX_LIGHTS-2) ); // 2.0 hardware gets two less
+ }
+
+#ifdef OSX
+ state->m_nNumLights = MIN(MAX_NUM_LIGHTS,m_DynamicState.m_NumLights);
+#else
+ state->m_nNumLights = m_DynamicState.m_NumLights;
+#endif
+
+ state->m_nNumLights = m_DynamicState.m_NumLights;
+ state->m_bStaticLightVertex = m_pRenderMesh->HasColorMesh();
+ state->m_bStaticLightTexel = false; // For now
+}
+
+MaterialFogMode_t CShaderAPIDx8::GetCurrentFogType( void ) const
+{
+ return m_DynamicState.m_SceneFog;
+}
+
+void CShaderAPIDx8::RecordString( const char *pStr )
+{
+ RECORD_STRING( pStr );
+}
+
+void CShaderAPIDx8::EvictManagedResourcesInternal()
+{
+ if ( IsX360() )
+ return;
+
+ if ( !ThreadOwnsDevice() || !ThreadInMainThread() )
+ {
+ ShaderUtil()->OnThreadEvent( SHADER_THREAD_EVICT_RESOURCES );
+ return;
+ }
+ if ( mat_debugalttab.GetBool() )
+ {
+ Warning( "mat_debugalttab: CShaderAPIDx8::EvictManagedResourcesInternal\n" );
+ }
+
+#if !defined( _X360 )
+ if ( Dx9Device() )
+ {
+ Dx9Device()->EvictManagedResources();
+ }
+#endif
+}
+
+void CShaderAPIDx8::EvictManagedResources( void )
+{
+ if ( IsX360() )
+ {
+ return;
+ }
+
+ LOCK_SHADERAPI();
+ Assert(ThreadOwnsDevice());
+ // Tell other material system applications to release resources
+ SendIPCMessage( EVICT_MESSAGE );
+ EvictManagedResourcesInternal();
+}
+
+bool CShaderAPIDx8::IsDebugTextureListFresh( int numFramesAllowed /* = 1 */ )
+{
+ return ( m_nDebugDataExportFrame <= m_CurrentFrame ) && ( m_nDebugDataExportFrame >= m_CurrentFrame - numFramesAllowed );
+}
+
+bool CShaderAPIDx8::SetDebugTextureRendering( bool bEnable )
+{
+ bool bVal = m_bDebugTexturesRendering;
+ m_bDebugTexturesRendering = bEnable;
+ return bVal;
+}
+
+void CShaderAPIDx8::EnableDebugTextureList( bool bEnable )
+{
+ m_bEnableDebugTextureList = bEnable;
+}
+
+void CShaderAPIDx8::EnableGetAllTextures( bool bEnable )
+{
+ m_bDebugGetAllTextures = bEnable;
+}
+
+KeyValues* CShaderAPIDx8::GetDebugTextureList()
+{
+ return m_pDebugTextureList;
+}
+
+int CShaderAPIDx8::GetTextureMemoryUsed( TextureMemoryType eTextureMemory )
+{
+ switch ( eTextureMemory )
+ {
+ case MEMORY_BOUND_LAST_FRAME:
+ return m_nTextureMemoryUsedLastFrame;
+ case MEMORY_TOTAL_LOADED:
+ return m_nTextureMemoryUsedTotal;
+ case MEMORY_ESTIMATE_PICMIP_1:
+ return m_nTextureMemoryUsedPicMip1;
+ case MEMORY_ESTIMATE_PICMIP_2:
+ return m_nTextureMemoryUsedPicMip2;
+ default:
+ return 0;
+ }
+}
+
+
+// Allocate and delete query objects.
+ShaderAPIOcclusionQuery_t CShaderAPIDx8::CreateOcclusionQueryObject( void )
+{
+ // don't allow this on <80 because it falls back to wireframe in that case
+ if( m_DeviceSupportsCreateQuery == 0 || g_pHardwareConfig->Caps().m_nDXSupportLevel < 80 )
+ return INVALID_SHADERAPI_OCCLUSION_QUERY_HANDLE;
+
+ // While we're deactivated, m_OcclusionQueryObjects just holds NULL pointers.
+ // Create a dummy one here and let ReacquireResources create the actual D3D object.
+ if ( IsDeactivated() )
+ return INVALID_SHADERAPI_OCCLUSION_QUERY_HANDLE;
+
+ IDirect3DQuery9 *pQuery = NULL;
+ HRESULT hr = Dx9Device()->CreateQuery( D3DQUERYTYPE_OCCLUSION, &pQuery );
+ return ( hr == D3D_OK ) ? (ShaderAPIOcclusionQuery_t)pQuery : INVALID_SHADERAPI_OCCLUSION_QUERY_HANDLE;
+}
+
+void CShaderAPIDx8::DestroyOcclusionQueryObject( ShaderAPIOcclusionQuery_t handle )
+{
+ IDirect3DQuery9 *pQuery = (IDirect3DQuery9 *)handle;
+
+ int nRetVal = pQuery->Release();
+ Assert( nRetVal == 0 );
+}
+
+// Bracket drawing with begin and end so that we can get counts next frame.
+void CShaderAPIDx8::BeginOcclusionQueryDrawing( ShaderAPIOcclusionQuery_t handle )
+{
+ IDirect3DQuery9 *pQuery = (IDirect3DQuery9 *)handle;
+
+ HRESULT hResult = pQuery->Issue( D3DISSUE_BEGIN );
+ Assert( hResult == D3D_OK );
+}
+
+void CShaderAPIDx8::EndOcclusionQueryDrawing( ShaderAPIOcclusionQuery_t handle )
+{
+ IDirect3DQuery9 *pQuery = (IDirect3DQuery9 *)handle;
+
+ HRESULT hResult = pQuery->Issue( D3DISSUE_END );
+ Assert( hResult == D3D_OK );
+}
+
+// Get the number of pixels rendered between begin and end on an earlier frame.
+// Calling this in the same frame is a huge perf hit!
+int CShaderAPIDx8::OcclusionQuery_GetNumPixelsRendered( ShaderAPIOcclusionQuery_t handle, bool bFlush )
+{
+ LOCK_SHADERAPI();
+ IDirect3DQuery9 *pQuery = (IDirect3DQuery9 *)handle;
+
+ tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "%s", __FUNCTION__ );
+
+ DWORD nPixels;
+ HRESULT hResult = pQuery->GetData( &nPixels, sizeof( nPixels ), bFlush ? D3DGETDATA_FLUSH : 0 );
+
+ // This means that the query will not finish and resulted in an error, game should use
+ // the previous query's results and not reissue the query
+ if ( ( hResult == D3DERR_DEVICELOST ) || ( hResult == D3DERR_NOTAVAILABLE ) )
+ return OCCLUSION_QUERY_RESULT_ERROR;
+
+ // This means the query isn't finished yet, game will have to use the previous query's
+ // results and not reissue the query; wait for query to finish later.
+ if ( hResult == S_FALSE )
+ return OCCLUSION_QUERY_RESULT_PENDING;
+
+ // NOTE: This appears to work around a driver bug for ATI on Vista
+ if ( nPixels & 0x80000000 )
+ {
+ nPixels = 0;
+ }
+ return nPixels;
+}
+
+
+void CShaderAPIDx8::SetPixelShaderFogParams( int reg, ShaderFogMode_t fogMode )
+{
+ m_DelayedShaderConstants.iPixelShaderFogParams = reg; //save it off in case the ShaderFogMode_t disables fog. We only find out later.
+ float fogParams[4];
+
+ if( (GetPixelFogMode() != MATERIAL_FOG_NONE) && (fogMode != SHADER_FOGMODE_DISABLED) )
+ {
+ float ooFogRange = 1.0f;
+
+ float fStart = m_VertexShaderFogParams[0];
+ float fEnd = m_VertexShaderFogParams[1];
+
+ // Check for divide by zero
+ if ( fEnd != fStart )
+ {
+ ooFogRange = 1.0f / ( fEnd - fStart );
+ }
+
+ fogParams[0] = fStart * ooFogRange; // fogStart / ( fogEnd - fogStart )
+ fogParams[1] = m_DynamicState.m_FogZ; // water height
+ fogParams[2] = clamp( m_flFogMaxDensity, 0.0f, 1.0f ); // Max fog density
+ fogParams[3] = ooFogRange; // 1 / ( fogEnd - fogStart );
+
+ if (GetPixelFogMode() == MATERIAL_FOG_LINEAR_BELOW_FOG_Z)
+ {
+ // terms are unused for height fog, forcing 1.0 allows unified PS math
+ fogParams[0] = 0.0f;
+ fogParams[2] = 1.0f;
+ }
+ }
+ else
+ {
+ //emulating MATERIAL_FOG_NONE by setting the parameters so that CalcRangeFog() always returns 0. Gets rid of a dynamic combo across the ps2x set.
+ fogParams[0] = 0.0f;
+ fogParams[1] = m_DynamicState.m_FogZ; // water height
+ fogParams[2] = 1.0f; // Max fog density
+ fogParams[3] = 0.0f;
+ }
+
+ // cFogEndOverFogRange, cFogOne, unused, cOOFogRange
+ SetPixelShaderConstant( reg, fogParams, 1 );
+}
+
+void CShaderAPIDx8::SetPixelShaderFogParams( int reg )
+{
+ SetPixelShaderFogParams( reg, m_TransitionTable.CurrentShadowState()->m_FogMode );
+}
+
+void CShaderAPIDx8::SetFlashlightState( const FlashlightState_t &state, const VMatrix &worldToTexture )
+{
+ LOCK_SHADERAPI();
+ SetFlashlightStateEx( state, worldToTexture, NULL );
+}
+
+void CShaderAPIDx8::SetFlashlightStateEx( const FlashlightState_t &state, const VMatrix &worldToTexture, ITexture *pFlashlightDepthTexture )
+{
+ LOCK_SHADERAPI();
+ // fixme: do a test here.
+ FlushBufferedPrimitives();
+ m_FlashlightState = state;
+ m_FlashlightWorldToTexture = worldToTexture;
+ m_pFlashlightDepthTexture = pFlashlightDepthTexture;
+
+ if ( !g_pHardwareConfig->SupportsPixelShaders_2_b() )
+ {
+ m_FlashlightState.m_bEnableShadows = false;
+ m_pFlashlightDepthTexture = NULL;
+ }
+}
+
+const FlashlightState_t &CShaderAPIDx8::GetFlashlightState( VMatrix &worldToTexture ) const
+{
+ worldToTexture = m_FlashlightWorldToTexture;
+ return m_FlashlightState;
+}
+
+const FlashlightState_t &CShaderAPIDx8::GetFlashlightStateEx( VMatrix &worldToTexture, ITexture **ppFlashlightDepthTexture ) const
+{
+ worldToTexture = m_FlashlightWorldToTexture;
+ *ppFlashlightDepthTexture = m_pFlashlightDepthTexture;
+ return m_FlashlightState;
+}
+
+bool CShaderAPIDx8::SupportsMSAAMode( int nMSAAMode )
+{
+ if ( IsX360() )
+ {
+ return false;
+ }
+
+ return ( D3D_OK == D3D()->CheckDeviceMultiSampleType( m_DisplayAdapter, m_DeviceType,
+ m_PresentParameters.BackBufferFormat,
+ m_PresentParameters.Windowed,
+ ComputeMultisampleType( nMSAAMode ), NULL ) );
+}
+
+bool CShaderAPIDx8::SupportsCSAAMode( int nNumSamples, int nQualityLevel )
+{
+#ifdef DX_TO_GL_ABSTRACTION
+ // GL_NV_framebuffer_multisample_coverage
+ return false;
+#endif
+
+ // Only nVidia does this kind of AA
+ if ( g_pHardwareConfig->Caps().m_VendorID != VENDORID_NVIDIA )
+ return false;
+
+ DWORD dwQualityLevels = 0;
+ HRESULT hr = D3D()->CheckDeviceMultiSampleType( m_DisplayAdapter, m_DeviceType,
+ m_PresentParameters.BackBufferFormat,
+ m_PresentParameters.Windowed,
+ ComputeMultisampleType( nNumSamples ), &dwQualityLevels );
+
+ return ( ( D3D_OK == hr ) && ( (int) dwQualityLevels >= nQualityLevel ) );
+}
+
+bool CShaderAPIDx8::SupportsShadowDepthTextures( void )
+{
+ return g_pHardwareConfig->Caps().m_bSupportsShadowDepthTextures;
+}
+
+bool CShaderAPIDx8::SupportsBorderColor( void ) const
+{
+ return g_pHardwareConfig->Caps().m_bSupportsBorderColor;
+}
+
+bool CShaderAPIDx8::SupportsFetch4( void )
+{
+ return IsPC() && g_pHardwareConfig->Caps().m_bSupportsFetch4;
+}
+
+ImageFormat CShaderAPIDx8::GetShadowDepthTextureFormat( void )
+{
+ return g_pHardwareConfig->Caps().m_ShadowDepthTextureFormat;
+}
+
+ImageFormat CShaderAPIDx8::GetNullTextureFormat( void )
+{
+ return g_pHardwareConfig->Caps().m_NullTextureFormat;
+}
+
+void CShaderAPIDx8::SetShadowDepthBiasFactors( float fShadowSlopeScaleDepthBias, float fShadowDepthBias )
+{
+ m_fShadowSlopeScaleDepthBias = fShadowSlopeScaleDepthBias;
+ m_fShadowDepthBias = fShadowDepthBias;
+}
+
+void CShaderAPIDx8::ClearVertexAndPixelShaderRefCounts()
+{
+ LOCK_SHADERAPI();
+ ShaderManager()->ClearVertexAndPixelShaderRefCounts();
+}
+
+void CShaderAPIDx8::PurgeUnusedVertexAndPixelShaders()
+{
+ LOCK_SHADERAPI();
+ ShaderManager()->PurgeUnusedVertexAndPixelShaders();
+}
+
+bool CShaderAPIDx8::UsingSoftwareVertexProcessing() const
+{
+ return g_pHardwareConfig->Caps().m_bSoftwareVertexProcessing;
+}
+
+ITexture *CShaderAPIDx8::GetRenderTargetEx( int nRenderTargetID )
+{
+ return ShaderUtil()->GetRenderTargetEx( nRenderTargetID );
+}
+
+float CShaderAPIDx8::GetLightMapScaleFactor( void ) const
+{
+ switch( HardwareConfig()->GetHDRType() )
+ {
+
+ case HDR_TYPE_FLOAT:
+ return 1.0;
+ break;
+
+ case HDR_TYPE_INTEGER:
+ return 16.0;
+
+ case HDR_TYPE_NONE:
+ default:
+ return GammaToLinearFullRange( 2.0 ); // light map scale
+ }
+}
+
+void CShaderAPIDx8::SetToneMappingScaleLinear( const Vector &scale )
+{
+ if ( g_pHardwareConfig->SupportsPixelShaders_2_0() )
+ {
+ // Flush buffered primitives before changing the tone map scalar!
+ FlushBufferedPrimitives();
+
+ Vector scale_to_use = scale;
+ m_ToneMappingScale.AsVector3D() = scale_to_use;
+
+ bool mode_uses_srgb=false;
+
+ switch( HardwareConfig()->GetHDRType() )
+ {
+ case HDR_TYPE_NONE:
+ m_ToneMappingScale.x = 1.0; // output scale
+ m_ToneMappingScale.z = 1.0; // reflection map scale
+ break;
+
+ case HDR_TYPE_FLOAT:
+ m_ToneMappingScale.x = scale_to_use.x; // output scale
+ m_ToneMappingScale.z = 1.0; // reflection map scale
+ break;
+
+ case HDR_TYPE_INTEGER:
+ mode_uses_srgb = true;
+ m_ToneMappingScale.x = scale_to_use.x; // output scale
+ m_ToneMappingScale.z = 16.0; // reflection map scale
+ break;
+ }
+
+ m_ToneMappingScale.y = GetLightMapScaleFactor(); // light map scale
+
+ // w component gets gamma scale
+ m_ToneMappingScale.w = LinearToGammaFullRange( m_ToneMappingScale.x );
+ SetPixelShaderConstant( TONE_MAPPING_SCALE_PSH_CONSTANT, m_ToneMappingScale.Base() );
+
+ // We have to change the fog color since we tone map directly in the shaders in integer HDR mode.
+ if ( HardwareConfig()->GetHDRType() == HDR_TYPE_INTEGER && m_TransitionTable.CurrentShadowState() )
+ {
+ // Get the shadow state in sync since it depends on SetToneMappingScaleLinear.
+ ApplyFogMode( m_TransitionTable.CurrentShadowState()->m_FogMode, mode_uses_srgb, m_TransitionTable.CurrentShadowState()->m_bDisableFogGammaCorrection );
+ }
+ }
+}
+
+const Vector & CShaderAPIDx8::GetToneMappingScaleLinear( void ) const
+{
+ return m_ToneMappingScale.AsVector3D();
+}
+
+void CShaderAPIDx8::EnableLinearColorSpaceFrameBuffer( bool bEnable )
+{
+ LOCK_SHADERAPI();
+ m_TransitionTable.EnableLinearColorSpaceFrameBuffer( bEnable );
+}
+
+
+void CShaderAPIDx8::SetPSNearAndFarZ( int pshReg )
+{
+ VMatrix m;
+ GetMatrix( MATERIAL_PROJECTION, m.m[0] );
+
+ // m[2][2] = F/(N-F) (flip sign if RH)
+ // m[3][2] = NF/(N-F)
+
+ float vNearFar[4];
+
+ float N = m[3][2] / m[2][2];
+ float F = (m[3][2]*N) / (N + m[3][2]);
+
+ vNearFar[0] = N;
+ vNearFar[1] = F;
+
+
+ SetPixelShaderConstant( pshReg, vNearFar, 1 );
+}
+
+
+void CShaderAPIDx8::SetFloatRenderingParameter( int parm_number, float value )
+{
+ LOCK_SHADERAPI();
+ if ( parm_number < ARRAYSIZE( FloatRenderingParameters ))
+ FloatRenderingParameters[parm_number] = value;
+}
+
+void CShaderAPIDx8::SetIntRenderingParameter( int parm_number, int value )
+{
+ LOCK_SHADERAPI();
+ if ( parm_number < ARRAYSIZE( IntRenderingParameters ))
+ IntRenderingParameters[parm_number] = value;
+}
+
+void CShaderAPIDx8::SetVectorRenderingParameter( int parm_number, Vector const & value )
+{
+ LOCK_SHADERAPI();
+ if ( parm_number < ARRAYSIZE( VectorRenderingParameters ))
+ VectorRenderingParameters[parm_number] = value;
+}
+
+float CShaderAPIDx8::GetFloatRenderingParameter( int parm_number ) const
+{
+ LOCK_SHADERAPI();
+ if ( parm_number < ARRAYSIZE( FloatRenderingParameters ))
+ return FloatRenderingParameters[parm_number];
+ else
+ return 0.0;
+}
+
+int CShaderAPIDx8::GetIntRenderingParameter( int parm_number ) const
+{
+ LOCK_SHADERAPI();
+ if ( parm_number < ARRAYSIZE( IntRenderingParameters ))
+ return IntRenderingParameters[parm_number];
+ else
+ return 0;
+}
+
+Vector CShaderAPIDx8::GetVectorRenderingParameter( int parm_number ) const
+{
+ LOCK_SHADERAPI();
+ if ( parm_number < ARRAYSIZE( VectorRenderingParameters ))
+ return VectorRenderingParameters[parm_number];
+ else
+ return Vector( 0, 0, 0 );
+}
+
+// stencil entry points
+void CShaderAPIDx8::SetStencilEnable( bool onoff )
+{
+ LOCK_SHADERAPI();
+ SetRenderState( D3DRS_STENCILENABLE, onoff?TRUE:FALSE, true );
+}
+
+void CShaderAPIDx8::SetStencilFailOperation( StencilOperation_t op )
+{
+ LOCK_SHADERAPI();
+ SetRenderState( D3DRS_STENCILFAIL, op, true );
+}
+
+void CShaderAPIDx8::SetStencilZFailOperation( StencilOperation_t op )
+{
+ LOCK_SHADERAPI();
+ SetRenderState( D3DRS_STENCILZFAIL, op, true );
+}
+
+void CShaderAPIDx8::SetStencilPassOperation( StencilOperation_t op )
+{
+ LOCK_SHADERAPI();
+ SetRenderState( D3DRS_STENCILPASS, op, true );
+}
+
+void CShaderAPIDx8::SetStencilCompareFunction( StencilComparisonFunction_t cmpfn )
+{
+ LOCK_SHADERAPI();
+ SetRenderState( D3DRS_STENCILFUNC, cmpfn, true );
+}
+
+void CShaderAPIDx8::SetStencilReferenceValue( int ref )
+{
+ LOCK_SHADERAPI();
+ SetRenderState( D3DRS_STENCILREF, ref, true );
+}
+
+void CShaderAPIDx8::SetStencilTestMask( uint32 msk )
+{
+ LOCK_SHADERAPI();
+ SetRenderState( D3DRS_STENCILMASK, msk, true );
+}
+
+void CShaderAPIDx8::SetStencilWriteMask( uint32 msk )
+{
+ LOCK_SHADERAPI();
+ SetRenderState( D3DRS_STENCILWRITEMASK, msk, true );
+}
+
+void CShaderAPIDx8::ClearStencilBufferRectangle(
+ int xmin, int ymin, int xmax, int ymax,int value)
+{
+ LOCK_SHADERAPI();
+ D3DRECT clear;
+ clear.x1 = xmin;
+ clear.y1 = ymin;
+ clear.x2 = xmax;
+ clear.y2 = ymax;
+
+ Dx9Device()->Clear(
+ 1, &clear, D3DCLEAR_STENCIL, 0, 0, value );
+}
+
+int CShaderAPIDx8::CompareSnapshots( StateSnapshot_t snapshot0, StateSnapshot_t snapshot1 )
+{
+ LOCK_SHADERAPI();
+ const ShadowState_t &shadow0 = m_TransitionTable.GetSnapshot(snapshot0);
+ const ShadowState_t &shadow1 = m_TransitionTable.GetSnapshot(snapshot1);
+ const ShadowShaderState_t &shader0 = m_TransitionTable.GetSnapshotShader(snapshot0);
+ const ShadowShaderState_t &shader1 = m_TransitionTable.GetSnapshotShader(snapshot1);
+
+ int dVertex = shader0.m_VertexShader - shader1.m_VertexShader;
+ if ( dVertex )
+ return dVertex;
+ int dVCombo = shader0.m_nStaticVshIndex - shader1.m_nStaticVshIndex;
+ if ( dVCombo)
+ return dVCombo;
+
+ int dPixel = shader0.m_PixelShader - shader1.m_PixelShader;
+ if ( dPixel )
+ return dPixel;
+ int dPCombo = shader0.m_nStaticPshIndex - shader1.m_nStaticPshIndex;
+ if ( dPCombo)
+ return dPCombo;
+
+ return snapshot0 - snapshot1;
+}
+
+//-----------------------------------------------------------------------------
+// X360 TTF support requires XUI state manipulation of d3d.
+// Font support lives inside the shaderapi in order to maintain privacy of d3d.
+//-----------------------------------------------------------------------------
+#if defined( _X360 )
+HXUIFONT CShaderAPIDx8::OpenTrueTypeFont( const char *pFontname, int tall, int style )
+{
+ LOCK_SHADERAPI();
+
+ struct fontTable_t
+ {
+ const char *pFontName;
+ const char *pPath;
+ };
+
+ // explicit mapping now required, dvd searching to expensive
+ static fontTable_t fontToFilename[] =
+ {
+ {"tf2", "tf/resource/tf2.ttf"},
+ {"tf2 build", "tf/resource/tf2build.ttf"},
+ {"tf2 professor", "tf/resource/tf2professor.ttf"},
+ {"tf2 secondary", "tf/resource/tf2secondary.ttf"},
+ {"team fortress", "tf/resource/tf.ttf"},
+ {"tfd", "tf/resource/tfd.ttf"},
+ {"tflogo", "tf/resource/tflogo.ttf"},
+ {"hl2ep2", "ep2/resource/hl2ep2.ttf"},
+ {"hl2ep1", "episodic/resource/hl2ep1.ttf"},
+ {"halflife2", "hl2/resource/halflife2.ttf"},
+ {"hl2cross", "hl2/resource/HL2Crosshairs.ttf"},
+ {"courier new", "platform/vgui/fonts/cour.ttf"},
+ {"times new roman", "platform/vgui/fonts/times.ttf"},
+ {"trebuchet ms", "platform/vgui/fonts/trebuc.ttf"},
+ {"verdana", "platform/vgui/fonts/verdana.ttf"},
+ {"tahoma", "platform/vgui/fonts/tahoma.ttf"},
+ };
+
+ // remap typeface to diskname
+ const char *pDiskname = NULL;
+ for ( int i=0; i<ARRAYSIZE( fontToFilename ); i++ )
+ {
+ if ( !V_stricmp( pFontname, fontToFilename[i].pFontName ) )
+ {
+ pDiskname = fontToFilename[i].pPath;
+ break;
+ }
+ }
+ if ( !pDiskname )
+ {
+ // not found
+ DevMsg( "True Type Font: '%s' unknown.\n", pFontname );
+ return NULL;
+ }
+
+ // font will be registered using typeface name
+ wchar_t wchFontname[MAX_PATH];
+ Q_UTF8ToUnicode( pFontname, wchFontname, sizeof( wchFontname ) );
+
+ // find font in registered typefaces
+ TypefaceDescriptor *pDescriptors = NULL;
+ DWORD numTypeFaces = 0;
+ HRESULT hr = XuiEnumerateTypefaces( &pDescriptors, &numTypeFaces );
+ if ( FAILED( hr ) )
+ {
+ return NULL;
+ }
+
+ bool bRegistered = false;
+ for ( DWORD i=0; i<numTypeFaces; i++ )
+ {
+ if ( !V_wcscmp( pDescriptors->szTypeface, wchFontname ) )
+ {
+ bRegistered = true;
+ break;
+ }
+ }
+
+ XuiDestroyTypefaceList( pDescriptors, numTypeFaces );
+
+ if ( !bRegistered )
+ {
+ // unregistered type face, register type face and retry
+ // only file based resource locators work
+ char filename[MAX_PATH];
+ V_snprintf( filename, sizeof( filename ), "file://d:/%s", pDiskname );
+ Q_FixSlashes( filename, '/' );
+
+ wchar_t wchFilename[MAX_PATH];
+ Q_UTF8ToUnicode( filename, wchFilename, sizeof( wchFilename ) );
+
+ TypefaceDescriptor desc;
+ desc.fBaselineAdjust = 0;
+ desc.szFallbackTypeface = NULL;
+ desc.szLocator = wchFilename;
+ desc.szReserved1 = 0;
+ desc.szTypeface = wchFontname;
+ hr = XuiRegisterTypeface( &desc, FALSE );
+ if ( FAILED( hr ) )
+ {
+ return NULL;
+ }
+ }
+
+ // empirically derived factor to achieve desired cell height
+ float pointSize = tall * 0.59f;
+ HXUIFONT hFont = NULL;
+ hr = XuiCreateFont( wchFontname, pointSize, style, 0, &hFont );
+ if ( FAILED( hr ) )
+ {
+ return NULL;
+ }
+
+ return hFont;
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// Release TTF
+//-----------------------------------------------------------------------------
+#if defined( _X360 )
+void CShaderAPIDx8::CloseTrueTypeFont( HXUIFONT hFont )
+{
+ if ( !hFont )
+ return;
+ LOCK_SHADERAPI();
+
+ XuiReleaseFont( hFont );
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// Get the TTF Metrics
+//-----------------------------------------------------------------------------
+#if defined( _X360 )
+bool CShaderAPIDx8::GetTrueTypeFontMetrics( HXUIFONT hFont, XUIFontMetrics *pFontMetrics, XUICharMetrics charMetrics[256] )
+{
+ if ( !hFont )
+ return false;
+
+ LOCK_SHADERAPI();
+
+ V_memset( charMetrics, 0, 256 * sizeof( XUICharMetrics ) );
+
+ HRESULT hr = XuiGetFontMetrics( hFont, pFontMetrics );
+ if ( !FAILED( hr ) )
+ {
+ // X360 issue: max character width may be too small.
+ // Run through each character and fixup
+ for ( int i = 1; i < 256; i++ )
+ {
+ wchar_t wch = i;
+ hr = XuiGetCharMetrics( hFont, wch, &charMetrics[i] );
+ if ( !FAILED( hr ) )
+ {
+ float maxWidth = charMetrics[i].fMaxX;
+ if ( charMetrics[i].fMinX < 0 )
+ {
+ maxWidth = charMetrics[i].fMaxX - charMetrics[i].fMinX;
+ }
+ if ( maxWidth > pFontMetrics->fMaxWidth )
+ {
+ pFontMetrics->fMaxWidth = maxWidth;
+ }
+ if ( charMetrics[i].fAdvance > pFontMetrics->fMaxWidth )
+ {
+ pFontMetrics->fMaxWidth = charMetrics[i].fAdvance;
+ }
+ }
+ }
+
+ // fonts are getting cut off, MaxHeight seems to be misreported smaller
+ // take MaxHeight to be the larger of its reported value or (ascent + descent)
+ float maxHeight = 0;
+ if ( pFontMetrics->fMaxDescent <= 0 )
+ {
+ // descent is negative for below baseline
+ maxHeight = pFontMetrics->fMaxAscent - pFontMetrics->fMaxDescent;
+ }
+ if ( maxHeight > pFontMetrics->fMaxHeight )
+ {
+ pFontMetrics->fMaxHeight = maxHeight;
+ }
+ }
+
+ return ( !FAILED( hr ) );
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// Gets the glyph bits in rgba order. This function PURPOSELY hijacks D3D
+// because XUI is involved. It is called at a very specific place in the VGUI
+// render frame where its deleterious affects are going to be harmless.
+//-----------------------------------------------------------------------------
+#if defined( _X360 )
+bool CShaderAPIDx8::GetTrueTypeGlyphs( HXUIFONT hFont, int numChars, wchar_t *pWch, int *pOffsetX, int *pOffsetY, int *pWidth, int *pHeight, unsigned char *pRGBA, int *pRGBAOffset )
+{
+ if ( !hFont )
+ return false;
+
+ // Ensure this doesn't talk to D3D at the same time as the loading bar
+ AUTO_LOCK_FM( m_nonInteractiveModeMutex );
+
+
+ LOCK_SHADERAPI();
+ bool bSuccess = false;
+ IDirect3DSurface *pRTSurface = NULL;
+ IDirect3DSurface *pSavedSurface = NULL;
+ IDirect3DSurface *pSavedDepthSurface = NULL;
+ IDirect3DTexture *pTexture = NULL;
+ D3DVIEWPORT9 savedViewport;
+ D3DXMATRIX matView;
+ D3DXMATRIX matXForm;
+ D3DLOCKED_RECT lockedRect;
+
+ // have to reset to default state to rasterize glyph correctly
+ // state will get re-established during next mesh draw
+ ResetRenderState( false );
+ Dx9Device()->SetRenderState( D3DRS_ZENABLE, FALSE );
+
+ Dx9Device()->GetRenderTarget( 0, &pSavedSurface );
+ Dx9Device()->GetDepthStencilSurface( &pSavedDepthSurface );
+ Dx9Device()->GetViewport( &savedViewport );
+
+ // Figure out the size of surface/texture we need to allocate
+ int rtWidth = 0;
+ int rtHeight = 0;
+ for ( int i = 0; i < numChars; i++ )
+ {
+ rtWidth += pWidth[i];
+ rtHeight = max( rtHeight, pHeight[i] );
+ }
+
+ // per resolve() restrictions
+ rtWidth = AlignValue( rtWidth, 32 );
+ rtHeight = AlignValue( rtHeight, 32 );
+
+ // create a render target to capture the glyph render
+ pRTSurface = g_TextureHeap.AllocRenderTargetSurface( rtWidth, rtHeight, D3DFMT_A8R8G8B8 );
+ if ( !pRTSurface )
+ goto cleanUp;
+
+ Dx9Device()->SetRenderTarget( 0, pRTSurface );
+ // Disable depth here otherwise you get a colour/depth multisample mismatch error (in 480p)
+ Dx9Device()->SetDepthStencilSurface( NULL );
+ Dx9Device()->Clear( 0, NULL, D3DCLEAR_TARGET, 0x00000000, ( ReverseDepthOnX360() ? 0.0 : 1.0f ), 0 );
+
+ // create texture to get glyph render from EDRAM
+ HRESULT hr = Dx9Device()->CreateTexture( rtWidth, rtHeight, 1, 0, D3DFMT_A8R8G8B8, 0, &pTexture, NULL );
+ if ( FAILED( hr ) )
+ goto cleanUp;
+
+
+ bool bPreviousOwnState = OwnGPUResources( false );
+ XuiRenderBegin( m_hDC, 0x00000000 );
+
+ D3DXMatrixIdentity( &matView );
+ XuiRenderSetViewTransform( m_hDC, &matView );
+ XuiRenderSetTransform( m_hDC, &matView );
+
+ // rasterize the glyph
+ XuiSelectFont( m_hDC, hFont );
+ XuiSetColorFactor( m_hDC, 0xFFFFFFFF );
+
+ // Draw the characters, stepping across the texture
+ int xCursor = 0;
+ for ( int i = 0; i < numChars; i++)
+ {
+ // FIXME: the drawRect params don't make much sense (should use "(xCursor+pWidth[i]), pHeight[i]", but then some characters disappear!)
+ XUIRect drawRect = XUIRect( xCursor + pOffsetX[i], pOffsetY[i], rtWidth, rtHeight );
+ wchar_t text[2] = { pWch[i], 0 };
+ XuiDrawText( m_hDC, text, XUI_FONT_STYLE_NORMAL|XUI_FONT_STYLE_SINGLE_LINE|XUI_FONT_STYLE_NO_WORDWRAP, 0, &drawRect );
+ xCursor += pWidth[i];
+ }
+
+ XuiRenderEnd( m_hDC );
+ OwnGPUResources( bPreviousOwnState );
+
+
+ // transfer from edram to system
+ hr = Dx9Device()->Resolve( 0, NULL, pTexture, NULL, 0, 0, NULL, 0, 0, NULL );
+ if ( FAILED( hr ) )
+ goto cleanUp;
+
+ hr = pTexture->LockRect( 0, &lockedRect, NULL, 0 );
+ if ( FAILED( hr ) )
+ goto cleanUp;
+
+ // transfer to linear format, one character at a time
+ xCursor = 0;
+ for ( int i = 0;i < numChars; i++ )
+ {
+ int destPitch = pWidth[i]*4;
+ unsigned char *pLinear = pRGBA + pRGBAOffset[i];
+ RECT copyRect = { xCursor, 0, xCursor + pWidth[i], pHeight[i] };
+ xCursor += pWidth[i];
+ XGUntileSurface( pLinear, destPitch, NULL, lockedRect.pBits, rtWidth, rtHeight, &copyRect, 4 );
+
+ // convert argb to rgba
+ float r, g, b, a;
+ for ( int y = 0; y < pHeight[i]; y++ )
+ {
+ unsigned char *pSrc = (unsigned char*)pLinear + y*destPitch;
+ for ( int x = 0; x < pWidth[i]; x++ )
+ {
+ // undo pre-multiplied alpha since glyph bits will be sourced as a rgba texture
+ if ( !pSrc[0] )
+ a = 1;
+ else
+ a = (float)pSrc[0] * 1.0f/255.0f;
+
+ r = ((float)pSrc[1] * 1.0f/255.0f)/a * 255.0f;
+ if ( r > 255 )
+ r = 255;
+
+ g = ((float)pSrc[2] * 1.0f/255.0f)/a * 255.0f;
+ if ( g > 255 )
+ g = 255;
+
+ b = ((float)pSrc[3] * 1.0f/255.0f)/a * 255.0f;
+ if ( b > 255 )
+ b = 255;
+
+ pSrc[3] = pSrc[0];
+ pSrc[2] = b;
+ pSrc[1] = g;
+ pSrc[0] = r;
+
+ pSrc += 4;
+ }
+ }
+ }
+
+ pTexture->UnlockRect( 0 );
+
+ bSuccess = true;
+
+cleanUp:
+ if ( pRTSurface )
+ {
+ Dx9Device()->SetRenderTarget( 0, pSavedSurface );
+ Dx9Device()->SetDepthStencilSurface( pSavedDepthSurface );
+ Dx9Device()->SetViewport( &savedViewport );
+ pRTSurface->Release();
+ }
+
+ if ( pTexture )
+ pTexture->Release();
+
+ if ( pSavedSurface )
+ pSavedSurface->Release();
+
+ // XUI changed renderstates behind our back, so we need to reset to defaults again to get back in synch:
+ ResetRenderState( false );
+
+ return bSuccess;
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// Create a 360 Render Target Surface
+//-----------------------------------------------------------------------------
+#if defined( _X360 )
+ShaderAPITextureHandle_t CShaderAPIDx8::CreateRenderTargetSurface( int width, int height, ImageFormat format, const char *pDebugName, const char *pTextureGroupName )
+{
+ LOCK_SHADERAPI();
+ ShaderAPITextureHandle_t textureHandle = CreateTextureHandle();
+ Texture_t *pTexture = &GetTexture( textureHandle );
+
+ pTexture->m_Flags = (Texture_t::IS_ALLOCATED | Texture_t::IS_RENDER_TARGET_SURFACE);
+
+ pTexture->m_DebugName = pDebugName;
+ pTexture->m_Width = width;
+ pTexture->m_Height = height;
+ pTexture->m_Depth = 1;
+ pTexture->m_NumCopies = 1;
+ pTexture->m_CurrentCopy = 0;
+
+ ImageFormat dstImageFormat = FindNearestSupportedFormat( format, false, true, false );
+ D3DFORMAT actualFormat = ImageLoader::ImageFormatToD3DFormat( dstImageFormat );
+
+ pTexture->GetRenderTargetSurface( false ) = g_TextureHeap.AllocRenderTargetSurface( width, height, actualFormat );
+ pTexture->GetRenderTargetSurface( true ) = g_TextureHeap.AllocRenderTargetSurface( width, height, (D3DFORMAT)MAKESRGBFMT( actualFormat ) );
+
+ pTexture->SetImageFormat( dstImageFormat );
+
+ pTexture->m_UTexWrap = D3DTADDRESS_CLAMP;
+ pTexture->m_VTexWrap = D3DTADDRESS_CLAMP;
+ pTexture->m_WTexWrap = D3DTADDRESS_CLAMP;
+ pTexture->m_MagFilter = D3DTEXF_LINEAR;
+
+ pTexture->m_NumLevels = 1;
+ pTexture->m_MipFilter = D3DTEXF_NONE;
+ pTexture->m_MinFilter = D3DTEXF_LINEAR;
+
+ pTexture->m_SwitchNeeded = false;
+
+ ComputeStatsInfo( textureHandle, false, false );
+ SetupTextureGroup( textureHandle, pTextureGroupName );
+
+ return textureHandle;
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// Shader constants are batched and written to gpu once prior to draw.
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::WriteShaderConstantsToGPU()
+{
+#if defined( _X360 )
+ // vector vertex constants can just blast their set range
+ if ( m_MaxVectorVertexShaderConstant )
+ {
+ if ( m_bGPUOwned )
+ {
+ // faster path, write directly into GPU command buffer, bypassing shadow state
+ // can only set what is actually owned
+ Assert( m_MaxVectorVertexShaderConstant <= VERTEX_SHADER_MODEL + 3*NUM_MODEL_TRANSFORMS );
+ int numVectors = AlignValue( m_MaxVectorVertexShaderConstant, 4 );
+ BYTE* pCommandBufferData;
+ Dx9Device()->GpuBeginVertexShaderConstantF4( 0, (D3DVECTOR4**)&pCommandBufferData, numVectors );
+ memcpy( pCommandBufferData, m_DesiredState.m_pVectorVertexShaderConstant[0].Base(), numVectors * (sizeof( float ) * 4) );
+ Dx9Device()->GpuEndVertexShaderConstantF4();
+ }
+ else
+ {
+ Dx9Device()->SetVertexShaderConstantF( 0, m_DesiredState.m_pVectorVertexShaderConstant[0].Base(), m_MaxVectorVertexShaderConstant );
+ }
+
+ memcpy( m_DynamicState.m_pVectorVertexShaderConstant[0].Base(), m_DesiredState.m_pVectorVertexShaderConstant[0].Base(), m_MaxVectorVertexShaderConstant * 4 * sizeof(float) );
+ m_MaxVectorVertexShaderConstant = 0;
+ }
+
+ if ( m_MaxVectorPixelShaderConstant )
+ {
+ if ( m_bGPUOwned )
+ {
+ // faster path, write directly into GPU command buffer, bypassing shadow state
+ // can only set what is actually owned
+ Assert( m_MaxVectorPixelShaderConstant <= 32 );
+ int numVectors = AlignValue( m_MaxVectorPixelShaderConstant, 4 );
+ BYTE* pCommandBufferData;
+ Dx9Device()->GpuBeginPixelShaderConstantF4( 0, (D3DVECTOR4**)&pCommandBufferData, numVectors );
+ memcpy( pCommandBufferData, m_DesiredState.m_pVectorPixelShaderConstant[0].Base(), numVectors * (sizeof( float ) * 4) );
+ Dx9Device()->GpuEndPixelShaderConstantF4();
+ }
+ else
+ {
+ Dx9Device()->SetPixelShaderConstantF( 0, m_DesiredState.m_pVectorPixelShaderConstant[0].Base(), m_MaxVectorPixelShaderConstant );
+ }
+
+ memcpy( m_DynamicState.m_pVectorPixelShaderConstant[0].Base(), m_DesiredState.m_pVectorPixelShaderConstant[0].Base(), m_MaxVectorPixelShaderConstant * 4 * sizeof(float) );
+ m_MaxVectorPixelShaderConstant = 0;
+ }
+
+ // boolean and integer constants can just blast their set range
+ // these are currently extremely small in number, if this changes they may benefit from a fast path pattern
+ if ( m_MaxBooleanVertexShaderConstant )
+ {
+ Dx9Device()->SetVertexShaderConstantB( 0, m_DesiredState.m_pBooleanVertexShaderConstant, m_MaxBooleanVertexShaderConstant );
+ memcpy( m_DynamicState.m_pBooleanVertexShaderConstant, m_DesiredState.m_pBooleanVertexShaderConstant, m_MaxBooleanVertexShaderConstant * sizeof(BOOL) );
+ m_MaxBooleanVertexShaderConstant = 0;
+ }
+ if ( m_MaxIntegerVertexShaderConstant )
+ {
+ Dx9Device()->SetVertexShaderConstantI( 0, (int *)m_DesiredState.m_pIntegerVertexShaderConstant, m_MaxIntegerVertexShaderConstant );
+ memcpy( m_DynamicState.m_pIntegerVertexShaderConstant[0].Base(), m_DesiredState.m_pIntegerVertexShaderConstant[0].Base(), m_MaxIntegerVertexShaderConstant * sizeof(IntVector4D) );
+ m_MaxIntegerVertexShaderConstant = 0;
+ }
+
+ if ( m_MaxBooleanPixelShaderConstant )
+ {
+ Dx9Device()->SetPixelShaderConstantB( 0, m_DesiredState.m_pBooleanPixelShaderConstant, m_MaxBooleanPixelShaderConstant );
+ memcpy( m_DynamicState.m_pBooleanPixelShaderConstant, m_DesiredState.m_pBooleanPixelShaderConstant, m_MaxBooleanPixelShaderConstant * sizeof(BOOL) );
+ m_MaxBooleanPixelShaderConstant = 0;
+ }
+
+ // integer pixel constants are not used, so not supporting
+#if 0
+ if ( m_MaxIntegerPixelShaderConstant )
+ {
+ Dx9Device()->SetPixelShaderConstantI( 0, (int *)m_DesiredState.m_pIntegerPixelShaderConstant, m_MaxIntegerPixelShaderConstant );
+ memcpy( m_DynamicState.m_pIntegerPixelShaderConstant[0].Base(), m_DesiredState.m_pIntegerPixelShaderConstant[0].Base(), m_MaxIntegerPixelShaderConstant * sizeof(IntVector4D) );
+ m_MaxIntegerPixelShaderConstant = 0;
+ }
+#endif
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// The application is about to perform a hard reboot, but wants to hide the screen flash
+// by persisting the front buffer across a reboot boundary. The persisted frame buffer
+// can be detected and restored.
+//-----------------------------------------------------------------------------
+#if defined( _X360 )
+void CShaderAPIDx8::PersistDisplay()
+{
+ if ( m_PresentParameters.FrontBufferFormat != D3DFMT_LE_X8R8G8B8 )
+ {
+ // The format must be what PersistDisplay() expects, otherwise D3DRIP.
+ // If this hits due to sRGB bit set that confuses PersistDisplay(),
+ // the fix may be to slam the presentation parameters to the expected format,
+ // do a ResetDevice(), and then PersistDisplay().
+ Assert( 0 );
+ return;
+ }
+
+ IDirect3DTexture *pTexture;
+ HRESULT hr = Dx9Device()->GetFrontBuffer( &pTexture );
+ if ( !FAILED( hr ) )
+ {
+ OwnGPUResources( false );
+ Dx9Device()->PersistDisplay( pTexture, NULL );
+ pTexture->Release();
+ }
+}
+#endif
+
+#if defined( _X360 )
+bool CShaderAPIDx8::PostQueuedTexture( const void *pData, int nDataSize, ShaderAPITextureHandle_t *pHandles, int numHandles, int nWidth, int nHeight, int nDepth, int numMips, int *pRefCount )
+{
+ CUtlBuffer vtfBuffer;
+ IVTFTexture *pVTFTexture = NULL;
+ bool bOK = false;
+
+ if ( !pData || !nDataSize )
+ {
+ // invalid
+ goto cleanUp;
+ }
+
+ // get a unique vtf and mount texture
+ // vtf can expect non-volatile buffer data to be stable through vtf lifetime
+ // this prevents redundant copious amounts of image memory transfers
+ pVTFTexture = CreateVTFTexture();
+ vtfBuffer.SetExternalBuffer( (void *)pData, nDataSize, nDataSize );
+ if ( !pVTFTexture->UnserializeFromBuffer( vtfBuffer, false, false, false, 0 ) )
+ {
+ goto cleanUp;
+ }
+
+ // provided vtf buffer is all mips, determine top mip due to possible picmip
+ int iTopMip = 0;
+ int mipWidth, mipHeight, mipDepth;
+ do
+ {
+ pVTFTexture->ComputeMipLevelDimensions( iTopMip, &mipWidth, &mipHeight, &mipDepth );
+ if ( nWidth == mipWidth && nHeight == mipHeight && nDepth == mipDepth )
+ {
+ break;
+ }
+ iTopMip++;
+ }
+ while ( mipWidth != 1 || mipHeight != 1 || mipDepth != 1 );
+
+ // create and blit
+ for ( int iFrame = 0; iFrame < numHandles; iFrame++ )
+ {
+ ShaderAPITextureHandle_t hTexture = pHandles[iFrame];
+ Texture_t *pTexture = &GetTexture( hTexture );
+
+ int nFaceCount = ( pTexture->m_CreationFlags & TEXTURE_CREATE_CUBEMAP ) ? CUBEMAP_FACE_COUNT-1 : 1;
+
+ IDirect3DBaseTexture *pD3DTexture;
+ if ( pTexture->m_CreationFlags & TEXTURE_CREATE_NOD3DMEMORY )
+ {
+ pD3DTexture = pTexture->GetTexture();
+ if ( !g_TextureHeap.AllocD3DMemory( pD3DTexture ) )
+ {
+ goto cleanUp;
+ }
+ }
+ else
+ {
+ pD3DTexture = pTexture->GetTexture();
+ }
+
+ // blit the hi-res texture bits into d3d memory
+ for ( int iFace = 0; iFace < nFaceCount; ++iFace )
+ {
+ for ( int iMip = 0; iMip < numMips; ++iMip )
+ {
+ pVTFTexture->ComputeMipLevelDimensions( iTopMip + iMip, &mipWidth, &mipHeight, &mipDepth );
+ unsigned char *pSourceBits = pVTFTexture->ImageData( iFrame, iFace, iTopMip + iMip, 0, 0, 0 );
+
+ TextureLoadInfo_t info;
+ info.m_TextureHandle = hTexture;
+ info.m_pTexture = pD3DTexture;
+ info.m_nLevel = iMip;
+ info.m_nCopy = 0;
+ info.m_CubeFaceID = (D3DCUBEMAP_FACES)iFace;
+ info.m_nWidth = mipWidth;
+ info.m_nHeight = mipHeight;
+ info.m_nZOffset = 0;
+ info.m_SrcFormat = pVTFTexture->Format();
+ info.m_pSrcData = pSourceBits;
+ info.m_bSrcIsTiled = pVTFTexture->IsPreTiled();
+ info.m_bCanConvertFormat = ( pTexture->m_Flags & Texture_t::CAN_CONVERT_FORMAT ) != 0;
+ LoadTexture( info );
+ }
+ }
+
+ pTexture->m_Flags |= Texture_t::IS_FINALIZED;
+ (*pRefCount)--;
+ }
+
+ // success
+ bOK = true;
+
+cleanUp:
+ if ( pVTFTexture )
+ {
+ DestroyVTFTexture( pVTFTexture );
+ }
+
+ if ( !bOK )
+ {
+ // undo artificial lock
+ (*pRefCount) -= numHandles;
+ }
+
+ return bOK;
+}
+#endif
+
+#if defined( _X360 )
+void *CShaderAPIDx8::GetD3DDevice()
+{
+ return Dx9Device();
+}
+#endif
+
+#if defined( _X360 )
+static void r_enable_gpr_allocations_callback( IConVar *var, const char *pOldValue, float flOldValue )
+{
+ if ( ((ConVar *)var)->GetBool() == false )
+ {
+ //reset back the default 64/64 allocation before we stop updating
+ if( Dx9Device() != NULL )
+ {
+ Dx9Device()->SetShaderGPRAllocation( 0, 0, 0 );
+ }
+ }
+}
+
+ConVar r_enable_gpr_allocations( "r_enable_gpr_allocations", "1", 0, "Enable usage of IDirect3DDevice9::SetShaderGPRAllocation()", r_enable_gpr_allocations_callback );
+
+static void CommitShaderGPRs( IDirect3DDevice9 *pDevice, const DynamicState_t &desiredState, DynamicState_t &currentState, bool bForce )
+{
+ if( desiredState.m_iVertexShaderGPRAllocation != currentState.m_iVertexShaderGPRAllocation )
+ {
+ pDevice->SetShaderGPRAllocation( 0, desiredState.m_iVertexShaderGPRAllocation, 128 - desiredState.m_iVertexShaderGPRAllocation );
+ currentState.m_iVertexShaderGPRAllocation = desiredState.m_iVertexShaderGPRAllocation;
+ }
+}
+
+void CShaderAPIDx8::PushVertexShaderGPRAllocation( int iVertexShaderCount )
+{
+ Assert( (iVertexShaderCount >= 16) && (iVertexShaderCount <= 112) );
+ m_VertexShaderGPRAllocationStack.Push( iVertexShaderCount );
+
+ if ( r_enable_gpr_allocations.GetBool() )
+ {
+ if ( m_DynamicState.m_iVertexShaderGPRAllocation != iVertexShaderCount )
+ {
+ m_DesiredState.m_iVertexShaderGPRAllocation = iVertexShaderCount;
+ ADD_COMMIT_FUNC( COMMIT_PER_DRAW, COMMIT_ALWAYS, CommitShaderGPRs );
+ }
+ }
+}
+
+void CShaderAPIDx8::PopVertexShaderGPRAllocation( void )
+{
+ m_VertexShaderGPRAllocationStack.Pop();
+
+ if ( r_enable_gpr_allocations.GetBool() )
+ {
+ int iVertexShaderCount;
+ if ( m_VertexShaderGPRAllocationStack.Count() )
+ iVertexShaderCount = m_VertexShaderGPRAllocationStack.Top();
+ else
+ iVertexShaderCount = 64;
+
+ if ( m_DynamicState.m_iVertexShaderGPRAllocation != iVertexShaderCount )
+ {
+ m_DesiredState.m_iVertexShaderGPRAllocation = iVertexShaderCount;
+ ADD_COMMIT_FUNC( COMMIT_PER_DRAW, COMMIT_ALWAYS, CommitShaderGPRs );
+ }
+ }
+}
+
+void CShaderAPIDx8::EnableVSync_360( bool bEnable )
+{
+ if( bEnable )
+ {
+ Dx9Device()->SetRenderState( D3DRS_PRESENTIMMEDIATETHRESHOLD, 0 ); //only swap on vertical blanks
+ }
+ else
+ {
+ Dx9Device()->SetRenderState( D3DRS_PRESENTIMMEDIATETHRESHOLD, 100 ); //allow a swap at any point in the DAC scan
+ }
+}
+#endif
+
+// ------------ New Vertex/Index Buffer interface ----------------------------
+
+void CShaderAPIDx8::BindVertexBuffer( int streamID, IVertexBuffer *pVertexBuffer, int nOffsetInBytes, int nFirstVertex, int nVertexCount, VertexFormat_t fmt, int nRepetitions )
+{
+ LOCK_SHADERAPI();
+ MeshMgr()->BindVertexBuffer( streamID, pVertexBuffer, nOffsetInBytes, nFirstVertex, nVertexCount, fmt, nRepetitions );
+}
+
+void CShaderAPIDx8::BindIndexBuffer( IIndexBuffer *pIndexBuffer, int nOffsetInBytes )
+{
+ LOCK_SHADERAPI();
+ MeshMgr()->BindIndexBuffer( pIndexBuffer, nOffsetInBytes );
+}
+
+void CShaderAPIDx8::Draw( MaterialPrimitiveType_t primitiveType, int nFirstIndex, int nIndexCount )
+{
+ LOCK_SHADERAPI();
+ MeshMgr()->Draw( primitiveType, nFirstIndex, nIndexCount );
+}
+
+// ------------ End ----------------------------
+
+float CShaderAPIDx8::GammaToLinear_HardwareSpecific( float fGamma ) const
+{
+ if( IsPC() )
+ {
+ return SrgbGammaToLinear( fGamma );
+ }
+ else if( IsX360() )
+ {
+ return SrgbGammaToLinear( fGamma );
+ }
+ else
+ {
+ // Unknown console
+ return pow( fGamma, 2.2f ); // Use a gamma 2.2 curve
+ }
+}
+
+float CShaderAPIDx8::LinearToGamma_HardwareSpecific( float fLinear ) const
+{
+ if ( IsPC() )
+ {
+ return SrgbLinearToGamma( fLinear );
+ }
+ else if ( IsX360() )
+ {
+ return SrgbLinearToGamma( fLinear );
+ }
+ else
+ {
+ // Unknown console
+ return pow( fLinear, ( 1.0f / 2.2f ) ); // Use a gamma 2.2 curve
+ }
+}
+
+
+bool CShaderAPIDx8::ShouldWriteDepthToDestAlpha( void ) const
+{
+ return IsPC() && g_pHardwareConfig->SupportsPixelShaders_2_b() &&
+ (m_SceneFogMode != MATERIAL_FOG_LINEAR_BELOW_FOG_Z) &&
+ (GetIntRenderingParameter(INT_RENDERPARM_WRITE_DEPTH_TO_DESTALPHA) != 0);
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::AcquireThreadOwnership()
+{
+ SetCurrentThreadAsOwner();
+#if (defined( _X360 ) || defined( DX_TO_GL_ABSTRACTION ))
+ Dx9Device()->AcquireThreadOwnership();
+#endif
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::ReleaseThreadOwnership()
+{
+ RemoveThreadOwner();
+#if (defined( _X360 ) || defined( DX_TO_GL_ABSTRACTION ))
+ Dx9Device()->ReleaseThreadOwnership();
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Actual low level setting of the color RT. All Xbox RT funnels here
+// to track the actual RT state. Returns true if the RT gets set, otherwise false.
+//-----------------------------------------------------------------------------
+bool CShaderAPIDx8::SetRenderTargetInternalXbox( ShaderAPITextureHandle_t hRenderTargetTexture, bool bForce )
+{
+ // valid for 360 only
+ if ( IsPC() )
+ {
+ Assert( 0 );
+ return false;
+ }
+
+ if ( hRenderTargetTexture == INVALID_SHADERAPI_TEXTURE_HANDLE )
+ {
+ // could be a reset, force to back buffer
+ hRenderTargetTexture = SHADER_RENDERTARGET_BACKBUFFER;
+ }
+
+ if ( m_hCachedRenderTarget == INVALID_SHADERAPI_TEXTURE_HANDLE )
+ {
+ // let the set go through to establish the initial state
+ bForce = true;
+ }
+
+ if ( !bForce && ( hRenderTargetTexture == m_hCachedRenderTarget && m_DynamicState.m_bSRGBWritesEnabled == m_bUsingSRGBRenderTarget ) )
+ {
+ // current RT matches expected state, leave state intact
+ return false;
+ }
+
+ // track the updated state
+ m_bUsingSRGBRenderTarget = m_DynamicState.m_bSRGBWritesEnabled;
+ m_hCachedRenderTarget = hRenderTargetTexture;
+
+ IDirect3DSurface *pSurface;
+ if ( m_hCachedRenderTarget == SHADER_RENDERTARGET_BACKBUFFER )
+ {
+ if ( !m_bUsingSRGBRenderTarget )
+ {
+ pSurface = m_pBackBufferSurface;
+ }
+ else
+ {
+ pSurface = m_pBackBufferSurfaceSRGB;
+ }
+ }
+ else
+ {
+ AssertValidTextureHandle( m_hCachedRenderTarget );
+ Texture_t *pTexture = &GetTexture( m_hCachedRenderTarget );
+ pSurface = pTexture->GetRenderTargetSurface( m_bUsingSRGBRenderTarget );
+ }
+
+ // the 360 does a wierd reset of some states on a SetRenderTarget()
+ // the viewport is a clobbered state, it may not be changed by later callers, so it MUST be put back as expected
+ // the other clobbered states are waiting to be discovered ... sigh
+#if defined( _X360 )
+ D3DVIEWPORT9 viewport;
+ Dx9Device()->GetViewport( &viewport );
+ Dx9Device()->SetRenderTarget( 0, pSurface );
+ Dx9Device()->SetViewport( &viewport );
+#endif
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// debug logging
+//-----------------------------------------------------------------------------
+void CShaderAPIDx8::PrintfVA( char *fmt, va_list vargs )
+{
+#ifdef DX_TO_GL_ABSTRACTION
+ #if GLMDEBUG
+ GLMPrintfVA( fmt, vargs );
+ #endif
+#else
+ AssertOnce( !"Impl me" );
+#endif
+}
+
+void CShaderAPIDx8::Printf( const char *fmt, ... )
+{
+#ifdef DX_TO_GL_ABSTRACTION
+ #if GLMDEBUG
+ va_list vargs;
+
+ va_start(vargs, fmt);
+
+ GLMPrintfVA( fmt, vargs );
+
+ va_end( vargs );
+ #endif
+#else
+ AssertOnce( !"Impl me" );
+#endif
+}
+
+float CShaderAPIDx8::Knob( char *knobname, float *setvalue )
+{
+#ifdef DX_TO_GL_ABSTRACTION
+ #if GLMDEBUG
+ return GLMKnob( knobname, setvalue );
+ #else
+ return 0.0f;
+ #endif
+#else
+ return 0.0f;
+#endif
+}
+
+
+
+#if defined( _X360 )
+
+extern ConVar r_blocking_spew_threshold;
+void D3DBlockingSpewCallback( DWORD Flags, D3DBLOCKTYPE BlockType, float ClockTime, DWORD ThreadTime )
+{
+ if( ClockTime >= r_blocking_spew_threshold.GetFloat() )
+ {
+ const char *pBlockType = "";
+ switch( BlockType )
+ {
+ case D3DBLOCKTYPE_NONE:
+ pBlockType = "D3DBLOCKTYPE_NONE";
+ break;
+ case D3DBLOCKTYPE_PRIMARY_OVERRUN:
+ pBlockType = "D3DBLOCKTYPE_PRIMARY_OVERRUN";
+ break;
+ case D3DBLOCKTYPE_SECONDARY_OVERRUN:
+ pBlockType = "D3DBLOCKTYPE_SECONDARY_OVERRUN";
+ break;
+ case D3DBLOCKTYPE_SWAP_THROTTLE:
+ pBlockType = "D3DBLOCKTYPE_SWAP_THROTTLE";
+ break;
+ case D3DBLOCKTYPE_BLOCK_UNTIL_IDLE:
+ pBlockType = "D3DBLOCKTYPE_BLOCK_UNTIL_IDLE";
+ break;
+ case D3DBLOCKTYPE_BLOCK_UNTIL_NOT_BUSY:
+ pBlockType = "D3DBLOCKTYPE_BLOCK_UNTIL_NOT_BUSY";
+ break;
+ case D3DBLOCKTYPE_BLOCK_ON_FENCE:
+ pBlockType = "D3DBLOCKTYPE_BLOCK_ON_FENCE";
+ break;
+ case D3DBLOCKTYPE_VERTEX_SHADER_RELEASE:
+ pBlockType = "D3DBLOCKTYPE_VERTEX_SHADER_RELEASE";
+ break;
+ case D3DBLOCKTYPE_PIXEL_SHADER_RELEASE:
+ pBlockType = "D3DBLOCKTYPE_PIXEL_SHADER_RELEASE";
+ break;
+ case D3DBLOCKTYPE_VERTEX_BUFFER_RELEASE:
+ pBlockType = "D3DBLOCKTYPE_VERTEX_BUFFER_RELEASE";
+ break;
+ case D3DBLOCKTYPE_VERTEX_BUFFER_LOCK:
+ pBlockType = "D3DBLOCKTYPE_VERTEX_BUFFER_LOCK";
+ break;
+ case D3DBLOCKTYPE_INDEX_BUFFER_RELEASE:
+ pBlockType = "D3DBLOCKTYPE_INDEX_BUFFER_RELEASE";
+ break;
+ case D3DBLOCKTYPE_INDEX_BUFFER_LOCK:
+ pBlockType = "D3DBLOCKTYPE_INDEX_BUFFER_LOCK";
+ break;
+ case D3DBLOCKTYPE_TEXTURE_RELEASE:
+ pBlockType = "D3DBLOCKTYPE_TEXTURE_RELEASE";
+ break;
+ case D3DBLOCKTYPE_TEXTURE_LOCK:
+ pBlockType = "D3DBLOCKTYPE_TEXTURE_LOCK";
+ break;
+ case D3DBLOCKTYPE_COMMAND_BUFFER_RELEASE:
+ pBlockType = "D3DBLOCKTYPE_COMMAND_BUFFER_RELEASE";
+ break;
+ case D3DBLOCKTYPE_COMMAND_BUFFER_LOCK:
+ pBlockType = "D3DBLOCKTYPE_COMMAND_BUFFER_LOCK";
+ break;
+ case D3DBLOCKTYPE_CONSTANT_BUFFER_RELEASE:
+ pBlockType = "D3DBLOCKTYPE_CONSTANT_BUFFER_RELEASE";
+ break;
+ case D3DBLOCKTYPE_CONSTANT_BUFFER_LOCK:
+ pBlockType = "D3DBLOCKTYPE_CONSTANT_BUFFER_LOCK";
+ break;
+
+ NO_DEFAULT;
+ };
+
+ Warning( "D3D Block: %s for %.2f ms\n", pBlockType, ClockTime );
+ }
+}
+
+static void r_blocking_spew_threshold_callback( IConVar *var, const char *pOldValue, float flOldValue )
+{
+ if( Dx9Device() != NULL )
+ {
+ if ( ((ConVar *)var)->GetFloat() >= 0.0f )
+ {
+ Dx9Device()->SetBlockCallback( 0, D3DBlockingSpewCallback );
+ }
+ else
+ {
+ Dx9Device()->SetBlockCallback( 0, NULL );
+ }
+ }
+}
+
+ConVar r_blocking_spew_threshold( "r_blocking_spew_threshold", "-1", 0, "Enable spew of Direct3D Blocks. Specify the minimum blocking time in milliseconds before spewing a warning.", r_blocking_spew_threshold_callback );
+#endif
+
diff --git a/materialsystem/shaderapidx9/shaderapidx8.h b/materialsystem/shaderapidx9/shaderapidx8.h
new file mode 100644
index 0000000..fae297b
--- /dev/null
+++ b/materialsystem/shaderapidx9/shaderapidx8.h
@@ -0,0 +1,118 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#ifndef SHADERAPIDX8_H
+#define SHADERAPIDX8_H
+
+#include "shaderapibase.h"
+#include "shaderapi/ishadershadow.h"
+#include "locald3dtypes.h"
+
+//-----------------------------------------------------------------------------
+// Vendor-specific defines
+//-----------------------------------------------------------------------------
+#define ATI_FETCH4_ENABLE MAKEFOURCC('G','E','T','4')
+#define ATI_FETCH4_DISABLE MAKEFOURCC('G','E','T','1')
+#define ATISAMP_FETCH4 D3DSAMP_MIPMAPLODBIAS
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class CMeshBase;
+class CMeshBuilder;
+struct ShadowState_t;
+class IMaterialInternal;
+
+
+//-----------------------------------------------------------------------------
+// State that matters to buffered meshes... (for debugging only)
+//-----------------------------------------------------------------------------
+struct BufferedState_t
+{
+ D3DXMATRIX m_Transform[3];
+ D3DVIEWPORT9 m_Viewport;
+ int m_BoundTexture[16];
+ void *m_VertexShader;
+ void *m_PixelShader;
+};
+
+
+//-----------------------------------------------------------------------------
+// The DX8 shader API
+//-----------------------------------------------------------------------------
+// FIXME: Remove this! Either move them into CShaderAPIBase or CShaderAPIDx8
+class IShaderAPIDX8 : public CShaderAPIBase
+{
+public:
+ // Draws the mesh
+ virtual void DrawMesh( CMeshBase *pMesh ) = 0;
+
+ // Draw the mesh with the currently bound vertex and index buffers.
+ virtual void DrawWithVertexAndIndexBuffers( void ) = 0;
+
+ // modifies the vertex data when necessary
+ virtual void ModifyVertexData( ) = 0;
+
+ // Gets the current buffered state... (debug only)
+ virtual void GetBufferedState( BufferedState_t &state ) = 0;
+
+ // Gets the current backface cull state....
+ virtual D3DCULL GetCullMode() const = 0;
+
+ // Measures fill rate
+ virtual void ComputeFillRate() = 0;
+
+ // Selection mode methods
+ virtual bool IsInSelectionMode() const = 0;
+
+ // We hit somefin in selection mode
+ virtual void RegisterSelectionHit( float minz, float maxz ) = 0;
+
+ // Get the currently bound material
+ virtual IMaterialInternal* GetBoundMaterial() = 0;
+
+ // These methods are called by the transition table
+ // They depend on dynamic state so can't exist inside the transition table
+ virtual void ApplyZBias( const ShadowState_t &shaderState ) = 0;
+ virtual void ApplyTextureEnable( const ShadowState_t &state, int stage ) = 0;
+ virtual void ApplyCullEnable( bool bEnable ) = 0;
+ virtual void SetVertexBlendState( int numBones ) = 0;
+ virtual void ApplyFogMode( ShaderFogMode_t fogMode, bool bSRGBWritesEnabled, bool bDisableGammaCorrection ) = 0;
+
+ virtual int GetActualTextureStageCount() const = 0;
+ virtual int GetActualSamplerCount() const = 0;
+
+ virtual bool IsRenderingMesh() const = 0;
+
+ // Fog methods...
+ virtual void FogMode( MaterialFogMode_t fogMode ) = 0;
+
+ virtual int GetCurrentFrameCounter( void ) const = 0;
+
+ // Workaround hack for visualization of selection mode
+ virtual void SetupSelectionModeVisualizationState() = 0;
+
+ virtual bool UsingSoftwareVertexProcessing() const = 0;
+
+ //notification that the SRGB write state is being changed
+ virtual void EnabledSRGBWrite( bool bEnabled ) = 0;
+
+ // Alpha to coverage
+ virtual void ApplyAlphaToCoverage( bool bEnable ) = 0;
+
+#if defined( _X360 )
+ virtual void ApplySRGBReadState( int iTextureStage, bool bSRGBReadEnabled ) = 0; //360 needs to rebind the texture over again instead of setting a sampler state
+#endif
+
+ virtual void PrintfVA( char *fmt, va_list vargs ) = 0;
+ virtual void Printf( PRINTF_FORMAT_STRING const char *fmt, ... ) = 0;
+ virtual float Knob( char *knobname, float *setvalue = NULL ) = 0;
+};
+
+
+#endif // SHADERAPIDX8_H
diff --git a/materialsystem/shaderapidx9/shaderapidx8_global.h b/materialsystem/shaderapidx9/shaderapidx8_global.h
new file mode 100644
index 0000000..2dab1e3
--- /dev/null
+++ b/materialsystem/shaderapidx9/shaderapidx8_global.h
@@ -0,0 +1,100 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#ifndef SHADERAPIDX8_GLOBAL_H
+#define SHADERAPIDX8_GLOBAL_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier0/dbg.h"
+#include "tier0/memalloc.h"
+#include "shaderapi_global.h"
+#include "tier2/tier2.h"
+#include "shaderdevicedx8.h"
+
+
+//-----------------------------------------------------------------------------
+// Use this to fill in structures with the current board state
+//-----------------------------------------------------------------------------
+
+#ifdef _DEBUG
+#define DEBUG_BOARD_STATE 0
+#endif
+
+#if !defined( _X360 )
+IDirect3DDevice9 *Dx9Device();
+IDirect3D9 *D3D();
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Measures driver allocations
+//-----------------------------------------------------------------------------
+//#define MEASURE_DRIVER_ALLOCATIONS 1
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class IShaderUtil;
+class IVertexBufferDX8;
+class IShaderShadowDX8;
+class IMeshMgr;
+class IShaderAPIDX8;
+class IFileSystem;
+class IShaderManager;
+
+
+//-----------------------------------------------------------------------------
+// A new shader draw flag we need to workaround dx8
+//-----------------------------------------------------------------------------
+enum
+{
+ SHADER_HAS_CONSTANT_COLOR = 0x80000000
+};
+
+//-----------------------------------------------------------------------------
+// The main shader API
+//-----------------------------------------------------------------------------
+extern IShaderAPIDX8 *g_pShaderAPIDX8;
+inline IShaderAPIDX8* ShaderAPI()
+{
+ return g_pShaderAPIDX8;
+}
+
+//-----------------------------------------------------------------------------
+// The shader shadow
+//-----------------------------------------------------------------------------
+IShaderShadowDX8* ShaderShadow();
+
+//-----------------------------------------------------------------------------
+// Manager of all vertex + pixel shaders
+//-----------------------------------------------------------------------------
+inline IShaderManager *ShaderManager()
+{
+ extern IShaderManager *g_pShaderManager;
+ return g_pShaderManager;
+}
+
+//-----------------------------------------------------------------------------
+// The mesh manager
+//-----------------------------------------------------------------------------
+IMeshMgr* MeshMgr();
+
+//-----------------------------------------------------------------------------
+// The main hardware config interface
+//-----------------------------------------------------------------------------
+inline IMaterialSystemHardwareConfig* HardwareConfig()
+{
+ return g_pMaterialSystemHardwareConfig;
+}
+
+
+#endif // SHADERAPIDX8_GLOBAL_H
diff --git a/materialsystem/shaderapidx9/shaderapidx9.vpc b/materialsystem/shaderapidx9/shaderapidx9.vpc
new file mode 100644
index 0000000..167a719
--- /dev/null
+++ b/materialsystem/shaderapidx9/shaderapidx9.vpc
@@ -0,0 +1,146 @@
+//-----------------------------------------------------------------------------
+// SHADERDX8.VPC
+//
+// Project Script
+//-----------------------------------------------------------------------------
+
+$Macro SRCDIR "..\.."
+$Macro OUTBINDIR "$SRCDIR\..\game\bin"
+$Macro OUTBINNAME "shaderapidx9"
+
+$include "$SRCDIR\vpc_scripts\source_dll_base.vpc"
+
+
+// Common Configuration
+$Configuration
+{
+ $Compiler
+ {
+ $AdditionalIncludeDirectories "$BASE;$SRCDIR\dx9sdk\include" [$WIN32 && !$GL]
+ $AdditionalIncludeDirectories "$BASE;$SRCDIR\x360xdk\include\xbox" [$X360]
+ $AdditionalIncludeDirectories "$BASE;..\"
+ $PreprocessorDefinitions "$BASE;SHADERAPIDX9;SHADER_DLL_EXPORT;PROTECTED_THINGS_ENABLE;strncpy=use_Q_strncpy_instead;_snprintf=use_Q_snprintf_instead"
+ $PreprocessorDefinitions "$BASE;USE_ACTUAL_DX" [($WIN32||$X360) && !$GL]
+ $PreprocessorDefinitions "$BASE;GL_GLEXT_PROTOTYPES;DX_TO_GL_ABSTRACTION" [$GL]
+// $AdditionalOptions "/FC"
+ }
+
+ $Linker
+ {
+ $SystemLibraries "iconv" [$OSXALL]
+ $GCC_ExtraLinkerFlags "-L/usr/lib32" [$LINUXALL]
+ $SystemFrameworks "Carbon;OpenGL;Quartz;Cocoa;IOKit" [$OSXALL]
+ $AdditionalDependencies "$BASE ws2_32.lib" [$WIN32]
+ }
+}
+
+$Configuration "Debug"
+{
+ $Linker [$X360]
+ {
+ $AdditionalDependencies "$BASE d3dx9d.lib xuirund.lib xuirenderd.lib xaudiod2.lib xmcored.lib"
+ }
+}
+
+$Configuration "Release"
+{
+ $Linker [$X360]
+ {
+ $AdditionalDependencies "$BASE d3dx9.lib xuirun.lib xuirender.lib xaudio2.lib xmcore.lib"
+ }
+}
+
+$Project "shaderapidx9"
+{
+ $Folder "Source Files"
+ {
+ $File "colorformatdx8.cpp"
+ $File "$SRCDIR\public\filesystem_helpers.cpp"
+ $File "hardwareconfig.cpp"
+ $File "meshbase.cpp"
+ $File "meshdx8.cpp"
+ $File "recording.cpp" [$WIN32 && !$GL]
+ $File "shaderapidx8.cpp"
+ $File "shaderdevicebase.cpp"
+ $File "shaderapibase.cpp"
+ $File "shaderdevicedx8.cpp"
+ $File "shadershadowdx8.cpp"
+ $File "texturedx8.cpp"
+ $File "TransitionTable.cpp"
+ $File "cvballoctracker.cpp"
+ $File "vertexdecl.cpp"
+ $File "vertexshaderdx8.cpp"
+ $File "wmi.cpp" [$WIN32 && !$GL]
+ $File "textureheap.cpp" [$X360]
+ $File "winutils.cpp" [!$WIN32]
+ }
+
+ $Folder "DirectX Header Files" [$WIN32 && !$GL]
+ {
+ $File "$SRCDIR\dx9sdk\include\d3dx9.h"
+ $File "$SRCDIR\dx9sdk\include\d3dx9anim.h"
+ $File "$SRCDIR\dx9sdk\include\d3dx9core.h"
+ $File "$SRCDIR\dx9sdk\include\d3dx9effect.h"
+ $File "$SRCDIR\dx9sdk\include\d3dx9math.h"
+ $File "$SRCDIR\dx9sdk\include\d3dx9math.inl"
+ $File "$SRCDIR\dx9sdk\include\d3dx9mesh.h"
+ $File "$SRCDIR\dx9sdk\include\d3dx9shader.h"
+ $File "$SRCDIR\dx9sdk\include\d3dx9shape.h"
+ $File "$SRCDIR\dx9sdk\include\d3dx9tex.h"
+ }
+
+ $Folder "Public Header Files"
+ {
+ $File "$SRCDIR\public\shaderapi\IShaderDevice.h"
+ $File "$SRCDIR\public\shaderapi\ishaderutil.h"
+ $File "$SRCDIR\public\shaderapi\ishaderapi.h"
+ $File "$SRCDIR\public\shaderapi\ishaderdynamic.h"
+ $File "$SRCDIR\public\shaderapi\ishadershadow.h"
+ $File "$SRCDIR\public\materialsystem\idebugtextureinfo.h"
+ $File "$SRCDIR\public\materialsystem\ivballoctracker.h"
+ $File "$SRCDIR\public\materialsystem\shader_vcs_version.h"
+ }
+
+ $Folder "Header Files"
+ {
+ $File "TransitionTable.h"
+ $File "vertexdecl.h"
+ $File "colorformatdx8.h"
+ $File "dynamicib.h"
+ $File "dynamicvb.h"
+ $File "hardwareconfig.h"
+ $File "meshbase.h"
+ $File "imeshdx8.h"
+ $File "locald3dtypes.h"
+ $File "recording.h"
+ $File "shaderapidx8.h"
+ $File "shaderdevicebase.h"
+ $File "shaderapibase.h"
+ $File "shaderdevicedx8.h"
+ $File "shaderapidx8_global.h"
+ $File "shadershadowdx8.h"
+ $File "stubd3ddevice.h"
+ $File "texturedx8.h"
+ $File "vertexshaderdx8.h"
+ $File "wmi.h" [$WIN32 && !$GL]
+ $File "textureheap.h" [$X360]
+ $File "winutils.h" [!$WIN32]
+ }
+
+ $Folder "Link Libraries" [$WIN32]
+ {
+
+ $File "$SRCDIR\dx9sdk\lib\d3d9.lib" [$WIN32 && !$GL]
+ $File "$SRCDIR\dx9sdk\lib\d3dx9.lib" [$WIN32 && !$GL&&!$VS2015]
+ $File "$LIBCOMMON\d3dx9.lib" [$WIN32 && !$GL &&$VS2015]
+ }
+
+ $Folder "Link Libraries"
+ {
+ $Lib bitmap
+ $Lib mathlib
+ $Lib tier2
+ $Lib "$LIBCOMMON/bzip2"
+ $ImpLib togl [!$IS_LIB_PROJECT && $GL]
+ }
+}
diff --git a/materialsystem/shaderapidx9/shaderdevicebase.cpp b/materialsystem/shaderapidx9/shaderdevicebase.cpp
new file mode 100644
index 0000000..aef5996
--- /dev/null
+++ b/materialsystem/shaderapidx9/shaderdevicebase.cpp
@@ -0,0 +1,1256 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#define DISABLE_PROTECTED_THINGS
+#include "togl/rendermechanism.h"
+#include "shaderdevicebase.h"
+#include "tier1/KeyValues.h"
+#include "tier1/convar.h"
+#include "tier1/utlbuffer.h"
+#include "tier0/icommandline.h"
+#include "tier2/tier2.h"
+#include "filesystem.h"
+#include "datacache/idatacache.h"
+#include "shaderapi/ishaderutil.h"
+#include "shaderapibase.h"
+#include "shaderapi/ishadershadow.h"
+#include "shaderapi_global.h"
+#include "winutils.h"
+
+#ifdef _X360
+#include "xbox/xbox_win32stubs.h"
+#endif
+
+//-----------------------------------------------------------------------------
+// Globals
+//-----------------------------------------------------------------------------
+IShaderUtil* g_pShaderUtil; // The main shader utility interface
+CShaderDeviceBase *g_pShaderDevice;
+CShaderDeviceMgrBase *g_pShaderDeviceMgr;
+CShaderAPIBase *g_pShaderAPI;
+IShaderShadow *g_pShaderShadow;
+
+bool g_bUseShaderMutex = false; // Shader mutex globals
+bool g_bShaderAccessDisallowed;
+CShaderMutex g_ShaderMutex;
+
+//-----------------------------------------------------------------------------
+// FIXME: Hack related to setting command-line values for convars. Remove!!!
+//-----------------------------------------------------------------------------
+class CShaderAPIConVarAccessor : public IConCommandBaseAccessor
+{
+public:
+ virtual bool RegisterConCommandBase( ConCommandBase *pCommand )
+ {
+ // Link to engine's list instead
+ g_pCVar->RegisterConCommand( pCommand );
+
+ char const *pValue = g_pCVar->GetCommandLineValue( pCommand->GetName() );
+ if( pValue && !pCommand->IsCommand() )
+ {
+ ( ( ConVar * )pCommand )->SetValue( pValue );
+ }
+ return true;
+ }
+};
+
+static void InitShaderAPICVars( )
+{
+ static CShaderAPIConVarAccessor g_ConVarAccessor;
+ if ( g_pCVar )
+ {
+ ConVar_Register( FCVAR_MATERIAL_SYSTEM_THREAD, &g_ConVarAccessor );
+ }
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Read dx support levels
+//-----------------------------------------------------------------------------
+#if defined( DX_TO_GL_ABSTRACTION )
+ #if defined( OSX )
+ // OSX
+ #define SUPPORT_CFG_FILE "dxsupport_mac.cfg"
+ // TODO: make this different for Mac?
+ #define SUPPORT_CFG_OVERRIDE_FILE "dxsupport_override.cfg"
+ #else
+ // Linux/Win GL
+ #define SUPPORT_CFG_FILE "dxsupport_linux.cfg"
+ // TODO: make this different for Linux?
+ #define SUPPORT_CFG_OVERRIDE_FILE "dxsupport_override.cfg"
+ #endif
+#else
+ // D3D
+ #define SUPPORT_CFG_FILE "dxsupport.cfg"
+ #define SUPPORT_CFG_OVERRIDE_FILE "dxsupport_override.cfg"
+#endif
+
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+CShaderDeviceMgrBase::CShaderDeviceMgrBase()
+{
+ m_pDXSupport = NULL;
+}
+
+CShaderDeviceMgrBase::~CShaderDeviceMgrBase()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Factory used to get at internal interfaces (used by shaderapi + shader dlls)
+//-----------------------------------------------------------------------------
+static CreateInterfaceFn s_TempFactory;
+void *ShaderDeviceFactory( const char *pName, int *pReturnCode )
+{
+ if (pReturnCode)
+ {
+ *pReturnCode = IFACE_OK;
+ }
+
+ void *pInterface = s_TempFactory( pName, pReturnCode );
+ if ( pInterface )
+ return pInterface;
+
+ pInterface = Sys_GetFactoryThis()( pName, pReturnCode );
+ if ( pInterface )
+ return pInterface;
+
+ if ( pReturnCode )
+ {
+ *pReturnCode = IFACE_FAILED;
+ }
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Connect, disconnect
+//-----------------------------------------------------------------------------
+bool CShaderDeviceMgrBase::Connect( CreateInterfaceFn factory )
+{
+ LOCK_SHADERAPI();
+
+ Assert( !g_pShaderDeviceMgr );
+
+ s_TempFactory = factory;
+
+ // Connection/convar registration
+ CreateInterfaceFn actualFactory = ShaderDeviceFactory;
+ ConnectTier1Libraries( &actualFactory, 1 );
+ InitShaderAPICVars();
+ ConnectTier2Libraries( &actualFactory, 1 );
+ g_pShaderUtil = (IShaderUtil*)ShaderDeviceFactory( SHADER_UTIL_INTERFACE_VERSION, NULL );
+ g_pShaderDeviceMgr = this;
+
+ s_TempFactory = NULL;
+
+ if ( !g_pShaderUtil || !g_pFullFileSystem || !g_pShaderDeviceMgr )
+ {
+ Warning( "ShaderAPIDx10 was unable to access the required interfaces!\n" );
+ return false;
+ }
+
+ // NOTE! : Overbright is 1.0 so that Hammer will work properly with the white bumped and unbumped lightmaps.
+ MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f );
+ return true;
+}
+
+void CShaderDeviceMgrBase::Disconnect()
+{
+ LOCK_SHADERAPI();
+
+ g_pShaderDeviceMgr = NULL;
+ g_pShaderUtil = NULL;
+ DisconnectTier2Libraries();
+ ConVar_Unregister();
+ DisconnectTier1Libraries();
+
+ if ( m_pDXSupport )
+ {
+ m_pDXSupport->deleteThis();
+ m_pDXSupport = NULL;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Query interface
+//-----------------------------------------------------------------------------
+void *CShaderDeviceMgrBase::QueryInterface( const char *pInterfaceName )
+{
+ if ( !Q_stricmp( pInterfaceName, SHADER_DEVICE_MGR_INTERFACE_VERSION ) )
+ return ( IShaderDeviceMgr* )this;
+ if ( !Q_stricmp( pInterfaceName, MATERIALSYSTEM_HARDWARECONFIG_INTERFACE_VERSION ) )
+ return ( IMaterialSystemHardwareConfig* )g_pHardwareConfig;
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the hardware caps for a particular adapter
+//-----------------------------------------------------------------------------
+const HardwareCaps_t& CShaderDeviceMgrBase::GetHardwareCaps( int nAdapter ) const
+{
+ Assert( ( nAdapter >= 0 ) && ( nAdapter < GetAdapterCount() ) );
+ return m_Adapters[nAdapter].m_ActualCaps;
+}
+
+
+//-----------------------------------------------------------------------------
+// Utility methods for reading config scripts
+//-----------------------------------------------------------------------------
+static inline int ReadHexValue( KeyValues *pVal, const char *pName )
+{
+ const char *pString = pVal->GetString( pName, NULL );
+ if (!pString)
+ {
+ return -1;
+ }
+
+ char *pTemp;
+ int nVal = strtol( pString, &pTemp, 16 );
+ return (pTemp != pString) ? nVal : -1;
+}
+
+static bool ReadBool( KeyValues *pGroup, const char *pKeyName, bool bDefault )
+{
+ int nVal = pGroup->GetInt( pKeyName, -1 );
+ if ( nVal != -1 )
+ {
+ // Warning( "\t%s = %s\n", pKeyName, (nVal != false) ? "true" : "false" );
+ return (nVal != false);
+ }
+ return bDefault;
+}
+
+static void ReadInt( KeyValues *pGroup, const char *pKeyName, int nInvalidValue, int *pResult )
+{
+ int nVal = pGroup->GetInt( pKeyName, nInvalidValue );
+ if ( nVal != nInvalidValue )
+ {
+ *pResult = nVal;
+ // Warning( "\t%s = %d\n", pKeyName, *pResult );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Utility method to copy over a keyvalue
+//-----------------------------------------------------------------------------
+static void AddKey( KeyValues *pDest, KeyValues *pSrc )
+{
+ // Note this will replace already-existing values
+ switch( pSrc->GetDataType() )
+ {
+ case KeyValues::TYPE_NONE:
+ break;
+ case KeyValues::TYPE_STRING:
+ pDest->SetString( pSrc->GetName(), pSrc->GetString() );
+ break;
+ case KeyValues::TYPE_INT:
+ pDest->SetInt( pSrc->GetName(), pSrc->GetInt() );
+ break;
+ case KeyValues::TYPE_FLOAT:
+ pDest->SetFloat( pSrc->GetName(), pSrc->GetFloat() );
+ break;
+ case KeyValues::TYPE_PTR:
+ pDest->SetPtr( pSrc->GetName(), pSrc->GetPtr() );
+ break;
+ case KeyValues::TYPE_WSTRING:
+ pDest->SetWString( pSrc->GetName(), pSrc->GetWString() );
+ break;
+ case KeyValues::TYPE_COLOR:
+ pDest->SetColor( pSrc->GetName(), pSrc->GetColor() );
+ break;
+ default:
+ Assert( 0 );
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Finds if we have a dxlevel-specific config in the support keyvalues
+//-----------------------------------------------------------------------------
+KeyValues *CShaderDeviceMgrBase::FindDXLevelSpecificConfig( KeyValues *pKeyValues, int nDxLevel )
+{
+ KeyValues *pGroup = pKeyValues->GetFirstSubKey();
+ for( pGroup = pKeyValues->GetFirstSubKey(); pGroup; pGroup = pGroup->GetNextKey() )
+ {
+ int nFoundDxLevel = pGroup->GetInt( "name", 0 );
+ if( nFoundDxLevel == nDxLevel )
+ return pGroup;
+ }
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Finds if we have a dxlevel and vendor-specific config in the support keyvalues
+//-----------------------------------------------------------------------------
+KeyValues *CShaderDeviceMgrBase::FindDXLevelAndVendorSpecificConfig( KeyValues *pKeyValues, int nDxLevel, int nVendorID )
+{
+ if ( IsX360() )
+ {
+ // 360 unique dxlevel implies hw config, vendor variance not applicable
+ return NULL;
+ }
+
+ KeyValues *pGroup = pKeyValues->GetFirstSubKey();
+ for( pGroup = pKeyValues->GetFirstSubKey(); pGroup; pGroup = pGroup->GetNextKey() )
+ {
+ int nFoundDxLevel = pGroup->GetInt( "name", 0 );
+ int nFoundVendorID = ReadHexValue( pGroup, "VendorID" );
+ if( nFoundDxLevel == nDxLevel && nFoundVendorID == nVendorID )
+ return pGroup;
+ }
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Finds if we have a vendor-specific config in the support keyvalues
+//-----------------------------------------------------------------------------
+KeyValues *CShaderDeviceMgrBase::FindCPUSpecificConfig( KeyValues *pKeyValues, int nCPUMhz, bool bAMD )
+{
+ if ( IsX360() )
+ {
+ // 360 unique dxlevel implies hw config, cpu variance not applicable
+ return NULL;
+ }
+
+ for( KeyValues *pGroup = pKeyValues->GetFirstSubKey(); pGroup; pGroup = pGroup->GetNextKey() )
+ {
+ const char *pName = pGroup->GetString( "name", NULL );
+ if ( !pName )
+ continue;
+
+ if ( ( bAMD && Q_stristr( pName, "AMD" ) ) ||
+ ( !bAMD && Q_stristr( pName, "Intel" ) ) )
+ {
+ int nMinMegahertz = pGroup->GetInt( "min megahertz", -1 );
+ int nMaxMegahertz = pGroup->GetInt( "max megahertz", -1 );
+ if( nMinMegahertz == -1 || nMaxMegahertz == -1 )
+ continue;
+
+ if( nMinMegahertz <= nCPUMhz && nCPUMhz < nMaxMegahertz )
+ return pGroup;
+ }
+ }
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Finds if we have a vendor-specific config in the support keyvalues
+//-----------------------------------------------------------------------------
+KeyValues *CShaderDeviceMgrBase::FindCardSpecificConfig( KeyValues *pKeyValues, int nVendorId, int nDeviceId )
+{
+ if ( IsX360() )
+ {
+ // 360 unique dxlevel implies hw config, vendor variance not applicable
+ return NULL;
+ }
+
+ KeyValues *pGroup = pKeyValues->GetFirstSubKey();
+ for( pGroup = pKeyValues->GetFirstSubKey(); pGroup; pGroup = pGroup->GetNextKey() )
+ {
+ int nFoundVendorId = ReadHexValue( pGroup, "VendorID" );
+ int nFoundDeviceIdMin = ReadHexValue( pGroup, "MinDeviceID" );
+ int nFoundDeviceIdMax = ReadHexValue( pGroup, "MaxDeviceID" );
+ if ( nFoundVendorId == nVendorId && nDeviceId >= nFoundDeviceIdMin && nDeviceId <= nFoundDeviceIdMax )
+ return pGroup;
+ }
+
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Finds if we have a vendor-specific config in the support keyvalues
+//-----------------------------------------------------------------------------
+KeyValues *CShaderDeviceMgrBase::FindMemorySpecificConfig( KeyValues *pKeyValues, int nSystemRamMB )
+{
+ if ( IsX360() )
+ {
+ // 360 unique dxlevel implies hw config, memory variance not applicable
+ return NULL;
+ }
+
+ for( KeyValues *pGroup = pKeyValues->GetFirstSubKey(); pGroup; pGroup = pGroup->GetNextKey() )
+ {
+ // Used to help us debug this code
+// const char *pDebugName = pGroup->GetString( "name", "blah" );
+
+ int nMinMB = pGroup->GetInt( "min megabytes", -1 );
+ int nMaxMB = pGroup->GetInt( "max megabytes", -1 );
+ if ( nMinMB == -1 || nMaxMB == -1 )
+ continue;
+
+ if ( nMinMB <= nSystemRamMB && nSystemRamMB < nMaxMB )
+ return pGroup;
+ }
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Finds if we have a texture mem size specific config
+//-----------------------------------------------------------------------------
+KeyValues *CShaderDeviceMgrBase::FindVidMemSpecificConfig( KeyValues *pKeyValues, int nVideoRamMB )
+{
+ if ( IsX360() )
+ {
+ // 360 unique dxlevel implies hw config, vidmem variance not applicable
+ return NULL;
+ }
+
+ for( KeyValues *pGroup = pKeyValues->GetFirstSubKey(); pGroup; pGroup = pGroup->GetNextKey() )
+ {
+ int nMinMB = pGroup->GetInt( "min megatexels", -1 );
+ int nMaxMB = pGroup->GetInt( "max megatexels", -1 );
+ if ( nMinMB == -1 || nMaxMB == -1 )
+ continue;
+
+ if ( nMinMB <= nVideoRamMB && nVideoRamMB < nMaxMB )
+ return pGroup;
+ }
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Methods related to reading DX support levels given particular devices
+//-----------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------
+// Reads in the dxsupport.cfg keyvalues
+//-----------------------------------------------------------------------------
+static void OverrideValues_R( KeyValues *pDest, KeyValues *pSrc )
+{
+ // Any same-named values get overridden in pDest.
+ for ( KeyValues *pSrcValue=pSrc->GetFirstValue(); pSrcValue; pSrcValue=pSrcValue->GetNextValue() )
+ {
+ // Shouldn't be a container for more keys.
+ Assert( pSrcValue->GetDataType() != KeyValues::TYPE_NONE );
+ AddKey( pDest, pSrcValue );
+ }
+
+ // Recurse.
+ for ( KeyValues *pSrcDir=pSrc->GetFirstTrueSubKey(); pSrcDir; pSrcDir=pSrcDir->GetNextTrueSubKey() )
+ {
+ Assert( pSrcDir->GetDataType() == KeyValues::TYPE_NONE );
+
+ KeyValues *pDestDir = pDest->FindKey( pSrcDir->GetName() );
+ if ( pDestDir && pDestDir->GetDataType() == KeyValues::TYPE_NONE )
+ {
+ OverrideValues_R( pDestDir, pSrcDir );
+ }
+ }
+}
+
+static KeyValues * FindMatchingGroup( KeyValues *pSrc, KeyValues *pMatch )
+{
+ KeyValues *pMatchSubKey = pMatch->FindKey( "name" );
+ bool bHasSubKey = ( pMatchSubKey && ( pMatchSubKey->GetDataType() != KeyValues::TYPE_NONE ) );
+ const char *name = bHasSubKey ? pMatchSubKey->GetString() : NULL;
+ int nMatchVendorID = ReadHexValue( pMatch, "VendorID" );
+ int nMatchMinDeviceID = ReadHexValue( pMatch, "MinDeviceID" );
+ int nMatchMaxDeviceID = ReadHexValue( pMatch, "MaxDeviceID" );
+
+ KeyValues *pSrcGroup = NULL;
+ for ( pSrcGroup = pSrc->GetFirstTrueSubKey(); pSrcGroup; pSrcGroup = pSrcGroup->GetNextTrueSubKey() )
+ {
+ if ( name )
+ {
+ KeyValues *pSrcGroupName = pSrcGroup->FindKey( "name" );
+ Assert( pSrcGroupName );
+ Assert( pSrcGroupName->GetDataType() != KeyValues::TYPE_NONE );
+ if ( Q_stricmp( pSrcGroupName->GetString(), name ) )
+ continue;
+ }
+
+ if ( nMatchVendorID >= 0 )
+ {
+ int nVendorID = ReadHexValue( pSrcGroup, "VendorID" );
+ if ( nMatchVendorID != nVendorID )
+ continue;
+ }
+
+ if ( nMatchMinDeviceID >= 0 && nMatchMaxDeviceID >= 0 )
+ {
+ int nMinDeviceID = ReadHexValue( pSrcGroup, "MinDeviceID" );
+ int nMaxDeviceID = ReadHexValue( pSrcGroup, "MaxDeviceID" );
+ if ( nMinDeviceID < 0 || nMaxDeviceID < 0 )
+ continue;
+
+ if ( nMatchMinDeviceID > nMinDeviceID || nMatchMaxDeviceID < nMaxDeviceID )
+ continue;
+ }
+
+ return pSrcGroup;
+ }
+ return NULL;
+}
+
+static void OverrideKeyValues( KeyValues *pDst, KeyValues *pSrc )
+{
+ KeyValues *pSrcGroup = NULL;
+ for ( pSrcGroup = pSrc->GetFirstTrueSubKey(); pSrcGroup; pSrcGroup = pSrcGroup->GetNextTrueSubKey() )
+ {
+ // Match each group in pSrc to one in pDst containing the same "name" value:
+ KeyValues * pDstGroup = FindMatchingGroup( pDst, pSrcGroup );
+ //Assert( pDstGroup );
+ if ( pDstGroup )
+ {
+ OverrideValues_R( pDstGroup, pSrcGroup );
+ }
+ }
+
+ // if( CommandLine()->FindParm( "-debugdxsupport" ) )
+ // {
+ // CUtlBuffer tmpBuf;
+ // pDst->RecursiveSaveToFile( tmpBuf, 0 );
+ // g_pFullFileSystem->WriteFile( "gary.txt", NULL, tmpBuf );
+ // }
+}
+
+KeyValues *CShaderDeviceMgrBase::ReadDXSupportKeyValues()
+{
+ if ( CommandLine()->CheckParm( "-ignoredxsupportcfg" ) )
+ return NULL;
+
+ if ( m_pDXSupport )
+ return m_pDXSupport;
+
+ KeyValues *pCfg = new KeyValues( "dxsupport" );
+
+ const char *pPathID = "EXECUTABLE_PATH";
+ if ( IsX360() && g_pFullFileSystem->GetDVDMode() == DVDMODE_STRICT )
+ {
+ // 360 dvd optimzation, expect it inside the platform zip
+ pPathID = "PLATFORM";
+ }
+
+ // First try to read a game-specific config, if it exists
+ if ( !pCfg->LoadFromFile( g_pFullFileSystem, SUPPORT_CFG_FILE, pPathID ) )
+ {
+ pCfg->deleteThis();
+ return NULL;
+ }
+
+ char pTempPath[1024];
+ if ( g_pFullFileSystem->GetSearchPath( "GAME", false, pTempPath, sizeof(pTempPath) ) > 1 )
+ {
+ // Is there a mod-specific override file?
+ KeyValues *pOverride = new KeyValues( "dxsupport_override" );
+ if ( pOverride->LoadFromFile( g_pFullFileSystem, SUPPORT_CFG_OVERRIDE_FILE, "GAME" ) )
+ {
+ OverrideKeyValues( pCfg, pOverride );
+ }
+
+ pOverride->deleteThis();
+ }
+
+ m_pDXSupport = pCfg;
+ return pCfg;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Returns the max dx support level achievable with this board
+//-----------------------------------------------------------------------------
+void CShaderDeviceMgrBase::ReadDXSupportLevels( HardwareCaps_t &caps )
+{
+ // See if the file tells us otherwise
+ KeyValues *pCfg = ReadDXSupportKeyValues();
+ if ( !pCfg )
+ return;
+
+ KeyValues *pDeviceKeyValues = FindCardSpecificConfig( pCfg, caps.m_VendorID, caps.m_DeviceID );
+ if ( pDeviceKeyValues )
+ {
+ // First, set the max dx level
+ int nMaxDXSupportLevel = 0;
+ ReadInt( pDeviceKeyValues, "MaxDXLevel", 0, &nMaxDXSupportLevel );
+ if ( nMaxDXSupportLevel != 0 )
+ {
+ caps.m_nMaxDXSupportLevel = nMaxDXSupportLevel;
+ }
+
+ // Next, set the preferred dx level
+ int nDXSupportLevel = 0;
+ ReadInt( pDeviceKeyValues, "DXLevel", 0, &nDXSupportLevel );
+ if ( nDXSupportLevel != 0 )
+ {
+ caps.m_nDXSupportLevel = nDXSupportLevel;
+ // Don't slam up the dxlevel level to 92 on DX10 cards in OpenGL Linux/Win mode (otherwise Intel will get dxlevel 92 when we want 90)
+ if ( !( IsOpenGL() && ( IsLinux() || IsWindows() ) ) )
+ {
+ if ( caps.m_bDX10Card )
+ {
+ caps.m_nDXSupportLevel = 92;
+ }
+ }
+ }
+ else
+ {
+ caps.m_nDXSupportLevel = caps.m_nMaxDXSupportLevel;
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Loads the hardware caps, for cases in which the D3D caps lie or where we need to augment the caps
+//-----------------------------------------------------------------------------
+void CShaderDeviceMgrBase::LoadHardwareCaps( KeyValues *pGroup, HardwareCaps_t &caps )
+{
+ if( !pGroup )
+ return;
+
+ // don't just blanket kill clip planes on POSIX, only shoot them down if we're running ARB, or asked for nouserclipplanes.
+ //FIXME need to take into account the caps bit that GLM can now provide, so NV can use normal clipping and ATI can fall back to fastclip.
+
+ if ( CommandLine()->FindParm("-arbmode") || CommandLine()->CheckParm( "-nouserclip" ) )
+ {
+ caps.m_UseFastClipping = true;
+ }
+ else
+ {
+ caps.m_UseFastClipping = ReadBool( pGroup, "NoUserClipPlanes", caps.m_UseFastClipping );
+ }
+
+ caps.m_bNeedsATICentroidHack = ReadBool( pGroup, "CentroidHack", caps.m_bNeedsATICentroidHack );
+ caps.m_bDisableShaderOptimizations = ReadBool( pGroup, "DisableShaderOptimizations", caps.m_bDisableShaderOptimizations );
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Reads in the hardware caps from the dxsupport.cfg file
+//-----------------------------------------------------------------------------
+void CShaderDeviceMgrBase::ReadHardwareCaps( HardwareCaps_t &caps, int nDxLevel )
+{
+ KeyValues *pCfg = ReadDXSupportKeyValues();
+ if ( !pCfg )
+ return;
+
+ // Next, read the hardware caps for that dx support level.
+ KeyValues *pDxLevelKeyValues = FindDXLevelSpecificConfig( pCfg, nDxLevel );
+ // Look for a vendor specific line for a given dxlevel.
+ KeyValues *pDXLevelAndVendorKeyValue = FindDXLevelAndVendorSpecificConfig( pCfg, nDxLevel, caps.m_VendorID );
+ // Finally, override the hardware caps based on the specific card
+ KeyValues *pCardKeyValues = FindCardSpecificConfig( pCfg, caps.m_VendorID, caps.m_DeviceID );
+
+ // Apply
+ if( pCardKeyValues && ReadHexValue( pCardKeyValues, "MinDeviceID" ) == 0 && ReadHexValue( pCardKeyValues, "MaxDeviceID" ) == 0xffff )
+ {
+ // The card specific case is a catch all for device ids, so run it before running the dxlevel and card specific stuff.
+ LoadHardwareCaps( pDxLevelKeyValues, caps );
+ LoadHardwareCaps( pCardKeyValues, caps );
+ LoadHardwareCaps( pDXLevelAndVendorKeyValue, caps );
+ }
+ else
+ {
+ // The card specific case is a small range of cards, so run it last to override all other configs.
+ LoadHardwareCaps( pDxLevelKeyValues, caps );
+ // don't run this one since we have a specific config for this card.
+ // LoadHardwareCaps( pDXLevelAndVendorKeyValue, caps );
+ LoadHardwareCaps( pCardKeyValues, caps );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Reads in ConVars + config variables
+//-----------------------------------------------------------------------------
+void CShaderDeviceMgrBase::LoadConfig( KeyValues *pKeyValues, KeyValues *pConfiguration )
+{
+ if( !pKeyValues )
+ return;
+
+ if( CommandLine()->FindParm( "-debugdxsupport" ) )
+ {
+ CUtlBuffer tmpBuf;
+ pKeyValues->RecursiveSaveToFile( tmpBuf, 0 );
+ Warning( "%s\n", ( const char * )tmpBuf.Base() );
+ }
+ for( KeyValues *pGroup = pKeyValues->GetFirstSubKey(); pGroup; pGroup = pGroup->GetNextKey() )
+ {
+ AddKey( pConfiguration, pGroup );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Computes amount of ram
+//-----------------------------------------------------------------------------
+static unsigned long GetRam()
+{
+ MEMORYSTATUS stat;
+ GlobalMemoryStatus( &stat );
+
+ char buf[256];
+ V_snprintf( buf, sizeof( buf ), "GlobalMemoryStatus: %llu\n", (uint64)(stat.dwTotalPhys) );
+ Plat_DebugString( buf );
+
+ return (stat.dwTotalPhys / (1024 * 1024));
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the recommended configuration associated with a particular dx level
+//-----------------------------------------------------------------------------
+bool CShaderDeviceMgrBase::GetRecommendedConfigurationInfo( int nAdapter, int nDXLevel, int nVendorID, int nDeviceID, KeyValues *pConfiguration )
+{
+ LOCK_SHADERAPI();
+
+ const HardwareCaps_t& caps = GetHardwareCaps( nAdapter );
+ if ( nDXLevel == 0 )
+ {
+ nDXLevel = caps.m_nDXSupportLevel;
+ }
+ nDXLevel = GetClosestActualDXLevel( nDXLevel );
+ if ( nDXLevel > caps.m_nMaxDXSupportLevel )
+ return false;
+
+ KeyValues *pCfg = ReadDXSupportKeyValues();
+ if ( !pCfg )
+ return true;
+
+ // Look for a dxlevel specific line
+ KeyValues *pDxLevelKeyValues = FindDXLevelSpecificConfig( pCfg, nDXLevel );
+ // Look for a vendor specific line for a given dxlevel.
+ KeyValues *pDXLevelAndVendorKeyValue = FindDXLevelAndVendorSpecificConfig( pCfg, nDXLevel, nVendorID );
+ // Next, override with device-specific overrides
+ KeyValues *pCardKeyValues = FindCardSpecificConfig( pCfg, nVendorID, nDeviceID );
+
+ // Apply
+ if ( pCardKeyValues && ReadHexValue( pCardKeyValues, "MinDeviceID" ) == 0 && ReadHexValue( pCardKeyValues, "MaxDeviceID" ) == 0xffff )
+ {
+ // The card specific case is a catch all for device ids, so run it before running the dxlevel and card specific stuff.
+ LoadConfig( pDxLevelKeyValues, pConfiguration );
+ LoadConfig( pCardKeyValues, pConfiguration );
+ LoadConfig( pDXLevelAndVendorKeyValue, pConfiguration );
+ }
+ else
+ {
+ // The card specific case is a small range of cards, so run it last to override all other configs.
+ LoadConfig( pDxLevelKeyValues, pConfiguration );
+ // don't run this one since we have a specific config for this card.
+ // LoadConfig( pDXLevelAndVendorKeyValue, pConfiguration );
+ LoadConfig( pCardKeyValues, pConfiguration );
+ }
+
+ // Next, override with cpu-speed based overrides
+ const CPUInformation& pi = *GetCPUInformation();
+ int nCPUSpeedMhz = (int)(pi.m_Speed / 1000000.0f);
+
+ bool bAMD = Q_stristr( pi.m_szProcessorID, "amd" ) != NULL;
+
+ char buf[256];
+ V_snprintf( buf, sizeof( buf ), "CShaderDeviceMgrBase::GetRecommendedConfigurationInfo: CPU speed: %d MHz, Processor: %s\n", nCPUSpeedMhz, pi.m_szProcessorID );
+ Plat_DebugString( buf );
+
+ KeyValues *pCPUKeyValues = FindCPUSpecificConfig( pCfg, nCPUSpeedMhz, bAMD );
+ LoadConfig( pCPUKeyValues, pConfiguration );
+
+ // override with system memory-size based overrides
+ int nSystemMB = GetRam();
+ DevMsg( "%d MB of system RAM\n", nSystemMB );
+ KeyValues *pMemoryKeyValues = FindMemorySpecificConfig( pCfg, nSystemMB );
+ LoadConfig( pMemoryKeyValues, pConfiguration );
+
+ // override with texture memory-size based overrides
+ int nTextureMemorySize = GetVidMemBytes( nAdapter );
+ int vidMemMB = nTextureMemorySize / ( 1024 * 1024 );
+ KeyValues *pVidMemKeyValues = FindVidMemSpecificConfig( pCfg, vidMemMB );
+ if ( pVidMemKeyValues && nTextureMemorySize > 0 )
+ {
+ if ( CommandLine()->FindParm( "-debugdxsupport" ) )
+ {
+ CUtlBuffer tmpBuf;
+ pVidMemKeyValues->RecursiveSaveToFile( tmpBuf, 0 );
+ Warning( "pVidMemKeyValues\n%s\n", ( const char * )tmpBuf.Base() );
+ }
+ KeyValues *pMatPicmipKeyValue = pVidMemKeyValues->FindKey( "ConVar.mat_picmip", false );
+
+ // FIXME: Man, is this brutal. If it wasn't 1 day till orange box ship, I'd do something in dxsupport maybe
+ if ( pMatPicmipKeyValue && ( ( nDXLevel == caps.m_nMaxDXSupportLevel ) || ( vidMemMB < 100 ) ) )
+ {
+ KeyValues *pConfigMatPicMip = pConfiguration->FindKey( "ConVar.mat_picmip", false );
+ int newPicMip = pMatPicmipKeyValue->GetInt();
+ int oldPicMip = pConfigMatPicMip ? pConfigMatPicMip->GetInt() : 0;
+ pConfiguration->SetInt( "ConVar.mat_picmip", max( newPicMip, oldPicMip ) );
+ }
+ }
+
+ // Hack to slam the mat_dxlevel ConVar to match the requested dxlevel
+ pConfiguration->SetInt( "ConVar.mat_dxlevel", nDXLevel );
+
+ if ( CommandLine()->FindParm( "-debugdxsupport" ) )
+ {
+ CUtlBuffer tmpBuf;
+ pConfiguration->RecursiveSaveToFile( tmpBuf, 0 );
+ Warning( "final config:\n%s\n", ( const char * )tmpBuf.Base() );
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets recommended congifuration for a particular adapter at a particular dx level
+//-----------------------------------------------------------------------------
+bool CShaderDeviceMgrBase::GetRecommendedConfigurationInfo( int nAdapter, int nDXLevel, KeyValues *pCongifuration )
+{
+ Assert( nAdapter >= 0 && nAdapter <= GetAdapterCount() );
+ MaterialAdapterInfo_t info;
+ GetAdapterInfo( nAdapter, info );
+ return GetRecommendedConfigurationInfo( nAdapter, nDXLevel, info.m_VendorID, info.m_DeviceID, pCongifuration );
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns only valid dx levels
+//-----------------------------------------------------------------------------
+int CShaderDeviceMgrBase::GetClosestActualDXLevel( int nDxLevel ) const
+{
+ if ( nDxLevel < ABSOLUTE_MINIMUM_DXLEVEL )
+ return ABSOLUTE_MINIMUM_DXLEVEL;
+
+ if ( nDxLevel == 80 )
+ return 80;
+ if ( nDxLevel <= 89 )
+ return 81;
+
+ if ( IsOpenGL() )
+ {
+ return ( nDxLevel <= 90 ) ? 90 : 92;
+ }
+
+ if ( nDxLevel <= 94 )
+ return 90;
+
+ if ( IsX360() && nDxLevel <= 98 )
+ return 98;
+ if ( nDxLevel <= 99 )
+ return 95;
+ return 100;
+}
+
+
+//-----------------------------------------------------------------------------
+// Mode change callback
+//-----------------------------------------------------------------------------
+void CShaderDeviceMgrBase::AddModeChangeCallback( ShaderModeChangeCallbackFunc_t func )
+{
+ LOCK_SHADERAPI();
+ Assert( func && m_ModeChangeCallbacks.Find( func ) < 0 );
+ m_ModeChangeCallbacks.AddToTail( func );
+}
+
+void CShaderDeviceMgrBase::RemoveModeChangeCallback( ShaderModeChangeCallbackFunc_t func )
+{
+ LOCK_SHADERAPI();
+ m_ModeChangeCallbacks.FindAndRemove( func );
+}
+
+void CShaderDeviceMgrBase::InvokeModeChangeCallbacks()
+{
+ int nCount = m_ModeChangeCallbacks.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ m_ModeChangeCallbacks[i]();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Factory to return from SetMode
+//-----------------------------------------------------------------------------
+void* CShaderDeviceMgrBase::ShaderInterfaceFactory( const char *pInterfaceName, int *pReturnCode )
+{
+ if ( pReturnCode )
+ {
+ *pReturnCode = IFACE_OK;
+ }
+ if ( !Q_stricmp( pInterfaceName, SHADER_DEVICE_INTERFACE_VERSION ) )
+ return static_cast< IShaderDevice* >( g_pShaderDevice );
+ if ( !Q_stricmp( pInterfaceName, SHADERAPI_INTERFACE_VERSION ) )
+ return static_cast< IShaderAPI* >( g_pShaderAPI );
+ if ( !Q_stricmp( pInterfaceName, SHADERSHADOW_INTERFACE_VERSION ) )
+ return static_cast< IShaderShadow* >( g_pShaderShadow );
+
+ if ( pReturnCode )
+ {
+ *pReturnCode = IFACE_FAILED;
+ }
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// The Base implementation of the shader device
+//
+//-----------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+CShaderDeviceBase::CShaderDeviceBase()
+{
+ m_bInitialized = false;
+ m_nAdapter = -1;
+ m_hWnd = NULL;
+ m_hWndCookie = NULL;
+ m_dwThreadId = ThreadGetCurrentId();
+}
+
+CShaderDeviceBase::~CShaderDeviceBase()
+{
+}
+
+void CShaderDeviceBase::SetCurrentThreadAsOwner()
+{
+ m_dwThreadId = ThreadGetCurrentId();
+}
+
+void CShaderDeviceBase::RemoveThreadOwner()
+{
+ m_dwThreadId = 0xFFFFFFFF;
+}
+
+bool CShaderDeviceBase::ThreadOwnsDevice()
+{
+ if ( ThreadGetCurrentId() == m_dwThreadId )
+ return true;
+ return false;
+}
+
+
+// Methods of IShaderDevice
+ImageFormat CShaderDeviceBase::GetBackBufferFormat() const
+{
+ return IMAGE_FORMAT_UNKNOWN;
+}
+
+int CShaderDeviceBase::StencilBufferBits() const
+{
+ return 0;
+}
+
+bool CShaderDeviceBase::IsAAEnabled() const
+{
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Methods for interprocess communication to release resources
+//-----------------------------------------------------------------------------
+#define MATERIAL_SYSTEM_WINDOW_ID 0xFEEDDEAD
+
+#ifdef USE_ACTUAL_DX
+static VD3DHWND GetTopmostParentWindow( VD3DHWND hWnd )
+{
+ // Find the parent window...
+ VD3DHWND hParent = GetParent( hWnd );
+ while ( hParent )
+ {
+ hWnd = hParent;
+ hParent = GetParent( hWnd );
+ }
+
+ return hWnd;
+}
+
+static BOOL CALLBACK EnumChildWindowsProc( VD3DHWND hWnd, LPARAM lParam )
+{
+ int windowId = GetWindowLongPtr( hWnd, GWLP_USERDATA );
+ if (windowId == MATERIAL_SYSTEM_WINDOW_ID)
+ {
+ COPYDATASTRUCT copyData;
+ copyData.dwData = lParam;
+ copyData.cbData = 0;
+ copyData.lpData = 0;
+
+ SendMessage(hWnd, WM_COPYDATA, 0, (LPARAM)&copyData);
+ }
+ return TRUE;
+}
+
+static BOOL CALLBACK EnumWindowsProc( VD3DHWND hWnd, LPARAM lParam )
+{
+ EnumChildWindows( hWnd, EnumChildWindowsProc, lParam );
+ return TRUE;
+}
+
+static BOOL CALLBACK EnumWindowsProcNotThis( VD3DHWND hWnd, LPARAM lParam )
+{
+ if ( g_pShaderDevice && ( GetTopmostParentWindow( (VD3DHWND)g_pShaderDevice->GetIPCHWnd() ) == hWnd ) )
+ return TRUE;
+
+ EnumChildWindows( hWnd, EnumChildWindowsProc, lParam );
+ return TRUE;
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// Adds a hook to let us know when other instances are setting the mode
+//-----------------------------------------------------------------------------
+
+#ifdef STRICT
+#define WINDOW_PROC WNDPROC
+#else
+#define WINDOW_PROC FARPROC
+#endif
+
+#ifdef USE_ACTUAL_DX
+static LRESULT CALLBACK ShaderDX8WndProc(VD3DHWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+#if !defined( _X360 )
+ // FIXME: Should these IPC messages tell when an app has focus or not?
+ // If so, we'd want to totally disable the shader api layer when an app
+ // doesn't have focus.
+
+ // Look for the special IPC message that tells us we're trying to set
+ // the mode....
+ switch(msg)
+ {
+ case WM_COPYDATA:
+ {
+ if ( !g_pShaderDevice )
+ break;
+
+ COPYDATASTRUCT* pData = (COPYDATASTRUCT*)lParam;
+
+ // that number is our magic cookie number
+ if ( pData->dwData == CShaderDeviceBase::RELEASE_MESSAGE )
+ {
+ g_pShaderDevice->OtherAppInitializing(true);
+ }
+ else if ( pData->dwData == CShaderDeviceBase::REACQUIRE_MESSAGE )
+ {
+ g_pShaderDevice->OtherAppInitializing(false);
+ }
+ else if ( pData->dwData == CShaderDeviceBase::EVICT_MESSAGE )
+ {
+ g_pShaderDevice->EvictManagedResourcesInternal( );
+ }
+ }
+ break;
+ }
+
+ return DefWindowProc( hWnd, msg, wParam, lParam );
+#endif
+}
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Install, remove ability to talk to other shaderapi apps
+//-----------------------------------------------------------------------------
+void CShaderDeviceBase::InstallWindowHook( void* hWnd )
+{
+ Assert( m_hWndCookie == NULL );
+#ifdef USE_ACTUAL_DX
+#if !defined( _X360 )
+ VD3DHWND hParent = GetTopmostParentWindow( (VD3DHWND)hWnd );
+
+ // Attach a child window to the parent; we're gonna store special info there
+ // We can't use the USERDATA, cause other apps may want to use this.
+ HINSTANCE hInst = (HINSTANCE)GetWindowLongPtr( hParent, GWLP_HINSTANCE );
+ WNDCLASS wc;
+ memset( &wc, 0, sizeof( wc ) );
+ wc.style = CS_NOCLOSE | CS_PARENTDC;
+ wc.lpfnWndProc = ShaderDX8WndProc;
+ wc.hInstance = hInst;
+ wc.lpszClassName = "shaderdx8";
+
+ // In case an old one is sitting around still...
+ UnregisterClass( "shaderdx8", hInst );
+
+ RegisterClass( &wc );
+
+ // Create the window
+ m_hWndCookie = CreateWindow( "shaderdx8", "shaderdx8", WS_CHILD,
+ 0, 0, 0, 0, hParent, NULL, hInst, NULL );
+
+ // Marks it as a material system window
+ SetWindowLongPtr( (VD3DHWND)m_hWndCookie, GWLP_USERDATA, MATERIAL_SYSTEM_WINDOW_ID );
+#endif
+#endif
+}
+
+void CShaderDeviceBase::RemoveWindowHook( void* hWnd )
+{
+#ifdef USE_ACTUAL_DX
+#if !defined( _X360 )
+ if ( m_hWndCookie )
+ {
+ DestroyWindow( (VD3DHWND)m_hWndCookie );
+ m_hWndCookie = 0;
+ }
+
+ VD3DHWND hParent = GetTopmostParentWindow( (VD3DHWND)hWnd );
+ HINSTANCE hInst = (HINSTANCE)GetWindowLongPtr( hParent, GWLP_HINSTANCE );
+ UnregisterClass( "shaderdx8", hInst );
+#endif
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Sends a message to other shaderapi applications
+//-----------------------------------------------------------------------------
+void CShaderDeviceBase::SendIPCMessage( IPCMessage_t msg )
+{
+#ifdef USE_ACTUAL_DX
+#if !defined( _X360 )
+ // Gotta send this to all windows, since we don't know which ones
+ // are material system apps...
+ if ( msg != EVICT_MESSAGE )
+ {
+ EnumWindows( EnumWindowsProc, (DWORD)msg );
+ }
+ else
+ {
+ EnumWindows( EnumWindowsProcNotThis, (DWORD)msg );
+ }
+#endif
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Find view
+//-----------------------------------------------------------------------------
+int CShaderDeviceBase::FindView( void* hWnd ) const
+{
+ /* FIXME: Is this necessary?
+ // Look for the view in the list of views
+ for (int i = m_Views.Count(); --i >= 0; )
+ {
+ if (m_Views[i].m_HWnd == (VD3DHWND)hwnd)
+ return i;
+ }
+ */
+ return -1;
+}
+
+//-----------------------------------------------------------------------------
+// Creates a child window
+//-----------------------------------------------------------------------------
+bool CShaderDeviceBase::AddView( void* hWnd )
+{
+ LOCK_SHADERAPI();
+ /*
+ // If we haven't created a device yet
+ if (!Dx9Device())
+ return false;
+
+ // Make sure no duplicate hwnds...
+ if (FindView(hwnd) >= 0)
+ return false;
+
+ // In this case, we need to create the device; this is our
+ // default swap chain. This here says we're gonna use a part of the
+ // existing buffer and just grab that.
+ int view = m_Views.AddToTail();
+ m_Views[view].m_HWnd = (VD3DHWND)hwnd;
+ // memcpy( &m_Views[view].m_PresentParamters, m_PresentParameters, sizeof(m_PresentParamters) );
+
+ HRESULT hr;
+ hr = Dx9Device()->CreateAdditionalSwapChain( &m_PresentParameters,
+ &m_Views[view].m_pSwapChain );
+ return !FAILED(hr);
+ */
+
+ return true;
+}
+
+void CShaderDeviceBase::RemoveView( void* hWnd )
+{
+ LOCK_SHADERAPI();
+ /*
+ // Look for the view in the list of views
+ int i = FindView(hwnd);
+ if (i >= 0)
+ {
+ // FIXME m_Views[i].m_pSwapChain->Release();
+ m_Views.FastRemove(i);
+ }
+ */
+}
+
+//-----------------------------------------------------------------------------
+// Activates a child window
+//-----------------------------------------------------------------------------
+void CShaderDeviceBase::SetView( void* hWnd )
+{
+ LOCK_SHADERAPI();
+
+ ShaderViewport_t viewport;
+ g_pShaderAPI->GetViewports( &viewport, 1 );
+
+ // Get the window (*not* client) rect of the view window
+ m_ViewHWnd = (VD3DHWND)hWnd;
+ GetWindowSize( m_nWindowWidth, m_nWindowHeight );
+
+ // Reset the viewport (takes into account the view rect)
+ // Don't need to set the viewport if it's not ready
+ g_pShaderAPI->SetViewports( 1, &viewport );
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the window size
+//-----------------------------------------------------------------------------
+void CShaderDeviceBase::GetWindowSize( int& nWidth, int& nHeight ) const
+{
+#if defined( USE_SDL )
+
+ // this matches up to what the threaded material system does
+ g_pShaderAPI->GetBackBufferDimensions( nWidth, nHeight );
+
+#else
+
+ // If the window was minimized last time swap buffers happened, or if it's iconic now,
+ // return 0 size
+#ifdef _WIN32
+ if ( !m_bIsMinimized && !IsIconic( ( HWND )m_hWnd ) )
+#else
+ if ( !m_bIsMinimized && !IsIconic( (VD3DHWND)m_hWnd ) )
+#endif
+ {
+ // NOTE: Use the 'current view' (which may be the same as the main window)
+ RECT rect;
+#ifdef _WIN32
+ GetClientRect( ( HWND )m_ViewHWnd, &rect );
+#else
+ toglGetClientRect( (VD3DHWND)m_ViewHWnd, &rect );
+#endif
+ nWidth = rect.right - rect.left;
+ nHeight = rect.bottom - rect.top;
+ }
+ else
+ {
+ nWidth = nHeight = 0;
+ }
+
+#endif
+}
+
+
diff --git a/materialsystem/shaderapidx9/shaderdevicebase.h b/materialsystem/shaderapidx9/shaderdevicebase.h
new file mode 100644
index 0000000..37d7cc0
--- /dev/null
+++ b/materialsystem/shaderapidx9/shaderdevicebase.h
@@ -0,0 +1,234 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#ifndef SHADERDEVICEBASE_H
+#define SHADERDEVICEBASE_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "togl/rendermechanism.h"
+#include "shaderapi/IShaderDevice.h"
+#include "IHardwareConfigInternal.h"
+#include "bitmap/imageformat.h"
+#include "materialsystem/imaterialsystem.h"
+#include "hardwareconfig.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class KeyValues;
+
+
+//-----------------------------------------------------------------------------
+// define this if you want to run with NVPERFHUD
+//-----------------------------------------------------------------------------
+//#define NVPERFHUD 1
+
+
+//-----------------------------------------------------------------------------
+// Uncomment this to activate the reference rasterizer
+//-----------------------------------------------------------------------------
+//#define USE_REFERENCE_RASTERIZER 1
+
+//-----------------------------------------------------------------------------
+// Uncomment to check for -nulldevice on command line and use D3DDEVTYPE_NULLREF.
+//-----------------------------------------------------------------------------
+#define ENABLE_NULLREF_DEVICE_SUPPORT
+
+//-----------------------------------------------------------------------------
+// The Base implementation of the shader device
+//-----------------------------------------------------------------------------
+class CShaderDeviceMgrBase : public IShaderDeviceMgr
+{
+public:
+ // constructor, destructor
+ CShaderDeviceMgrBase();
+ virtual ~CShaderDeviceMgrBase();
+
+ // Methods of IAppSystem
+ virtual bool Connect( CreateInterfaceFn factory );
+ virtual void Disconnect();
+ virtual void *QueryInterface( const char *pInterfaceName );
+
+ // Methods of IShaderDeviceMgr
+ virtual bool GetRecommendedConfigurationInfo( int nAdapter, int nDXLevel, KeyValues *pCongifuration );
+ virtual void AddModeChangeCallback( ShaderModeChangeCallbackFunc_t func );
+ virtual void RemoveModeChangeCallback( ShaderModeChangeCallbackFunc_t func );
+
+ // Reads in the hardware caps from the dxsupport.cfg file
+ void ReadHardwareCaps( HardwareCaps_t &caps, int nDxLevel );
+
+ // Reads in the max + preferred DX support level
+ void ReadDXSupportLevels( HardwareCaps_t &caps );
+
+ // Returns the hardware caps for a particular adapter
+ const HardwareCaps_t& GetHardwareCaps( int nAdapter ) const;
+
+ // Invokes mode change callbacks
+ void InvokeModeChangeCallbacks();
+
+ // Factory to return from SetMode
+ static void* ShaderInterfaceFactory( const char *pInterfaceName, int *pReturnCode );
+
+ // Returns only valid dx levels
+ int GetClosestActualDXLevel( int nDxLevel ) const;
+
+protected:
+ struct AdapterInfo_t
+ {
+ HardwareCaps_t m_ActualCaps;
+ };
+
+private:
+ // Reads in the dxsupport.cfg keyvalues
+ KeyValues *ReadDXSupportKeyValues();
+
+ // Reads in ConVars + config variables
+ void LoadConfig( KeyValues *pKeyValues, KeyValues *pConfiguration );
+
+ // Loads the hardware caps, for cases in which the D3D caps lie or where we need to augment the caps
+ void LoadHardwareCaps( KeyValues *pGroup, HardwareCaps_t &caps );
+
+ // Gets the recommended configuration associated with a particular dx level
+ bool GetRecommendedConfigurationInfo( int nAdapter, int nDXLevel, int nVendorID, int nDeviceID, KeyValues *pConfiguration );
+
+ // Returns the amount of video memory in bytes for a particular adapter
+ virtual int GetVidMemBytes( int nAdapter ) const = 0;
+
+ // Looks for override keyvalues in the dxsupport cfg keyvalues
+ KeyValues *FindDXLevelSpecificConfig( KeyValues *pKeyValues, int nDxLevel );
+ KeyValues *FindDXLevelAndVendorSpecificConfig( KeyValues *pKeyValues, int nDxLevel, int nVendorID );
+ KeyValues *FindCPUSpecificConfig( KeyValues *pKeyValues, int nCPUMhz, bool bAMD );
+ KeyValues *FindMemorySpecificConfig( KeyValues *pKeyValues, int nSystemRamMB );
+ KeyValues *FindVidMemSpecificConfig( KeyValues *pKeyValues, int nVideoRamMB );
+ KeyValues *FindCardSpecificConfig( KeyValues *pKeyValues, int nVendorID, int nDeviceID );
+
+protected:
+ // Stores adapter info for all adapters
+ CUtlVector<AdapterInfo_t> m_Adapters;
+
+ // Installed mode change callbacks
+ CUtlVector< ShaderModeChangeCallbackFunc_t > m_ModeChangeCallbacks;
+
+ KeyValues *m_pDXSupport;
+};
+
+
+//-----------------------------------------------------------------------------
+// The Base implementation of the shader device
+//-----------------------------------------------------------------------------
+class CShaderDeviceBase : public IShaderDevice
+{
+public:
+ enum IPCMessage_t
+ {
+ RELEASE_MESSAGE = 0x5E740DE0,
+ REACQUIRE_MESSAGE = 0x5E740DE1,
+ EVICT_MESSAGE = 0x5E740DE2,
+ };
+
+ // Methods of IShaderDevice
+public:
+ virtual ImageFormat GetBackBufferFormat() const;
+ virtual int StencilBufferBits() const;
+ virtual bool IsAAEnabled() const;
+ virtual bool AddView( void* hWnd );
+ virtual void RemoveView( void* hWnd );
+ virtual void SetView( void* hWnd );
+ virtual void GetWindowSize( int& nWidth, int& nHeight ) const;
+
+ // Methods exposed to the rest of shader api
+ virtual bool InitDevice( void *hWnd, int nAdapter, const ShaderDeviceInfo_t& mode ) = 0;
+ virtual void ShutdownDevice() = 0;
+ virtual bool IsDeactivated() const = 0;
+
+public:
+ // constructor, destructor
+ CShaderDeviceBase();
+ virtual ~CShaderDeviceBase();
+
+ virtual void OtherAppInitializing( bool initializing ) {}
+ virtual void EvictManagedResourcesInternal() {}
+
+ void* GetIPCHWnd();
+ void SendIPCMessage( IPCMessage_t message );
+
+protected:
+ // IPC communication for multiple shaderapi apps
+ void InstallWindowHook( void *hWnd );
+ void RemoveWindowHook( void *hWnd );
+ void SetCurrentThreadAsOwner();
+ void RemoveThreadOwner();
+ bool ThreadOwnsDevice();
+
+ // Finds a child window
+ int FindView( void* hWnd ) const;
+
+ int m_nAdapter;
+ void *m_hWnd;
+ void* m_hWndCookie;
+ bool m_bInitialized : 1;
+ bool m_bIsMinimized : 1;
+
+ // The current view hwnd
+ void* m_ViewHWnd;
+
+ int m_nWindowWidth;
+ int m_nWindowHeight;
+ uint32 m_dwThreadId;
+};
+
+
+//-----------------------------------------------------------------------------
+// Inline methods
+//-----------------------------------------------------------------------------
+inline void* CShaderDeviceBase::GetIPCHWnd()
+{
+ return m_hWndCookie;
+}
+
+
+//-----------------------------------------------------------------------------
+// Helper class to reduce code related to shader buffers
+//-----------------------------------------------------------------------------
+template< class T >
+class CShaderBuffer : public IShaderBuffer
+{
+public:
+ CShaderBuffer( T *pBlob ) : m_pBlob( pBlob ) {}
+
+ virtual size_t GetSize() const
+ {
+ return m_pBlob ? m_pBlob->GetBufferSize() : 0;
+ }
+
+ virtual const void* GetBits() const
+ {
+ return m_pBlob ? m_pBlob->GetBufferPointer() : NULL;
+ }
+
+ virtual void Release()
+ {
+ if ( m_pBlob )
+ {
+ m_pBlob->Release();
+ }
+ delete this;
+ }
+
+private:
+ T *m_pBlob;
+};
+
+
+
+#endif // SHADERDEVICEBASE_H \ No newline at end of file
diff --git a/materialsystem/shaderapidx9/shaderdevicedx10.cpp b/materialsystem/shaderapidx9/shaderdevicedx10.cpp
new file mode 100644
index 0000000..39de5a1
--- /dev/null
+++ b/materialsystem/shaderapidx9/shaderdevicedx10.cpp
@@ -0,0 +1,1002 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#include <d3d10.h>
+#include <d3dx10.h>
+
+#include "shaderdevicedx10.h"
+#include "shaderdevicedx8.h"
+#include "shaderapi/ishaderutil.h"
+#include "shaderapidx10.h"
+#include "shadershadowdx10.h"
+#include "meshdx10.h"
+#include "shaderapidx10_global.h"
+#include "tier1/KeyValues.h"
+#include "tier2/tier2.h"
+#include "tier0/icommandline.h"
+#include "inputlayoutdx10.h"
+#include "shaderapibase.h"
+
+
+//-----------------------------------------------------------------------------
+// Explicit instantiation of shader buffer implementation
+//-----------------------------------------------------------------------------
+template class CShaderBuffer< ID3D10Blob >;
+
+
+//-----------------------------------------------------------------------------
+//
+// Device manager
+//
+//-----------------------------------------------------------------------------
+static CShaderDeviceMgrDx10 g_ShaderDeviceMgrDx10;
+
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CShaderDeviceMgrDx10, IShaderDeviceMgr,
+ SHADER_DEVICE_MGR_INTERFACE_VERSION, g_ShaderDeviceMgrDx10 )
+
+static CShaderDeviceDx10 g_ShaderDeviceDx10;
+CShaderDeviceDx10* g_pShaderDeviceDx10 = &g_ShaderDeviceDx10;
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+CShaderDeviceMgrDx10::CShaderDeviceMgrDx10()
+{
+ m_pDXGIFactory = NULL;
+ m_bObeyDxCommandlineOverride = true;
+}
+
+CShaderDeviceMgrDx10::~CShaderDeviceMgrDx10()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Connect, disconnect
+//-----------------------------------------------------------------------------
+bool CShaderDeviceMgrDx10::Connect( CreateInterfaceFn factory )
+{
+ LOCK_SHADERAPI();
+
+ if ( !BaseClass::Connect( factory ) )
+ return false;
+
+ HRESULT hr = CreateDXGIFactory( __uuidof(IDXGIFactory), (void**)(&m_pDXGIFactory) );
+ if ( FAILED( hr ) )
+ {
+ Warning( "Failed to create the DXGI Factory!\n" );
+ return false;
+ }
+
+ InitAdapterInfo();
+ return true;
+}
+
+void CShaderDeviceMgrDx10::Disconnect()
+{
+ LOCK_SHADERAPI();
+
+ if ( m_pDXGIFactory )
+ {
+ m_pDXGIFactory->Release();
+ m_pDXGIFactory = NULL;
+ }
+
+ BaseClass::Disconnect();
+}
+
+
+//-----------------------------------------------------------------------------
+// Initialization
+//-----------------------------------------------------------------------------
+InitReturnVal_t CShaderDeviceMgrDx10::Init( )
+{
+ LOCK_SHADERAPI();
+
+ return INIT_OK;
+}
+
+
+//-----------------------------------------------------------------------------
+// Shutdown
+//-----------------------------------------------------------------------------
+void CShaderDeviceMgrDx10::Shutdown( )
+{
+ LOCK_SHADERAPI();
+
+ if ( g_pShaderDevice )
+ {
+ g_pShaderDevice->ShutdownDevice();
+ g_pShaderDevice = NULL;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Initialize adapter information
+//-----------------------------------------------------------------------------
+void CShaderDeviceMgrDx10::InitAdapterInfo()
+{
+ m_Adapters.RemoveAll();
+
+ IDXGIAdapter *pAdapter;
+ for( UINT nCount = 0; m_pDXGIFactory->EnumAdapters( nCount, &pAdapter ) != DXGI_ERROR_NOT_FOUND; ++nCount )
+ {
+ int j = m_Adapters.AddToTail();
+ AdapterInfo_t &info = m_Adapters[j];
+
+#ifdef _DEBUG
+ memset( &info.m_ActualCaps, 0xDD, sizeof(info.m_ActualCaps) );
+#endif
+
+ IDXGIOutput *pOutput = GetAdapterOutput( nCount );
+ info.m_ActualCaps.m_bDeviceOk = ComputeCapsFromD3D( &info.m_ActualCaps, pAdapter, pOutput );
+ if ( !info.m_ActualCaps.m_bDeviceOk )
+ continue;
+
+ ReadDXSupportLevels( info.m_ActualCaps );
+
+ // Read dxsupport.cfg which has config overrides for particular cards.
+ ReadHardwareCaps( info.m_ActualCaps, info.m_ActualCaps.m_nMaxDXSupportLevel );
+
+ // What's in "-shader" overrides dxsupport.cfg
+ const char *pShaderParam = CommandLine()->ParmValue( "-shader" );
+ if ( pShaderParam )
+ {
+ Q_strncpy( info.m_ActualCaps.m_pShaderDLL, pShaderParam, sizeof( info.m_ActualCaps.m_pShaderDLL ) );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Determines hardware caps from D3D
+//-----------------------------------------------------------------------------
+bool CShaderDeviceMgrDx10::ComputeCapsFromD3D( HardwareCaps_t *pCaps, IDXGIAdapter *pAdapter, IDXGIOutput *pOutput )
+{
+ HRESULT hr = pAdapter->CheckInterfaceSupport( __uuidof(ID3D10Device), NULL );
+ if ( hr != S_OK )
+ {
+ // Fall back to Dx9
+ return false;
+ }
+
+ DXGI_ADAPTER_DESC desc;
+ hr = pAdapter->GetDesc( &desc );
+ Assert( !FAILED( hr ) );
+ if ( FAILED(hr) )
+ return false;
+
+ bool bForceFloatHDR = ( CommandLine()->CheckParm( "-floathdr" ) != NULL );
+
+ // DX10 settings
+ // NOTE: We'll need to have different settings for dx10.1 and dx11
+ Q_UnicodeToUTF8( desc.Description, pCaps->m_pDriverName, MATERIAL_ADAPTER_NAME_LENGTH );
+ pCaps->m_VendorID = desc.VendorId;
+ pCaps->m_DeviceID = desc.DeviceId;
+ pCaps->m_SubSysID = desc.SubSysId;
+ pCaps->m_Revision = desc.Revision;
+ pCaps->m_NumSamplers = 16;
+ pCaps->m_NumTextureStages = 0;
+ pCaps->m_HasSetDeviceGammaRamp = true;
+ pCaps->m_bSoftwareVertexProcessing = false;
+ pCaps->m_SupportsVertexShaders = true;
+ pCaps->m_SupportsVertexShaders_2_0 = false;
+ pCaps->m_SupportsPixelShaders = true;
+ pCaps->m_SupportsPixelShaders_1_4 = false;
+ pCaps->m_SupportsPixelShaders_2_0 = false;
+ pCaps->m_SupportsPixelShaders_2_b = false;
+ pCaps->m_SupportsShaderModel_3_0 = false;
+ pCaps->m_SupportsCompressedTextures = COMPRESSED_TEXTURES_ON;
+ pCaps->m_SupportsCompressedVertices = VERTEX_COMPRESSION_ON;
+ pCaps->m_bSupportsAnisotropicFiltering = true;
+ pCaps->m_bSupportsMagAnisotropicFiltering = true;
+ pCaps->m_bSupportsVertexTextures = true;
+ pCaps->m_nMaxAnisotropy = 16;
+ pCaps->m_MaxTextureWidth = D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION;
+ pCaps->m_MaxTextureHeight = D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION;
+ pCaps->m_MaxTextureDepth = D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION;
+ pCaps->m_MaxTextureAspectRatio = 1024; // FIXME
+ pCaps->m_MaxPrimitiveCount = 65536; // FIXME
+ pCaps->m_ZBiasAndSlopeScaledDepthBiasSupported = true;
+ pCaps->m_SupportsMipmapping = true;
+ pCaps->m_SupportsOverbright = true;
+ pCaps->m_SupportsCubeMaps = true;
+ pCaps->m_NumPixelShaderConstants = 1024; // FIXME
+ pCaps->m_NumVertexShaderConstants = 1024; // FIXME
+ pCaps->m_TextureMemorySize = desc.DedicatedVideoMemory;
+ pCaps->m_MaxNumLights = 4;
+ pCaps->m_SupportsHardwareLighting = false;
+ pCaps->m_MaxBlendMatrices = 0;
+ pCaps->m_MaxBlendMatrixIndices = 0;
+ pCaps->m_MaxVertexShaderBlendMatrices = 53; // FIXME
+ pCaps->m_SupportsMipmappedCubemaps = true;
+ pCaps->m_SupportsNonPow2Textures = true;
+ pCaps->m_nDXSupportLevel = 100;
+ pCaps->m_PreferDynamicTextures = false;
+ pCaps->m_HasProjectedBumpEnv = true;
+ pCaps->m_MaxUserClipPlanes = 6; // FIXME
+ pCaps->m_HDRType = bForceFloatHDR ? HDR_TYPE_FLOAT : HDR_TYPE_INTEGER;
+ pCaps->m_SupportsSRGB = true;
+ pCaps->m_FakeSRGBWrite = true;
+ pCaps->m_CanDoSRGBReadFromRTs = true;
+ pCaps->m_bSupportsSpheremapping = true;
+ pCaps->m_UseFastClipping = false;
+ pCaps->m_pShaderDLL[0] = 0;
+ pCaps->m_bNeedsATICentroidHack = false;
+ pCaps->m_bColorOnSecondStream = true;
+ pCaps->m_bSupportsStreamOffset = true;
+ pCaps->m_nMaxDXSupportLevel = 100;
+ pCaps->m_bFogColorSpecifiedInLinearSpace = ( desc.VendorId == VENDORID_NVIDIA );
+ pCaps->m_nVertexTextureCount = 16;
+ pCaps->m_nMaxVertexTextureDimension = D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION;
+ pCaps->m_bSupportsAlphaToCoverage = false; // FIXME
+ pCaps->m_bSupportsShadowDepthTextures = true;
+ pCaps->m_bSupportsFetch4 = ( desc.VendorId == VENDORID_ATI );
+ pCaps->m_bSupportsBorderColor = true;
+ pCaps->m_ShadowDepthTextureFormat = IMAGE_FORMAT_UNKNOWN;
+ pCaps->m_nMaxViewports = 4;
+
+ DXGI_GAMMA_CONTROL_CAPABILITIES gammaCaps;
+ pOutput->GetGammaControlCapabilities( &gammaCaps );
+ pCaps->m_flMinGammaControlPoint = gammaCaps.MinConvertedValue;
+ pCaps->m_flMaxGammaControlPoint = gammaCaps.MaxConvertedValue;
+ pCaps->m_nGammaControlPointCount = gammaCaps.NumGammaControlPoints;
+ pCaps->m_bCanStretchRectFromTextures = true;
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the number of adapters...
+//-----------------------------------------------------------------------------
+int CShaderDeviceMgrDx10::GetAdapterCount() const
+{
+ return m_Adapters.Count();
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns info about each adapter
+//-----------------------------------------------------------------------------
+void CShaderDeviceMgrDx10::GetAdapterInfo( int nAdapter, MaterialAdapterInfo_t& info ) const
+{
+ Assert( ( nAdapter >= 0 ) && ( nAdapter < m_Adapters.Count() ) );
+ const HardwareCaps_t &caps = m_Adapters[ nAdapter ].m_ActualCaps;
+ memcpy( &info, &caps, sizeof(MaterialAdapterInfo_t) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the adapter interface for a particular adapter
+//-----------------------------------------------------------------------------
+IDXGIAdapter* CShaderDeviceMgrDx10::GetAdapter( int nAdapter ) const
+{
+ Assert( m_pDXGIFactory && ( nAdapter < GetAdapterCount() ) );
+
+ IDXGIAdapter *pAdapter;
+ HRESULT hr = m_pDXGIFactory->EnumAdapters( nAdapter, &pAdapter );
+ return ( FAILED(hr) ) ? NULL : pAdapter;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the amount of video memory in bytes for a particular adapter
+//-----------------------------------------------------------------------------
+int CShaderDeviceMgrDx10::GetVidMemBytes( int nAdapter ) const
+{
+ LOCK_SHADERAPI();
+ IDXGIAdapter *pAdapter = GetAdapter( nAdapter );
+ if ( !pAdapter )
+ return 0;
+
+ DXGI_ADAPTER_DESC desc;
+
+#ifdef DBGFLAG_ASSERT
+ HRESULT hr =
+#endif
+ pAdapter->GetDesc( &desc );
+ Assert( !FAILED( hr ) );
+ return desc.DedicatedVideoMemory;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the appropriate adapter output to use
+//-----------------------------------------------------------------------------
+IDXGIOutput* CShaderDeviceMgrDx10::GetAdapterOutput( int nAdapter ) const
+{
+ LOCK_SHADERAPI();
+ IDXGIAdapter *pAdapter = GetAdapter( nAdapter );
+ if ( !pAdapter )
+ return 0;
+
+ IDXGIOutput *pOutput;
+ for( UINT i = 0; pAdapter->EnumOutputs( i, &pOutput ) != DXGI_ERROR_NOT_FOUND; ++i )
+ {
+ DXGI_OUTPUT_DESC desc;
+ HRESULT hr = pOutput->GetDesc( &desc );
+ if ( FAILED( hr ) )
+ continue;
+
+ // FIXME: Is this what I want? Or should I be looking at other fields,
+ // like DXGI_MODE_ROTATION_IDENTITY?
+ if ( !desc.AttachedToDesktop )
+ continue;
+
+ return pOutput;
+ }
+
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the number of modes
+//-----------------------------------------------------------------------------
+int CShaderDeviceMgrDx10::GetModeCount( int nAdapter ) const
+{
+ LOCK_SHADERAPI();
+ Assert( m_pDXGIFactory && ( nAdapter < GetAdapterCount() ) );
+
+ IDXGIOutput *pOutput = GetAdapterOutput( nAdapter );
+ if ( !pOutput )
+ return 0;
+
+ UINT num = 0;
+ DXGI_FORMAT format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; //desired color format
+ UINT flags = 0; //desired scanline order and/or scaling
+
+ // get the number of available display mode for the given format and scanline order
+ HRESULT hr = pOutput->GetDisplayModeList( format, flags, &num, 0 );
+ return ( FAILED(hr) ) ? 0 : num;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns mode information..
+//-----------------------------------------------------------------------------
+void CShaderDeviceMgrDx10::GetModeInfo( ShaderDisplayMode_t* pInfo, int nAdapter, int nMode ) const
+{
+ // Default error state
+ pInfo->m_nWidth = pInfo->m_nHeight = 0;
+ pInfo->m_Format = IMAGE_FORMAT_UNKNOWN;
+ pInfo->m_nRefreshRateNumerator = pInfo->m_nRefreshRateDenominator = 0;
+
+ LOCK_SHADERAPI();
+ Assert( m_pDXGIFactory && ( nAdapter < GetAdapterCount() ) );
+
+ IDXGIOutput *pOutput = GetAdapterOutput( nAdapter );
+ if ( !pOutput )
+ return;
+
+ UINT num = 0;
+ DXGI_FORMAT format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; //desired color format
+ UINT flags = DXGI_ENUM_MODES_INTERLACED; //desired scanline order and/or scaling
+
+ // get the number of available display mode for the given format and scanline order
+ HRESULT hr = pOutput->GetDisplayModeList( format, flags, &num, 0 );
+ Assert( !FAILED( hr ) );
+
+ if ( (UINT)nMode >= num )
+ return;
+
+ DXGI_MODE_DESC *pDescs = (DXGI_MODE_DESC*)_alloca( num * sizeof( DXGI_MODE_DESC ) );
+ hr = pOutput->GetDisplayModeList( format, flags, &num, pDescs );
+ Assert( !FAILED( hr ) );
+
+ pInfo->m_nWidth = pDescs[nMode].Width;
+ pInfo->m_nHeight = pDescs[nMode].Height;
+// pInfo->m_Format = ImageLoader::D3DFormatToImageFormat( pDescs[nMode].Format );
+ pInfo->m_nRefreshRateNumerator = pDescs[nMode].RefreshRate.Numerator;
+ pInfo->m_nRefreshRateDenominator = pDescs[nMode].RefreshRate.Denominator;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the current mode for an adapter
+//-----------------------------------------------------------------------------
+void CShaderDeviceMgrDx10::GetCurrentModeInfo( ShaderDisplayMode_t* pInfo, int nAdapter ) const
+{
+ // FIXME: Implement!
+ Assert( 0 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Initialization, shutdown
+//-----------------------------------------------------------------------------
+bool CShaderDeviceMgrDx10::SetAdapter( int nAdapter, int nFlags )
+{
+ /*
+ if ( !g_pShaderDeviceDx10->Init() )
+ {
+ Warning( "Unable to initialize dx10 device!\n" );
+ return false;
+ }
+
+ g_pMaterialSystemHardwareConfig = g_pShaderDeviceDx10;
+ g_pShaderDevice = g_pShaderDeviceDx10;
+ */
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the mode
+//-----------------------------------------------------------------------------
+CreateInterfaceFn CShaderDeviceMgrDx10::SetMode( void *hWnd, int nAdapter, const ShaderDeviceInfo_t& mode )
+{
+ LOCK_SHADERAPI();
+
+ Assert( nAdapter < GetAdapterCount() );
+ int nDXLevel = mode.m_nDXLevel != 0 ? mode.m_nDXLevel : m_Adapters[nAdapter].m_ActualCaps.m_nDXSupportLevel;
+ if ( m_bObeyDxCommandlineOverride )
+ {
+ nDXLevel = CommandLine()->ParmValue( "-dxlevel", nDXLevel );
+ m_bObeyDxCommandlineOverride = false;
+ }
+ if ( nDXLevel > m_Adapters[nAdapter].m_ActualCaps.m_nMaxDXSupportLevel )
+ {
+ nDXLevel = m_Adapters[nAdapter].m_ActualCaps.m_nMaxDXSupportLevel;
+ }
+ nDXLevel = GetClosestActualDXLevel( nDXLevel );
+
+ if ( nDXLevel < 100 )
+ {
+ // Fall back to the Dx9 implementations
+ return g_pShaderDeviceMgrDx8->SetMode( hWnd, nAdapter, mode );
+ }
+
+ if ( g_pShaderAPI )
+ {
+ g_pShaderAPI->OnDeviceShutdown();
+ g_pShaderAPI = NULL;
+ }
+
+ if ( g_pShaderDevice )
+ {
+ g_pShaderDevice->ShutdownDevice();
+ g_pShaderDevice = NULL;
+ }
+
+ g_pShaderShadow = NULL;
+
+ ShaderDeviceInfo_t adjustedMode = mode;
+ adjustedMode.m_nDXLevel = nDXLevel;
+ if ( !g_pShaderDeviceDx10->InitDevice( hWnd, nAdapter, adjustedMode ) )
+ return NULL;
+
+ if ( !g_pShaderAPIDx10->OnDeviceInit() )
+ return NULL;
+
+ g_pShaderDevice = g_pShaderDeviceDx10;
+ g_pShaderAPI = g_pShaderAPIDx10;
+ g_pShaderShadow = g_pShaderShadowDx10;
+
+ return ShaderInterfaceFactory;
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// Device
+//
+//-----------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+CShaderDeviceDx10::CShaderDeviceDx10()
+{
+ m_pDevice = NULL;
+ m_pOutput = NULL;
+ m_pSwapChain = NULL;
+ m_pRenderTargetView = NULL;
+}
+
+CShaderDeviceDx10::~CShaderDeviceDx10()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the mode
+//-----------------------------------------------------------------------------
+bool CShaderDeviceDx10::InitDevice( void *hWnd, int nAdapter, const ShaderDeviceInfo_t& mode )
+{
+ // Make sure we've been shutdown previously
+ if ( m_nAdapter != -1 )
+ {
+ Warning( "CShaderDeviceDx10::SetMode: Previous mode has not been shut down!\n" );
+ return false;
+ }
+
+ LOCK_SHADERAPI();
+ IDXGIAdapter *pAdapter = g_ShaderDeviceMgrDx10.GetAdapter( nAdapter );
+ if ( !pAdapter )
+ return false;
+
+ m_pOutput = g_ShaderDeviceMgrDx10.GetAdapterOutput( nAdapter );
+ if ( !m_pOutput )
+ return false;
+ m_pOutput->AddRef();
+
+ DXGI_SWAP_CHAIN_DESC sd;
+ ZeroMemory( &sd, sizeof(sd) );
+ sd.BufferDesc.Width = mode.m_DisplayMode.m_nWidth;
+ sd.BufferDesc.Height = mode.m_DisplayMode.m_nHeight;
+ sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ sd.BufferDesc.RefreshRate.Numerator = mode.m_DisplayMode.m_nRefreshRateNumerator;
+ sd.BufferDesc.RefreshRate.Denominator = mode.m_DisplayMode.m_nRefreshRateDenominator;
+ sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+ sd.BufferCount = mode.m_nBackBufferCount;
+ sd.OutputWindow = (HWND)hWnd;
+ sd.Windowed = mode.m_bWindowed ? TRUE : FALSE;
+ sd.Flags = mode.m_bWindowed ? 0 : DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
+
+ // NOTE: Having more than 1 back buffer disables MSAA!
+ sd.SwapEffect = mode.m_nBackBufferCount > 1 ? DXGI_SWAP_EFFECT_SEQUENTIAL : DXGI_SWAP_EFFECT_DISCARD;
+
+ // FIXME: Chicken + egg problem with SampleDesc.
+ sd.SampleDesc.Count = mode.m_nAASamples ? mode.m_nAASamples : 1;
+ sd.SampleDesc.Quality = mode.m_nAAQuality;
+
+ UINT nDeviceFlags = 0;
+#ifdef _DEBUG
+ nDeviceFlags |= D3D10_CREATE_DEVICE_DEBUG;
+#endif
+
+ HRESULT hr = D3D10CreateDeviceAndSwapChain( pAdapter, D3D10_DRIVER_TYPE_HARDWARE,
+ NULL, nDeviceFlags, D3D10_SDK_VERSION, &sd, &m_pSwapChain, &m_pDevice );
+
+ if ( FAILED( hr ) )
+ return false;
+
+ // Create a render target view
+ ID3D10Texture2D *pBackBuffer;
+ hr = m_pSwapChain->GetBuffer( 0, __uuidof( ID3D10Texture2D ), (LPVOID*)&pBackBuffer );
+ if ( FAILED( hr ) )
+ return FALSE;
+
+ hr = m_pDevice->CreateRenderTargetView( pBackBuffer, NULL, &m_pRenderTargetView );
+ pBackBuffer->Release();
+ if( FAILED( hr ) )
+ return FALSE;
+
+ m_pDevice->OMSetRenderTargets( 1, &m_pRenderTargetView, NULL );
+
+ m_hWnd = hWnd;
+ m_nAdapter = nAdapter;
+
+ // This is our current view.
+ m_ViewHWnd = hWnd;
+ GetWindowSize( m_nWindowWidth, m_nWindowHeight );
+
+ g_pHardwareConfig->SetupHardwareCaps( mode, g_ShaderDeviceMgrDx10.GetHardwareCaps( nAdapter ) );
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Shuts down the mode
+//-----------------------------------------------------------------------------
+void CShaderDeviceDx10::ShutdownDevice()
+{
+ if ( m_pRenderTargetView )
+ {
+ m_pRenderTargetView->Release();
+ m_pRenderTargetView = NULL;
+ }
+
+ if ( m_pDevice )
+ {
+ m_pDevice->Release();
+ m_pDevice = NULL;
+ }
+
+ if ( m_pSwapChain )
+ {
+ m_pSwapChain->Release();
+ m_pSwapChain = NULL;
+ }
+
+ if ( m_pOutput )
+ {
+ m_pOutput->Release();
+ m_pOutput = NULL;
+ }
+
+ m_hWnd = NULL;
+ m_nAdapter = -1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Are we using graphics?
+//-----------------------------------------------------------------------------
+bool CShaderDeviceDx10::IsUsingGraphics() const
+{
+ return ( m_nAdapter >= 0 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the adapter
+//-----------------------------------------------------------------------------
+int CShaderDeviceDx10::GetCurrentAdapter() const
+{
+ return m_nAdapter;
+}
+
+
+//-----------------------------------------------------------------------------
+// Get back buffer information
+//-----------------------------------------------------------------------------
+ImageFormat CShaderDeviceDx10::GetBackBufferFormat() const
+{
+ return IMAGE_FORMAT_RGB888;
+}
+
+void CShaderDeviceDx10::GetBackBufferDimensions( int& width, int& height ) const
+{
+ width = 1024;
+ height = 768;
+}
+
+
+//-----------------------------------------------------------------------------
+// Use this to spew information about the 3D layer
+//-----------------------------------------------------------------------------
+void CShaderDeviceDx10::SpewDriverInfo() const
+{
+ Warning( "Dx10 Driver!\n" );
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Swap buffers
+//-----------------------------------------------------------------------------
+void CShaderDeviceDx10::Present()
+{
+ // FIXME: Deal with window occlusion, alt-tab, etc.
+ HRESULT hr = m_pSwapChain->Present( 0, 0 );
+ if ( FAILED(hr) )
+ {
+ Assert( 0 );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Camma ramp
+//-----------------------------------------------------------------------------
+void CShaderDeviceDx10::SetHardwareGammaRamp( float fGamma, float fGammaTVRangeMin, float fGammaTVRangeMax, float fGammaTVExponent, bool bTVEnabled )
+{
+ DevMsg( "SetHardwareGammaRamp( %f )\n", fGamma );
+
+ Assert( m_pOutput );
+ if( !m_pOutput )
+ return;
+
+ float flMin = g_pHardwareConfig->Caps().m_flMinGammaControlPoint;
+ float flMax = g_pHardwareConfig->Caps().m_flMaxGammaControlPoint;
+ int nGammaPoints = g_pHardwareConfig->Caps().m_nGammaControlPointCount;
+
+ DXGI_GAMMA_CONTROL gammaControl;
+ gammaControl.Scale.Red = gammaControl.Scale.Green = gammaControl.Scale.Blue = 1.0f;
+ gammaControl.Offset.Red = gammaControl.Offset.Green = gammaControl.Offset.Blue = 0.0f;
+ float flOOCount = 1.0f / ( nGammaPoints - 1 );
+ for ( int i = 0; i < nGammaPoints; i++ )
+ {
+ float flGamma22 = i * flOOCount;
+ float flCorrection = pow( flGamma22, fGamma / 2.2f );
+ flCorrection = clamp( flCorrection, flMin, flMax );
+
+ gammaControl.GammaCurve[i].Red = flCorrection;
+ gammaControl.GammaCurve[i].Green = flCorrection;
+ gammaControl.GammaCurve[i].Blue = flCorrection;
+ }
+
+ HRESULT hr = m_pOutput->SetGammaControl( &gammaControl );
+ if ( FAILED(hr) )
+ {
+ Warning( "CShaderDeviceDx10::SetHardwareGammaRamp: Unable to set gamma controls!\n" );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Compiles all manner of shaders
+//-----------------------------------------------------------------------------
+IShaderBuffer* CShaderDeviceDx10::CompileShader( const char *pProgram, size_t nBufLen, const char *pShaderVersion )
+{
+ int nCompileFlags = D3D10_SHADER_AVOID_FLOW_CONTROL;
+ nCompileFlags |= D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY;
+
+#ifdef _DEBUG
+ nCompileFlags |= D3D10_SHADER_DEBUG;
+#endif
+
+ ID3D10Blob *pCompiledShader, *pErrorMessages;
+ HRESULT hr = D3DX10CompileFromMemory( pProgram, nBufLen, "",
+ NULL, NULL, "main", pShaderVersion, nCompileFlags, 0, NULL,
+ &pCompiledShader, &pErrorMessages, NULL );
+
+ if ( FAILED( hr ) )
+ {
+ if ( pErrorMessages )
+ {
+ const char *pErrorMessage = (const char *)pErrorMessages->GetBufferPointer();
+ Warning( "Vertex shader compilation failed! Reported the following errors:\n%s\n", pErrorMessage );
+ pErrorMessages->Release();
+ }
+ return NULL;
+ }
+
+ // NOTE: This uses small block heap allocator; so I'm not going
+ // to bother creating a memory pool.
+ CShaderBuffer< ID3D10Blob > *pShaderBuffer = new CShaderBuffer< ID3D10Blob >( pCompiledShader );
+ if ( pErrorMessages )
+ {
+ pErrorMessages->Release();
+ }
+
+ return pShaderBuffer;
+}
+
+
+//-----------------------------------------------------------------------------
+// Release input layouts
+//-----------------------------------------------------------------------------
+void CShaderDeviceDx10::ReleaseInputLayouts( VertexShaderIndex_t nIndex )
+{
+ InputLayoutDict_t &dict = m_VertexShaderDict[nIndex].m_InputLayouts;
+ unsigned short hCurr = dict.FirstInorder();
+ while( hCurr != dict.InvalidIndex() )
+ {
+ if ( dict[hCurr].m_pInputLayout )
+ {
+ dict[hCurr].m_pInputLayout->Release();
+ dict[hCurr].m_pInputLayout = NULL;
+ }
+ hCurr = dict.NextInorder( hCurr );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Create, destroy vertex shader
+//-----------------------------------------------------------------------------
+VertexShaderHandle_t CShaderDeviceDx10::CreateVertexShader( IShaderBuffer* pShaderBuffer )
+{
+ // Create the vertex shader
+ ID3D10VertexShader *pShader = NULL;
+ HRESULT hr = m_pDevice->CreateVertexShader( pShaderBuffer->GetBits(),
+ pShaderBuffer->GetSize(), &pShader );
+
+ if ( FAILED( hr ) || !pShader )
+ return VERTEX_SHADER_HANDLE_INVALID;
+
+ ID3D10ShaderReflection *pInfo;
+ hr = D3D10ReflectShader( pShaderBuffer->GetBits(), pShaderBuffer->GetSize(), &pInfo );
+ if ( FAILED( hr ) || !pInfo )
+ {
+ pShader->Release();
+ return VERTEX_SHADER_HANDLE_INVALID;
+ }
+
+ // Insert the shader into the dictionary of shaders
+ VertexShaderIndex_t i = m_VertexShaderDict.AddToTail( );
+ VertexShader_t &dict = m_VertexShaderDict[i];
+ dict.m_pShader = pShader;
+ dict.m_pInfo = pInfo;
+ dict.m_nByteCodeLen = pShaderBuffer->GetSize();
+ dict.m_pByteCode = new unsigned char[ dict.m_nByteCodeLen ];
+ memcpy( dict.m_pByteCode, pShaderBuffer->GetBits(), dict.m_nByteCodeLen );
+ return (VertexShaderHandle_t)i;
+}
+
+void CShaderDeviceDx10::DestroyVertexShader( VertexShaderHandle_t hShader )
+{
+ if ( hShader == VERTEX_SHADER_HANDLE_INVALID )
+ return;
+
+ g_pShaderAPIDx10->Unbind( hShader );
+
+ VertexShaderIndex_t i = (VertexShaderIndex_t)hShader;
+ VertexShader_t &dict = m_VertexShaderDict[i];
+ VerifyEquals( dict.m_pShader->Release(), 0 );
+ VerifyEquals( dict.m_pInfo->Release(), 0 );
+ delete[] dict.m_pByteCode;
+ ReleaseInputLayouts( i );
+ m_VertexShaderDict.Remove( i );
+}
+
+
+//-----------------------------------------------------------------------------
+// Create, destroy geometry shader
+//-----------------------------------------------------------------------------
+GeometryShaderHandle_t CShaderDeviceDx10::CreateGeometryShader( IShaderBuffer* pShaderBuffer )
+{
+ // Create the geometry shader
+ ID3D10GeometryShader *pShader = NULL;
+ HRESULT hr = m_pDevice->CreateGeometryShader( pShaderBuffer->GetBits(),
+ pShaderBuffer->GetSize(), &pShader );
+
+ if ( FAILED( hr ) || !pShader )
+ return GEOMETRY_SHADER_HANDLE_INVALID;
+
+ ID3D10ShaderReflection *pInfo;
+ hr = D3D10ReflectShader( pShaderBuffer->GetBits(), pShaderBuffer->GetSize(), &pInfo );
+ if ( FAILED( hr ) || !pInfo )
+ {
+ pShader->Release();
+ return GEOMETRY_SHADER_HANDLE_INVALID;
+ }
+
+ // Insert the shader into the dictionary of shaders
+ GeometryShaderIndex_t i = m_GeometryShaderDict.AddToTail( );
+ m_GeometryShaderDict[i].m_pShader = pShader;
+ m_GeometryShaderDict[i].m_pInfo = pInfo;
+ return (GeometryShaderHandle_t)i;
+}
+
+void CShaderDeviceDx10::DestroyGeometryShader( GeometryShaderHandle_t hShader )
+{
+ if ( hShader == GEOMETRY_SHADER_HANDLE_INVALID )
+ return;
+
+ g_pShaderAPIDx10->Unbind( hShader );
+
+ GeometryShaderIndex_t i = (GeometryShaderIndex_t)hShader;
+ VerifyEquals( m_GeometryShaderDict[ i ].m_pShader->Release(), 0 );
+ VerifyEquals( m_GeometryShaderDict[ i ].m_pInfo->Release(), 0 );
+ m_GeometryShaderDict.Remove( i );
+}
+
+
+//-----------------------------------------------------------------------------
+// Create, destroy pixel shader
+//-----------------------------------------------------------------------------
+PixelShaderHandle_t CShaderDeviceDx10::CreatePixelShader( IShaderBuffer* pShaderBuffer )
+{
+ // Create the pixel shader
+ ID3D10PixelShader *pShader = NULL;
+ HRESULT hr = m_pDevice->CreatePixelShader( pShaderBuffer->GetBits(),
+ pShaderBuffer->GetSize(), &pShader );
+
+ if ( FAILED( hr ) || !pShader )
+ return PIXEL_SHADER_HANDLE_INVALID;
+
+ ID3D10ShaderReflection *pInfo;
+ hr = D3D10ReflectShader( pShaderBuffer->GetBits(), pShaderBuffer->GetSize(), &pInfo );
+ if ( FAILED( hr ) || !pInfo )
+ {
+ pShader->Release();
+ return PIXEL_SHADER_HANDLE_INVALID;
+ }
+
+ // Insert the shader into the dictionary of shaders
+ PixelShaderIndex_t i = m_PixelShaderDict.AddToTail( );
+ m_PixelShaderDict[i].m_pShader = pShader;
+ m_PixelShaderDict[i].m_pInfo = pInfo;
+ return (PixelShaderHandle_t)i;
+}
+
+void CShaderDeviceDx10::DestroyPixelShader( PixelShaderHandle_t hShader )
+{
+ if ( hShader == PIXEL_SHADER_HANDLE_INVALID )
+ return;
+
+ g_pShaderAPIDx10->Unbind( hShader );
+
+ PixelShaderIndex_t i = (PixelShaderIndex_t)hShader;
+ VerifyEquals( m_PixelShaderDict[ i ].m_pShader->Release(), 0 );
+ VerifyEquals( m_PixelShaderDict[ i ].m_pInfo->Release(), 0 );
+ m_PixelShaderDict.Remove( i );
+}
+
+
+//-----------------------------------------------------------------------------
+// Finds or creates an input layout for a given vertex shader + stream format
+//-----------------------------------------------------------------------------
+ID3D10InputLayout* CShaderDeviceDx10::GetInputLayout( VertexShaderHandle_t hShader, VertexFormat_t format )
+{
+ if ( hShader == VERTEX_SHADER_HANDLE_INVALID )
+ return NULL;
+
+ // FIXME: VertexFormat_t is not the appropriate way of specifying this
+ // because it has no stream information
+ InputLayout_t insert;
+ insert.m_VertexFormat = format;
+
+ VertexShaderIndex_t i = (VertexShaderIndex_t)hShader;
+ InputLayoutDict_t &dict = m_VertexShaderDict[i].m_InputLayouts;
+ unsigned short hIndex = dict.Find( insert );
+ if ( hIndex != dict.InvalidIndex() )
+ return dict[hIndex].m_pInputLayout;
+
+ VertexShader_t &shader = m_VertexShaderDict[i];
+ insert.m_pInputLayout = CreateInputLayout( format, shader.m_pInfo, shader.m_pByteCode, shader.m_nByteCodeLen );
+ dict.Insert( insert );
+ return insert.m_pInputLayout;
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates/destroys Mesh
+//-----------------------------------------------------------------------------
+IMesh* CShaderDeviceDx10::CreateStaticMesh( VertexFormat_t vertexFormat, const char *pBudgetGroup, IMaterial * pMaterial )
+{
+ LOCK_SHADERAPI();
+ return NULL;
+}
+
+void CShaderDeviceDx10::DestroyStaticMesh( IMesh* pMesh )
+{
+ LOCK_SHADERAPI();
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates/destroys vertex buffers + index buffers
+//-----------------------------------------------------------------------------
+IVertexBuffer *CShaderDeviceDx10::CreateVertexBuffer( ShaderBufferType_t type, VertexFormat_t fmt, int nVertexCount, const char *pBudgetGroup )
+{
+ LOCK_SHADERAPI();
+ CVertexBufferDx10 *pVertexBuffer = new CVertexBufferDx10( type, fmt, nVertexCount, pBudgetGroup );
+ return pVertexBuffer;
+}
+
+void CShaderDeviceDx10::DestroyVertexBuffer( IVertexBuffer *pVertexBuffer )
+{
+ LOCK_SHADERAPI();
+ if ( pVertexBuffer )
+ {
+ CVertexBufferDx10 *pVertexBufferBase = assert_cast<CVertexBufferDx10*>( pVertexBuffer );
+ g_pShaderAPIDx10->UnbindVertexBuffer( pVertexBufferBase->GetDx10Buffer() );
+ delete pVertexBufferBase;
+ }
+}
+
+IIndexBuffer *CShaderDeviceDx10::CreateIndexBuffer( ShaderBufferType_t type, MaterialIndexFormat_t fmt, int nIndexCount, const char *pBudgetGroup )
+{
+ LOCK_SHADERAPI();
+ CIndexBufferDx10 *pIndexBuffer = new CIndexBufferDx10( type, fmt, nIndexCount, pBudgetGroup );
+ return pIndexBuffer;
+}
+
+void CShaderDeviceDx10::DestroyIndexBuffer( IIndexBuffer *pIndexBuffer )
+{
+ LOCK_SHADERAPI();
+ if ( pIndexBuffer )
+ {
+ CIndexBufferDx10 *pIndexBufferBase = assert_cast<CIndexBufferDx10*>( pIndexBuffer );
+ g_pShaderAPIDx10->UnbindIndexBuffer( pIndexBufferBase->GetDx10Buffer() );
+ delete pIndexBufferBase;
+ }
+}
+
+IVertexBuffer *CShaderDeviceDx10::GetDynamicVertexBuffer( int nStreamID, VertexFormat_t vertexFormat, bool bBuffered )
+{
+ LOCK_SHADERAPI();
+ return NULL;
+}
+
+IIndexBuffer *CShaderDeviceDx10::GetDynamicIndexBuffer( MaterialIndexFormat_t fmt, bool bBuffered )
+{
+ LOCK_SHADERAPI();
+ return NULL;
+}
+
+
+
diff --git a/materialsystem/shaderapidx9/shaderdevicedx10.h b/materialsystem/shaderapidx9/shaderdevicedx10.h
new file mode 100644
index 0000000..ecf6a8d
--- /dev/null
+++ b/materialsystem/shaderapidx9/shaderdevicedx10.h
@@ -0,0 +1,254 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#ifndef SHADERDEVICEDX10_H
+#define SHADERDEVICEDX10_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "shaderdevicebase.h"
+#include "tier1/utlvector.h"
+#include "tier1/utlrbtree.h"
+#include "tier1/utllinkedlist.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declaration
+//-----------------------------------------------------------------------------
+struct IDXGIFactory;
+struct IDXGIAdapter;
+struct IDXGIOutput;
+struct IDXGISwapChain;
+struct ID3D10Device;
+struct ID3D10RenderTargetView;
+struct ID3D10VertexShader;
+struct ID3D10PixelShader;
+struct ID3D10GeometryShader;
+struct ID3D10InputLayout;
+struct ID3D10ShaderReflection;
+
+
+//-----------------------------------------------------------------------------
+// The Base implementation of the shader device
+//-----------------------------------------------------------------------------
+class CShaderDeviceMgrDx10 : public CShaderDeviceMgrBase
+{
+ typedef CShaderDeviceMgrBase BaseClass;
+
+public:
+ // constructor, destructor
+ CShaderDeviceMgrDx10();
+ virtual ~CShaderDeviceMgrDx10();
+
+ // Methods of IAppSystem
+ virtual bool Connect( CreateInterfaceFn factory );
+ virtual void Disconnect();
+ virtual InitReturnVal_t Init();
+ virtual void Shutdown();
+
+ // Methods of IShaderDeviceMgr
+ virtual int GetAdapterCount() const;
+ virtual void GetAdapterInfo( int adapter, MaterialAdapterInfo_t& info ) const;
+ virtual int GetModeCount( int nAdapter ) const;
+ virtual void GetModeInfo( ShaderDisplayMode_t* pInfo, int nAdapter, int mode ) const;
+ virtual void GetCurrentModeInfo( ShaderDisplayMode_t* pInfo, int nAdapter ) const;
+ virtual bool SetAdapter( int nAdapter, int nFlags );
+ virtual CreateInterfaceFn SetMode( void *hWnd, int nAdapter, const ShaderDeviceInfo_t& mode );
+
+private:
+ // Initialize adapter information
+ void InitAdapterInfo();
+
+ // Determines hardware caps from D3D
+ bool ComputeCapsFromD3D( HardwareCaps_t *pCaps, IDXGIAdapter *pAdapter, IDXGIOutput *pOutput );
+
+ // Returns the amount of video memory in bytes for a particular adapter
+ virtual int GetVidMemBytes( int nAdapter ) const;
+
+ // Returns the appropriate adapter output to use
+ IDXGIOutput* GetAdapterOutput( int nAdapter ) const;
+
+ // Returns the adapter interface for a particular adapter
+ IDXGIAdapter* GetAdapter( int nAdapter ) const;
+
+ // Used to enumerate adapters, attach to windows
+ IDXGIFactory *m_pDXGIFactory;
+
+ bool m_bObeyDxCommandlineOverride: 1;
+
+ friend class CShaderDeviceDx10;
+};
+
+
+//-----------------------------------------------------------------------------
+// The Dx10 implementation of the shader device
+//-----------------------------------------------------------------------------
+class CShaderDeviceDx10 : public CShaderDeviceBase
+{
+public:
+ // constructor, destructor
+ CShaderDeviceDx10();
+ virtual ~CShaderDeviceDx10();
+
+public:
+ // Methods of IShaderDevice
+ virtual bool IsUsingGraphics() const;
+ virtual int GetCurrentAdapter() const;
+ virtual ImageFormat GetBackBufferFormat() const;
+ virtual void GetBackBufferDimensions( int& width, int& height ) const;
+ virtual void SpewDriverInfo() const;
+ virtual void Present();
+ virtual IShaderBuffer* CompileShader( const char *pProgram, size_t nBufLen, const char *pShaderVersion );
+ virtual VertexShaderHandle_t CreateVertexShader( IShaderBuffer *pShader );
+ virtual void DestroyVertexShader( VertexShaderHandle_t hShader );
+ virtual GeometryShaderHandle_t CreateGeometryShader( IShaderBuffer* pShaderBuffer );
+ virtual void DestroyGeometryShader( GeometryShaderHandle_t hShader );
+ virtual PixelShaderHandle_t CreatePixelShader( IShaderBuffer* pShaderBuffer );
+ virtual void DestroyPixelShader( PixelShaderHandle_t hShader );
+ virtual void ReleaseResources() {}
+ virtual void ReacquireResources() {}
+ virtual IMesh* CreateStaticMesh( VertexFormat_t format, const char *pTextureBudgetGroup, IMaterial * pMaterial );
+ virtual void DestroyStaticMesh( IMesh* mesh );
+ virtual IVertexBuffer *CreateVertexBuffer( ShaderBufferType_t type, VertexFormat_t fmt, int nVertexCount, const char *pTextureBudgetGroup );
+ virtual void DestroyVertexBuffer( IVertexBuffer *pVertexBuffer );
+ virtual IIndexBuffer *CreateIndexBuffer( ShaderBufferType_t type, MaterialIndexFormat_t fmt, int nIndexCount, const char *pTextureBudgetGroup );
+ virtual void DestroyIndexBuffer( IIndexBuffer *pIndexBuffer );
+ virtual IVertexBuffer *GetDynamicVertexBuffer( int nStreamID, VertexFormat_t vertexFormat, bool bBuffered = true );
+ virtual IIndexBuffer *GetDynamicIndexBuffer( MaterialIndexFormat_t fmt, bool bBuffered = true );
+ virtual void SetHardwareGammaRamp( float fGamma, float fGammaTVRangeMin, float fGammaTVRangeMax, float fGammaTVExponent, bool bTVEnabled );
+
+ // A special path used to tick the front buffer while loading on the 360
+ virtual void EnableNonInteractiveMode( MaterialNonInteractiveMode_t mode, ShaderNonInteractiveInfo_t *pInfo ) {}
+ virtual void RefreshFrontBufferNonInteractive( ) {}
+ virtual void HandleThreadEvent( uint32 threadEvent ) {}
+
+public:
+ // Methods of CShaderDeviceBase
+ virtual bool InitDevice( void *hWnd, int nAdapter, const ShaderDeviceInfo_t& mode );
+ virtual void ShutdownDevice();
+ virtual bool IsDeactivated() const { return false; }
+
+ // Other public methods
+ ID3D10VertexShader* GetVertexShader( VertexShaderHandle_t hShader ) const;
+ ID3D10GeometryShader* GetGeometryShader( GeometryShaderHandle_t hShader ) const;
+ ID3D10PixelShader* GetPixelShader( PixelShaderHandle_t hShader ) const;
+ ID3D10InputLayout* GetInputLayout( VertexShaderHandle_t hShader, VertexFormat_t format );
+
+private:
+ struct InputLayout_t
+ {
+ ID3D10InputLayout *m_pInputLayout;
+ VertexFormat_t m_VertexFormat;
+ };
+
+ typedef CUtlRBTree< InputLayout_t, unsigned short > InputLayoutDict_t;
+
+ static bool InputLayoutLessFunc( const InputLayout_t &lhs, const InputLayout_t &rhs )
+ {
+ return ( lhs.m_VertexFormat < rhs.m_VertexFormat );
+ }
+
+ struct VertexShader_t
+ {
+ ID3D10VertexShader *m_pShader;
+ ID3D10ShaderReflection *m_pInfo;
+ void *m_pByteCode;
+ size_t m_nByteCodeLen;
+ InputLayoutDict_t m_InputLayouts;
+
+ VertexShader_t() : m_InputLayouts( 0, 0, InputLayoutLessFunc ) {}
+ };
+
+ struct GeometryShader_t
+ {
+ ID3D10GeometryShader *m_pShader;
+ ID3D10ShaderReflection *m_pInfo;
+ };
+
+ struct PixelShader_t
+ {
+ ID3D10PixelShader *m_pShader;
+ ID3D10ShaderReflection *m_pInfo;
+ };
+
+ typedef CUtlFixedLinkedList< VertexShader_t >::IndexType_t VertexShaderIndex_t;
+ typedef CUtlFixedLinkedList< GeometryShader_t >::IndexType_t GeometryShaderIndex_t;
+ typedef CUtlFixedLinkedList< PixelShader_t >::IndexType_t PixelShaderIndex_t;
+
+ void SetupHardwareCaps();
+ void ReleaseInputLayouts( VertexShaderIndex_t nIndex );
+
+ IDXGIOutput *m_pOutput;
+ ID3D10Device *m_pDevice;
+ IDXGISwapChain *m_pSwapChain;
+ ID3D10RenderTargetView *m_pRenderTargetView;
+
+ CUtlFixedLinkedList< VertexShader_t > m_VertexShaderDict;
+ CUtlFixedLinkedList< GeometryShader_t > m_GeometryShaderDict;
+ CUtlFixedLinkedList< PixelShader_t > m_PixelShaderDict;
+
+ friend ID3D10Device *D3D10Device();
+ friend IDXGISwapChain *D3D10SwapChain();
+ friend ID3D10RenderTargetView *D3D10RenderTargetView();
+};
+
+
+//-----------------------------------------------------------------------------
+// Inline methods of CShaderDeviceDx10
+//-----------------------------------------------------------------------------
+inline ID3D10VertexShader* CShaderDeviceDx10::GetVertexShader( VertexShaderHandle_t hShader ) const
+{
+ if ( hShader != VERTEX_SHADER_HANDLE_INVALID )
+ return m_VertexShaderDict[ (VertexShaderIndex_t)hShader ].m_pShader;
+ return NULL;
+}
+
+inline ID3D10GeometryShader* CShaderDeviceDx10::GetGeometryShader( GeometryShaderHandle_t hShader ) const
+{
+ if ( hShader != GEOMETRY_SHADER_HANDLE_INVALID )
+ return m_GeometryShaderDict[ (GeometryShaderIndex_t)hShader ].m_pShader;
+ return NULL;
+}
+
+inline ID3D10PixelShader* CShaderDeviceDx10::GetPixelShader( PixelShaderHandle_t hShader ) const
+{
+ if ( hShader != PIXEL_SHADER_HANDLE_INVALID )
+ return m_PixelShaderDict[ (PixelShaderIndex_t)hShader ].m_pShader;
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Singleton
+//-----------------------------------------------------------------------------
+extern CShaderDeviceDx10* g_pShaderDeviceDx10;
+
+
+//-----------------------------------------------------------------------------
+// Utility methods
+//-----------------------------------------------------------------------------
+inline ID3D10Device *D3D10Device()
+{
+ return g_pShaderDeviceDx10->m_pDevice;
+}
+
+inline IDXGISwapChain *D3D10SwapChain()
+{
+ return g_pShaderDeviceDx10->m_pSwapChain;
+}
+
+inline ID3D10RenderTargetView *D3D10RenderTargetView()
+{
+ return g_pShaderDeviceDx10->m_pRenderTargetView;
+}
+
+
+#endif // SHADERDEVICEDX10_H \ No newline at end of file
diff --git a/materialsystem/shaderapidx9/shaderdevicedx8.cpp b/materialsystem/shaderapidx9/shaderdevicedx8.cpp
new file mode 100644
index 0000000..5b094e1
--- /dev/null
+++ b/materialsystem/shaderapidx9/shaderdevicedx8.cpp
@@ -0,0 +1,3707 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+#define DISABLE_PROTECTED_THINGS
+#include "locald3dtypes.h"
+
+#include "shaderdevicedx8.h"
+#include "shaderapi/ishaderutil.h"
+#include "shaderapidx8_global.h"
+#include "filesystem.h"
+#include "tier0/icommandline.h"
+#include "tier2/tier2.h"
+#include "shadershadowdx8.h"
+#include "colorformatdx8.h"
+#include "materialsystem/IShader.h"
+#include "shaderapidx8.h"
+#include "shaderapidx8_global.h"
+#include "imeshdx8.h"
+#include "materialsystem/materialsystem_config.h"
+#include "vertexshaderdx8.h"
+#include "recording.h"
+#include "winutils.h"
+#include "tier0/vprof_telemetry.h"
+
+#if defined ( DX_TO_GL_ABSTRACTION )
+// Placed here so inlines placed in dxabstract.h can access gGL
+COpenGLEntryPoints *gGL = NULL;
+#endif
+
+#define D3D_BATCH_PERF_ANALYSIS 0
+
+#if D3D_BATCH_PERF_ANALYSIS
+#if defined( DX_TO_GL_ABSTRACTION )
+#error Cannot enable D3D_BATCH_PERF_ANALYSIS when using DX_TO_GL_ABSTRACTION, use GL_BATCH_PERF_ANALYSIS instead.
+#endif
+// Define this if you want all d3d9 interfaces hooked and run through the dx9hook.h shim interfaces. For profiling, etc.
+#define DO_DX9_HOOK
+#endif
+
+#ifdef DO_DX9_HOOK
+
+#if D3D_BATCH_PERF_ANALYSIS
+ConVar d3d_batch_vis( "d3d_batch_vis", "0" );
+ConVar d3d_batch_vis_abs_scale( "d3d_batch_vis_abs_scale", ".050" );
+ConVar d3d_present_vis_abs_scale( "d3d_batch_vis_abs_scale", ".050" );
+ConVar d3d_batch_vis_y_scale( "d3d_batch_vis_y_scale", "0.0" );
+uint64 g_nTotalD3DCalls, g_nTotalD3DCycles;
+static double s_rdtsc_to_ms;
+#endif
+
+#include "dx9hook.h"
+#endif
+
+#ifndef _X360
+#include "wmi.h"
+#endif
+
+#if defined( _X360 )
+#include "xbox/xbox_console.h"
+#include "xbox/xbox_win32stubs.h"
+#endif
+
+
+//#define DX8_COMPATABILITY_MODE
+
+//-----------------------------------------------------------------------------
+// Globals
+//-----------------------------------------------------------------------------
+static CShaderDeviceMgrDx8 g_ShaderDeviceMgrDx8;
+CShaderDeviceMgrDx8* g_pShaderDeviceMgrDx8 = &g_ShaderDeviceMgrDx8;
+
+#ifndef SHADERAPIDX10
+
+// In the shaderapidx10.dll, we use its version of IShaderDeviceMgr.
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CShaderDeviceMgrDx8, IShaderDeviceMgr,
+ SHADER_DEVICE_MGR_INTERFACE_VERSION, g_ShaderDeviceMgrDx8 )
+
+#endif
+
+#if defined( _X360 )
+IDirect3D9 *m_pD3D;
+#endif
+
+IDirect3DDevice *g_pD3DDevice = NULL;
+
+#if defined(IS_WINDOWS_PC) && defined(SHADERAPIDX9)
+// HACK: need to pass knowledge of D3D9Ex usage into callers of D3D Create* methods
+// so they do not try to specify D3DPOOL_MANAGED, which is unsupported in D3D9Ex
+bool g_ShaderDeviceUsingD3D9Ex = false;
+static ConVar mat_supports_d3d9ex( "mat_supports_d3d9ex", "0", FCVAR_HIDDEN );
+#endif
+
+// hook into mat_forcedynamic from the engine.
+static ConVar mat_forcedynamic( "mat_forcedynamic", "0", FCVAR_CHEAT );
+
+// this is hooked into the engines convar
+ConVar mat_debugalttab( "mat_debugalttab", "0", FCVAR_CHEAT );
+
+
+//-----------------------------------------------------------------------------
+//
+// Device manager
+//
+//-----------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+CShaderDeviceMgrDx8::CShaderDeviceMgrDx8()
+{
+ m_pD3D = NULL;
+ m_bObeyDxCommandlineOverride = true;
+ m_bAdapterInfoIntialized = false;
+
+#if defined( PIX_INSTRUMENTATION ) && defined ( DX_TO_GL_ABSTRACTION ) && defined( _WIN32 )
+ m_hD3D9 = NULL;
+ m_pBeginEvent = NULL;
+ m_pEndEvent = NULL;
+ m_pSetMarker = NULL;
+ m_pSetOptions = NULL;
+#endif
+}
+
+CShaderDeviceMgrDx8::~CShaderDeviceMgrDx8()
+{
+}
+
+#ifdef OSX
+#include <Carbon/Carbon.h>
+#endif
+//-----------------------------------------------------------------------------
+// Connect, disconnect
+//-----------------------------------------------------------------------------
+bool CShaderDeviceMgrDx8::Connect( CreateInterfaceFn factory )
+{
+ LOCK_SHADERAPI();
+
+ if ( !BaseClass::Connect( factory ) )
+ return false;
+
+#if defined ( DX_TO_GL_ABSTRACTION )
+ gGL = ToGLConnectLibraries( factory );
+#endif
+
+#if defined(IS_WINDOWS_PC) && defined(SHADERAPIDX9) && !defined(RECORDING) && !defined( DX_TO_GL_ABSTRACTION )
+ m_pD3D = NULL;
+
+ // Attempt to create a D3D9Ex device (Windows Vista and later) if possible
+ bool bD3D9ExForceDisable = ( CommandLine()->FindParm( "-nod3d9ex" ) != 0 ) ||
+ ( CommandLine()->ParmValue( "-dxlevel", 95 ) < 90 );
+
+ bool bD3D9ExAvailable = false;
+ if ( HMODULE hMod = ::LoadLibraryA( "d3d9.dll" ) )
+ {
+ typedef HRESULT ( WINAPI *CreateD3D9ExFunc_t )( UINT, IUnknown** );
+ if ( CreateD3D9ExFunc_t pfnCreateD3D9Ex = (CreateD3D9ExFunc_t) ::GetProcAddress( hMod, "Direct3DCreate9Ex" ) )
+ {
+ IUnknown *pD3D9Ex = NULL;
+ if ( (*pfnCreateD3D9Ex)( D3D_SDK_VERSION, &pD3D9Ex ) == S_OK && pD3D9Ex )
+ {
+ bD3D9ExAvailable = true;
+ if ( bD3D9ExForceDisable )
+ {
+ pD3D9Ex->Release();
+ }
+ else
+ {
+ g_ShaderDeviceUsingD3D9Ex = true;
+ // The following is more "correct" but incompatible with the Steam overlay:
+ //pD3D9Ex->QueryInterface( IID_IDirect3D9, (void**) &m_pD3D );
+ //pD3D9Ex->Release();
+ m_pD3D = static_cast< IDirect3D9* >( pD3D9Ex );
+ }
+ }
+ }
+ ::FreeLibrary( hMod );
+ }
+
+ if ( !m_pD3D )
+ {
+ g_ShaderDeviceUsingD3D9Ex = false;
+ m_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
+ }
+
+ mat_supports_d3d9ex.SetValue( bD3D9ExAvailable ? 1 : 0 );
+#else
+ #if defined( DO_DX9_HOOK )
+ m_pD3D = Direct3DCreate9Hook(D3D_SDK_VERSION);
+ #else
+ m_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
+ #endif
+#endif
+
+ if ( !m_pD3D )
+ {
+ Warning( "Failed to create D3D9!\n" );
+ return false;
+ }
+
+#if defined( PIX_INSTRUMENTATION ) && defined ( DX_TO_GL_ABSTRACTION ) && defined( _WIN32 )
+ // This is a little odd, but AMD PerfStudio hooks D3D9.DLL and intercepts all of the D3DPERF API's (even for OpenGL apps).
+ // So dynamically load d3d9.dll and get the address of these exported functions.
+ if ( !m_hD3D9 )
+ {
+ m_hD3D9 = LoadLibraryA("d3d9.dll");
+ }
+ if ( m_hD3D9 )
+ {
+ Plat_DebugString( "PIX_INSTRUMENTATION: Loaded d3d9.dll\n" );
+ printf( "PIX_INSTRUMENTATION: Loaded d3d9.dll\n" );
+
+ m_pBeginEvent = (D3DPERF_BeginEvent_FuncPtr)GetProcAddress( m_hD3D9, "D3DPERF_BeginEvent" );
+ m_pEndEvent = (D3DPERF_EndEvent_FuncPtr)GetProcAddress( m_hD3D9, "D3DPERF_EndEvent" );
+ m_pSetMarker = (D3DPERF_SetMarker_FuncPtr)GetProcAddress( m_hD3D9, "D3DPERF_SetOptions" );
+ m_pSetOptions = (D3DPERF_SetOptions_FuncPtr)GetProcAddress( m_hD3D9, "D3DPERF_SetMarker" );
+ }
+#endif
+
+ // FIXME: Want this to be here, but we can't because Steam
+ // hasn't had it's application ID set up yet.
+
+// InitAdapterInfo();
+ return true;
+}
+
+void CShaderDeviceMgrDx8::Disconnect()
+{
+ LOCK_SHADERAPI();
+
+#if defined( PIX_INSTRUMENTATION ) && defined ( DX_TO_GL_ABSTRACTION ) && defined( _WIN32 )
+ if ( m_hD3D9 )
+ {
+ m_pBeginEvent = NULL;
+ m_pEndEvent = NULL;
+ m_pSetMarker = NULL;
+ m_pSetOptions = NULL;
+
+ FreeLibrary( m_hD3D9 );
+ m_hD3D9 = NULL;
+ }
+#endif
+
+ if ( m_pD3D )
+ {
+ m_pD3D->Release();
+ m_pD3D = 0;
+ }
+
+#if defined ( DX_TO_GL_ABSTRACTION )
+ ToGLDisconnectLibraries();
+#endif
+
+ BaseClass::Disconnect();
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Initialization
+//-----------------------------------------------------------------------------
+InitReturnVal_t CShaderDeviceMgrDx8::Init( )
+{
+ // FIXME: Remove call to InitAdapterInfo once Steam startup issues are resolved.
+ // Do it in Connect instead.
+ InitAdapterInfo();
+
+ return INIT_OK;
+}
+
+
+//-----------------------------------------------------------------------------
+// Shutdown
+//-----------------------------------------------------------------------------
+void CShaderDeviceMgrDx8::Shutdown( )
+{
+ LOCK_SHADERAPI();
+
+// FIXME: Make PIX work
+
+// BeginPIXEvent( PIX_VALVE_ORANGE, "Shutdown" );
+
+ if ( g_pShaderAPI )
+ {
+ g_pShaderAPI->OnDeviceShutdown();
+ }
+
+ if ( g_pShaderDevice )
+ {
+ g_pShaderDevice->ShutdownDevice();
+ g_pMaterialSystemHardwareConfig = NULL;
+ }
+
+// EndPIXEvent();
+
+
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Inline methods
+//-----------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------
+// Initialize adapter information
+//-----------------------------------------------------------------------------
+void CShaderDeviceMgrDx8::InitAdapterInfo()
+{
+ if ( m_bAdapterInfoIntialized )
+ return;
+
+ m_bAdapterInfoIntialized = true;
+ m_Adapters.RemoveAll();
+
+ Assert(m_pD3D);
+ int nCount = m_pD3D->GetAdapterCount( );
+ for( int i = 0; i < nCount; ++i )
+ {
+ int j = m_Adapters.AddToTail();
+ AdapterInfo_t &info = m_Adapters[j];
+
+#ifdef _DEBUG
+ memset( &info.m_ActualCaps, 0xDD, sizeof(info.m_ActualCaps) );
+#endif
+
+ info.m_ActualCaps.m_bDeviceOk = ComputeCapsFromD3D( &info.m_ActualCaps, i );
+ if ( !info.m_ActualCaps.m_bDeviceOk )
+ continue;
+
+ ReadDXSupportLevels( info.m_ActualCaps );
+
+ // Read dxsupport.cfg which has config overrides for particular cards.
+ ReadHardwareCaps( info.m_ActualCaps, info.m_ActualCaps.m_nMaxDXSupportLevel );
+
+ // What's in "-shader" overrides dxsupport.cfg
+ const char *pShaderParam = CommandLine()->ParmValue( "-shader" );
+ if ( pShaderParam )
+ {
+ Q_strncpy( info.m_ActualCaps.m_pShaderDLL, pShaderParam, sizeof( info.m_ActualCaps.m_pShaderDLL ) );
+ }
+ }
+}
+
+//--------------------------------------------------------------------------------
+// Code to detect support for texture border color (widely supported but the caps
+// bit is messed up in drivers due to a stupid WHQL test that requires this to work
+// with float textures which we don't generally care about wrt this address mode)
+//--------------------------------------------------------------------------------
+void CShaderDeviceMgrDx8::CheckBorderColorSupport( HardwareCaps_t *pCaps, int nAdapter )
+{
+#ifdef DX_TO_GL_ABSTRACTION
+ if( true )
+#else
+ if( IsX360() )
+#endif
+ {
+ pCaps->m_bSupportsBorderColor = true;
+ }
+ else // Most PC parts do this, but let's not deal with that yet (JasonM)
+ {
+ pCaps->m_bSupportsBorderColor = false;
+ }
+}
+
+//--------------------------------------------------------------------------------
+// Vendor-dependent code to detect support for various flavors of shadow mapping
+//--------------------------------------------------------------------------------
+void CShaderDeviceMgrDx8::CheckVendorDependentShadowMappingSupport( HardwareCaps_t *pCaps, int nAdapter )
+{
+ // Set a default null texture format...may be overridden below by IHV-specific surface type
+ pCaps->m_NullTextureFormat = IMAGE_FORMAT_ARGB8888;
+ if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, D3DFMT_R5G6B5 ) == S_OK )
+ {
+ pCaps->m_NullTextureFormat = IMAGE_FORMAT_RGB565;
+ }
+
+#if defined( _X360 )
+ pCaps->m_ShadowDepthTextureFormat = ReverseDepthOnX360() ? IMAGE_FORMAT_X360_DST24F : IMAGE_FORMAT_X360_DST24;
+ pCaps->m_bSupportsShadowDepthTextures = true;
+ pCaps->m_bSupportsFetch4 = false;
+ return;
+#elif defined ( DX_TO_GL_ABSTRACTION )
+ // We may want to only do this on the higher-end Mac SKUs, since it's not free...
+ pCaps->m_ShadowDepthTextureFormat = IMAGE_FORMAT_NV_DST16; // This format shunts us down the right shader combo path
+
+ pCaps->m_bSupportsShadowDepthTextures = true;
+
+ pCaps->m_bSupportsFetch4 = false;
+ return;
+#endif
+
+ if ( IsPC() || !IsX360() )
+ {
+ bool bToolsMode = IsWindows() && ( CommandLine()->CheckParm( "-tools" ) != NULL );
+ bool bFound16Bit = false;
+
+ if ( ( pCaps->m_VendorID == VENDORID_NVIDIA ) && ( pCaps->m_SupportsShaderModel_3_0 ) ) // ps_3_0 parts from nVidia
+ {
+ // First, test for null texture support
+ if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, NVFMT_NULL ) == S_OK )
+ {
+ pCaps->m_NullTextureFormat = IMAGE_FORMAT_NV_NULL;
+ }
+
+ //
+ // NVIDIA has two no-PCF formats (these are not filtering modes, but surface formats
+ // NVFMT_RAWZ is supported by NV4x (not supported here yet...requires a dp3 to reconstruct in shader code, which doesn't seem to work)
+ // NVFMT_INTZ is supported on newer chips as of G8x (just read like ATI non-fetch4 mode)
+ //
+/*
+ if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, NVFMT_INTZ ) == S_OK )
+ {
+ pCaps->m_ShadowDepthTextureFormat = IMAGE_FORMAT_NV_INTZ;
+ pCaps->m_bSupportsFetch4 = false;
+ pCaps->m_bSupportsShadowDepthTextures = true;
+ return;
+ }
+*/
+ if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, D3DFMT_D16 ) == S_OK )
+ {
+ pCaps->m_ShadowDepthTextureFormat = IMAGE_FORMAT_NV_DST16;
+ pCaps->m_bSupportsFetch4 = false;
+ pCaps->m_bSupportsShadowDepthTextures = true;
+ bFound16Bit = true;
+
+ if ( !bToolsMode ) // Tools will continue on and try for 24 bit...
+ return;
+ }
+
+ if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, D3DFMT_D24S8 ) == S_OK )
+ {
+ pCaps->m_ShadowDepthTextureFormat = IMAGE_FORMAT_NV_DST24;
+ pCaps->m_bSupportsFetch4 = false;
+ pCaps->m_bSupportsShadowDepthTextures = true;
+ return;
+ }
+
+ if ( bFound16Bit ) // Found 16 bit but not 24
+ return;
+ }
+ else if ( ( pCaps->m_VendorID == VENDORID_ATI ) && pCaps->m_SupportsPixelShaders_2_b ) // ps_2_b parts from ATI
+ {
+ // Initially, check for Fetch4 (tied to ATIFMT_D24S8 support)
+ pCaps->m_bSupportsFetch4 = false;
+ if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, ATIFMT_D24S8 ) == S_OK )
+ {
+ pCaps->m_bSupportsFetch4 = true;
+ }
+
+ if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, ATIFMT_D16 ) == S_OK ) // Prefer 16-bit
+ {
+ pCaps->m_ShadowDepthTextureFormat = IMAGE_FORMAT_ATI_DST16;
+ pCaps->m_bSupportsShadowDepthTextures = true;
+ bFound16Bit = true;
+
+ if ( !bToolsMode ) // Tools will continue on and try for 24 bit...
+ return;
+ }
+
+ if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, ATIFMT_D24S8 ) == S_OK )
+ {
+ pCaps->m_ShadowDepthTextureFormat = IMAGE_FORMAT_ATI_DST24;
+ pCaps->m_bSupportsShadowDepthTextures = true;
+ return;
+ }
+
+ if ( bFound16Bit ) // Found 16 bit but not 24
+ return;
+ }
+ }
+
+ // Other vendor or old hardware
+ pCaps->m_ShadowDepthTextureFormat = IMAGE_FORMAT_UNKNOWN;
+ pCaps->m_bSupportsShadowDepthTextures = false;
+ pCaps->m_bSupportsFetch4 = false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Vendor-dependent code to detect Alpha To Coverage Backdoors
+//-----------------------------------------------------------------------------
+void CShaderDeviceMgrDx8::CheckVendorDependentAlphaToCoverage( HardwareCaps_t *pCaps, int nAdapter )
+{
+ pCaps->m_bSupportsAlphaToCoverage = false;
+
+ // Bail out on OpenGL
+#ifdef DX_TO_GL_ABSTRACTION
+ pCaps->m_bSupportsAlphaToCoverage = true;
+ pCaps->m_AlphaToCoverageEnableValue = TRUE;
+ pCaps->m_AlphaToCoverageDisableValue = FALSE;
+ pCaps->m_AlphaToCoverageState = D3DRS_ADAPTIVETESS_Y; // Just match the NVIDIA state hackery
+ return;
+#endif
+
+ if ( pCaps->m_nDXSupportLevel < 90 )
+ return;
+
+#ifdef _X360
+ {
+ pCaps->m_bSupportsAlphaToCoverage = true;
+ pCaps->m_AlphaToCoverageEnableValue = TRUE;
+ pCaps->m_AlphaToCoverageDisableValue = FALSE;
+ pCaps->m_AlphaToCoverageState = D3DRS_ALPHATOMASKENABLE;
+ return;
+ }
+#endif // _X360
+
+ if ( pCaps->m_VendorID == VENDORID_NVIDIA )
+ {
+ // nVidia has two modes...assume SSAA is superior to MSAA and hence more desirable (though it's probably not)
+ //
+ // Currently, they only seem to expose any of this on 7800 and up though older parts certainly
+ // support at least the MSAA mode since they support it on OpenGL via the arb_multisample extension
+ bool bNVIDIA_MSAA = false;
+ bool bNVIDIA_SSAA = false;
+
+ if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, // Check MSAA version
+ D3DFMT_X8R8G8B8, 0, D3DRTYPE_SURFACE,
+ (D3DFORMAT)MAKEFOURCC('A', 'T', 'O', 'C')) == S_OK )
+ {
+ bNVIDIA_MSAA = true;
+ }
+
+ if ( m_pD3D->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, // Check SSAA version
+ D3DFMT_X8R8G8B8, 0, D3DRTYPE_SURFACE,
+ (D3DFORMAT)MAKEFOURCC('S', 'S', 'A', 'A')) == S_OK )
+ {
+ bNVIDIA_SSAA = true;
+ }
+
+ // nVidia pitches SSAA but we prefer ATOC
+ if ( bNVIDIA_MSAA )// || bNVIDIA_SSAA )
+ {
+ // if ( bNVIDIA_SSAA )
+ // m_AlphaToCoverageEnableValue = MAKEFOURCC('S', 'S', 'A', 'A');
+ // else
+ pCaps->m_AlphaToCoverageEnableValue = MAKEFOURCC('A', 'T', 'O', 'C');
+
+ pCaps->m_AlphaToCoverageState = D3DRS_ADAPTIVETESS_Y;
+ pCaps->m_AlphaToCoverageDisableValue = (DWORD)D3DFMT_UNKNOWN;
+ pCaps->m_bSupportsAlphaToCoverage = true;
+ return;
+ }
+ }
+ else if ( pCaps->m_VendorID == VENDORID_ATI )
+ {
+ // Supported on all ATI parts...just go ahead and set the state when appropriate
+ pCaps->m_AlphaToCoverageState = D3DRS_POINTSIZE;
+ pCaps->m_AlphaToCoverageEnableValue = MAKEFOURCC('A','2','M','1');
+ pCaps->m_AlphaToCoverageDisableValue = MAKEFOURCC('A','2','M','0');
+ pCaps->m_bSupportsAlphaToCoverage = true;
+ return;
+ }
+}
+
+ConVar mat_hdr_level( "mat_hdr_level", "2", FCVAR_ARCHIVE );
+ConVar mat_slopescaledepthbias_shadowmap( "mat_slopescaledepthbias_shadowmap", "16", FCVAR_CHEAT );
+#ifdef DX_TO_GL_ABSTRACTION
+ConVar mat_depthbias_shadowmap( "mat_depthbias_shadowmap", "20", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY );
+#else
+ConVar mat_depthbias_shadowmap( "mat_depthbias_shadowmap", "0.0005", FCVAR_CHEAT );
+#endif
+
+// For testing Fast Clip
+ConVar mat_fastclip( "mat_fastclip", "0", FCVAR_CHEAT );
+
+//-----------------------------------------------------------------------------
+// Determine capabilities
+//-----------------------------------------------------------------------------
+bool CShaderDeviceMgrDx8::ComputeCapsFromD3D( HardwareCaps_t *pCaps, int nAdapter )
+{
+ D3DCAPS caps;
+ D3DADAPTER_IDENTIFIER9 ident;
+ HRESULT hr;
+
+ // NOTE: When getting the caps, we want to be limited by the hardware
+ // even if we're running with software T&L...
+ hr = m_pD3D->GetDeviceCaps( nAdapter, DX8_DEVTYPE, &caps );
+ if ( FAILED( hr ) )
+ return false;
+
+ hr = m_pD3D->GetAdapterIdentifier( nAdapter, D3DENUM_WHQL_LEVEL, &ident );
+ if ( FAILED( hr ) )
+ return false;
+
+ if ( IsOpenGL() )
+ {
+ if ( !ident.DeviceId && !ident.VendorId )
+ {
+ ident.DeviceId = 1; // fake default device/vendor ID for OpenGL
+ ident.VendorId = 1;
+ }
+ }
+
+ // Intended for debugging only
+ if ( CommandLine()->CheckParm( "-force_device_id" ) )
+ {
+ const char *pDevID = CommandLine()->ParmValue( "-force_device_id", "" );
+ if ( pDevID )
+ {
+ int nDevID = V_atoi( pDevID ); // use V_atoi for hex support
+ if ( nDevID > 0 )
+ {
+ ident.DeviceId = nDevID;
+ }
+ }
+ }
+
+ // Intended for debugging only
+ if ( CommandLine()->CheckParm( "-force_vendor_id" ) )
+ {
+ const char *pVendorID = CommandLine()->ParmValue( "-force_vendor_id", "" );
+ if ( pVendorID )
+ {
+ int nVendorID = V_atoi( pVendorID ); // use V_atoi for hex support
+ if ( pVendorID > 0 )
+ {
+ ident.VendorId = nVendorID;
+ }
+ }
+ }
+
+ Q_strncpy( pCaps->m_pDriverName, ident.Description, MATERIAL_ADAPTER_NAME_LENGTH );
+ pCaps->m_VendorID = ident.VendorId;
+ pCaps->m_DeviceID = ident.DeviceId;
+ pCaps->m_SubSysID = ident.SubSysId;
+ pCaps->m_Revision = ident.Revision;
+
+ pCaps->m_nDriverVersionHigh = ident.DriverVersion.HighPart;
+ pCaps->m_nDriverVersionLow = ident.DriverVersion.LowPart;
+
+ pCaps->m_pShaderDLL[0] = 0;
+ pCaps->m_nMaxViewports = 1;
+
+ pCaps->m_PreferDynamicTextures = ( caps.Caps2 & D3DCAPS2_DYNAMICTEXTURES ) ? 1 : 0;
+
+ pCaps->m_HasProjectedBumpEnv = ( caps.TextureCaps & D3DPTEXTURECAPS_NOPROJECTEDBUMPENV ) == 0;
+
+ pCaps->m_HasSetDeviceGammaRamp = (caps.Caps2 & D3DCAPS2_CANCALIBRATEGAMMA) != 0;
+ pCaps->m_SupportsVertexShaders = ((caps.VertexShaderVersion >> 8) & 0xFF) >= 1;
+ pCaps->m_SupportsPixelShaders = ((caps.PixelShaderVersion >> 8) & 0xFF) >= 1;
+
+ pCaps->m_bScissorSupported = ( caps.RasterCaps & D3DPRASTERCAPS_SCISSORTEST ) != 0;
+
+#if defined( DX8_COMPATABILITY_MODE )
+ pCaps->m_SupportsPixelShaders_1_4 = false;
+ pCaps->m_SupportsPixelShaders_2_0 = false;
+ pCaps->m_SupportsPixelShaders_2_b = false;
+ pCaps->m_SupportsVertexShaders_2_0 = false;
+ pCaps->m_SupportsShaderModel_3_0 = false;
+ pCaps->m_SupportsMipmappedCubemaps = false;
+#else
+ pCaps->m_SupportsPixelShaders_1_4 = ( caps.PixelShaderVersion & 0xffff ) >= 0x0104;
+ pCaps->m_SupportsPixelShaders_2_0 = ( caps.PixelShaderVersion & 0xffff ) >= 0x0200;
+ pCaps->m_SupportsPixelShaders_2_b = ( ( caps.PixelShaderVersion & 0xffff ) >= 0x0200) && (caps.PS20Caps.NumInstructionSlots >= 512); // More caps to this, but this will do
+ pCaps->m_SupportsVertexShaders_2_0 = ( caps.VertexShaderVersion & 0xffff ) >= 0x0200;
+ pCaps->m_SupportsShaderModel_3_0 = ( caps.PixelShaderVersion & 0xffff ) >= 0x0300;
+ pCaps->m_SupportsMipmappedCubemaps = ( caps.TextureCaps & D3DPTEXTURECAPS_MIPCUBEMAP ) ? true : false;
+#endif
+
+ // Slam this off for OpenGL
+ if ( IsOpenGL() )
+ {
+ pCaps->m_SupportsShaderModel_3_0 = false;
+ }
+
+ // Slam 3.0 shaders off for Intel
+ if ( pCaps->m_VendorID == VENDORID_INTEL )
+ {
+ pCaps->m_SupportsShaderModel_3_0 = false;
+ }
+
+ pCaps->m_MaxVertexShader30InstructionSlots = 0;
+ pCaps->m_MaxPixelShader30InstructionSlots = 0;
+
+ if ( pCaps->m_SupportsShaderModel_3_0 )
+ {
+ pCaps->m_MaxVertexShader30InstructionSlots = caps.MaxVertexShader30InstructionSlots;
+ pCaps->m_MaxPixelShader30InstructionSlots = caps.MaxPixelShader30InstructionSlots;
+ }
+
+ if( CommandLine()->CheckParm( "-nops2b" ) )
+ {
+ pCaps->m_SupportsPixelShaders_2_b = false;
+ }
+
+ pCaps->m_bSoftwareVertexProcessing = false;
+ if ( IsWindows() && CommandLine()->CheckParm( "-mat_softwaretl" ) )
+ {
+ pCaps->m_bSoftwareVertexProcessing = true;
+ }
+
+ if ( IsWindows() && !( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT ) )
+ {
+ // no hardware t&l. . use software
+ pCaps->m_bSoftwareVertexProcessing = true;
+ }
+
+ // Set mat_forcedynamic if software vertex processing since the software vp pipe has
+ // problems with sparse vertex buffers (it transforms the whole thing.)
+ if ( pCaps->m_bSoftwareVertexProcessing )
+ {
+ mat_forcedynamic.SetValue( 1 );
+ }
+
+ if ( pCaps->m_bSoftwareVertexProcessing )
+ {
+ pCaps->m_SupportsVertexShaders = true;
+ pCaps->m_SupportsVertexShaders_2_0 = true;
+ }
+
+#ifdef OSX
+ // Static control flow is disabled by default on OSX (the Mac version of togl has known bugs preventing this path from working properly that we've fixed in togl linux/win)
+ pCaps->m_bSupportsStaticControlFlow = CommandLine()->CheckParm( "-glslcontrolflow" ) != NULL;
+#else
+ pCaps->m_bSupportsStaticControlFlow = !CommandLine()->CheckParm( "-noglslcontrolflow" );
+#endif
+
+ // NOTE: Texture stages is a fixed-function concept
+ // NOTE: Normally, the number of texture units == the number of texture
+ // stages except for NVidia hardware, which reports more stages than units.
+ // The reason for this is because they expose the inner hardware pixel
+ // pipeline through the extra stages. The only thing we use stages for
+ // in the hardware is for configuring the color + alpha args + ops.
+ pCaps->m_NumSamplers = caps.MaxSimultaneousTextures;
+ pCaps->m_NumTextureStages = caps.MaxTextureBlendStages;
+ if ( pCaps->m_SupportsPixelShaders_2_0 )
+ {
+ pCaps->m_NumSamplers = 16;
+ }
+ else
+ {
+ Assert( pCaps->m_NumSamplers <= pCaps->m_NumTextureStages );
+ }
+
+ // Clamp
+ pCaps->m_NumSamplers = min( pCaps->m_NumSamplers, (int)MAX_SAMPLERS );
+ pCaps->m_NumTextureStages = min( pCaps->m_NumTextureStages, (int)MAX_TEXTURE_STAGES );
+
+ if ( D3DSupportsCompressedTextures() )
+ {
+ pCaps->m_SupportsCompressedTextures = COMPRESSED_TEXTURES_ON;
+ }
+ else
+ {
+ pCaps->m_SupportsCompressedTextures = COMPRESSED_TEXTURES_OFF;
+ }
+
+ pCaps->m_bSupportsAnisotropicFiltering = (caps.TextureFilterCaps & D3DPTFILTERCAPS_MINFANISOTROPIC) != 0;
+ pCaps->m_bSupportsMagAnisotropicFiltering = (caps.TextureFilterCaps & D3DPTFILTERCAPS_MAGFANISOTROPIC) != 0;
+
+ // OpenGL does not support this--at least not on OSX which is the primary GL target, so just don't use that path on GL at all.
+#if !defined( DX_TO_GL_ABSTRACTION )
+ pCaps->m_bCanStretchRectFromTextures = ( ( caps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES ) != 0 ) && ( pCaps->m_VendorID != VENDORID_INTEL );
+#else
+ pCaps->m_bCanStretchRectFromTextures = false;
+#endif
+
+ pCaps->m_nMaxAnisotropy = pCaps->m_bSupportsAnisotropicFiltering ? caps.MaxAnisotropy : 1;
+
+ pCaps->m_SupportsCubeMaps = ( caps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP ) ? true : false;
+ pCaps->m_SupportsNonPow2Textures =
+ ( !( caps.TextureCaps & D3DPTEXTURECAPS_POW2 ) ||
+ ( caps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL ) );
+
+ Assert( caps.TextureCaps & D3DPTEXTURECAPS_PROJECTED );
+
+ if ( pCaps->m_bSoftwareVertexProcessing )
+ {
+ // This should be pushed down based on pixel shaders.
+ pCaps->m_NumVertexShaderConstants = 256;
+ pCaps->m_NumBooleanVertexShaderConstants = pCaps->m_SupportsPixelShaders_2_0 ? 16 : 0; // 2.0 parts have 16 bool vs registers
+ pCaps->m_NumBooleanPixelShaderConstants = pCaps->m_SupportsPixelShaders_2_0 ? 16 : 0; // 2.0 parts have 16 bool ps registers
+ pCaps->m_NumIntegerVertexShaderConstants = pCaps->m_SupportsPixelShaders_2_0 ? 16 : 0; // 2.0 parts have 16 bool vs registers
+ pCaps->m_NumIntegerPixelShaderConstants = pCaps->m_SupportsPixelShaders_2_0 ? 16 : 0; // 2.0 parts have 16 bool ps registers
+ }
+ else
+ {
+ pCaps->m_NumVertexShaderConstants = caps.MaxVertexShaderConst;
+ if ( CommandLine()->FindParm( "-limitvsconst" ) )
+ {
+ pCaps->m_NumVertexShaderConstants = min( 256, pCaps->m_NumVertexShaderConstants );
+ }
+ pCaps->m_NumBooleanVertexShaderConstants = pCaps->m_SupportsPixelShaders_2_0 ? 16 : 0; // 2.0 parts have 16 bool vs registers
+ pCaps->m_NumBooleanPixelShaderConstants = pCaps->m_SupportsPixelShaders_2_0 ? 16 : 0; // 2.0 parts have 16 bool ps registers
+
+ // This is a little misleading...this is really 16 int4 registers
+ pCaps->m_NumIntegerVertexShaderConstants = pCaps->m_SupportsPixelShaders_2_0 ? 16 : 0; // 2.0 parts have 16 bool vs registers
+ pCaps->m_NumIntegerPixelShaderConstants = pCaps->m_SupportsPixelShaders_2_0 ? 16 : 0; // 2.0 parts have 16 bool ps registers
+ }
+
+ if ( pCaps->m_SupportsPixelShaders )
+ {
+ if ( pCaps->m_SupportsPixelShaders_2_0 )
+ {
+ pCaps->m_NumPixelShaderConstants = 32;
+ }
+ else
+ {
+ pCaps->m_NumPixelShaderConstants = 8;
+ }
+ }
+ else
+ {
+ pCaps->m_NumPixelShaderConstants = 0;
+ }
+
+ pCaps->m_SupportsHardwareLighting = (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0;
+
+ pCaps->m_MaxNumLights = caps.MaxActiveLights;
+ if ( pCaps->m_MaxNumLights > MAX_NUM_LIGHTS )
+ {
+ pCaps->m_MaxNumLights = MAX_NUM_LIGHTS;
+ }
+
+ if ( IsOpenGL() )
+ {
+ // Set according to control flow bit on OpenGL
+ pCaps->m_MaxNumLights = MIN( pCaps->m_MaxNumLights, ( pCaps->m_bSupportsStaticControlFlow && pCaps->m_SupportsPixelShaders_2_b ) ? MAX_NUM_LIGHTS : ( MAX_NUM_LIGHTS - 2 ) );
+ }
+
+ if ( pCaps->m_bSoftwareVertexProcessing )
+ {
+ pCaps->m_SupportsHardwareLighting = true;
+ pCaps->m_MaxNumLights = 2;
+ }
+ pCaps->m_MaxTextureWidth = caps.MaxTextureWidth;
+ pCaps->m_MaxTextureHeight = caps.MaxTextureHeight;
+ pCaps->m_MaxTextureDepth = caps.MaxVolumeExtent ? caps.MaxVolumeExtent : 1;
+ pCaps->m_MaxTextureAspectRatio = caps.MaxTextureAspectRatio;
+ if ( pCaps->m_MaxTextureAspectRatio == 0 )
+ {
+ pCaps->m_MaxTextureAspectRatio = max( pCaps->m_MaxTextureWidth, pCaps->m_MaxTextureHeight);
+ }
+ pCaps->m_MaxPrimitiveCount = caps.MaxPrimitiveCount;
+ pCaps->m_MaxBlendMatrices = caps.MaxVertexBlendMatrices;
+ pCaps->m_MaxBlendMatrixIndices = caps.MaxVertexBlendMatrixIndex;
+
+ bool addSupported = (caps.TextureOpCaps & D3DTEXOPCAPS_ADD) != 0;
+ bool modSupported = (caps.TextureOpCaps & D3DTEXOPCAPS_MODULATE2X) != 0;
+
+ pCaps->m_bNeedsATICentroidHack = false;
+ pCaps->m_bDisableShaderOptimizations = false;
+
+ pCaps->m_SupportsMipmapping = true;
+ pCaps->m_SupportsOverbright = true;
+
+ // Thank you to all you driver writers who actually correctly return caps
+ if ( !modSupported || !addSupported )
+ {
+ Assert( 0 );
+ pCaps->m_SupportsOverbright = false;
+ }
+
+ // Check if ZBias and SlopeScaleDepthBias are supported. .if not, tweak the projection matrix instead
+ // for polyoffset.
+ pCaps->m_ZBiasAndSlopeScaledDepthBiasSupported =
+ ( ( caps.RasterCaps & D3DPRASTERCAPS_DEPTHBIAS) != 0 ) &&
+ ( ( caps.RasterCaps & D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS ) != 0 );
+ if ( IsX360() )
+ {
+ // driver lies, force it
+ pCaps->m_ZBiasAndSlopeScaledDepthBiasSupported = true;
+ }
+
+ // Spheremapping supported?
+ pCaps->m_bSupportsSpheremapping = (caps.VertexProcessingCaps & D3DVTXPCAPS_TEXGEN_SPHEREMAP) != 0;
+
+ // How many user clip planes?
+ pCaps->m_MaxUserClipPlanes = caps.MaxUserClipPlanes;
+ if ( CommandLine()->CheckParm( "-nouserclip" ) /* || (IsOpenGL() && (!CommandLine()->FindParm("-glslmode"))) || r_emulategl.GetBool() */ )
+ {
+ // rbarris 03Feb10: this now ignores POSIX / -glslmode / r_emulategl because we're defaulting GLSL mode "on".
+ // so this will mean that the engine will always ask for user clip planes.
+ // this will misbehave under ARB mode, since ARB shaders won't respect that state.
+ // it's difficult to make this fluid without teaching the engine about a cap that could change during run.
+
+ pCaps->m_MaxUserClipPlanes = 0;
+ }
+
+ if ( pCaps->m_MaxUserClipPlanes > MAXUSERCLIPPLANES )
+ {
+ pCaps->m_MaxUserClipPlanes = MAXUSERCLIPPLANES;
+ }
+
+ pCaps->m_FakeSRGBWrite = false;
+ pCaps->m_CanDoSRGBReadFromRTs = true;
+ pCaps->m_bSupportsGLMixedSizeTargets = false;
+#ifdef DX_TO_GL_ABSTRACTION
+ // using #if because we're referencing fields in the RHS which don't exist in Windows headers for the caps9 struct
+ pCaps->m_FakeSRGBWrite = caps.FakeSRGBWrite != 0;
+ pCaps->m_CanDoSRGBReadFromRTs = caps.CanDoSRGBReadFromRTs != 0;
+ pCaps->m_bSupportsGLMixedSizeTargets = caps.MixedSizeTargets != 0;
+#endif
+
+ // Query for SRGB support as needed for our DX 9 stuff
+ if ( IsPC() || !IsX360() )
+ {
+ pCaps->m_SupportsSRGB = ( D3D()->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_SRGBREAD, D3DRTYPE_TEXTURE, D3DFMT_DXT1 ) == S_OK);
+
+ if ( pCaps->m_SupportsSRGB )
+ {
+ pCaps->m_SupportsSRGB = ( D3D()->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_SRGBWRITE, D3DRTYPE_TEXTURE, D3DFMT_A8R8G8B8 ) == S_OK);
+ }
+ }
+ else
+ {
+ // 360 does support it, but is queried in the wrong manner, so force it
+ pCaps->m_SupportsSRGB = true;
+ }
+
+ if ( CommandLine()->CheckParm( "-nosrgb" ) )
+ {
+ pCaps->m_SupportsSRGB = false;
+ }
+
+ pCaps->m_bSupportsVertexTextures = ( D3D()->CheckDeviceFormat( nAdapter, DX8_DEVTYPE, D3DFMT_X8R8G8B8,
+ D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R32F ) == S_OK );
+
+ if ( IsOpenGL() )
+ {
+ pCaps->m_bSupportsVertexTextures = false;
+ }
+
+ // FIXME: vs30 has a fixed setting here at 4.
+ // Future hardware will need some other way of computing this.
+ pCaps->m_nVertexTextureCount = pCaps->m_bSupportsVertexTextures ? 4 : 0;
+
+ // FIXME: How do I actually compute this?
+ pCaps->m_nMaxVertexTextureDimension = pCaps->m_bSupportsVertexTextures ? 4096 : 0;
+
+ // Does the device support filterable int16 textures?
+ bool bSupportsInteger16Textures =
+ ( D3D()->CheckDeviceFormat( nAdapter, DX8_DEVTYPE,
+ D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_FILTER,
+ D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16 ) == S_OK );
+
+ // Does the device support filterable fp16 textures?
+ bool bSupportsFloat16Textures =
+ ( D3D()->CheckDeviceFormat( nAdapter, DX8_DEVTYPE,
+ D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_FILTER,
+ D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F ) == S_OK );
+
+ // Does the device support blendable fp16 render targets?
+ bool bSupportsFloat16RenderTargets =
+ ( D3D()->CheckDeviceFormat( nAdapter, DX8_DEVTYPE,
+ D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING | D3DUSAGE_RENDERTARGET,
+ D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F ) == S_OK );
+
+ // Essentially a proxy for a DX10 device running DX9 code path
+ pCaps->m_bSupportsFloat32RenderTargets = ( D3D()->CheckDeviceFormat( nAdapter, DX8_DEVTYPE,
+ D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING | D3DUSAGE_RENDERTARGET,
+ D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F ) == S_OK );
+
+ pCaps->m_bFogColorSpecifiedInLinearSpace = false;
+ pCaps->m_bFogColorAlwaysLinearSpace = false;
+
+ // Assume not DX10. Check below.
+ pCaps->m_bDX10Card = false;
+ pCaps->m_bDX10Blending = false;
+
+ if ( IsOpenGL() && ( pCaps->m_VendorID == 1 ) )
+ {
+ // Linux/Win OpenGL - always assume the device supports DX10 style blending
+ pCaps->m_bFogColorAlwaysLinearSpace = true;
+ pCaps->m_bDX10Card = true;
+ pCaps->m_bDX10Blending = true;
+ }
+
+ // NVidia wants fog color to be specified in linear space
+ if ( IsPC() && pCaps->m_SupportsSRGB )
+ {
+ if ( pCaps->m_VendorID == VENDORID_NVIDIA )
+ {
+ pCaps->m_bFogColorSpecifiedInLinearSpace = true;
+
+ if ( IsOpenGL() )
+ {
+ // If we're not the Quadro 4500 or GeForce 7x000, we're an NVIDIA DX10 part on MacOS
+ if ( !( (pCaps->m_DeviceID == 0x009d) || ( (pCaps->m_DeviceID >= 0x0391) && (pCaps->m_DeviceID <= 0x0395) ) ) )
+ {
+ pCaps->m_bFogColorAlwaysLinearSpace = true;
+ pCaps->m_bDX10Card = true;
+ pCaps->m_bDX10Blending = true;
+ }
+ }
+ else
+ {
+ // On G80 and later, always specify in linear space
+ if ( pCaps->m_bSupportsFloat32RenderTargets )
+ {
+ pCaps->m_bFogColorAlwaysLinearSpace = true;
+ pCaps->m_bDX10Card = true;
+ pCaps->m_bDX10Blending = true;
+ }
+ }
+ }
+ else if ( pCaps->m_VendorID == VENDORID_ATI )
+ {
+ if ( IsOpenGL() )
+ {
+ // If we're not a Radeon X1x00 (device IDs in this range), we're a DX10 chip
+ if ( !( (pCaps->m_DeviceID >= 0x7109) && (pCaps->m_DeviceID <= 0x7291) ) )
+ {
+ pCaps->m_bFogColorSpecifiedInLinearSpace = true;
+ pCaps->m_bFogColorAlwaysLinearSpace = true;
+ pCaps->m_bDX10Card = true;
+ pCaps->m_bDX10Blending = true;
+ }
+ }
+ else
+ {
+ // Check for DX10 part
+ pCaps->m_bDX10Card = pCaps->m_SupportsShaderModel_3_0 &&
+ ( pCaps->m_MaxVertexShader30InstructionSlots > 1024 ) &&
+ ( pCaps->m_MaxPixelShader30InstructionSlots > 512 ) ;
+
+ // On ATI, DX10 card means DX10 blending
+ pCaps->m_bDX10Blending = pCaps->m_bDX10Card;
+
+ if( pCaps->m_bDX10Blending )
+ {
+ pCaps->m_bFogColorSpecifiedInLinearSpace = true;
+ pCaps->m_bFogColorAlwaysLinearSpace = true;
+ }
+ }
+ }
+ else if ( pCaps->m_VendorID == VENDORID_INTEL )
+ {
+ // Intel does not have performant vertex textures
+ pCaps->m_bDX10Card = false;
+
+ // Intel supports DX10 SRGB on Broadwater and better
+ // The two checks are for devices from GMA generation (0x29A2-0x2A43) and HD graphics (0x0042-0x2500)
+ pCaps->m_bDX10Blending = ( ( pCaps->m_DeviceID >= 0x29A2 ) && ( pCaps->m_DeviceID <= 0x2A43 ) ) ||
+ ( ( pCaps->m_DeviceID >= 0x0042 ) && ( pCaps->m_DeviceID <= 0x2500 ) );
+
+ if( pCaps->m_bDX10Blending )
+ {
+ pCaps->m_bFogColorSpecifiedInLinearSpace = true;
+ pCaps->m_bFogColorAlwaysLinearSpace = true;
+ }
+ }
+ }
+
+ // Do we have everything necessary to run with integer HDR? Note that
+ // even if we don't support integer 16-bit/component textures, we
+ // can still run in this mode if fp16 textures are supported.
+ bool bSupportsIntegerHDR = pCaps->m_SupportsPixelShaders_2_0 &&
+ pCaps->m_SupportsVertexShaders_2_0 &&
+ // (caps.Caps3 & D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD) &&
+ // (caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) &&
+ ( bSupportsInteger16Textures || bSupportsFloat16Textures ) &&
+ pCaps->m_SupportsSRGB;
+
+ // Do we have everything necessary to run with float HDR?
+ bool bSupportsFloatHDR = pCaps->m_SupportsShaderModel_3_0 &&
+ // (caps.Caps3 & D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD) &&
+ // (caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) &&
+ bSupportsFloat16Textures &&
+ bSupportsFloat16RenderTargets &&
+ pCaps->m_SupportsSRGB &&
+ !IsX360();
+
+ pCaps->m_MaxHDRType = HDR_TYPE_NONE;
+ if ( bSupportsFloatHDR )
+ pCaps->m_MaxHDRType = HDR_TYPE_FLOAT;
+ else
+ if ( bSupportsIntegerHDR )
+ pCaps->m_MaxHDRType = HDR_TYPE_INTEGER;
+
+ if ( bSupportsFloatHDR && ( mat_hdr_level.GetInt() == 3 ) )
+ {
+ pCaps->m_HDRType = HDR_TYPE_FLOAT;
+ }
+ else if ( bSupportsIntegerHDR )
+ {
+ pCaps->m_HDRType = HDR_TYPE_INTEGER;
+ }
+ else
+ {
+ pCaps->m_HDRType = HDR_TYPE_NONE;
+ }
+
+ pCaps->m_bColorOnSecondStream = caps.MaxStreams > 1;
+
+ pCaps->m_bSupportsStreamOffset = ( ( caps.DevCaps2 & D3DDEVCAPS2_STREAMOFFSET ) && // Tie these caps together since we want to filter out
+ pCaps->m_SupportsPixelShaders_2_0 ); // any DX8 parts which export D3DDEVCAPS2_STREAMOFFSET
+
+ pCaps->m_flMinGammaControlPoint = 0.0f;
+ pCaps->m_flMaxGammaControlPoint = 65535.0f;
+ pCaps->m_nGammaControlPointCount = 256;
+
+ // Compute the effective DX support level based on all the other caps
+ ComputeDXSupportLevel( *pCaps );
+ int nCmdlineMaxDXLevel = CommandLine()->ParmValue( "-maxdxlevel", 0 );
+ if ( IsOpenGL() && ( nCmdlineMaxDXLevel > 0 ) )
+ {
+ // Prevent customers from slamming us below DX level 90 in OpenGL mode.
+ nCmdlineMaxDXLevel = MAX( nCmdlineMaxDXLevel, 90 );
+ }
+ if( nCmdlineMaxDXLevel > 0 )
+ {
+ pCaps->m_nMaxDXSupportLevel = min( pCaps->m_nMaxDXSupportLevel, nCmdlineMaxDXLevel );
+ }
+ pCaps->m_nDXSupportLevel = pCaps->m_nMaxDXSupportLevel;
+
+ int nModelIndex = pCaps->m_nDXSupportLevel < 90 ? VERTEX_SHADER_MODEL - 10 : VERTEX_SHADER_MODEL;
+ pCaps->m_MaxVertexShaderBlendMatrices = (pCaps->m_NumVertexShaderConstants - nModelIndex) / 3;
+
+ if ( pCaps->m_MaxVertexShaderBlendMatrices > NUM_MODEL_TRANSFORMS )
+ {
+ pCaps->m_MaxVertexShaderBlendMatrices = NUM_MODEL_TRANSFORMS;
+ }
+
+ CheckBorderColorSupport( pCaps, nAdapter );
+
+ // This may get more complex if we start using multiple flavors of compressed vertex - for now it's "on or off"
+ pCaps->m_SupportsCompressedVertices = ( pCaps->m_nDXSupportLevel >= 90 ) && ( pCaps->m_CanDoSRGBReadFromRTs ) ? VERTEX_COMPRESSION_ON : VERTEX_COMPRESSION_NONE;
+ if ( CommandLine()->CheckParm( "-no_compressed_verts" ) ) // m_CanDoSRGBReadFromRTs limits us to Snow Leopard or later on OSX
+ {
+ pCaps->m_SupportsCompressedVertices = VERTEX_COMPRESSION_NONE;
+ }
+
+ // Various vendor-dependent checks...
+ CheckVendorDependentAlphaToCoverage( pCaps, nAdapter );
+ CheckVendorDependentShadowMappingSupport( pCaps, nAdapter );
+
+ // If we're not on a 3.0 part, these values are more appropriate (X800 & X850 parts from ATI do shadow mapping but not 3.0 )
+ if ( !IsOpenGL() )
+ {
+ if ( !pCaps->m_SupportsShaderModel_3_0 )
+ {
+ mat_slopescaledepthbias_shadowmap.SetValue( 5.9f );
+ mat_depthbias_shadowmap.SetValue( 0.003f );
+ }
+ }
+
+ if( pCaps->m_MaxUserClipPlanes == 0 )
+ {
+ pCaps->m_UseFastClipping = true;
+ }
+
+ pCaps->m_MaxSimultaneousRenderTargets = caps.NumSimultaneousRTs;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Compute the effective DX support level based on all the other caps
+//-----------------------------------------------------------------------------
+void CShaderDeviceMgrDx8::ComputeDXSupportLevel( HardwareCaps_t &caps )
+{
+ // NOTE: Support level is actually DX level * 10 + subversion
+ // So, 70 = DX7, 80 = DX8, 81 = DX8 w/ 1.4 pixel shaders
+ // 90 = DX9 w/ 2.0 pixel shaders
+ // 95 = DX9 w/ 3.0 pixel shaders and vertex textures
+ // 98 = DX9 XBox360
+ // NOTE: 82 = NVidia nv3x cards, which can't run dx9 fast
+
+ // FIXME: Improve this!! There should be a whole list of features
+ // we require in order to be considered a DX7 board, DX8 board, etc.
+
+ if ( IsX360() )
+ {
+ caps.m_nMaxDXSupportLevel = 98;
+ return;
+ }
+
+ bool bIsOpenGL = IsOpenGL();
+
+ if ( caps.m_SupportsShaderModel_3_0 && !bIsOpenGL ) // Note that we don't tie vertex textures to 30 shaders anymore
+ {
+ caps.m_nMaxDXSupportLevel = 95;
+ return;
+ }
+
+ // NOTE: sRGB is currently required for DX90 because it isn't doing
+ // gamma correctly if that feature doesn't exist
+ if ( caps.m_SupportsVertexShaders_2_0 && caps.m_SupportsPixelShaders_2_0 && caps.m_SupportsSRGB )
+ {
+ caps.m_nMaxDXSupportLevel = 90;
+ return;
+ }
+
+ if ( caps.m_SupportsPixelShaders && caps.m_SupportsVertexShaders )// && caps.m_bColorOnSecondStream)
+ {
+ if (caps.m_SupportsPixelShaders_1_4)
+ {
+ caps.m_nMaxDXSupportLevel = 81;
+ return;
+ }
+ caps.m_nMaxDXSupportLevel = 80;
+ return;
+ }
+
+ if( caps.m_SupportsCubeMaps && ( caps.m_MaxBlendMatrices >= 2 ) )
+ {
+ caps.m_nMaxDXSupportLevel = 70;
+ return;
+ }
+
+ if ( ( caps.m_NumSamplers >= 2) && caps.m_SupportsMipmapping )
+ {
+ caps.m_nMaxDXSupportLevel = 60;
+ return;
+ }
+
+ Assert( 0 );
+ // we don't support this!
+ caps.m_nMaxDXSupportLevel = 50;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Gets the number of adapters...
+//-----------------------------------------------------------------------------
+int CShaderDeviceMgrDx8::GetAdapterCount() const
+{
+ // FIXME: Remove call to InitAdapterInfo once Steam startup issues are resolved.
+ const_cast<CShaderDeviceMgrDx8*>( this )->InitAdapterInfo();
+
+ return m_Adapters.Count();
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns info about each adapter
+//-----------------------------------------------------------------------------
+void CShaderDeviceMgrDx8::GetAdapterInfo( int nAdapter, MaterialAdapterInfo_t& info ) const
+{
+ // FIXME: Remove call to InitAdapterInfo once Steam startup issues are resolved.
+ const_cast<CShaderDeviceMgrDx8*>( this )->InitAdapterInfo();
+
+ Assert( ( nAdapter >= 0 ) && ( nAdapter < m_Adapters.Count() ) );
+ const HardwareCaps_t &caps = m_Adapters[ nAdapter ].m_ActualCaps;
+ memcpy( &info, &caps, sizeof(MaterialAdapterInfo_t) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the adapter
+//-----------------------------------------------------------------------------
+bool CShaderDeviceMgrDx8::SetAdapter( int nAdapter, int nAdapterFlags )
+{
+ LOCK_SHADERAPI();
+
+ // FIXME:
+ // g_pShaderDeviceDx8->m_bReadPixelsEnabled = (nAdapterFlags & MATERIAL_INIT_READ_PIXELS_ENABLED) != 0;
+
+ // Set up hardware information for this adapter...
+ g_pShaderDeviceDx8->m_DeviceType = (nAdapterFlags & MATERIAL_INIT_REFERENCE_RASTERIZER) ?
+ D3DDEVTYPE_REF : D3DDEVTYPE_HAL;
+
+ g_pShaderDeviceDx8->m_DisplayAdapter = nAdapter;
+ if ( g_pShaderDeviceDx8->m_DisplayAdapter >= (UINT)GetAdapterCount() )
+ {
+ g_pShaderDeviceDx8->m_DisplayAdapter = 0;
+ }
+
+#ifdef NVPERFHUD
+ // hack for nvperfhud
+ g_pShaderDeviceDx8->m_DisplayAdapter = m_pD3D->GetAdapterCount() - 1;
+ g_pShaderDeviceDx8->m_DeviceType = D3DDEVTYPE_REF;
+#endif
+
+ // backward compat
+ if ( !g_pShaderDeviceDx8->OnAdapterSet() )
+ return false;
+
+// if ( !g_pShaderDeviceDx8->Init() )
+// {
+// Warning( "Unable to initialize dx8 device!\n" );
+// return false;
+// }
+
+ g_pShaderDevice = g_pShaderDeviceDx8;
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the number of modes
+//-----------------------------------------------------------------------------
+int CShaderDeviceMgrDx8::GetModeCount( int nAdapter ) const
+{
+ LOCK_SHADERAPI();
+ Assert( m_pD3D && (nAdapter < GetAdapterCount() ) );
+
+#if !defined( _X360 )
+ // fixme - what format should I use here?
+ return m_pD3D->GetAdapterModeCount( nAdapter, D3DFMT_X8R8G8B8 );
+#else
+ return 1; // Only one mode, which is the current mode set in the 360 dashboard. Going to fill it in with exactly what the 360 is set to.
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns mode information..
+//-----------------------------------------------------------------------------
+void CShaderDeviceMgrDx8::GetModeInfo( ShaderDisplayMode_t* pInfo, int nAdapter, int nMode ) const
+{
+ Assert( pInfo->m_nVersion == SHADER_DISPLAY_MODE_VERSION );
+
+ LOCK_SHADERAPI();
+ Assert( m_pD3D && (nAdapter < GetAdapterCount() ) );
+ Assert( nMode < GetModeCount( nAdapter ) );
+
+#if !defined( _X360 )
+ HRESULT hr;
+ D3DDISPLAYMODE d3dInfo;
+
+ // fixme - what format should I use here?
+ hr = D3D()->EnumAdapterModes( nAdapter, D3DFMT_X8R8G8B8, nMode, &d3dInfo );
+ Assert( !FAILED(hr) );
+
+ pInfo->m_nWidth = d3dInfo.Width;
+ pInfo->m_nHeight = d3dInfo.Height;
+ pInfo->m_Format = ImageLoader::D3DFormatToImageFormat( d3dInfo.Format );
+ pInfo->m_nRefreshRateNumerator = d3dInfo.RefreshRate;
+ pInfo->m_nRefreshRateDenominator = 1;
+#else
+ pInfo->m_Format = ImageLoader::D3DFormatToImageFormat( D3DFMT_X8R8G8B8 );
+ pInfo->m_nRefreshRateNumerator = 60;
+ pInfo->m_nRefreshRateDenominator = 1;
+
+ pInfo->m_nWidth = GetSystemMetrics( SM_CXSCREEN );
+ pInfo->m_nHeight = GetSystemMetrics( SM_CYSCREEN );
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the current mode information for an adapter
+//-----------------------------------------------------------------------------
+void CShaderDeviceMgrDx8::GetCurrentModeInfo( ShaderDisplayMode_t* pInfo, int nAdapter ) const
+{
+ Assert( pInfo->m_nVersion == SHADER_DISPLAY_MODE_VERSION );
+
+ LOCK_SHADERAPI();
+ Assert( D3D() );
+
+ HRESULT hr;
+ D3DDISPLAYMODE mode = { 0 };
+#if !defined( _X360 )
+ hr = D3D()->GetAdapterDisplayMode( nAdapter, &mode );
+ Assert( !FAILED(hr) );
+#else
+ if ( !g_pD3DDevice )
+ {
+ // the console has no prior display or mode until its created
+ mode.Width = GetSystemMetrics( SM_CXSCREEN );
+ mode.Height = GetSystemMetrics( SM_CYSCREEN );
+ mode.RefreshRate = 60;
+ mode.Format = D3DFMT_X8R8G8B8;
+ }
+ else
+ {
+ hr = g_pD3DDevice->GetDisplayMode( 0, &mode );
+ Assert( !FAILED(hr) );
+ }
+#endif
+
+ pInfo->m_nWidth = mode.Width;
+ pInfo->m_nHeight = mode.Height;
+ pInfo->m_Format = ImageLoader::D3DFormatToImageFormat( mode.Format );
+ pInfo->m_nRefreshRateNumerator = mode.RefreshRate;
+ pInfo->m_nRefreshRateDenominator = 1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the video mode
+//-----------------------------------------------------------------------------
+CreateInterfaceFn CShaderDeviceMgrDx8::SetMode( void *hWnd, int nAdapter, const ShaderDeviceInfo_t& mode )
+{
+ LOCK_SHADERAPI();
+
+ Assert( nAdapter < GetAdapterCount() );
+ int nDXLevel = mode.m_nDXLevel != 0 ? mode.m_nDXLevel : m_Adapters[nAdapter].m_ActualCaps.m_nDXSupportLevel;
+ if ( m_bObeyDxCommandlineOverride )
+ {
+ nDXLevel = CommandLine()->ParmValue( "-dxlevel", nDXLevel );
+ m_bObeyDxCommandlineOverride = false;
+ }
+ if ( nDXLevel > m_Adapters[nAdapter].m_ActualCaps.m_nMaxDXSupportLevel )
+ {
+ nDXLevel = m_Adapters[nAdapter].m_ActualCaps.m_nMaxDXSupportLevel;
+ }
+ nDXLevel = GetClosestActualDXLevel( nDXLevel );
+
+ if ( nDXLevel >= 100 )
+ return NULL;
+
+ bool bReacquireResourcesNeeded = false;
+ if ( g_pShaderDevice )
+ {
+ bReacquireResourcesNeeded = IsPC();
+ g_pShaderDevice->ReleaseResources();
+ }
+
+ if ( g_pShaderAPI )
+ {
+ g_pShaderAPI->OnDeviceShutdown();
+ g_pShaderAPI = NULL;
+ }
+
+ if ( g_pShaderDevice )
+ {
+ g_pShaderDevice->ShutdownDevice();
+ g_pShaderDevice = NULL;
+ }
+
+ g_pShaderShadow = NULL;
+
+ ShaderDeviceInfo_t adjustedMode = mode;
+ adjustedMode.m_nDXLevel = nDXLevel;
+ if ( !g_pShaderDeviceDx8->InitDevice( hWnd, nAdapter, adjustedMode ) )
+ return NULL;
+
+ if ( !g_pShaderAPIDX8->OnDeviceInit() )
+ return NULL;
+
+ g_pShaderDevice = g_pShaderDeviceDx8;
+ g_pShaderAPI = g_pShaderAPIDX8;
+ g_pShaderShadow = g_pShaderShadowDx8;
+
+ if ( bReacquireResourcesNeeded )
+ {
+ g_pShaderDevice->ReacquireResources();
+ }
+
+ return ShaderInterfaceFactory;
+}
+
+
+//-----------------------------------------------------------------------------
+// Validates the mode...
+//-----------------------------------------------------------------------------
+bool CShaderDeviceMgrDx8::ValidateMode( int nAdapter, const ShaderDeviceInfo_t &info ) const
+{
+ if ( nAdapter >= (int)D3D()->GetAdapterCount() )
+ return false;
+
+ ShaderDisplayMode_t displayMode;
+
+ if ( info.m_bWindowed )
+ {
+ // windowed mode always appears on the primary display, so we should use that adapter's
+ // settings
+ GetCurrentModeInfo( &displayMode, 0 );
+
+ // make sure the window fits within the current video mode
+ if ( ( info.m_DisplayMode.m_nWidth > displayMode.m_nWidth ) ||
+ ( info.m_DisplayMode.m_nHeight > displayMode.m_nHeight ) )
+ return false;
+ }
+ else
+ {
+ GetCurrentModeInfo( &displayMode, nAdapter );
+ }
+
+ // Make sure the image format requested is valid
+ ImageFormat backBufferFormat = FindNearestSupportedBackBufferFormat( nAdapter,
+ DX8_DEVTYPE, displayMode.m_Format, info.m_DisplayMode.m_Format, info.m_bWindowed );
+ return ( backBufferFormat != IMAGE_FORMAT_UNKNOWN );
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the amount of video memory in bytes for a particular adapter
+//-----------------------------------------------------------------------------
+int CShaderDeviceMgrDx8::GetVidMemBytes( int nAdapter ) const
+{
+#if defined( _X360 )
+ return 256*1024*1024;
+#elif defined (DX_TO_GL_ABSTRACTION)
+ D3DADAPTER_IDENTIFIER9 devIndentifier;
+ D3D()->GetAdapterIdentifier( nAdapter, D3DENUM_WHQL_LEVEL, &devIndentifier );
+ return devIndentifier.VideoMemory;
+#else
+ // FIXME: This currently ignores the adapter
+ uint64 nBytes = ::GetVidMemBytes();
+ if ( nBytes > INT_MAX )
+ return INT_MAX;
+ return nBytes;
+#endif
+}
+
+
+
+//-----------------------------------------------------------------------------
+//
+// Shader device
+//
+//-----------------------------------------------------------------------------
+
+#if 0
+// FIXME: Enable after I've separated it out from shaderapidx8 a little better
+static CShaderDeviceDx8 s_ShaderDeviceDX8;
+CShaderDeviceDx8* g_pShaderDeviceDx8 = &s_ShaderDeviceDX8;
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Constructor, destructor
+//-----------------------------------------------------------------------------
+CShaderDeviceDx8::CShaderDeviceDx8()
+{
+ g_pD3DDevice = NULL;
+ for ( int i = 0; i < ARRAYSIZE(m_pFrameSyncQueryObject); i++ )
+ {
+ m_pFrameSyncQueryObject[i] = NULL;
+ m_bQueryIssued[i] = false;
+ }
+ m_pFrameSyncTexture = NULL;
+ m_bQueuedDeviceLost = false;
+ m_DeviceState = DEVICE_STATE_OK;
+ m_bOtherAppInitializing = false;
+ m_IsResizing = false;
+ m_bPendingVideoModeChange = false;
+ m_DeviceSupportsCreateQuery = -1;
+ m_bUsingStencil = false;
+ m_bResourcesReleased = false;
+ m_iStencilBufferBits = 0;
+ m_NonInteractiveRefresh.m_Mode = MATERIAL_NON_INTERACTIVE_MODE_NONE;
+ m_NonInteractiveRefresh.m_pVertexShader = NULL;
+ m_NonInteractiveRefresh.m_pPixelShader = NULL;
+ m_NonInteractiveRefresh.m_pPixelShaderStartup = NULL;
+ m_NonInteractiveRefresh.m_pPixelShaderStartupPass2 = NULL;
+ m_NonInteractiveRefresh.m_pVertexDecl = NULL;
+ m_NonInteractiveRefresh.m_nPacifierFrame = 0;
+ m_numReleaseResourcesRefCount = 0;
+}
+
+CShaderDeviceDx8::~CShaderDeviceDx8()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Computes device creation paramters
+//-----------------------------------------------------------------------------
+static DWORD ComputeDeviceCreationFlags( D3DCAPS& caps, bool bSoftwareVertexProcessing )
+{
+ // Find out what type of device to make
+ bool bPureDeviceSupported = (caps.DevCaps & D3DDEVCAPS_PUREDEVICE) != 0;
+
+ DWORD nDeviceCreationFlags;
+ if ( !bSoftwareVertexProcessing )
+ {
+ nDeviceCreationFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING;
+ if ( bPureDeviceSupported )
+ {
+ nDeviceCreationFlags |= D3DCREATE_PUREDEVICE;
+ }
+ }
+ else
+ {
+ nDeviceCreationFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
+ }
+ nDeviceCreationFlags |= D3DCREATE_FPU_PRESERVE;
+
+#ifdef _X360
+ nDeviceCreationFlags |= D3DCREATE_BUFFER_2_FRAMES;
+#endif
+
+ return nDeviceCreationFlags;
+}
+
+
+//-----------------------------------------------------------------------------
+// Computes the supersample flags
+//-----------------------------------------------------------------------------
+D3DMULTISAMPLE_TYPE CShaderDeviceDx8::ComputeMultisampleType( int nSampleCount )
+{
+ switch (nSampleCount)
+ {
+#if !defined( _X360 )
+ case 2: return D3DMULTISAMPLE_2_SAMPLES;
+ case 3: return D3DMULTISAMPLE_3_SAMPLES;
+ case 4: return D3DMULTISAMPLE_4_SAMPLES;
+ case 5: return D3DMULTISAMPLE_5_SAMPLES;
+ case 6: return D3DMULTISAMPLE_6_SAMPLES;
+ case 7: return D3DMULTISAMPLE_7_SAMPLES;
+ case 8: return D3DMULTISAMPLE_8_SAMPLES;
+ case 9: return D3DMULTISAMPLE_9_SAMPLES;
+ case 10: return D3DMULTISAMPLE_10_SAMPLES;
+ case 11: return D3DMULTISAMPLE_11_SAMPLES;
+ case 12: return D3DMULTISAMPLE_12_SAMPLES;
+ case 13: return D3DMULTISAMPLE_13_SAMPLES;
+ case 14: return D3DMULTISAMPLE_14_SAMPLES;
+ case 15: return D3DMULTISAMPLE_15_SAMPLES;
+ case 16: return D3DMULTISAMPLE_16_SAMPLES;
+#else
+ case 2: return D3DMULTISAMPLE_2_SAMPLES;
+ case 4: return D3DMULTISAMPLE_4_SAMPLES;
+#endif
+ default:
+ case 0:
+ case 1:
+ return D3DMULTISAMPLE_NONE;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the present parameters
+//-----------------------------------------------------------------------------
+void CShaderDeviceDx8::SetPresentParameters( void* hWnd, int nAdapter, const ShaderDeviceInfo_t &info )
+{
+ ShaderDisplayMode_t mode;
+ g_pShaderDeviceMgr->GetCurrentModeInfo( &mode, nAdapter );
+
+ HRESULT hr;
+ ZeroMemory( &m_PresentParameters, sizeof(m_PresentParameters) );
+
+ m_PresentParameters.Windowed = info.m_bWindowed;
+ m_PresentParameters.SwapEffect = info.m_bUsingMultipleWindows ? D3DSWAPEFFECT_COPY : D3DSWAPEFFECT_DISCARD;
+
+ // for 360, we want to create it ourselves for hierarchical z support
+ m_PresentParameters.EnableAutoDepthStencil = IsX360() ? FALSE : TRUE;
+
+ // What back-buffer format should we use?
+ ImageFormat backBufferFormat = FindNearestSupportedBackBufferFormat( nAdapter,
+ DX8_DEVTYPE, m_AdapterFormat, info.m_DisplayMode.m_Format, info.m_bWindowed );
+
+ // What depth format should we use?
+ m_bUsingStencil = info.m_bUseStencil;
+ if ( info.m_nDXLevel >= 80 )
+ {
+ // always stencil for dx9/hdr
+ m_bUsingStencil = true;
+ }
+#if defined( _X360 )
+ D3DFORMAT nDepthFormat = ReverseDepthOnX360() ? D3DFMT_D24FS8 : D3DFMT_D24S8;
+#else
+ D3DFORMAT nDepthFormat = m_bUsingStencil ? D3DFMT_D24S8 : D3DFMT_D24X8;
+#endif
+ m_PresentParameters.AutoDepthStencilFormat = FindNearestSupportedDepthFormat(
+ nAdapter, m_AdapterFormat, backBufferFormat, nDepthFormat );
+ m_PresentParameters.hDeviceWindow = (VD3DHWND)hWnd;
+
+ // store how many stencil buffer bits we have available with the depth/stencil buffer
+ switch( m_PresentParameters.AutoDepthStencilFormat )
+ {
+ case D3DFMT_D24S8:
+ m_iStencilBufferBits = 8;
+ break;
+#if defined( _X360 )
+ case D3DFMT_D24FS8:
+ m_iStencilBufferBits = 8;
+ break;
+#else
+ case D3DFMT_D24X4S4:
+ m_iStencilBufferBits = 4;
+ break;
+ case D3DFMT_D15S1:
+ m_iStencilBufferBits = 1;
+ break;
+#endif
+ default:
+ m_iStencilBufferBits = 0;
+ m_bUsingStencil = false; //couldn't acquire a stencil buffer
+ };
+
+ if ( IsX360() || !info.m_bWindowed )
+ {
+ bool useDefault = ( info.m_DisplayMode.m_nWidth == 0 ) || ( info.m_DisplayMode.m_nHeight == 0 );
+ m_PresentParameters.BackBufferCount = 1;
+ m_PresentParameters.BackBufferWidth = useDefault ? mode.m_nWidth : info.m_DisplayMode.m_nWidth;
+ m_PresentParameters.BackBufferHeight = useDefault ? mode.m_nHeight : info.m_DisplayMode.m_nHeight;
+ m_PresentParameters.BackBufferFormat = ImageLoader::ImageFormatToD3DFormat( backBufferFormat );
+#if defined( _X360 )
+ m_PresentParameters.FrontBufferFormat = D3DFMT_LE_X8R8G8B8;
+#endif
+ if ( !info.m_bWaitForVSync || CommandLine()->FindParm( "-forcenovsync" ) )
+ {
+ m_PresentParameters.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
+ }
+ else
+ {
+ m_PresentParameters.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
+ }
+
+ m_PresentParameters.FullScreen_RefreshRateInHz = info.m_DisplayMode.m_nRefreshRateDenominator ?
+ info.m_DisplayMode.m_nRefreshRateNumerator / info.m_DisplayMode.m_nRefreshRateDenominator : D3DPRESENT_RATE_DEFAULT;
+
+#if defined( _X360 )
+ XVIDEO_MODE videoMode;
+ XGetVideoMode( &videoMode );
+
+ // want 30 for 60Hz, and 25 for 50Hz (PAL)
+ int nNewFpsMax = ( ( int )( videoMode.RefreshRate + 0.5f ) ) >> 1;
+ // slam to either 30 or 25 so that we don't end up with any other cases.
+ if( nNewFpsMax < 26 )
+ {
+ nNewFpsMax = 25;
+ }
+ else
+ {
+ nNewFpsMax = 30;
+ }
+ DevMsg( "*******Monitor refresh is %f, setting fps_max to %d*********\n", videoMode.RefreshRate, nNewFpsMax );
+ ConVarRef fps_max( "fps_max" );
+ fps_max.SetValue( nNewFpsMax );
+
+ // setup hardware scaling - should be native 720p upsampling to 1080i
+ if ( info.m_bScaleToOutputResolution )
+ {
+ m_PresentParameters.VideoScalerParameters.ScalerSourceRect.x2 = m_PresentParameters.BackBufferWidth;
+ m_PresentParameters.VideoScalerParameters.ScalerSourceRect.y2 = m_PresentParameters.BackBufferHeight;
+ m_PresentParameters.VideoScalerParameters.ScaledOutputWidth = videoMode.dwDisplayWidth;
+ m_PresentParameters.VideoScalerParameters.ScaledOutputHeight = videoMode.dwDisplayHeight;
+ DevMsg( "VIDEO SCALING: scaling from %dx%d to %dx%d\n", ( int )m_PresentParameters.BackBufferWidth, ( int )m_PresentParameters.BackBufferHeight,
+ ( int )videoMode.dwDisplayWidth, ( int )videoMode.dwDisplayHeight );
+ }
+ else
+ {
+ DevMsg( "VIDEO SCALING: No scaling: %dx%d\n", ( int )m_PresentParameters.BackBufferWidth, ( int )m_PresentParameters.BackBufferHeight );
+ }
+#endif
+ }
+ else
+ {
+ // NJS: We are seeing a lot of time spent in present in some cases when this isn't set.
+ m_PresentParameters.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
+ if ( info.m_bResizing )
+ {
+ if ( info.m_bLimitWindowedSize &&
+ ( info.m_nWindowedSizeLimitWidth < mode.m_nWidth || info.m_nWindowedSizeLimitHeight < mode.m_nHeight ) )
+ {
+ // When using material system in windowed resizing apps, it's
+ // sometimes not a good idea to allocate stuff as big as the screen
+ // video cards can soo run out of resources
+ m_PresentParameters.BackBufferWidth = info.m_nWindowedSizeLimitWidth;
+ m_PresentParameters.BackBufferHeight = info.m_nWindowedSizeLimitHeight;
+ }
+ else
+ {
+ // When in resizing windowed mode,
+ // we want to allocate enough memory to deal with any resizing...
+ m_PresentParameters.BackBufferWidth = mode.m_nWidth;
+ m_PresentParameters.BackBufferHeight = mode.m_nHeight;
+ }
+ }
+ else
+ {
+ m_PresentParameters.BackBufferWidth = info.m_DisplayMode.m_nWidth;
+ m_PresentParameters.BackBufferHeight = info.m_DisplayMode.m_nHeight;
+ }
+ m_PresentParameters.BackBufferFormat = ImageLoader::ImageFormatToD3DFormat( backBufferFormat );
+ m_PresentParameters.BackBufferCount = 1;
+ }
+
+ if ( info.m_nAASamples > 0 && ( m_PresentParameters.SwapEffect == D3DSWAPEFFECT_DISCARD ) )
+ {
+ D3DMULTISAMPLE_TYPE multiSampleType = ComputeMultisampleType( info.m_nAASamples );
+ DWORD nQualityLevel;
+
+ // FIXME: Should we add the quality level to the ShaderAdapterMode_t struct?
+ // 16x on nVidia refers to CSAA or "Coverage Sampled Antialiasing"
+ const HardwareCaps_t &adapterCaps = g_ShaderDeviceMgrDx8.GetHardwareCaps( nAdapter );
+ if ( ( info.m_nAASamples == 16 ) && ( adapterCaps.m_VendorID == VENDORID_NVIDIA ) )
+ {
+ multiSampleType = ComputeMultisampleType(4);
+ hr = D3D()->CheckDeviceMultiSampleType( nAdapter, DX8_DEVTYPE,
+ m_PresentParameters.BackBufferFormat, m_PresentParameters.Windowed,
+ multiSampleType, &nQualityLevel ); // 4x at highest quality level
+
+ if ( !FAILED( hr ) && ( nQualityLevel == 16 ) )
+ {
+ nQualityLevel = nQualityLevel - 1; // Highest quality level triggers 16x CSAA
+ }
+ else
+ {
+ nQualityLevel = 0; // No CSAA
+ }
+ }
+ else // Regular MSAA on any old vendor
+ {
+ hr = D3D()->CheckDeviceMultiSampleType( nAdapter, DX8_DEVTYPE,
+ m_PresentParameters.BackBufferFormat, m_PresentParameters.Windowed,
+ multiSampleType, &nQualityLevel );
+
+ nQualityLevel = 0;
+ }
+
+ if ( !FAILED( hr ) )
+ {
+ m_PresentParameters.MultiSampleType = multiSampleType;
+ m_PresentParameters.MultiSampleQuality = nQualityLevel;
+ }
+ }
+ else
+ {
+ m_PresentParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
+ m_PresentParameters.MultiSampleQuality = 0;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Initializes, shuts down the D3D device
+//-----------------------------------------------------------------------------
+bool CShaderDeviceDx8::InitDevice( void* hwnd, int nAdapter, const ShaderDeviceInfo_t &info )
+{
+ //Debugger();
+
+ // good place to run some self tests.
+ //#if OSX
+ //{
+ // extern void GLMgrSelfTests( void );
+ // GLMgrSelfTests();
+ //}
+ //#endif
+
+ // windowed
+ if ( !CreateD3DDevice( (VD3DHWND)hwnd, nAdapter, info ) )
+ return false;
+
+ // Hook up our own windows proc to get at messages to tell us when
+ // other instances of the material system are trying to set the mode
+ InstallWindowHook( (VD3DHWND)m_hWnd );
+ return true;
+}
+
+void CShaderDeviceDx8::ShutdownDevice()
+{
+ if ( IsPC() && IsActive() )
+ {
+ Dx9Device()->Release();
+
+#ifdef STUBD3D
+ delete ( CStubD3DDevice * )Dx9Device();
+#endif
+
+ g_pD3DDevice = NULL;
+
+ RemoveWindowHook( (VD3DHWND)m_hWnd );
+ m_hWnd = 0;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Are we using graphics?
+//-----------------------------------------------------------------------------
+bool CShaderDeviceDx8::IsUsingGraphics() const
+{
+ //*****LOCK_SHADERAPI();
+ return IsActive();
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the current adapter in use
+//-----------------------------------------------------------------------------
+int CShaderDeviceDx8::GetCurrentAdapter() const
+{
+ LOCK_SHADERAPI();
+ return m_DisplayAdapter;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the current adapter in use
+//-----------------------------------------------------------------------------
+char *CShaderDeviceDx8::GetDisplayDeviceName()
+{
+ if( m_sDisplayDeviceName.IsEmpty() )
+ {
+ D3DADAPTER_IDENTIFIER9 ident;
+ // On Win10, this function is getting called with m_nAdapter still initialized to -1.
+ // It's failing, and m_sDisplayDeviceName has garbage, and tf2 fails to launch.
+ // To repro this, run "hl2.exe -dev -fullscreen -game tf" on Win10.
+ HRESULT hr = D3D()->GetAdapterIdentifier( Max( m_nAdapter, 0 ), 0, &ident );
+ if ( FAILED(hr) )
+ {
+ Assert( false );
+ ident.DeviceName[0] = 0;
+ }
+ m_sDisplayDeviceName = ident.DeviceName;
+ }
+ return m_sDisplayDeviceName.GetForModify();
+}
+
+
+//-----------------------------------------------------------------------------
+// Use this to spew information about the 3D layer
+//-----------------------------------------------------------------------------
+void CShaderDeviceDx8::SpewDriverInfo() const
+{
+ LOCK_SHADERAPI();
+ HRESULT hr;
+ D3DCAPS caps;
+ D3DADAPTER_IDENTIFIER9 ident;
+
+ RECORD_COMMAND( DX8_GET_DEVICE_CAPS, 0 );
+
+ RECORD_COMMAND( DX8_GET_ADAPTER_IDENTIFIER, 2 );
+ RECORD_INT( m_nAdapter );
+ RECORD_INT( 0 );
+
+ Dx9Device()->GetDeviceCaps( &caps );
+ hr = D3D()->GetAdapterIdentifier( m_nAdapter, D3DENUM_WHQL_LEVEL, &ident );
+
+ Warning("Shader API Driver Info:\n\nDriver : %s Version : %lld\n",
+ ident.Driver, ident.DriverVersion.QuadPart );
+ Warning("Driver Description : %s\n", ident.Description );
+ Warning("Chipset version %d %d %d %d\n\n",
+ ident.VendorId, ident.DeviceId, ident.SubSysId, ident.Revision );
+
+ ShaderDisplayMode_t mode;
+ g_pShaderDeviceMgr->GetCurrentModeInfo( &mode, m_nAdapter );
+ Warning("Display mode : %d x %d (%s)\n",
+ mode.m_nWidth, mode.m_nHeight, ImageLoader::GetName( mode.m_Format ) );
+ Warning("Vertex Shader Version : %d.%d Pixel Shader Version : %d.%d\n",
+ (caps.VertexShaderVersion >> 8) & 0xFF, caps.VertexShaderVersion & 0xFF,
+ (caps.PixelShaderVersion >> 8) & 0xFF, caps.PixelShaderVersion & 0xFF);
+ Warning("\nDevice Caps :\n");
+ Warning("CANBLTSYSTONONLOCAL %s CANRENDERAFTERFLIP %s HWRASTERIZATION %s\n",
+ (caps.DevCaps & D3DDEVCAPS_CANBLTSYSTONONLOCAL) ? " Y " : " N ",
+ (caps.DevCaps & D3DDEVCAPS_CANRENDERAFTERFLIP) ? " Y " : " N ",
+ (caps.DevCaps & D3DDEVCAPS_HWRASTERIZATION) ? " Y " : "*N*" );
+ Warning("HWTRANSFORMANDLIGHT %s NPATCHES %s PUREDEVICE %s\n",
+ (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) ? " Y " : " N ",
+ (caps.DevCaps & D3DDEVCAPS_NPATCHES) ? " Y " : " N ",
+ (caps.DevCaps & D3DDEVCAPS_PUREDEVICE) ? " Y " : " N " );
+ Warning("SEPARATETEXTUREMEMORIES %s TEXTURENONLOCALVIDMEM %s TEXTURESYSTEMMEMORY %s\n",
+ (caps.DevCaps & D3DDEVCAPS_SEPARATETEXTUREMEMORIES) ? "*Y*" : " N ",
+ (caps.DevCaps & D3DDEVCAPS_TEXTURENONLOCALVIDMEM) ? " Y " : " N ",
+ (caps.DevCaps & D3DDEVCAPS_TEXTURESYSTEMMEMORY) ? " Y " : " N " );
+ Warning("TEXTUREVIDEOMEMORY %s TLVERTEXSYSTEMMEMORY %s TLVERTEXVIDEOMEMORY %s\n",
+ (caps.DevCaps & D3DDEVCAPS_TEXTUREVIDEOMEMORY) ? " Y " : "*N*",
+ (caps.DevCaps & D3DDEVCAPS_TLVERTEXSYSTEMMEMORY) ? " Y " : "*N*",
+ (caps.DevCaps & D3DDEVCAPS_TLVERTEXVIDEOMEMORY) ? " Y " : " N " );
+
+ Warning("\nPrimitive Caps :\n");
+ Warning("BLENDOP %s CLIPPLANESCALEDPOINTS %s CLIPTLVERTS %s\n",
+ (caps.PrimitiveMiscCaps & D3DPMISCCAPS_BLENDOP) ? " Y " : " N ",
+ (caps.PrimitiveMiscCaps & D3DPMISCCAPS_CLIPPLANESCALEDPOINTS) ? " Y " : " N ",
+ (caps.PrimitiveMiscCaps & D3DPMISCCAPS_CLIPTLVERTS) ? " Y " : " N " );
+ Warning("COLORWRITEENABLE %s MASKZ %s TSSARGTEMP %s\n",
+ (caps.PrimitiveMiscCaps & D3DPMISCCAPS_COLORWRITEENABLE) ? " Y " : " N ",
+ (caps.PrimitiveMiscCaps & D3DPMISCCAPS_MASKZ) ? " Y " : "*N*",
+ (caps.PrimitiveMiscCaps & D3DPMISCCAPS_TSSARGTEMP) ? " Y " : " N " );
+
+ Warning("\nRaster Caps :\n");
+ Warning("FOGRANGE %s FOGTABLE %s FOGVERTEX %s ZFOG %s WFOG %s\n",
+ (caps.RasterCaps & D3DPRASTERCAPS_FOGRANGE) ? " Y " : " N ",
+ (caps.RasterCaps & D3DPRASTERCAPS_FOGTABLE) ? " Y " : " N ",
+ (caps.RasterCaps & D3DPRASTERCAPS_FOGVERTEX) ? " Y " : " N ",
+ (caps.RasterCaps & D3DPRASTERCAPS_ZFOG) ? " Y " : " N ",
+ (caps.RasterCaps & D3DPRASTERCAPS_WFOG) ? " Y " : " N " );
+ Warning("MIPMAPLODBIAS %s WBUFFER %s ZBIAS %s ZTEST %s\n",
+ (caps.RasterCaps & D3DPRASTERCAPS_MIPMAPLODBIAS) ? " Y " : " N ",
+ (caps.RasterCaps & D3DPRASTERCAPS_WBUFFER) ? " Y " : " N ",
+ (caps.RasterCaps & D3DPRASTERCAPS_DEPTHBIAS) ? " Y " : " N ",
+ (caps.RasterCaps & D3DPRASTERCAPS_ZTEST) ? " Y " : "*N*" );
+
+ Warning("Size of Texture Memory : %d kb\n", g_pHardwareConfig->Caps().m_TextureMemorySize / 1024 );
+ Warning("Max Texture Dimensions : %d x %d\n",
+ caps.MaxTextureWidth, caps.MaxTextureHeight );
+ if (caps.MaxTextureAspectRatio != 0)
+ Warning("Max Texture Aspect Ratio : *%d*\n", caps.MaxTextureAspectRatio );
+ Warning("Max Textures : %d Max Stages : %d\n",
+ caps.MaxSimultaneousTextures, caps.MaxTextureBlendStages );
+
+ Warning("\nTexture Caps :\n");
+ Warning("ALPHA %s CUBEMAP %s MIPCUBEMAP %s SQUAREONLY %s\n",
+ (caps.TextureCaps & D3DPTEXTURECAPS_ALPHA) ? " Y " : " N ",
+ (caps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP) ? " Y " : " N ",
+ (caps.TextureCaps & D3DPTEXTURECAPS_MIPCUBEMAP) ? " Y " : " N ",
+ (caps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY) ? "*Y*" : " N " );
+
+ Warning( "vendor id: 0x%x\n", g_pHardwareConfig->ActualCaps().m_VendorID );
+ Warning( "device id: 0x%x\n", g_pHardwareConfig->ActualCaps().m_DeviceID );
+
+ Warning( "SHADERAPI CAPS:\n" );
+ Warning( "m_NumSamplers: %d\n", g_pHardwareConfig->Caps().m_NumSamplers );
+ Warning( "m_NumTextureStages: %d\n", g_pHardwareConfig->Caps().m_NumTextureStages );
+ Warning( "m_HasSetDeviceGammaRamp: %s\n", g_pHardwareConfig->Caps().m_HasSetDeviceGammaRamp ? "yes" : "no" );
+ Warning( "m_SupportsVertexShaders (1.1): %s\n", g_pHardwareConfig->Caps().m_SupportsVertexShaders ? "yes" : "no" );
+ Warning( "m_SupportsVertexShaders_2_0: %s\n", g_pHardwareConfig->Caps().m_SupportsVertexShaders_2_0 ? "yes" : "no" );
+ Warning( "m_SupportsPixelShaders (1.1): %s\n", g_pHardwareConfig->Caps().m_SupportsPixelShaders ? "yes" : "no" );
+ Warning( "m_SupportsPixelShaders_1_4: %s\n", g_pHardwareConfig->Caps().m_SupportsPixelShaders_1_4 ? "yes" : "no" );
+ Warning( "m_SupportsPixelShaders_2_0: %s\n", g_pHardwareConfig->Caps().m_SupportsPixelShaders_2_0 ? "yes" : "no" );
+ Warning( "m_SupportsPixelShaders_2_b: %s\n", g_pHardwareConfig->Caps().m_SupportsPixelShaders_2_b ? "yes" : "no" );
+ Warning( "m_SupportsShaderModel_3_0: %s\n", g_pHardwareConfig->Caps().m_SupportsShaderModel_3_0 ? "yes" : "no" );
+
+ switch( g_pHardwareConfig->Caps().m_SupportsCompressedTextures )
+ {
+ case COMPRESSED_TEXTURES_ON:
+ Warning( "m_SupportsCompressedTextures: COMPRESSED_TEXTURES_ON\n" );
+ break;
+ case COMPRESSED_TEXTURES_OFF:
+ Warning( "m_SupportsCompressedTextures: COMPRESSED_TEXTURES_ON\n" );
+ break;
+ case COMPRESSED_TEXTURES_NOT_INITIALIZED:
+ Warning( "m_SupportsCompressedTextures: COMPRESSED_TEXTURES_NOT_INITIALIZED\n" );
+ break;
+ default:
+ Assert( 0 );
+ break;
+ }
+ Warning( "m_SupportsCompressedVertices: %d\n", g_pHardwareConfig->Caps().m_SupportsCompressedVertices );
+ Warning( "m_bSupportsAnisotropicFiltering: %s\n", g_pHardwareConfig->Caps().m_bSupportsAnisotropicFiltering ? "yes" : "no" );
+ Warning( "m_nMaxAnisotropy: %d\n", g_pHardwareConfig->Caps().m_nMaxAnisotropy );
+ Warning( "m_MaxTextureWidth: %d\n", g_pHardwareConfig->Caps().m_MaxTextureWidth );
+ Warning( "m_MaxTextureHeight: %d\n", g_pHardwareConfig->Caps().m_MaxTextureHeight );
+ Warning( "m_MaxTextureAspectRatio: %d\n", g_pHardwareConfig->Caps().m_MaxTextureAspectRatio );
+ Warning( "m_MaxPrimitiveCount: %d\n", g_pHardwareConfig->Caps().m_MaxPrimitiveCount );
+ Warning( "m_ZBiasAndSlopeScaledDepthBiasSupported: %s\n", g_pHardwareConfig->Caps().m_ZBiasAndSlopeScaledDepthBiasSupported ? "yes" : "no" );
+ Warning( "m_SupportsMipmapping: %s\n", g_pHardwareConfig->Caps().m_SupportsMipmapping ? "yes" : "no" );
+ Warning( "m_SupportsOverbright: %s\n", g_pHardwareConfig->Caps().m_SupportsOverbright ? "yes" : "no" );
+ Warning( "m_SupportsCubeMaps: %s\n", g_pHardwareConfig->Caps().m_SupportsCubeMaps ? "yes" : "no" );
+ Warning( "m_NumPixelShaderConstants: %d\n", g_pHardwareConfig->Caps().m_NumPixelShaderConstants );
+ Warning( "m_NumVertexShaderConstants: %d\n", g_pHardwareConfig->Caps().m_NumVertexShaderConstants );
+ Warning( "m_NumBooleanVertexShaderConstants: %d\n", g_pHardwareConfig->Caps().m_NumBooleanVertexShaderConstants );
+ Warning( "m_NumIntegerVertexShaderConstants: %d\n", g_pHardwareConfig->Caps().m_NumIntegerVertexShaderConstants );
+ Warning( "m_TextureMemorySize: %d\n", g_pHardwareConfig->Caps().m_TextureMemorySize );
+ Warning( "m_MaxNumLights: %d\n", g_pHardwareConfig->Caps().m_MaxNumLights );
+ Warning( "m_SupportsHardwareLighting: %s\n", g_pHardwareConfig->Caps().m_SupportsHardwareLighting ? "yes" : "no" );
+ Warning( "m_MaxBlendMatrices: %d\n", g_pHardwareConfig->Caps().m_MaxBlendMatrices );
+ Warning( "m_MaxBlendMatrixIndices: %d\n", g_pHardwareConfig->Caps().m_MaxBlendMatrixIndices );
+ Warning( "m_MaxVertexShaderBlendMatrices: %d\n", g_pHardwareConfig->Caps().m_MaxVertexShaderBlendMatrices );
+ Warning( "m_SupportsMipmappedCubemaps: %s\n", g_pHardwareConfig->Caps().m_SupportsMipmappedCubemaps ? "yes" : "no" );
+ Warning( "m_SupportsNonPow2Textures: %s\n", g_pHardwareConfig->Caps().m_SupportsNonPow2Textures ? "yes" : "no" );
+ Warning( "m_nDXSupportLevel: %d\n", g_pHardwareConfig->Caps().m_nDXSupportLevel );
+ Warning( "m_PreferDynamicTextures: %s\n", g_pHardwareConfig->Caps().m_PreferDynamicTextures ? "yes" : "no" );
+ Warning( "m_HasProjectedBumpEnv: %s\n", g_pHardwareConfig->Caps().m_HasProjectedBumpEnv ? "yes" : "no" );
+ Warning( "m_MaxUserClipPlanes: %d\n", g_pHardwareConfig->Caps().m_MaxUserClipPlanes );
+ Warning( "m_SupportsSRGB: %s\n", g_pHardwareConfig->Caps().m_SupportsSRGB ? "yes" : "no" );
+ switch( g_pHardwareConfig->Caps().m_HDRType )
+ {
+ case HDR_TYPE_NONE:
+ Warning( "m_HDRType: HDR_TYPE_NONE\n" );
+ break;
+ case HDR_TYPE_INTEGER:
+ Warning( "m_HDRType: HDR_TYPE_INTEGER\n" );
+ break;
+ case HDR_TYPE_FLOAT:
+ Warning( "m_HDRType: HDR_TYPE_FLOAT\n" );
+ break;
+ default:
+ Assert( 0 );
+ break;
+ }
+ Warning( "m_bSupportsSpheremapping: %s\n", g_pHardwareConfig->Caps().m_bSupportsSpheremapping ? "yes" : "no" );
+ Warning( "m_UseFastClipping: %s\n", g_pHardwareConfig->Caps().m_UseFastClipping ? "yes" : "no" );
+ Warning( "m_pShaderDLL: %s\n", g_pHardwareConfig->Caps().m_pShaderDLL );
+ Warning( "m_bNeedsATICentroidHack: %s\n", g_pHardwareConfig->Caps().m_bNeedsATICentroidHack ? "yes" : "no" );
+ Warning( "m_bDisableShaderOptimizations: %s\n", g_pHardwareConfig->Caps().m_bDisableShaderOptimizations ? "yes" : "no" );
+ Warning( "m_bColorOnSecondStream: %s\n", g_pHardwareConfig->Caps().m_bColorOnSecondStream ? "yes" : "no" );
+ Warning( "m_MaxSimultaneousRenderTargets: %d\n", g_pHardwareConfig->Caps().m_MaxSimultaneousRenderTargets );
+}
+
+
+//-----------------------------------------------------------------------------
+// Back buffer information
+//-----------------------------------------------------------------------------
+ImageFormat CShaderDeviceDx8::GetBackBufferFormat() const
+{
+ return ImageLoader::D3DFormatToImageFormat( m_PresentParameters.BackBufferFormat );
+}
+
+void CShaderDeviceDx8::GetBackBufferDimensions( int& width, int& height ) const
+{
+ width = m_PresentParameters.BackBufferWidth;
+ height = m_PresentParameters.BackBufferHeight;
+}
+
+
+//-----------------------------------------------------------------------------
+// Detects support for CreateQuery
+//-----------------------------------------------------------------------------
+void CShaderDeviceDx8::DetectQuerySupport( IDirect3DDevice9 *pD3DDevice )
+{
+ // Do I need to detect whether this device supports CreateQuery before creating it?
+ if ( m_DeviceSupportsCreateQuery != -1 )
+ return;
+
+ IDirect3DQuery9 *pQueryObject = NULL;
+
+ // Detect whether query is supported by creating and releasing:
+ HRESULT hr = pD3DDevice->CreateQuery( D3DQUERYTYPE_EVENT, &pQueryObject );
+ if ( !FAILED(hr) && pQueryObject )
+ {
+ pQueryObject->Release();
+ m_DeviceSupportsCreateQuery = 1;
+ }
+ else
+ {
+ m_DeviceSupportsCreateQuery = 0;
+ }
+}
+
+
+const char *GetD3DErrorText( HRESULT hr )
+{
+ const char *pszMoreInfo = NULL;
+
+#if defined( _WIN32 ) && !defined(DX_TO_GL_ABSTRACTION)
+ switch ( hr )
+ {
+ case D3DERR_WRONGTEXTUREFORMAT:
+ pszMoreInfo = "D3DERR_WRONGTEXTUREFORMAT: The pixel format of the texture surface is not valid.";
+ break;
+ case D3DERR_UNSUPPORTEDCOLOROPERATION:
+ pszMoreInfo = "D3DERR_UNSUPPORTEDCOLOROPERATION: The device does not support a specified texture-blending operation for color values.";
+ break;
+ case D3DERR_UNSUPPORTEDCOLORARG:
+ pszMoreInfo = "D3DERR_UNSUPPORTEDCOLORARG: The device does not support a specified texture-blending argument for color values.";
+ break;
+ case D3DERR_UNSUPPORTEDALPHAOPERATION:
+ pszMoreInfo = "D3DERR_UNSUPPORTEDALPHAOPERATION: The device does not support a specified texture-blending operation for the alpha channel.";
+ break;
+ case D3DERR_UNSUPPORTEDALPHAARG:
+ pszMoreInfo = "D3DERR_UNSUPPORTEDALPHAARG: The device does not support a specified texture-blending argument for the alpha channel.";
+ break;
+ case D3DERR_TOOMANYOPERATIONS:
+ pszMoreInfo = "D3DERR_TOOMANYOPERATIONS: The application is requesting more texture-filtering operations than the device supports.";
+ break;
+ case D3DERR_CONFLICTINGTEXTUREFILTER:
+ pszMoreInfo = "D3DERR_CONFLICTINGTEXTUREFILTER: The current texture filters cannot be used together.";
+ break;
+ case D3DERR_UNSUPPORTEDFACTORVALUE:
+ pszMoreInfo = "D3DERR_UNSUPPORTEDFACTORVALUE: The device does not support the specified texture factor value.";
+ break;
+ case D3DERR_CONFLICTINGRENDERSTATE:
+ pszMoreInfo = "D3DERR_CONFLICTINGRENDERSTATE: The currently set render states cannot be used together.";
+ break;
+ case D3DERR_UNSUPPORTEDTEXTUREFILTER:
+ pszMoreInfo = "D3DERR_UNSUPPORTEDTEXTUREFILTER: The device does not support the specified texture filter.";
+ break;
+ case D3DERR_CONFLICTINGTEXTUREPALETTE:
+ pszMoreInfo = "D3DERR_CONFLICTINGTEXTUREPALETTE: The current textures cannot be used simultaneously.";
+ break;
+ case D3DERR_DRIVERINTERNALERROR:
+ pszMoreInfo = "D3DERR_DRIVERINTERNALERROR: Internal driver error.";
+ break;
+ case D3DERR_NOTFOUND:
+ pszMoreInfo = "D3DERR_NOTFOUND: The requested item was not found.";
+ break;
+ case D3DERR_DEVICELOST:
+ pszMoreInfo = "D3DERR_DEVICELOST: The device has been lost but cannot be reset at this time. Therefore, rendering is not possible.";
+ break;
+ case D3DERR_DEVICENOTRESET:
+ pszMoreInfo = "D3DERR_DEVICENOTRESET: The device has been lost.";
+ break;
+ case D3DERR_NOTAVAILABLE:
+ pszMoreInfo = "D3DERR_NOTAVAILABLE: This device does not support the queried technique.";
+ break;
+ case D3DERR_OUTOFVIDEOMEMORY:
+ pszMoreInfo = "D3DERR_OUTOFVIDEOMEMORY: Direct3D does not have enough display memory to perform the operation. The device is using more resources in a single scene than can fit simultaneously into video memory.";
+ break;
+ case D3DERR_INVALIDDEVICE:
+ pszMoreInfo = "D3DERR_INVALIDDEVICE: The requested device type is not valid.";
+ break;
+ case D3DERR_INVALIDCALL:
+ pszMoreInfo = "D3DERR_INVALIDCALL: The method call is invalid.";
+ break;
+ case D3DERR_DRIVERINVALIDCALL:
+ pszMoreInfo = "D3DERR_DRIVERINVALIDCALL";
+ break;
+ case D3DERR_WASSTILLDRAWING:
+ pszMoreInfo = "D3DERR_WASSTILLDRAWING: The previous blit operation that is transferring information to or from this surface is incomplete.";
+ break;
+ }
+#endif // _WIN32
+
+ return pszMoreInfo;
+}
+
+
+//-----------------------------------------------------------------------------
+// Actually creates the D3D Device once the present parameters are set up
+//-----------------------------------------------------------------------------
+IDirect3DDevice9* CShaderDeviceDx8::InvokeCreateDevice( void* hWnd, int nAdapter, DWORD deviceCreationFlags )
+{
+ IDirect3DDevice9 *pD3DDevice = NULL;
+ D3DDEVTYPE devType = DX8_DEVTYPE;
+
+#if NVPERFHUD
+ nAdapter = D3D()->GetAdapterCount()-1;
+ devType = D3DDEVTYPE_REF;
+ deviceCreationFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_HARDWARE_VERTEXPROCESSING;
+#endif
+
+#if 1 // with the changes for opengl to enable threading, we no longer need the d3d device to have threading guards
+#ifndef _X360
+ // Create the device with multi-threaded safeguards if we're using mat_queue_mode 2.
+ // The logic to enable multithreaded rendering happens well after the device has been created,
+ // so we replicate some of that logic here.
+ ConVarRef mat_queue_mode( "mat_queue_mode" );
+ if ( mat_queue_mode.GetInt() == 2 ||
+ ( mat_queue_mode.GetInt() == -2 && GetCPUInformation()->m_nPhysicalProcessors >= 2 ) ||
+ ( mat_queue_mode.GetInt() == -1 && GetCPUInformation()->m_nPhysicalProcessors >= 2 ) )
+ {
+ deviceCreationFlags |= D3DCREATE_MULTITHREADED;
+ }
+#endif
+#endif
+
+#ifdef ENABLE_NULLREF_DEVICE_SUPPORT
+ devType = CommandLine()->FindParm( "-nulldevice" ) ? D3DDEVTYPE_NULLREF: devType;
+#endif
+
+ HRESULT hr = D3D()->CreateDevice( nAdapter, devType,
+ (VD3DHWND)hWnd, deviceCreationFlags, &m_PresentParameters, &pD3DDevice );
+
+ if ( !FAILED( hr ) && pD3DDevice )
+ return pD3DDevice;
+
+ if ( !IsPC() )
+ return NULL;
+
+ // try again, other applications may be taking their time
+ Sleep( 1000 );
+ hr = D3D()->CreateDevice( nAdapter, devType,
+ (VD3DHWND)hWnd, deviceCreationFlags, &m_PresentParameters, &pD3DDevice );
+ if ( !FAILED( hr ) && pD3DDevice )
+ return pD3DDevice;
+
+ // in this case, we actually are allocating too much memory....
+ // This will cause us to use less buffers...
+ if ( m_PresentParameters.Windowed )
+ {
+ m_PresentParameters.SwapEffect = D3DSWAPEFFECT_COPY;
+ m_PresentParameters.BackBufferCount = 0;
+ hr = D3D()->CreateDevice( nAdapter, devType,
+ (VD3DHWND)hWnd, deviceCreationFlags, &m_PresentParameters, &pD3DDevice );
+ }
+ if ( !FAILED( hr ) && pD3DDevice )
+ return pD3DDevice;
+
+ const char *pszMoreInfo = NULL;
+ switch ( hr )
+ {
+#ifdef _WIN32
+ case D3DERR_INVALIDCALL:
+ // Override the error text for this error since it has a known meaning for CreateDevice failures.
+ pszMoreInfo = "D3DERR_INVALIDCALL: The device or the device driver may not support Direct3D or may not support the resolution or color depth specified.";
+ break;
+#endif // _WIN32
+ default:
+ pszMoreInfo = GetD3DErrorText( hr );
+ break;
+ }
+
+ // Otherwise we failed, show a message and shutdown
+ if ( pszMoreInfo )
+ {
+ DWarning( "init", 0, "Failed to create %s device!\nError 0x%lX: %s\n\nPlease see the following for more info.\n"
+ "http://support.steampowered.com/cgi-bin/steampowered.cfg/php/enduser/std_adp.php?p_faqid=772\n", IsOpenGL() ? "OpenGL" : "D3D", hr, pszMoreInfo );
+ }
+ else
+ {
+ DWarning( "init", 0, "Failed to create %s device!\nError 0x%lX.\n\nPlease see the following for more info.\n"
+ "http://support.steampowered.com/cgi-bin/steampowered.cfg/php/enduser/std_adp.php?p_faqid=772\n", IsOpenGL() ? "OpenGL" : "D3D", hr );
+ }
+
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates the D3D Device
+//-----------------------------------------------------------------------------
+bool CShaderDeviceDx8::CreateD3DDevice( void* pHWnd, int nAdapter, const ShaderDeviceInfo_t &info )
+{
+ Assert( info.m_nVersion == SHADER_DEVICE_INFO_VERSION );
+
+ MEM_ALLOC_CREDIT_( __FILE__ ": D3D Device" );
+
+ VD3DHWND hWnd = (VD3DHWND)pHWnd;
+
+#if ( !defined( PIX_INSTRUMENTATION ) && !defined( _X360 ) && !defined( NVPERFHUD ) )
+ D3DPERF_SetOptions(1); // Explicitly disallow PIX instrumented profiling in external builds
+#endif
+
+ // Get some caps....
+ D3DCAPS caps;
+ HRESULT hr = D3D()->GetDeviceCaps( nAdapter, DX8_DEVTYPE, &caps );
+ if ( FAILED( hr ) )
+ return false;
+
+ // Determine the adapter format
+ ShaderDisplayMode_t mode;
+ g_pShaderDeviceMgrDx8->GetCurrentModeInfo( &mode, nAdapter );
+ m_AdapterFormat = mode.m_Format;
+
+ // FIXME: Need to do this prior to SetPresentParameters. Fix.
+ // Make it part of HardwareCaps_t
+ InitializeColorInformation( nAdapter, DX8_DEVTYPE, m_AdapterFormat );
+
+ const HardwareCaps_t &adapterCaps = g_ShaderDeviceMgrDx8.GetHardwareCaps( nAdapter );
+ DWORD deviceCreationFlags = ComputeDeviceCreationFlags( caps, adapterCaps.m_bSoftwareVertexProcessing );
+ SetPresentParameters( hWnd, nAdapter, info );
+
+ // Tell all other instances of the material system to let go of memory
+ SendIPCMessage( RELEASE_MESSAGE );
+
+ // Creates the device
+ IDirect3DDevice9 *pD3DDevice = InvokeCreateDevice( pHWnd, nAdapter, deviceCreationFlags );
+
+ if ( !pD3DDevice )
+ return false;
+
+ // Check to see if query is supported
+ DetectQuerySupport( pD3DDevice );
+
+#ifdef STUBD3D
+ Dx9Device() = new CStubD3DDevice( pD3DDevice, g_pFullFileSystem );
+#else
+ g_pD3DDevice = pD3DDevice;
+#endif
+
+#if defined( _X360 )
+ // Create the depth buffer, created manually to enable hierarchical z
+ {
+ D3DSURFACE_PARAMETERS DepthStencilParams;
+
+ // Depth is immediately after the back buffer in EDRAM
+ // allocate the hierarchical z tiles at the end of the area so all other allocations can trivially allocate at 0
+ DepthStencilParams.Base = XGSurfaceSize(
+ m_PresentParameters.BackBufferWidth,
+ m_PresentParameters.BackBufferHeight,
+ m_PresentParameters.BackBufferFormat,
+ m_PresentParameters.MultiSampleType );
+ DepthStencilParams.ColorExpBias = 0;
+ DepthStencilParams.HierarchicalZBase = GPU_HIERARCHICAL_Z_TILES - XGHierarchicalZSize( m_PresentParameters.BackBufferWidth, m_PresentParameters.BackBufferHeight, m_PresentParameters.MultiSampleType );
+
+ IDirect3DSurface *pDepthStencilSurface = NULL;
+ hr = Dx9Device()->CreateDepthStencilSurface(
+ m_PresentParameters.BackBufferWidth,
+ m_PresentParameters.BackBufferHeight,
+ m_PresentParameters.AutoDepthStencilFormat,
+ m_PresentParameters.MultiSampleType,
+ m_PresentParameters.MultiSampleQuality,
+ TRUE,
+ &pDepthStencilSurface,
+ &DepthStencilParams );
+ Assert( SUCCEEDED( hr ) );
+ if ( FAILED( hr ) )
+ return false;
+
+ hr = Dx9Device()->SetDepthStencilSurface( pDepthStencilSurface );
+ Assert( SUCCEEDED( hr ) );
+ if ( FAILED( hr ) )
+ return false;
+ }
+
+ // Initialize XUI, needed for TTF font rasterization
+ // xui requires and shares our d3d device
+ {
+ hr = XuiRenderInitShared( pD3DDevice, &m_PresentParameters, XuiD3DXTextureLoader );
+ if ( FAILED( hr ) )
+ return false;
+
+ XUIInitParams xuiInit;
+ XUI_INIT_PARAMS( xuiInit );
+ xuiInit.dwFlags = XUI_INIT_PARAMS_FLAGS_NONE;
+ xuiInit.pHooks = NULL;
+ hr = XuiInit( &xuiInit );
+ if ( FAILED( hr ) )
+ return false;
+
+ hr = XuiRenderCreateDC( &m_hDC );
+ if ( FAILED( hr ) )
+ return false;
+ }
+#endif
+
+ // CheckDeviceLost();
+
+ // Tell all other instances of the material system it's ok to grab memory
+ SendIPCMessage( REACQUIRE_MESSAGE );
+
+ m_hWnd = pHWnd;
+ m_nAdapter = m_DisplayAdapter = nAdapter;
+ m_DeviceState = DEVICE_STATE_OK;
+ m_bIsMinimized = false;
+ m_bQueuedDeviceLost = false;
+
+ m_IsResizing = info.m_bWindowed && info.m_bResizing;
+
+ // This is our current view.
+ m_ViewHWnd = hWnd;
+ GetWindowSize( m_nWindowWidth, m_nWindowHeight );
+
+ g_pHardwareConfig->SetupHardwareCaps( info, g_ShaderDeviceMgrDx8.GetHardwareCaps( nAdapter ) );
+
+ // FIXME: Bake this into hardware config
+ // What texture formats do we support?
+ if ( D3DSupportsCompressedTextures() )
+ {
+ g_pHardwareConfig->ActualCapsForEdit().m_SupportsCompressedTextures = COMPRESSED_TEXTURES_ON;
+ g_pHardwareConfig->CapsForEdit().m_SupportsCompressedTextures = COMPRESSED_TEXTURES_ON;
+ }
+ else
+ {
+ g_pHardwareConfig->ActualCapsForEdit().m_SupportsCompressedTextures = COMPRESSED_TEXTURES_OFF;
+ g_pHardwareConfig->CapsForEdit().m_SupportsCompressedTextures = COMPRESSED_TEXTURES_OFF;
+ }
+
+ return ( !FAILED( hr ) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Frame sync
+//-----------------------------------------------------------------------------
+void CShaderDeviceDx8::AllocFrameSyncTextureObject()
+{
+ if ( IsX360() )
+ return;
+
+ FreeFrameSyncTextureObject();
+
+ // Create a tiny managed texture.
+ HRESULT hr = Dx9Device()->CreateTexture(
+ 1, 1, // width, height
+ 0, // levels
+ D3DUSAGE_DYNAMIC, // usage
+ D3DFMT_A8R8G8B8, // format
+ D3DPOOL_DEFAULT,
+ &m_pFrameSyncTexture,
+ NULL );
+ if ( FAILED( hr ) )
+ {
+ m_pFrameSyncTexture = NULL;
+ }
+}
+
+void CShaderDeviceDx8::FreeFrameSyncTextureObject()
+{
+ if ( IsX360() )
+ return;
+
+ if ( m_pFrameSyncTexture )
+ {
+ m_pFrameSyncTexture->Release();
+ m_pFrameSyncTexture = NULL;
+ }
+}
+
+void CShaderDeviceDx8::AllocFrameSyncObjects( void )
+{
+ if ( IsX360() )
+ return;
+
+ if ( mat_debugalttab.GetBool() )
+ {
+ Warning( "mat_debugalttab: CShaderAPIDX8::AllocFrameSyncObjects\n" );
+ }
+
+ // Allocate the texture for frame syncing in case we force that to be on.
+ AllocFrameSyncTextureObject();
+
+ if ( m_DeviceSupportsCreateQuery == 0 )
+ {
+ for ( int i = 0; i < ARRAYSIZE(m_pFrameSyncQueryObject); i++ )
+ {
+ m_pFrameSyncQueryObject[i] = NULL;
+ m_bQueryIssued[i] = false;
+ }
+ return;
+ }
+
+ // FIXME FIXME FIXME!!!!! Need to record this.
+ for ( int i = 0; i < ARRAYSIZE(m_pFrameSyncQueryObject); i++ )
+ {
+ HRESULT hr = Dx9Device()->CreateQuery( D3DQUERYTYPE_EVENT, &m_pFrameSyncQueryObject[i] );
+ if( hr == D3DERR_NOTAVAILABLE )
+ {
+ Warning( "D3DQUERYTYPE_EVENT not available on this driver\n" );
+ Assert( m_pFrameSyncQueryObject[i] == NULL );
+ }
+ else
+ {
+ Assert( hr == D3D_OK );
+ Assert( m_pFrameSyncQueryObject[i] );
+ m_pFrameSyncQueryObject[i]->Issue( D3DISSUE_END );
+ m_bQueryIssued[i] = true;
+ }
+ }
+}
+
+void CShaderDeviceDx8::FreeFrameSyncObjects( void )
+{
+ if ( IsX360() )
+ return;
+
+ if ( mat_debugalttab.GetBool() )
+ {
+ Warning( "mat_debugalttab: CShaderAPIDX8::FreeFrameSyncObjects\n" );
+ }
+
+ FreeFrameSyncTextureObject();
+
+ // FIXME FIXME FIXME!!!!! Need to record this.
+ for ( int i = 0; i < ARRAYSIZE(m_pFrameSyncQueryObject); i++ )
+ {
+ if ( m_pFrameSyncQueryObject[i] )
+ {
+ if ( m_bQueryIssued[i] )
+ {
+ tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "D3DQueryGetData %t", tmSendCallStack( TELEMETRY_LEVEL0, 0 ) );
+
+ double flStartTime = Plat_FloatTime();
+ BOOL dummyData = 0;
+ HRESULT hr = S_OK;
+
+ // Make every attempt (within 2 seconds) to get the result from the query. Doing so may prevent
+ // crashes in the driver if we try to release outstanding queries.
+ do
+ {
+ hr = m_pFrameSyncQueryObject[i]->GetData( &dummyData, sizeof( dummyData ), D3DGETDATA_FLUSH );
+ double flCurrTime = Plat_FloatTime();
+
+ // don't wait more than 2 seconds for these
+ if ( flCurrTime - flStartTime > 2.00 )
+ break;
+ } while ( hr == S_FALSE );
+ }
+#ifdef DBGFLAG_ASSERT
+ int nRetVal =
+#endif
+ m_pFrameSyncQueryObject[i]->Release();
+ Assert( nRetVal == 0 );
+ m_pFrameSyncQueryObject[i] = NULL;
+ m_bQueryIssued[i] = false;
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Occurs when another application is initializing
+//-----------------------------------------------------------------------------
+void CShaderDeviceDx8::OtherAppInitializing( bool initializing )
+{
+ if ( !ThreadOwnsDevice() || !ThreadInMainThread() )
+ {
+ if ( initializing )
+ {
+ ShaderUtil()->OnThreadEvent( SHADER_THREAD_OTHER_APP_START );
+ }
+ else
+ {
+ ShaderUtil()->OnThreadEvent( SHADER_THREAD_OTHER_APP_END );
+ }
+ return;
+ }
+ Assert( m_bOtherAppInitializing != initializing );
+
+ if ( !IsDeactivated() )
+ {
+ Dx9Device()->EndScene();
+ }
+
+ // NOTE: OtherApp is set in this way because we need to know we're
+ // active as we release and restore everything
+ CheckDeviceLost( initializing );
+
+ if ( !IsDeactivated() )
+ {
+ Dx9Device()->BeginScene();
+ }
+}
+
+
+void CShaderDeviceDx8::HandleThreadEvent( uint32 threadEvent )
+{
+ Assert(ThreadOwnsDevice());
+ switch ( threadEvent )
+ {
+ case SHADER_THREAD_OTHER_APP_START:
+ OtherAppInitializing(true);
+ break;
+ case SHADER_THREAD_RELEASE_RESOURCES:
+ ReleaseResources();
+ break;
+ case SHADER_THREAD_EVICT_RESOURCES:
+ EvictManagedResourcesInternal();
+ break;
+ case SHADER_THREAD_RESET_RENDER_STATE:
+ ResetRenderState();
+ break;
+ case SHADER_THREAD_ACQUIRE_RESOURCES:
+ ReacquireResources();
+ break;
+ case SHADER_THREAD_OTHER_APP_END:
+ OtherAppInitializing(false);
+ break;
+
+ }
+}
+
+//-----------------------------------------------------------------------------
+// We lost the device, but we have a chance to recover
+//-----------------------------------------------------------------------------
+bool CShaderDeviceDx8::TryDeviceReset()
+{
+ if ( IsX360() )
+ return true;
+
+ // Don't try to reset the device until we're sure our resources have been released
+ if ( !m_bResourcesReleased )
+ {
+ return false;
+ }
+
+ // FIXME: Make this rebuild the Dx9Device from scratch!
+ // Helps with compatibility
+ HRESULT hr = Dx9Device()->Reset( &m_PresentParameters );
+ bool bResetSuccess = !FAILED(hr);
+
+#if defined(IS_WINDOWS_PC) && defined(SHADERAPIDX9)
+ if ( bResetSuccess && g_ShaderDeviceUsingD3D9Ex )
+ {
+ bResetSuccess = SUCCEEDED( Dx9Device()->TestCooperativeLevel() );
+ if ( bResetSuccess )
+ {
+ Warning("video driver has crashed and been reset, re-uploading resources now");
+ }
+ }
+#endif
+
+ if ( bResetSuccess )
+ m_bResourcesReleased = false;
+ return bResetSuccess;
+}
+
+
+//-----------------------------------------------------------------------------
+// Release, reacquire resources
+//-----------------------------------------------------------------------------
+void CShaderDeviceDx8::ReleaseResources()
+{
+ if ( !ThreadOwnsDevice() || !ThreadInMainThread() )
+ {
+ // Set our resources as not being released yet.
+ // We reset this in two places since release resources can be called without a call to TryDeviceReset.
+ m_bResourcesReleased = false;
+ ShaderUtil()->OnThreadEvent( SHADER_THREAD_RELEASE_RESOURCES );
+ return;
+ }
+
+ // Only the initial "ReleaseResources" actually has effect
+ if ( m_numReleaseResourcesRefCount ++ != 0 )
+ {
+ Warning( "ReleaseResources has no effect, now at level %d.\n", m_numReleaseResourcesRefCount );
+ DevWarning( "ReleaseResources called twice is a bug: use IsDeactivated to check for a valid device.\n" );
+ Assert( 0 );
+ return;
+ }
+
+ LOCK_SHADERAPI();
+ CPixEvent( PIX_VALVE_ORANGE, "ReleaseResources" );
+
+ FreeFrameSyncObjects();
+ FreeNonInteractiveRefreshObjects();
+ ShaderUtil()->ReleaseShaderObjects();
+ MeshMgr()->ReleaseBuffers();
+ g_pShaderAPI->ReleaseShaderObjects();
+
+#ifdef _DEBUG
+ if ( MeshMgr()->BufferCount() != 0 )
+ {
+ for( int i = 0; i < MeshMgr()->BufferCount(); i++ )
+ {
+ }
+ }
+#endif
+
+ // All meshes cleaned up?
+ Assert( MeshMgr()->BufferCount() == 0 );
+
+ // Signal that our resources have been released so that we can try to reset the device
+ m_bResourcesReleased = true;
+}
+
+
+void CShaderDeviceDx8::ReacquireResources()
+{
+ ReacquireResourcesInternal();
+}
+
+void CShaderDeviceDx8::ReacquireResourcesInternal( bool bResetState, bool bForceReacquire, char const *pszForceReason )
+{
+ if ( !ThreadOwnsDevice() || !ThreadInMainThread() )
+ {
+ if ( bResetState )
+ {
+ ShaderUtil()->OnThreadEvent( SHADER_THREAD_RESET_RENDER_STATE );
+ }
+ ShaderUtil()->OnThreadEvent( SHADER_THREAD_ACQUIRE_RESOURCES );
+ return;
+ }
+ if ( bForceReacquire )
+ {
+ // If we are forcing reacquire then warn if release calls are remaining unpaired
+ if ( m_numReleaseResourcesRefCount > 1 )
+ {
+ Warning( "Forcefully resetting device (%s), resources release level was %d.\n", pszForceReason ? pszForceReason : "unspecified", m_numReleaseResourcesRefCount );
+ Assert( 0 );
+ }
+ m_numReleaseResourcesRefCount = 0;
+ }
+ else
+ {
+ // Only the final "ReacquireResources" actually has effect
+ if ( -- m_numReleaseResourcesRefCount != 0 )
+ {
+ Warning( "ReacquireResources has no effect, now at level %d.\n", m_numReleaseResourcesRefCount );
+ DevWarning( "ReacquireResources being discarded is a bug: use IsDeactivated to check for a valid device.\n" );
+ Assert( 0 );
+
+ if ( m_numReleaseResourcesRefCount < 0 )
+ {
+ m_numReleaseResourcesRefCount = 0;
+ }
+
+ return;
+ }
+ }
+
+ if ( bResetState )
+ {
+ ResetRenderState();
+ }
+
+ LOCK_SHADERAPI();
+ CPixEvent event( PIX_VALVE_ORANGE, "ReacquireResources" );
+
+ g_pShaderAPI->RestoreShaderObjects();
+ AllocFrameSyncObjects();
+ AllocNonInteractiveRefreshObjects();
+ MeshMgr()->RestoreBuffers();
+ ShaderUtil()->RestoreShaderObjects( CShaderDeviceMgrBase::ShaderInterfaceFactory );
+}
+
+
+//-----------------------------------------------------------------------------
+// Changes the window size
+//-----------------------------------------------------------------------------
+bool CShaderDeviceDx8::ResizeWindow( const ShaderDeviceInfo_t &info )
+{
+ if ( IsX360() )
+ return false;
+
+ m_bPendingVideoModeChange = false;
+
+ // We don't need to do crap if the window was set up to set up
+ // to be resizing...
+ if ( info.m_bResizing )
+ return false;
+
+ g_pShaderDeviceMgr->InvokeModeChangeCallbacks();
+
+ ReleaseResources();
+
+ SetPresentParameters( (VD3DHWND)m_hWnd, m_DisplayAdapter, info );
+ HRESULT hr = Dx9Device()->Reset( &m_PresentParameters );
+ if ( FAILED( hr ) )
+ {
+ Warning( "ResizeWindow: Reset failed, hr = 0x%08lX.\n", hr );
+ return false;
+ }
+ else
+ {
+ ReacquireResourcesInternal( true, true, "ResizeWindow" );
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Queue up the fact that the device was lost
+//-----------------------------------------------------------------------------
+void CShaderDeviceDx8::MarkDeviceLost( )
+{
+ if ( IsX360() )
+ return;
+
+ m_bQueuedDeviceLost = true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Checks if the device was lost
+//-----------------------------------------------------------------------------
+#if defined( _DEBUG ) && !defined( _X360 )
+ConVar mat_forcelostdevice( "mat_forcelostdevice", "0" );
+#endif
+
+void CShaderDeviceDx8::CheckDeviceLost( bool bOtherAppInitializing )
+{
+#if !defined( _X360 )
+ // FIXME: We could also queue up if WM_SIZE changes and look at that
+ // but that seems to only make sense if we have resizable windows where
+ // we do *not* allocate buffers as large as the entire current video mode
+ // which we're not doing
+#ifdef _WIN32
+ m_bIsMinimized = ( static_cast<BOOL>(IsIconic( ( HWND )m_hWnd )) == (BOOL)TRUE );
+#else
+ m_bIsMinimized = ( IsIconic( (VD3DHWND)m_hWnd ) == TRUE );
+#endif
+ m_bOtherAppInitializing = bOtherAppInitializing;
+
+#ifdef _DEBUG
+ if ( mat_forcelostdevice.GetBool() )
+ {
+ mat_forcelostdevice.SetValue( 0 );
+ MarkDeviceLost();
+ }
+#endif
+
+ HRESULT hr = D3D_OK;
+#if defined(IS_WINDOWS_PC) && defined(SHADERAPIDX9)
+ if ( g_ShaderDeviceUsingD3D9Ex && m_DeviceState == DEVICE_STATE_OK )
+ {
+ // Steady state - PresentEx return value will mark us lost if necessary.
+ // We do not care if we are minimized in this state.
+ m_bIsMinimized = false;
+ }
+ else
+#endif
+ {
+ RECORD_COMMAND( DX8_TEST_COOPERATIVE_LEVEL, 0 );
+ hr = Dx9Device()->TestCooperativeLevel();
+ }
+
+ // If some other call returned device lost previously in the frame, spoof the return value from TCL
+ if ( m_bQueuedDeviceLost )
+ {
+ hr = (hr != D3D_OK) ? hr : D3DERR_DEVICENOTRESET;
+ m_bQueuedDeviceLost = false;
+ }
+
+ if ( m_DeviceState == DEVICE_STATE_OK )
+ {
+ // We can transition out of ok if bOtherAppInitializing is set
+ // or if we become minimized, or if TCL returns anything other than D3D_OK.
+ if ( ( hr != D3D_OK ) || m_bIsMinimized )
+ {
+ // purge unreferenced materials
+ g_pShaderUtil->UncacheUnusedMaterials( true );
+
+ // We were ok, now we're not. Release resources
+ ReleaseResources();
+ m_DeviceState = DEVICE_STATE_LOST_DEVICE;
+ }
+ else if ( bOtherAppInitializing )
+ {
+ // purge unreferenced materials
+ g_pShaderUtil->UncacheUnusedMaterials( true );
+
+ // We were ok, now we're not. Release resources
+ ReleaseResources();
+ m_DeviceState = DEVICE_STATE_OTHER_APP_INIT;
+ }
+ }
+
+ // Immediately checking devicelost after ok helps in the case where we got D3DERR_DEVICENOTRESET
+ // in which case we want to immdiately try to switch out of DEVICE_STATE_LOST and into DEVICE_STATE_NEEDS_RESET
+ if ( m_DeviceState == DEVICE_STATE_LOST_DEVICE )
+ {
+ // We can only try to reset if we're not minimized and not lost
+ if ( !m_bIsMinimized && (hr != D3DERR_DEVICELOST) )
+ {
+ m_DeviceState = DEVICE_STATE_NEEDS_RESET;
+ }
+ }
+
+ // Immediately checking needs reset also helps for the case where we got D3DERR_DEVICENOTRESET
+ if ( m_DeviceState == DEVICE_STATE_NEEDS_RESET )
+ {
+ if ( ( hr == D3DERR_DEVICELOST ) || m_bIsMinimized )
+ {
+ m_DeviceState = DEVICE_STATE_LOST_DEVICE;
+ }
+ else
+ {
+ bool bResetSucceeded = TryDeviceReset();
+ if ( bResetSucceeded )
+ {
+ if ( !bOtherAppInitializing )
+ {
+ m_DeviceState = DEVICE_STATE_OK;
+
+ // We were bad, now we're ok. Restore resources and reset render state.
+ ReacquireResourcesInternal( true, true, "NeedsReset" );
+ }
+ else
+ {
+ m_DeviceState = DEVICE_STATE_OTHER_APP_INIT;
+ }
+ }
+ }
+ }
+
+ if ( m_DeviceState == DEVICE_STATE_OTHER_APP_INIT )
+ {
+ if ( ( hr != D3D_OK ) || m_bIsMinimized )
+ {
+ m_DeviceState = DEVICE_STATE_LOST_DEVICE;
+ }
+ else if ( !bOtherAppInitializing )
+ {
+ m_DeviceState = DEVICE_STATE_OK;
+
+ // We were bad, now we're ok. Restore resources and reset render state.
+ ReacquireResourcesInternal( true, true, "OtherAppInit" );
+ }
+ }
+
+ // Do mode change if we have a video mode change.
+ if ( m_bPendingVideoModeChange && !IsDeactivated() )
+ {
+#ifdef _DEBUG
+ Warning( "mode change!\n" );
+#endif
+ // now purge unreferenced materials
+ g_pShaderUtil->UncacheUnusedMaterials( true );
+
+ ResizeWindow( m_PendingVideoModeChangeConfig );
+ }
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Special method to refresh the screen on the XBox360
+//-----------------------------------------------------------------------------
+bool CShaderDeviceDx8::AllocNonInteractiveRefreshObjects()
+{
+#if defined( _X360 )
+
+ const char *strVertexShaderProgram =
+ " float4x4 matWVP : register(c0);"
+ " struct VS_IN"
+ " {"
+ " float4 ObjPos : POSITION;"
+ " float2 TexCoord : TEXCOORD;"
+ " };"
+ " struct VS_OUT"
+ " {"
+ " float4 ProjPos : POSITION;"
+ " float2 TexCoord : TEXCOORD;"
+ " };"
+ " VS_OUT main( VS_IN In )"
+ " {"
+ " VS_OUT Out; "
+ " Out.ProjPos = mul( matWVP, In.ObjPos );"
+ " Out.TexCoord = In.TexCoord;"
+ " return Out;"
+ " }";
+
+ const char *strPixelShaderProgram =
+ " struct PS_IN"
+ " {"
+ " float2 TexCoord : TEXCOORD;"
+ " };"
+ " sampler detail : register( s0 );"
+ " float4 main( PS_IN In ) : COLOR"
+ " {"
+ " return tex2D( detail, In.TexCoord );"
+ " }";
+
+ const char *strPixelShaderProgram2 =
+ " struct PS_IN"
+ " {"
+ " float2 TexCoord : TEXCOORD;"
+ " };"
+ " sampler detail : register( s0 );"
+ " float4 main( PS_IN In ) : COLOR"
+ " {"
+ " return tex2D( detail, In.TexCoord );"
+ " }";
+
+ const char *strPixelShaderProgram3 =
+ " struct PS_IN"
+ " {"
+ " float2 TexCoord : TEXCOORD;"
+ " };"
+ " float SrgbGammaToLinear( float flSrgbGammaValue )"
+ " {"
+ " float x = saturate( flSrgbGammaValue );"
+ " return ( x <= 0.04045f ) ? ( x / 12.92f ) : ( pow( ( x + 0.055f ) / 1.055f, 2.4f ) );"
+ " }"
+ "float X360LinearToGamma( float flLinearValue )"
+ "{"
+ " float fl360GammaValue;"
+ ""
+ " flLinearValue = saturate( flLinearValue );"
+ " if ( flLinearValue < ( 128.0f / 1023.0f ) )"
+ " {"
+ " if ( flLinearValue < ( 64.0f / 1023.0f ) )"
+ " {"
+ " fl360GammaValue = flLinearValue * ( 1023.0f * ( 1.0f / 255.0f ) );"
+ " }"
+ " else"
+ " {"
+ " fl360GammaValue = flLinearValue * ( ( 1023.0f / 2.0f ) * ( 1.0f / 255.0f ) ) + ( 32.0f / 255.0f );"
+ " }"
+ " }"
+ " else"
+ " {"
+ " if ( flLinearValue < ( 512.0f / 1023.0f ) )"
+ " {"
+ " fl360GammaValue = flLinearValue * ( ( 1023.0f / 4.0f ) * ( 1.0f / 255.0f ) ) + ( 64.0f / 255.0f );"
+ " }"
+ " else"
+ " {"
+ " fl360GammaValue = flLinearValue * ( ( 1023.0f /8.0f ) * ( 1.0f / 255.0f ) ) + ( 128.0f /255.0f );"
+ " if ( fl360GammaValue > 1.0f )"
+ " {"
+ " fl360GammaValue = 1.0f;"
+ " }"
+ " }"
+ " }"
+ ""
+ " fl360GammaValue = saturate( fl360GammaValue );"
+ " return fl360GammaValue;"
+ "}"
+ " sampler detail : register( s0 );"
+ " float4 main( PS_IN In ) : COLOR"
+ " {"
+ " float4 vTextureColor = tex2D( detail, In.TexCoord );"
+ " vTextureColor.r = X360LinearToGamma( SrgbGammaToLinear( vTextureColor.r ) );"
+ " vTextureColor.g = X360LinearToGamma( SrgbGammaToLinear( vTextureColor.g ) );"
+ " vTextureColor.b = X360LinearToGamma( SrgbGammaToLinear( vTextureColor.b ) );"
+ " return vTextureColor;"
+ " }";
+
+ D3DVERTEXELEMENT9 VertexElements[4] =
+ {
+ { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
+ { 0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
+ D3DDECL_END()
+ };
+
+ ID3DXBuffer *pErrorMsg = NULL;
+ ID3DXBuffer *pShaderCode = NULL;
+
+ HRESULT hr = D3DXCompileShader( strVertexShaderProgram, (UINT)strlen( strVertexShaderProgram ), NULL, NULL, "main", "vs_2_0", 0, &pShaderCode, &pErrorMsg, NULL );
+ if ( FAILED( hr ) )
+ return false;
+
+ Dx9Device()->CreateVertexShader( (DWORD*)pShaderCode->GetBufferPointer(), &m_NonInteractiveRefresh.m_pVertexShader );
+ pShaderCode->Release();
+ pShaderCode = NULL;
+ if ( pErrorMsg )
+ {
+ pErrorMsg->Release();
+ pErrorMsg = NULL;
+ }
+
+ hr = D3DXCompileShader( strPixelShaderProgram, (UINT)strlen( strPixelShaderProgram ), NULL, NULL, "main", "ps_2_0", 0, &pShaderCode, &pErrorMsg, NULL );
+ if ( FAILED(hr) )
+ return false;
+
+ Dx9Device()->CreatePixelShader( (DWORD*)pShaderCode->GetBufferPointer(), &m_NonInteractiveRefresh.m_pPixelShader );
+ pShaderCode->Release();
+ if ( pErrorMsg )
+ {
+ pErrorMsg->Release();
+ pErrorMsg = NULL;
+ }
+
+ hr = D3DXCompileShader( strPixelShaderProgram3, (UINT)strlen( strPixelShaderProgram3 ), NULL, NULL, "main", "ps_2_0", 0, &pShaderCode, &pErrorMsg, NULL );
+ if ( FAILED(hr) )
+ return false;
+
+ Dx9Device()->CreatePixelShader( (DWORD*)pShaderCode->GetBufferPointer(), &m_NonInteractiveRefresh.m_pPixelShaderStartup );
+ pShaderCode->Release();
+ if ( pErrorMsg )
+ {
+ pErrorMsg->Release();
+ pErrorMsg = NULL;
+ }
+
+ hr = D3DXCompileShader( strPixelShaderProgram2, (UINT)strlen( strPixelShaderProgram2 ), NULL, NULL, "main", "ps_2_0", 0, &pShaderCode, &pErrorMsg, NULL );
+ if ( FAILED(hr) )
+ return false;
+
+ Dx9Device()->CreatePixelShader( (DWORD*)pShaderCode->GetBufferPointer(), &m_NonInteractiveRefresh.m_pPixelShaderStartupPass2 );
+ pShaderCode->Release();
+ if ( pErrorMsg )
+ {
+ pErrorMsg->Release();
+ pErrorMsg = NULL;
+ }
+
+ // Create a vertex declaration from the element descriptions.
+ Dx9Device()->CreateVertexDeclaration( VertexElements, &m_NonInteractiveRefresh.m_pVertexDecl );
+
+#endif
+
+ return true;
+}
+
+void CShaderDeviceDx8::FreeNonInteractiveRefreshObjects()
+{
+ if ( m_NonInteractiveRefresh.m_pVertexShader )
+ {
+ m_NonInteractiveRefresh.m_pVertexShader->Release();
+ m_NonInteractiveRefresh.m_pVertexShader = NULL;
+ }
+
+ if ( m_NonInteractiveRefresh.m_pPixelShader )
+ {
+ m_NonInteractiveRefresh.m_pPixelShader->Release();
+ m_NonInteractiveRefresh.m_pPixelShader = NULL;
+ }
+
+ if ( m_NonInteractiveRefresh.m_pPixelShaderStartup )
+ {
+ m_NonInteractiveRefresh.m_pPixelShaderStartup->Release();
+ m_NonInteractiveRefresh.m_pPixelShaderStartup = NULL;
+ }
+
+ if ( m_NonInteractiveRefresh.m_pPixelShaderStartupPass2 )
+ {
+ m_NonInteractiveRefresh.m_pPixelShaderStartupPass2->Release();
+ m_NonInteractiveRefresh.m_pPixelShaderStartupPass2 = NULL;
+ }
+
+ if ( m_NonInteractiveRefresh.m_pVertexDecl )
+ {
+ m_NonInteractiveRefresh.m_pVertexDecl->Release();
+ m_NonInteractiveRefresh.m_pVertexDecl = NULL;
+ }
+}
+
+bool CShaderDeviceDx8::InNonInteractiveMode() const
+{
+ return m_NonInteractiveRefresh.m_Mode != MATERIAL_NON_INTERACTIVE_MODE_NONE;
+}
+
+void CShaderDeviceDx8::EnableNonInteractiveMode( MaterialNonInteractiveMode_t mode, ShaderNonInteractiveInfo_t *pInfo )
+{
+ if ( !IsX360() )
+ return;
+ if ( pInfo && ( pInfo->m_hTempFullscreenTexture == INVALID_SHADERAPI_TEXTURE_HANDLE ) )
+ {
+ mode = MATERIAL_NON_INTERACTIVE_MODE_NONE;
+ }
+ m_NonInteractiveRefresh.m_Mode = mode;
+ if ( pInfo )
+ {
+ m_NonInteractiveRefresh.m_Info = *pInfo;
+ }
+ m_NonInteractiveRefresh.m_nPacifierFrame = 0;
+
+ if ( mode != MATERIAL_NON_INTERACTIVE_MODE_NONE )
+ {
+ ConVarRef mat_monitorgamma( "mat_monitorgamma" );
+ ConVarRef mat_monitorgamma_tv_range_min( "mat_monitorgamma_tv_range_min" );
+ ConVarRef mat_monitorgamma_tv_range_max( "mat_monitorgamma_tv_range_max" );
+ ConVarRef mat_monitorgamma_tv_exp( "mat_monitorgamma_tv_exp" );
+ ConVarRef mat_monitorgamma_tv_enabled( "mat_monitorgamma_tv_enabled" );
+ SetHardwareGammaRamp( mat_monitorgamma.GetFloat(), mat_monitorgamma_tv_range_min.GetFloat(), mat_monitorgamma_tv_range_max.GetFloat(),
+ mat_monitorgamma_tv_exp.GetFloat(), mat_monitorgamma_tv_enabled.GetBool() );
+ }
+
+#ifdef _X360
+ if ( mode != MATERIAL_NON_INTERACTIVE_MODE_NONE )
+ {
+ // HACK: VSync off (prevents us wasting time blocking on VSync due to our irregular present intervals)
+ Dx9Device()->SetRenderState( D3DRS_PRESENTINTERVAL, D3DPRESENT_INTERVAL_IMMEDIATE );
+ }
+ else
+ {
+ // HACK: VSync on (defaulting to on on 360 is fine, but really should save+restore this state)
+ Dx9Device()->SetRenderState( D3DRS_PRESENTINTERVAL, D3DPRESENT_INTERVAL_ONE );
+ }
+#endif
+
+// Msg( "Time elapsed: %.3f Peak %.3f Ave %.5f Count %d Count Above %d\n", Plat_FloatTime() - m_NonInteractiveRefresh.m_flStartTime,
+// m_NonInteractiveRefresh.m_flPeakDt, m_NonInteractiveRefresh.m_flTotalDt / m_NonInteractiveRefresh.m_nSamples, m_NonInteractiveRefresh.m_nSamples, m_NonInteractiveRefresh.m_nCountAbove66 );
+
+ m_NonInteractiveRefresh.m_flStartTime = m_NonInteractiveRefresh.m_flLastPresentTime =
+ m_NonInteractiveRefresh.m_flLastPacifierTime = Plat_FloatTime();
+ m_NonInteractiveRefresh.m_flPeakDt = 0.0f;
+ m_NonInteractiveRefresh.m_flTotalDt = 0.0f;
+ m_NonInteractiveRefresh.m_nSamples = 0;
+ m_NonInteractiveRefresh.m_nCountAbove66 = 0;
+}
+
+void CShaderDeviceDx8::UpdatePresentStats()
+{
+ float t = Plat_FloatTime();
+ float flActualDt = t - m_NonInteractiveRefresh.m_flLastPresentTime;
+ if ( flActualDt > m_NonInteractiveRefresh.m_flPeakDt )
+ {
+ m_NonInteractiveRefresh.m_flPeakDt = flActualDt;
+ }
+ if ( flActualDt > 0.066 )
+ {
+ ++m_NonInteractiveRefresh.m_nCountAbove66;
+ }
+
+ m_NonInteractiveRefresh.m_flTotalDt += flActualDt;
+ ++m_NonInteractiveRefresh.m_nSamples;
+
+ t = Plat_FloatTime();
+ m_NonInteractiveRefresh.m_flLastPresentTime = t;
+}
+
+void CShaderDeviceDx8::RefreshFrontBufferNonInteractive()
+{
+ if ( !IsX360() || !InNonInteractiveMode() )
+ return;
+
+ // Other code should not be talking to D3D at the same time as this
+ AUTO_LOCK( m_nonInteractiveModeMutex );
+
+#ifdef _X360
+ g_pShaderAPI->OwnGPUResources( false );
+ IDirect3DBaseTexture *pTexture = g_pShaderAPI->GetD3DTexture( m_NonInteractiveRefresh.m_Info.m_hTempFullscreenTexture );
+
+ int w, h;
+ g_pShaderAPI->GetBackBufferDimensions( w, h );
+ XMMATRIX matWVP = XMMatrixOrthographicOffCenterLH( 0, (FLOAT)w, (FLOAT)h, 0, 0, 1 );
+
+ // Structure to hold vertex data.
+ struct TEXVERTEX
+ {
+ FLOAT Position[3];
+ FLOAT TexCoord[2];
+ };
+ TEXVERTEX Vertices[4];
+
+ Vertices[0].Position[0] = -0.5f;
+ Vertices[0].Position[1] = -0.5f;
+ Vertices[0].Position[2] = 0;
+ Vertices[0].TexCoord[0] = 0;
+ Vertices[0].TexCoord[1] = 0;
+
+ Vertices[1].Position[0] = w-0.5f;
+ Vertices[1].Position[1] = -0.5f;
+ Vertices[1].Position[2] = 0;
+ Vertices[1].TexCoord[0] = 1;
+ Vertices[1].TexCoord[1] = 0;
+
+ Vertices[2].Position[0] = w-0.5f;
+ Vertices[2].Position[1] = h-0.5f;
+ Vertices[2].Position[2] = 0;
+ Vertices[2].TexCoord[0] = 1;
+ Vertices[2].TexCoord[1] = 1;
+
+ Vertices[3].Position[0] = -0.5f;
+ Vertices[3].Position[1] = h-0.5f;
+ Vertices[3].Position[2] = 0;
+ Vertices[3].TexCoord[0] = 0;
+ Vertices[3].TexCoord[1] = 1;
+
+ D3DVIEWPORT9 viewport;
+ viewport.X = viewport.Y = 0;
+ viewport.Width = w; viewport.Height = h;
+ viewport.MinZ = ReverseDepthOnX360() ? 1.0f : 0.0f;
+ viewport.MaxZ = 1.0f - viewport.MinZ;
+
+ bool bInStartupMode = ( m_NonInteractiveRefresh.m_Mode == MATERIAL_NON_INTERACTIVE_MODE_STARTUP );
+
+ float flDepth = (ShaderUtil()->GetConfig().bReverseDepth ^ ReverseDepthOnX360()) ? 0.0f : 1.0f;
+ Dx9Device()->Clear( 0, NULL, D3DCLEAR_ZBUFFER, 0, flDepth, 0L );
+
+ Dx9Device()->SetViewport( &viewport );
+ Dx9Device()->SetTexture( 0, pTexture );
+ Dx9Device()->SetVertexShader( m_NonInteractiveRefresh.m_pVertexShader );
+ Dx9Device()->SetPixelShader( bInStartupMode ? m_NonInteractiveRefresh.m_pPixelShaderStartup : m_NonInteractiveRefresh.m_pPixelShader );
+ Dx9Device()->SetVertexShaderConstantF( 0, (FLOAT*)&matWVP, 4 );
+ Dx9Device()->SetVertexDeclaration( m_NonInteractiveRefresh.m_pVertexDecl );
+ Dx9Device()->SetSamplerState( 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP );
+ Dx9Device()->SetSamplerState( 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP );
+ Dx9Device()->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
+ Dx9Device()->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
+
+ tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "%s", __FUNCTION__ );
+
+ Dx9Device()->DrawPrimitiveUP( D3DPT_QUADLIST, 1, Vertices, sizeof( TEXVERTEX ) );
+
+ if ( bInStartupMode )
+ {
+ float flXPos = m_NonInteractiveRefresh.m_Info.m_flNormalizedX;
+ float flYPos = m_NonInteractiveRefresh.m_Info.m_flNormalizedY;
+ float flHeight = m_NonInteractiveRefresh.m_Info.m_flNormalizedSize;
+ int nSize = h * flHeight;
+ int x = w * flXPos - nSize * 0.5f;
+ int y = h * flYPos - nSize * 0.5f;
+ w = h = nSize;
+
+ Vertices[0].Position[0] = x - 0.5f;
+ Vertices[0].Position[1] = y - 0.5f;
+ Vertices[1].Position[0] = x+w-0.5f;
+ Vertices[1].Position[1] = y - 0.5f;
+ Vertices[2].Position[0] = x+w-0.5f;
+ Vertices[2].Position[1] = y+h-0.5f;
+ Vertices[3].Position[0] = x - 0.5f;
+ Vertices[3].Position[1] = y+h-0.5f;
+
+ float t = Plat_FloatTime();
+ float flDt = t - m_NonInteractiveRefresh.m_flLastPacifierTime;
+ if ( flDt > 0.030f )
+ {
+ if ( ++m_NonInteractiveRefresh.m_nPacifierFrame >= m_NonInteractiveRefresh.m_Info.m_nPacifierCount )
+ {
+ m_NonInteractiveRefresh.m_nPacifierFrame = 0;
+ }
+ m_NonInteractiveRefresh.m_flLastPacifierTime = t;
+ }
+
+ pTexture = g_pShaderAPI->GetD3DTexture( m_NonInteractiveRefresh.m_Info.m_pPacifierTextures[ m_NonInteractiveRefresh.m_nPacifierFrame ] );
+ Dx9Device()->SetRenderState( D3DRS_ALPHABLENDENABLE, 1 );
+ Dx9Device()->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
+ Dx9Device()->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
+ Dx9Device()->SetTexture( 0, pTexture );
+ Dx9Device()->SetPixelShader( m_NonInteractiveRefresh.m_pPixelShaderStartupPass2 );
+ Dx9Device()->DrawPrimitiveUP( D3DPT_QUADLIST, 1, Vertices, sizeof( TEXVERTEX ) );
+ }
+
+ Dx9Device()->SetVertexShader( NULL );
+ Dx9Device()->SetPixelShader( NULL );
+ Dx9Device()->SetTexture( 0, NULL );
+ Dx9Device()->SetVertexDeclaration( NULL );
+
+ tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "D3DPresent" );
+
+ Dx9Device()->Present( 0, 0, 0, 0 );
+ g_pShaderAPI->QueueResetRenderState();
+ g_pShaderAPI->OwnGPUResources( true );
+
+ UpdatePresentStats();
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Page flip
+//-----------------------------------------------------------------------------
+void CShaderDeviceDx8::Present()
+{
+ LOCK_SHADERAPI();
+
+ // need to flush the dynamic buffer
+ g_pShaderAPI->FlushBufferedPrimitives();
+
+ if ( !IsDeactivated() )
+ {
+ Dx9Device()->EndScene();
+ }
+
+ HRESULT hr = S_OK;
+
+ // if we're in queued mode, don't present if the device is already lost
+ bool bValidPresent = true;
+ bool bInMainThread = ThreadInMainThread();
+ if ( !bInMainThread )
+ {
+ // don't present if the device is in an invalid state and in queued mode
+ if ( m_DeviceState != DEVICE_STATE_OK )
+ {
+ bValidPresent = false;
+ }
+ // check for lost device early in threaded mode
+ CheckDeviceLost( m_bOtherAppInitializing );
+ if ( m_DeviceState != DEVICE_STATE_OK )
+ {
+ bValidPresent = false;
+ }
+ }
+ // Copy the back buffer into the non-interactive temp buffer
+ if ( m_NonInteractiveRefresh.m_Mode == MATERIAL_NON_INTERACTIVE_MODE_LEVEL_LOAD )
+ {
+ g_pShaderAPI->CopyRenderTargetToTextureEx( m_NonInteractiveRefresh.m_Info.m_hTempFullscreenTexture, 0, NULL, NULL );
+ }
+
+ // If we're not iconified, try to present (without this check, we can flicker when Alt-Tabbed away)
+#ifdef _WIN32
+ if ( IsX360() || (IsIconic( ( HWND )m_hWnd ) == 0 && bValidPresent) )
+#else
+ if ( IsX360() || (IsIconic( (VD3DHWND)m_hWnd ) == 0 && bValidPresent) )
+#endif
+ {
+ if ( IsPC() && ( m_IsResizing || ( m_ViewHWnd != (VD3DHWND)m_hWnd ) ) )
+ {
+ RECT destRect;
+ #ifndef DX_TO_GL_ABSTRACTION
+ GetClientRect( ( HWND )m_ViewHWnd, &destRect );
+ #else
+ toglGetClientRect( (VD3DHWND)m_ViewHWnd, &destRect );
+ #endif
+
+ ShaderViewport_t viewport;
+ g_pShaderAPI->GetViewports( &viewport, 1 );
+
+ RECT srcRect;
+ srcRect.left = viewport.m_nTopLeftX;
+ srcRect.right = viewport.m_nTopLeftX + viewport.m_nWidth;
+ srcRect.top = viewport.m_nTopLeftY;
+ srcRect.bottom = viewport.m_nTopLeftY + viewport.m_nHeight;
+
+ hr = Dx9Device()->Present( &srcRect, &destRect, (VD3DHWND)m_ViewHWnd, 0 );
+ }
+ else
+ {
+ g_pShaderAPI->OwnGPUResources( false );
+ hr = Dx9Device()->Present( 0, 0, 0, 0 );
+ }
+ }
+
+ UpdatePresentStats();
+
+ if ( IsWindows() )
+ {
+ if ( hr == D3DERR_DRIVERINTERNALERROR )
+ {
+ /* Usually this bug means that the driver has run out of internal video
+ memory, due to leaking it slowly over several application restarts.
+ As of summer 2007, IE in particular seemed to leak a lot of driver
+ memory for every image context it created in the browser window. A
+ reboot clears out the leaked memory and will generally allow the game
+ to be run again; occasionally (but not frequently) it's necessary to
+ reduce video settings in the game as well to run. But, this is too
+ fine a distinction to explain in a dialog, so place the guilt on the
+ user and ask them to reduce video settings regardless.
+ */
+
+ Error( "Internal driver error at Present.\n"
+ "You're likely out of OS Paged Pool Memory! For more info, see\n"
+ "http://support.steampowered.com/cgi-bin/steampowered.cfg/php/enduser/std_adp.php?p_faqid=150\n" );
+ }
+ if ( hr == D3DERR_DEVICELOST )
+ {
+ MarkDeviceLost();
+ }
+ }
+
+ MeshMgr()->DiscardVertexBuffers();
+
+ if ( bInMainThread )
+ {
+ CheckDeviceLost( m_bOtherAppInitializing );
+ }
+
+ if ( IsX360() )
+ {
+ // according to docs - "Mandatory Reset of GPU Registers"
+ // 360 must force the cached state to be dirty after any present()
+ g_pShaderAPI->ResetRenderState( false );
+ }
+
+#ifdef RECORD_KEYFRAMES
+ static int frame = 0;
+ ++frame;
+ if (frame == KEYFRAME_INTERVAL)
+ {
+ RECORD_COMMAND( DX8_KEYFRAME, 0 );
+
+ g_pShaderAPI->ResetRenderState();
+ frame = 0;
+ }
+#endif
+
+ g_pShaderAPI->AdvancePIXFrame();
+
+ if ( !IsDeactivated() )
+ {
+#ifndef DX_TO_GL_ABSTRACTION
+ if ( ( ShaderUtil()->GetConfig().bMeasureFillRate || ShaderUtil()->GetConfig().bVisualizeFillRate ) )
+ {
+ g_pShaderAPI->ClearBuffers( true, true, true, -1, -1 );
+ }
+#endif
+
+ Dx9Device()->BeginScene();
+ }
+}
+
+
+// We need to scale our colors to the range [16, 235] to keep our colors within TV standards. Some colors might
+// still be out of gamut if any of the R, G, or B channels are more than 191 units apart from each other in
+// the 0-255 scale, but it looks like the 360 deals with this for us by lowering the bright saturated color components.
+// NOTE: I'm leaving the max at 255 to retain whiter than whites. On most TV's, we seems a little dark in the bright colors
+// compared to TV and movies when played in the same conditions. This keeps out brights on par with what customers are
+// used to seeing.
+// TV's generally have a 2.5 gamma, so we need to convert our 2.2 frame buffer into a 2.5 frame buffer for display on a TV
+
+void CShaderDeviceDx8::SetHardwareGammaRamp( float fGamma, float fGammaTVRangeMin, float fGammaTVRangeMax, float fGammaTVExponent, bool bTVEnabled )
+{
+ DevMsg( 2, "SetHardwareGammaRamp( %f )\n", fGamma );
+
+ Assert( Dx9Device() );
+ if( !Dx9Device() )
+ return;
+
+ D3DGAMMARAMP gammaRamp;
+ for ( int i = 0; i < 256; i++ )
+ {
+ float flInputValue = float( i ) / 255.0f;
+
+ // Since the 360's sRGB read/write is a piecewise linear approximation, we need to correct for the difference in gamma space here
+ float flSrgbGammaValue;
+ if ( IsX360() ) // Should we also do this for the PS3?
+ {
+ // First undo the 360 broken sRGB curve by bringing the value back into linear space
+ float flLinearValue = X360GammaToLinear( flInputValue );
+ flLinearValue = clamp( flLinearValue, 0.0f, 1.0f );
+
+ // Now apply a true sRGB curve to mimic PC hardware
+ flSrgbGammaValue = SrgbLinearToGamma( flLinearValue ); // ( flLinearValue <= 0.0031308f ) ? ( flLinearValue * 12.92f ) : ( 1.055f * powf( flLinearValue, ( 1.0f / 2.4f ) ) ) - 0.055f;
+ flSrgbGammaValue = clamp( flSrgbGammaValue, 0.0f, 1.0f );
+ }
+ else
+ {
+ flSrgbGammaValue = flInputValue;
+ }
+
+ // Apply the user controlled exponent curve
+ float flCorrection = pow( flSrgbGammaValue, ( fGamma / 2.2f ) );
+ flCorrection = clamp( flCorrection, 0.0f, 1.0f );
+
+ // TV adjustment - Apply an exp and a scale and bias
+ if ( bTVEnabled )
+ {
+ // Adjust for TV gamma of 2.5 by applying an exponent of 2.2 / 2.5 = 0.88
+ flCorrection = pow( flCorrection, 2.2f / fGammaTVExponent );
+ flCorrection = clamp( flCorrection, 0.0f, 1.0f );
+
+ // Scale and bias to fit into the 16-235 range for TV's
+ flCorrection = ( flCorrection * ( fGammaTVRangeMax - fGammaTVRangeMin ) / 255.0f ) + ( fGammaTVRangeMin / 255.0f );
+ flCorrection = clamp( flCorrection, 0.0f, 1.0f );
+ }
+
+ // Generate final int value
+ unsigned int val = ( int )( flCorrection * 65535.0f );
+ gammaRamp.red[i] = val;
+ gammaRamp.green[i] = val;
+ gammaRamp.blue[i] = val;
+ }
+
+ Dx9Device()->SetGammaRamp( 0, D3DSGR_NO_CALIBRATION, &gammaRamp );
+}
+
+
+//-----------------------------------------------------------------------------
+// Shader compilation
+//-----------------------------------------------------------------------------
+IShaderBuffer* CShaderDeviceDx8::CompileShader( const char *pProgram, size_t nBufLen, const char *pShaderVersion )
+{
+ return ShaderManager()->CompileShader( pProgram, nBufLen, pShaderVersion );
+}
+
+VertexShaderHandle_t CShaderDeviceDx8::CreateVertexShader( IShaderBuffer *pBuffer )
+{
+ return ShaderManager()->CreateVertexShader( pBuffer );
+}
+
+void CShaderDeviceDx8::DestroyVertexShader( VertexShaderHandle_t hShader )
+{
+ ShaderManager()->DestroyVertexShader( hShader );
+}
+
+GeometryShaderHandle_t CShaderDeviceDx8::CreateGeometryShader( IShaderBuffer* pShaderBuffer )
+{
+ Assert( 0 );
+ return GEOMETRY_SHADER_HANDLE_INVALID;
+}
+
+void CShaderDeviceDx8::DestroyGeometryShader( GeometryShaderHandle_t hShader )
+{
+ Assert( hShader == GEOMETRY_SHADER_HANDLE_INVALID );
+}
+
+PixelShaderHandle_t CShaderDeviceDx8::CreatePixelShader( IShaderBuffer *pBuffer )
+{
+ return ShaderManager()->CreatePixelShader( pBuffer );
+}
+
+void CShaderDeviceDx8::DestroyPixelShader( PixelShaderHandle_t hShader )
+{
+ ShaderManager()->DestroyPixelShader( hShader );
+}
+
+#ifdef DX_TO_GL_ABSTRACTION
+void CShaderDeviceDx8::DoStartupShaderPreloading( void )
+{
+ ShaderManager()->DoStartupShaderPreloading();
+}
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Creates/destroys Mesh
+// NOTE: Will be deprecated soon!
+//-----------------------------------------------------------------------------
+IMesh* CShaderDeviceDx8::CreateStaticMesh( VertexFormat_t vertexFormat, const char *pTextureBudgetGroup, IMaterial * pMaterial )
+{
+ LOCK_SHADERAPI();
+ return MeshMgr()->CreateStaticMesh( vertexFormat, pTextureBudgetGroup, pMaterial );
+}
+
+void CShaderDeviceDx8::DestroyStaticMesh( IMesh* pMesh )
+{
+ LOCK_SHADERAPI();
+ MeshMgr()->DestroyStaticMesh( pMesh );
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates/destroys vertex buffers + index buffers
+//-----------------------------------------------------------------------------
+IVertexBuffer *CShaderDeviceDx8::CreateVertexBuffer( ShaderBufferType_t type, VertexFormat_t fmt, int nVertexCount, const char *pBudgetGroup )
+{
+ LOCK_SHADERAPI();
+ return MeshMgr()->CreateVertexBuffer( type, fmt, nVertexCount, pBudgetGroup );
+}
+
+void CShaderDeviceDx8::DestroyVertexBuffer( IVertexBuffer *pVertexBuffer )
+{
+ LOCK_SHADERAPI();
+ MeshMgr()->DestroyVertexBuffer( pVertexBuffer );
+}
+
+IIndexBuffer *CShaderDeviceDx8::CreateIndexBuffer( ShaderBufferType_t bufferType, MaterialIndexFormat_t fmt, int nIndexCount, const char *pBudgetGroup )
+{
+ LOCK_SHADERAPI();
+ return MeshMgr()->CreateIndexBuffer( bufferType, fmt, nIndexCount, pBudgetGroup );
+}
+
+void CShaderDeviceDx8::DestroyIndexBuffer( IIndexBuffer *pIndexBuffer )
+{
+ LOCK_SHADERAPI();
+ MeshMgr()->DestroyIndexBuffer( pIndexBuffer );
+}
+
+IVertexBuffer *CShaderDeviceDx8::GetDynamicVertexBuffer( int streamID, VertexFormat_t vertexFormat, bool bBuffered )
+{
+ LOCK_SHADERAPI();
+ return MeshMgr()->GetDynamicVertexBuffer( streamID, vertexFormat, bBuffered );
+}
+
+IIndexBuffer *CShaderDeviceDx8::GetDynamicIndexBuffer( MaterialIndexFormat_t fmt, bool bBuffered )
+{
+ LOCK_SHADERAPI();
+ return MeshMgr()->GetDynamicIndexBuffer( fmt, bBuffered );
+}
+
+#ifdef _X360
+void CShaderDeviceDx8::SpewVideoInfo360( const CCommand &args )
+{
+ XVIDEO_MODE videoMode;
+ XGetVideoMode( &videoMode );
+
+ Warning( "back buffer size: %dx%d\n", m_PresentParameters.BackBufferWidth, m_PresentParameters.BackBufferHeight );
+ Warning( "display resolution: %dx%d %s\n", videoMode.dwDisplayWidth, videoMode.dwDisplayHeight, videoMode.fIsInterlaced ? "interlaced" : "progressive" );
+ Warning( "refresh rate: %f\n", videoMode.RefreshRate );
+ Warning( "aspect: %s\n", videoMode.fIsWideScreen ? "16x9 (widescreen)" : "4x3 (normal)" );
+ Warning( "%s\n", videoMode.fIsHiDef ? "hidef" : "lodef" );
+ switch( videoMode.VideoStandard )
+ {
+ case XC_VIDEO_STANDARD_NTSC_M:
+ Warning( "video standard: NTSC_M\n" );
+ break;
+ case XC_VIDEO_STANDARD_NTSC_J:
+ Warning( "video standard: NTSC_J\n" );
+ break;
+ case XC_VIDEO_STANDARD_PAL_I:
+ Warning( "video standard: PAL_I\n" );
+ break;
+ default:
+ Warning( "error: UNKNOWN VIDEO STANDARD!\n" );
+ Assert( 0 );
+ break;
+ }
+ ConVarRef fps_max( "fps_max" );
+ Warning( "fps_max: %f\n", fps_max.GetFloat() );
+ switch( m_PresentParameters.MultiSampleType )
+ {
+ case D3DMULTISAMPLE_NONE:
+ Warning( "multisample type: D3DMULTISAMPLE_NONE\n" );
+ break;
+ case D3DMULTISAMPLE_2_SAMPLES:
+ Warning( "multisample type: D3DMULTISAMPLE_2_SAMPLES\n" );
+ break;
+ case D3DMULTISAMPLE_4_SAMPLES:
+ Warning( "multisample type: D3DMULTISAMPLE_4_SAMPLES\n" );
+ break;
+ }
+}
+#endif
diff --git a/materialsystem/shaderapidx9/shaderdevicedx8.h b/materialsystem/shaderapidx9/shaderdevicedx8.h
new file mode 100644
index 0000000..4e20efe
--- /dev/null
+++ b/materialsystem/shaderapidx9/shaderdevicedx8.h
@@ -0,0 +1,382 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#ifndef SHADERDEVICEDX8_H
+#define SHADERDEVICEDX8_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "shaderdevicebase.h"
+#include "shaderapidx8_global.h"
+#include "tier1/utlvector.h"
+
+
+
+//-----------------------------------------------------------------------------
+// Describes which D3DDEVTYPE to use
+//-----------------------------------------------------------------------------
+#ifndef USE_REFERENCE_RASTERIZER
+#define DX8_DEVTYPE D3DDEVTYPE_HAL
+#else
+#define DX8_DEVTYPE D3DDEVTYPE_REF
+#endif
+
+
+// PC: By default, PIX profiling is explicitly disallowed using the D3DPERF_SetOptions(1) API on PC
+// X360: PIX_INSTRUMENTATION will only generate PIX events in RELEASE builds on 360
+// Uncomment to use PIX instrumentation:
+#if PIX_ENABLE
+#define PIX_INSTRUMENTATION
+#endif
+
+#define MAX_PIX_ERRORS 3
+
+#if defined( PIX_INSTRUMENTATION ) && defined ( DX_TO_GL_ABSTRACTION ) && defined( _WIN32 )
+typedef int (WINAPI *D3DPERF_BeginEvent_FuncPtr)( D3DCOLOR col, LPCWSTR wszName );
+typedef int (WINAPI *D3DPERF_EndEvent_FuncPtr)( void );
+typedef void (WINAPI *D3DPERF_SetMarker_FuncPtr)( D3DCOLOR col, LPCWSTR wszName );
+typedef void (WINAPI *D3DPERF_SetOptions_FuncPtr)( DWORD dwOptions );
+#endif
+
+//-----------------------------------------------------------------------------
+// The Base implementation of the shader device
+//-----------------------------------------------------------------------------
+class CShaderDeviceMgrDx8 : public CShaderDeviceMgrBase
+{
+ typedef CShaderDeviceMgrBase BaseClass;
+
+public:
+ // constructor, destructor
+ CShaderDeviceMgrDx8();
+ virtual ~CShaderDeviceMgrDx8();
+
+ // Methods of IAppSystem
+ virtual bool Connect( CreateInterfaceFn factory );
+ virtual void Disconnect();
+ virtual InitReturnVal_t Init();
+ virtual void Shutdown();
+
+ // Methods of IShaderDevice
+ virtual int GetAdapterCount() const;
+ virtual void GetAdapterInfo( int adapter, MaterialAdapterInfo_t& info ) const;
+ virtual int GetModeCount( int nAdapter ) const;
+ virtual void GetModeInfo( ShaderDisplayMode_t* pInfo, int nAdapter, int mode ) const;
+ virtual void GetCurrentModeInfo( ShaderDisplayMode_t* pInfo, int nAdapter ) const;
+ virtual bool SetAdapter( int nAdapter, int nFlags );
+ virtual CreateInterfaceFn SetMode( void *hWnd, int nAdapter, const ShaderDeviceInfo_t& mode );
+
+ // Determines hardware caps from D3D
+ bool ComputeCapsFromD3D( HardwareCaps_t *pCaps, int nAdapter );
+
+ // Forces caps to a specific dx level
+ void ForceCapsToDXLevel( HardwareCaps_t *pCaps, int nDxLevel, const HardwareCaps_t &actualCaps );
+
+ // Validates the mode...
+ bool ValidateMode( int nAdapter, const ShaderDeviceInfo_t &info ) const;
+
+ // Returns the amount of video memory in bytes for a particular adapter
+ virtual int GetVidMemBytes( int nAdapter ) const;
+
+#if !defined( _X360 )
+ FORCEINLINE IDirect3D9 *D3D() const
+ {
+ return m_pD3D;
+ }
+#endif
+
+#if defined( PIX_INSTRUMENTATION ) && defined ( DX_TO_GL_ABSTRACTION ) && defined( _WIN32 )
+ HMODULE m_hD3D9;
+ D3DPERF_BeginEvent_FuncPtr m_pBeginEvent;
+ D3DPERF_EndEvent_FuncPtr m_pEndEvent;
+ D3DPERF_SetMarker_FuncPtr m_pSetMarker;
+ D3DPERF_SetOptions_FuncPtr m_pSetOptions;
+#endif
+
+protected:
+ // Determine capabilities
+ bool DetermineHardwareCaps( );
+
+private:
+ // Initialize adapter information
+ void InitAdapterInfo();
+
+ // Code to detect support for texture border mode (not a simple caps check)
+ void CheckBorderColorSupport( HardwareCaps_t *pCaps, int nAdapter );
+
+ // Vendor-dependent code to detect support for various flavors of shadow mapping
+ void CheckVendorDependentShadowMappingSupport( HardwareCaps_t *pCaps, int nAdapter );
+
+ // Vendor-dependent code to detect Alpha To Coverage Backdoors
+ void CheckVendorDependentAlphaToCoverage( HardwareCaps_t *pCaps, int nAdapter );
+
+ // Compute the effective DX support level based on all the other caps
+ void ComputeDXSupportLevel( HardwareCaps_t &caps );
+
+ // Used to enumerate adapters, attach to windows
+#if !defined( _X360 )
+ IDirect3D9 *m_pD3D;
+#endif
+
+ bool m_bObeyDxCommandlineOverride : 1;
+ bool m_bAdapterInfoIntialized : 1;
+};
+
+extern CShaderDeviceMgrDx8* g_pShaderDeviceMgrDx8;
+
+
+//-----------------------------------------------------------------------------
+// IDirect3D accessor
+//-----------------------------------------------------------------------------
+#if defined( _X360 )
+
+extern IDirect3D9 *m_pD3D;
+inline IDirect3D9* D3D()
+{
+ return m_pD3D;
+}
+
+#else
+
+inline IDirect3D9* D3D()
+{
+ return g_pShaderDeviceMgrDx8->D3D();
+}
+
+#endif
+
+#define NUM_FRAME_SYNC_QUERIES 2
+#define NUM_FRAME_SYNC_FRAMES_LATENCY 0
+
+//-----------------------------------------------------------------------------
+// The Dx8implementation of the shader device
+//-----------------------------------------------------------------------------
+class CShaderDeviceDx8 : public CShaderDeviceBase
+{
+ // Methods of IShaderDevice
+public:
+ virtual bool IsUsingGraphics() const;
+ virtual ImageFormat GetBackBufferFormat() const;
+ virtual void GetBackBufferDimensions( int& width, int& height ) const;
+ virtual void Present();
+ virtual IShaderBuffer* CompileShader( const char *pProgram, size_t nBufLen, const char *pShaderVersion );
+ virtual VertexShaderHandle_t CreateVertexShader( IShaderBuffer *pBuffer );
+ virtual void DestroyVertexShader( VertexShaderHandle_t hShader );
+ virtual GeometryShaderHandle_t CreateGeometryShader( IShaderBuffer* pShaderBuffer );
+ virtual void DestroyGeometryShader( GeometryShaderHandle_t hShader );
+ virtual PixelShaderHandle_t CreatePixelShader( IShaderBuffer* pShaderBuffer );
+ virtual void DestroyPixelShader( PixelShaderHandle_t hShader );
+ virtual void ReleaseResources();
+ virtual void ReacquireResources();
+ virtual IMesh* CreateStaticMesh( VertexFormat_t format, const char *pBudgetGroup, IMaterial * pMaterial = NULL );
+ virtual void DestroyStaticMesh( IMesh* mesh );
+ virtual IVertexBuffer *CreateVertexBuffer( ShaderBufferType_t type, VertexFormat_t fmt, int nVertexCount, const char *pBudgetGroup );
+ virtual void DestroyVertexBuffer( IVertexBuffer *pVertexBuffer );
+ virtual IIndexBuffer *CreateIndexBuffer( ShaderBufferType_t bufferType, MaterialIndexFormat_t fmt, int nIndexCount, const char *pBudgetGroup );
+ virtual void DestroyIndexBuffer( IIndexBuffer *pIndexBuffer );
+ virtual IVertexBuffer *GetDynamicVertexBuffer( int nStreamID, VertexFormat_t vertexFormat, bool bBuffered = true );
+ virtual IIndexBuffer *GetDynamicIndexBuffer( MaterialIndexFormat_t fmt, bool bBuffered = true );
+ virtual void SetHardwareGammaRamp( float fGamma, float fGammaTVRangeMin, float fGammaTVRangeMax, float fGammaTVExponent, bool bTVEnabled );
+ virtual void SpewDriverInfo() const;
+ virtual int GetCurrentAdapter() const;
+ virtual void EnableNonInteractiveMode( MaterialNonInteractiveMode_t mode, ShaderNonInteractiveInfo_t *pInfo = NULL );
+ virtual void RefreshFrontBufferNonInteractive();
+ virtual char *GetDisplayDeviceName() OVERRIDE;
+
+ // Alternative method for ib/vs
+ // NOTE: If this works, remove GetDynamicVertexBuffer/IndexBuffer
+
+ // Methods of CShaderDeviceBase
+public:
+ virtual bool InitDevice( void* hWnd, int nAdapter, const ShaderDeviceInfo_t &info );
+ virtual void ShutdownDevice();
+ virtual bool IsDeactivated() const;
+
+ // Other public methods
+public:
+ // constructor, destructor
+ CShaderDeviceDx8();
+ virtual ~CShaderDeviceDx8();
+
+ // Call this when another app is initializing or finished initializing
+ virtual void OtherAppInitializing( bool initializing );
+
+ // This handles any events queued because they were called outside of the owning thread
+ virtual void HandleThreadEvent( uint32 threadEvent );
+
+ // FIXME: Make private
+ // Which device are we using?
+ UINT m_DisplayAdapter;
+ D3DDEVTYPE m_DeviceType;
+
+protected:
+ enum DeviceState_t
+ {
+ DEVICE_STATE_OK = 0,
+ DEVICE_STATE_OTHER_APP_INIT,
+ DEVICE_STATE_LOST_DEVICE,
+ DEVICE_STATE_NEEDS_RESET,
+ };
+
+ struct NonInteractiveRefreshState_t
+ {
+ IDirect3DVertexShader9 *m_pVertexShader;
+ IDirect3DPixelShader9 *m_pPixelShader;
+ IDirect3DPixelShader9 *m_pPixelShaderStartup;
+ IDirect3DPixelShader9 *m_pPixelShaderStartupPass2;
+ IDirect3DVertexDeclaration9 *m_pVertexDecl;
+ ShaderNonInteractiveInfo_t m_Info;
+ MaterialNonInteractiveMode_t m_Mode;
+ float m_flLastPacifierTime;
+ int m_nPacifierFrame;
+
+ float m_flStartTime;
+ float m_flLastPresentTime;
+ float m_flPeakDt;
+ float m_flTotalDt;
+ int m_nSamples;
+ int m_nCountAbove66;
+ };
+
+protected:
+ // Creates the D3D Device
+ bool CreateD3DDevice( void* pHWnd, int nAdapter, const ShaderDeviceInfo_t &info );
+
+ // Actually creates the D3D Device once the present parameters are set up
+ IDirect3DDevice9* InvokeCreateDevice( void* hWnd, int nAdapter, DWORD deviceCreationFlags );
+
+ // Checks for CreateQuery support
+ void DetectQuerySupport( IDirect3DDevice9* pD3DDevice );
+
+ // Computes the presentation parameters
+ void SetPresentParameters( void* hWnd, int nAdapter, const ShaderDeviceInfo_t &info );
+
+ // Computes the supersample flags
+ D3DMULTISAMPLE_TYPE ComputeMultisampleType( int nSampleCount );
+
+ // Is the device active?
+ bool IsActive() const;
+
+ // Try to reset the device, returned true if it succeeded
+ bool TryDeviceReset();
+
+ // Queue up the fact that the device was lost
+ void MarkDeviceLost();
+
+ // Deals with lost devices
+ void CheckDeviceLost( bool bOtherAppInitializing );
+
+ // Changes the window size
+ bool ResizeWindow( const ShaderDeviceInfo_t &info );
+
+ // Deals with the frame synching object
+ void AllocFrameSyncObjects( void );
+ void FreeFrameSyncObjects( void );
+
+ // Alloc and free objects that are necessary for frame syncing
+ void AllocFrameSyncTextureObject();
+ void FreeFrameSyncTextureObject();
+
+ // Alloc and free objects necessary for noninteractive frame refresh on the x360
+ bool AllocNonInteractiveRefreshObjects();
+ void FreeNonInteractiveRefreshObjects();
+
+ // FIXME: This is for backward compat; I still haven't solved a way of decoupling this
+ virtual bool OnAdapterSet() = 0;
+ virtual void ResetRenderState( bool bFullReset = true ) = 0;
+
+ // For measuring if we meed TCR 022 on the XBox (refreshing often enough)
+ void UpdatePresentStats();
+
+ bool InNonInteractiveMode() const;
+
+ void ReacquireResourcesInternal( bool bResetState = false, bool bForceReacquire = false, char const *pszForceReason = NULL );
+
+#ifdef DX_TO_GL_ABSTRACTION
+public:
+ virtual void DoStartupShaderPreloading( void );
+protected:
+#endif
+
+ D3DPRESENT_PARAMETERS m_PresentParameters;
+ ImageFormat m_AdapterFormat;
+
+ // Mode info
+ int m_DeviceSupportsCreateQuery;
+
+ ShaderDeviceInfo_t m_PendingVideoModeChangeConfig;
+ DeviceState_t m_DeviceState;
+
+ bool m_bOtherAppInitializing : 1;
+ bool m_bQueuedDeviceLost : 1;
+ bool m_IsResizing : 1;
+ bool m_bPendingVideoModeChange : 1;
+ bool m_bUsingStencil : 1;
+ bool m_bResourcesReleased : 1;
+
+ // amount of stencil variation we have available
+ int m_iStencilBufferBits;
+
+#ifdef _X360
+ CON_COMMAND_MEMBER_F( CShaderDeviceDx8, "360vidinfo", SpewVideoInfo360, "Get information on the video mode on the 360", 0 );
+#endif
+
+ // Frame sync objects
+ IDirect3DQuery9 *m_pFrameSyncQueryObject[NUM_FRAME_SYNC_QUERIES];
+ bool m_bQueryIssued[NUM_FRAME_SYNC_QUERIES];
+ int m_currentSyncQuery;
+ IDirect3DTexture9 *m_pFrameSyncTexture;
+
+#if defined( _X360 )
+ HXUIDC m_hDC;
+#endif
+
+ CUtlString m_sDisplayDeviceName;
+
+ // Used for x360 only
+ NonInteractiveRefreshState_t m_NonInteractiveRefresh;
+ CThreadFastMutex m_nonInteractiveModeMutex;
+ friend class CShaderDeviceMgrDx8;
+
+ int m_numReleaseResourcesRefCount; // This is holding the number of ReleaseResources calls queued up,
+ // for every ReleaseResources call there should be a matching call to
+ // ReacquireResources, only the last top-level ReacquireResources will
+ // have effect. Nested ReleaseResources calls are bugs.
+};
+
+
+//-----------------------------------------------------------------------------
+// Globals
+//-----------------------------------------------------------------------------
+extern IDirect3DDevice9 *g_pD3DDevice;
+FORCEINLINE IDirect3DDevice9 *Dx9Device()
+{
+ return g_pD3DDevice;
+}
+
+extern CShaderDeviceDx8* g_pShaderDeviceDx8;
+
+
+//-----------------------------------------------------------------------------
+// Inline methods
+//-----------------------------------------------------------------------------
+FORCEINLINE bool CShaderDeviceDx8::IsActive() const
+{
+ return ( g_pD3DDevice != NULL );
+}
+
+// used to determine if we're deactivated
+FORCEINLINE bool CShaderDeviceDx8::IsDeactivated() const
+{
+ return ( IsPC() && ( ( m_DeviceState != DEVICE_STATE_OK ) || m_bQueuedDeviceLost || m_numReleaseResourcesRefCount ) );
+}
+
+
+#endif // SHADERDEVICEDX8_H
diff --git a/materialsystem/shaderapidx9/shadershadowdx10.cpp b/materialsystem/shaderapidx9/shadershadowdx10.cpp
new file mode 100644
index 0000000..d67cc4b
--- /dev/null
+++ b/materialsystem/shaderapidx9/shadershadowdx10.cpp
@@ -0,0 +1,227 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#include "shadershadowdx10.h"
+#include "utlvector.h"
+#include "materialsystem/imaterialsystem.h"
+#include "IHardwareConfigInternal.h"
+#include "shadersystem.h"
+#include "shaderapi/ishaderutil.h"
+#include "materialsystem/imesh.h"
+#include "tier0/dbg.h"
+#include "materialsystem/idebugtextureinfo.h"
+
+
+//-----------------------------------------------------------------------------
+// Class Factory
+//-----------------------------------------------------------------------------
+static CShaderShadowDx10 s_ShaderShadow;
+CShaderShadowDx10 *g_pShaderShadowDx10 = &s_ShaderShadow;
+
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CShaderShadowDx10, IShaderShadow,
+ SHADERSHADOW_INTERFACE_VERSION, s_ShaderShadow )
+
+//-----------------------------------------------------------------------------
+// The shader shadow interface
+//-----------------------------------------------------------------------------
+CShaderShadowDx10::CShaderShadowDx10()
+{
+ m_IsTranslucent = false;
+ m_IsAlphaTested = false;
+ m_bIsDepthWriteEnabled = true;
+ m_bUsesVertexAndPixelShaders = false;
+}
+
+CShaderShadowDx10::~CShaderShadowDx10()
+{
+}
+
+// Sets the default *shadow* state
+void CShaderShadowDx10::SetDefaultState()
+{
+ m_IsTranslucent = false;
+ m_IsAlphaTested = false;
+ m_bIsDepthWriteEnabled = true;
+ m_bUsesVertexAndPixelShaders = false;
+}
+
+// Methods related to depth buffering
+void CShaderShadowDx10::DepthFunc( ShaderDepthFunc_t depthFunc )
+{
+}
+
+void CShaderShadowDx10::EnableDepthWrites( bool bEnable )
+{
+ m_bIsDepthWriteEnabled = bEnable;
+}
+
+void CShaderShadowDx10::EnableDepthTest( bool bEnable )
+{
+}
+
+void CShaderShadowDx10::EnablePolyOffset( PolygonOffsetMode_t nOffsetMode )
+{
+}
+
+// Suppresses/activates color writing
+void CShaderShadowDx10::EnableColorWrites( bool bEnable )
+{
+}
+
+// Suppresses/activates alpha writing
+void CShaderShadowDx10::EnableAlphaWrites( bool bEnable )
+{
+}
+
+// Methods related to alpha blending
+void CShaderShadowDx10::EnableBlending( bool bEnable )
+{
+ m_IsTranslucent = bEnable;
+}
+
+void CShaderShadowDx10::BlendFunc( ShaderBlendFactor_t srcFactor, ShaderBlendFactor_t dstFactor )
+{
+}
+
+void CShaderShadowDx10::BlendOp( ShaderBlendOp_t blendOp )
+{
+}
+
+void CShaderShadowDx10::BlendOpSeparateAlpha( ShaderBlendOp_t blendOp )
+{
+}
+
+// A simpler method of dealing with alpha modulation
+void CShaderShadowDx10::EnableAlphaPipe( bool bEnable )
+{
+}
+
+void CShaderShadowDx10::EnableConstantAlpha( bool bEnable )
+{
+}
+
+void CShaderShadowDx10::EnableVertexAlpha( bool bEnable )
+{
+}
+
+void CShaderShadowDx10::EnableTextureAlpha( TextureStage_t stage, bool bEnable )
+{
+}
+
+void CShaderShadowDx10::SetShadowDepthFiltering( Sampler_t stage )
+{
+}
+
+// Alpha testing
+void CShaderShadowDx10::EnableAlphaTest( bool bEnable )
+{
+ m_IsAlphaTested = bEnable;
+}
+
+void CShaderShadowDx10::AlphaFunc( ShaderAlphaFunc_t alphaFunc, float alphaRef /* [0-1] */ )
+{
+}
+
+// Wireframe/filled polygons
+void CShaderShadowDx10::PolyMode( ShaderPolyModeFace_t face, ShaderPolyMode_t polyMode )
+{
+}
+
+
+// Back face culling
+void CShaderShadowDx10::EnableCulling( bool bEnable )
+{
+}
+
+// Alpha to coverage
+void CShaderShadowDx10::EnableAlphaToCoverage( bool bEnable )
+{
+}
+
+// constant color + transparency
+void CShaderShadowDx10::EnableConstantColor( bool bEnable )
+{
+}
+
+
+// Indicates the vertex format for use with a vertex shader
+// The flags to pass in here come from the VertexFormatFlags_t enum
+// If pTexCoordDimensions is *not* specified, we assume all coordinates
+// are 2-dimensional
+void CShaderShadowDx10::VertexShaderVertexFormat( unsigned int flags,
+ int numTexCoords, int* pTexCoordDimensions,
+ int userDataSize )
+{
+}
+
+// Indicates we're going to light the model
+void CShaderShadowDx10::EnableLighting( bool bEnable )
+{
+}
+
+void CShaderShadowDx10::EnableSpecular( bool bEnable )
+{
+}
+
+// Activate/deactivate skinning
+void CShaderShadowDx10::EnableVertexBlend( bool bEnable )
+{
+}
+
+// per texture unit stuff
+void CShaderShadowDx10::OverbrightValue( TextureStage_t stage, float value )
+{
+}
+
+void CShaderShadowDx10::EnableTexture( Sampler_t stage, bool bEnable )
+{
+}
+
+void CShaderShadowDx10::EnableCustomPixelPipe( bool bEnable )
+{
+}
+
+void CShaderShadowDx10::CustomTextureStages( int stageCount )
+{
+}
+
+void CShaderShadowDx10::CustomTextureOperation( TextureStage_t stage, ShaderTexChannel_t channel,
+ ShaderTexOp_t op, ShaderTexArg_t arg1, ShaderTexArg_t arg2 )
+{
+}
+
+void CShaderShadowDx10::EnableTexGen( TextureStage_t stage, bool bEnable )
+{
+}
+
+void CShaderShadowDx10::TexGen( TextureStage_t stage, ShaderTexGenParam_t param )
+{
+}
+
+// Sets the vertex and pixel shaders
+void CShaderShadowDx10::SetVertexShader( const char *pShaderName, int vshIndex )
+{
+ m_bUsesVertexAndPixelShaders = ( pShaderName != NULL );
+}
+
+void CShaderShadowDx10::EnableBlendingSeparateAlpha( bool bEnable )
+{
+}
+void CShaderShadowDx10::SetPixelShader( const char *pShaderName, int pshIndex )
+{
+ m_bUsesVertexAndPixelShaders = ( pShaderName != NULL );
+}
+
+void CShaderShadowDx10::BlendFuncSeparateAlpha( ShaderBlendFactor_t srcFactor, ShaderBlendFactor_t dstFactor )
+{
+}
+// indicates what per-vertex data we're providing
+void CShaderShadowDx10::DrawFlags( unsigned int drawFlags )
+{
+}
+
diff --git a/materialsystem/shaderapidx9/shadershadowdx8.cpp b/materialsystem/shaderapidx9/shadershadowdx8.cpp
new file mode 100644
index 0000000..8c231c9
--- /dev/null
+++ b/materialsystem/shaderapidx9/shadershadowdx8.cpp
@@ -0,0 +1,1826 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#define DISABLE_PROTECTED_THINGS
+#include "togl/rendermechanism.h"
+#include "shadershadowdx8.h"
+#include "locald3dtypes.h"
+#include "utlvector.h"
+#include "shaderapi/ishaderutil.h"
+#include "shaderapidx8_global.h"
+#include "shaderapidx8.h"
+#include "materialsystem/imaterialsystemhardwareconfig.h"
+#include "materialsystem/imaterialsystem.h"
+#include "imeshdx8.h"
+#include "materialsystem/materialsystem_config.h"
+#include "vertexshaderdx8.h"
+
+// NOTE: This must be the last file included!
+#include "tier0/memdbgon.h"
+
+
+//-----------------------------------------------------------------------------
+// The DX8 implementation of the shader setup interface
+//-----------------------------------------------------------------------------
+class CShaderShadowDX8 : public IShaderShadowDX8
+{
+public:
+ // constructor, destructor
+ CShaderShadowDX8( );
+ virtual ~CShaderShadowDX8();
+
+ // Initialize render state
+ void Init( );
+
+ // Sets the default state
+ void SetDefaultState();
+
+ // Methods related to depth buffering
+ void DepthFunc( ShaderDepthFunc_t depthFunc );
+ void EnableDepthWrites( bool bEnable );
+ void EnableDepthTest( bool bEnable );
+ void EnablePolyOffset( PolygonOffsetMode_t nOffsetMode );
+
+ // Methods related to stencil. obsolete
+ virtual void EnableStencil( bool bEnable )
+ {
+ }
+ virtual void StencilFunc( ShaderStencilFunc_t stencilFunc )
+ {
+ }
+ virtual void StencilPassOp( ShaderStencilOp_t stencilOp )
+ {
+ }
+ virtual void StencilFailOp( ShaderStencilOp_t stencilOp )
+ {
+ }
+ virtual void StencilDepthFailOp( ShaderStencilOp_t stencilOp )
+ {
+ }
+ virtual void StencilReference( int nReference )
+ {
+ }
+ virtual void StencilMask( int nMask )
+ {
+ }
+ virtual void StencilWriteMask( int nMask )
+ {
+ }
+
+ // Suppresses/activates color writing
+ void EnableColorWrites( bool bEnable );
+ void EnableAlphaWrites( bool bEnable );
+
+ // Methods related to alpha blending
+ void EnableBlending( bool bEnable );
+
+ void BlendFunc( ShaderBlendFactor_t srcFactor, ShaderBlendFactor_t dstFactor );
+ void BlendOp( ShaderBlendOp_t blendOp );
+ void BlendOpSeparateAlpha( ShaderBlendOp_t blendOp );
+
+ // Alpha testing
+ void EnableAlphaTest( bool bEnable );
+ void AlphaFunc( ShaderAlphaFunc_t alphaFunc, float alphaRef /* [0-1] */ );
+
+ // Wireframe/filled polygons
+ void PolyMode( ShaderPolyModeFace_t face, ShaderPolyMode_t polyMode );
+
+ // Back face culling
+ void EnableCulling( bool bEnable );
+
+ // constant color
+ void EnableConstantColor( bool bEnable );
+
+ // Indicates we're going to light the model
+ void EnableLighting( bool bEnable );
+
+ // Indicates specular lighting is going to be used
+ void EnableSpecular( bool bEnable );
+
+ // Convert from linear to gamma color space on writes to frame buffer.
+ void EnableSRGBWrite( bool bEnable );
+
+ // Convert from gamma to linear on texture fetch.
+ void EnableSRGBRead( Sampler_t stage, bool bEnable );
+
+ // Set up appropriate shadow filtering state (such as Fetch4 on ATI)
+ void SetShadowDepthFiltering( Sampler_t stage );
+
+ // Computes the vertex format
+ virtual void VertexShaderVertexFormat( unsigned int nFlags,
+ int nTexCoordCount, int* pTexCoordDimensions, int nUserDataSize );
+
+ // Pixel and vertex shader methods
+ virtual void SetVertexShader( const char* pFileName, int nStaticVshIndex );
+ virtual void SetPixelShader( const char* pFileName, int nStaticPshIndex );
+
+ // Indicates we're going to be using the ambient cube
+ void EnableAmbientLightCubeOnStage0( bool bEnable );
+
+ // Activate/deactivate skinning
+ void EnableVertexBlend( bool bEnable );
+
+ // per texture unit stuff
+ void OverbrightValue( TextureStage_t stage, float value );
+ void EnableTexture( Sampler_t stage, bool bEnable );
+ void EnableTexGen( TextureStage_t stage, bool bEnable );
+ void TexGen( TextureStage_t stage, ShaderTexGenParam_t param );
+ void TextureCoordinate( TextureStage_t stage, int useCoord );
+
+ // alternate method of specifying per-texture unit stuff, more flexible and more complicated
+ // Can be used to specify different operation per channel (alpha/color)...
+ void EnableCustomPixelPipe( bool bEnable );
+ void CustomTextureStages( int stageCount );
+ void CustomTextureOperation( TextureStage_t stage, ShaderTexChannel_t channel,
+ ShaderTexOp_t op, ShaderTexArg_t arg1, ShaderTexArg_t arg2 );
+
+ // A simpler method of dealing with alpha modulation
+ void EnableAlphaPipe( bool bEnable );
+ void EnableConstantAlpha( bool bEnable );
+ void EnableVertexAlpha( bool bEnable );
+ void EnableTextureAlpha( TextureStage_t stage, bool bEnable );
+
+ // helper functions
+ void EnableSphereMapping( TextureStage_t stage, bool bEnable );
+
+ // Last call to be make before snapshotting
+ void ComputeAggregateShadowState( );
+
+ // Gets at the shadow state
+ const ShadowState_t & GetShadowState();
+ const ShadowShaderState_t & GetShadowShaderState();
+
+ // GR - Separate alpha blending
+ void EnableBlendingSeparateAlpha( bool bEnable );
+ void BlendFuncSeparateAlpha( ShaderBlendFactor_t srcFactor, ShaderBlendFactor_t dstFactor );
+
+ void FogMode( ShaderFogMode_t fogMode );
+ void DisableFogGammaCorrection( bool bDisable );
+
+ void SetDiffuseMaterialSource( ShaderMaterialSource_t materialSource );
+ virtual void SetMorphFormat( MorphFormat_t flags );
+
+ // Alpha to coverage
+ void EnableAlphaToCoverage( bool bEnable );
+
+private:
+ struct TextureStageState_t
+ {
+ int m_TexCoordIndex;
+ int m_TexCoordinate;
+ float m_OverbrightVal;
+ ShaderTexArg_t m_Arg[2][2];
+ ShaderTexOp_t m_Op[2];
+ unsigned char m_TexGenEnable:1;
+ unsigned char m_TextureAlphaEnable:1;
+ };
+
+ struct SamplerState_t
+ {
+ bool m_TextureEnable : 1;
+ };
+
+ // Computes the blend factor
+ D3DBLEND BlendFuncValue( ShaderBlendFactor_t factor ) const;
+
+ // Computes the blend op
+ D3DBLENDOP BlendOpValue( ShaderBlendOp_t blendOp ) const;
+
+ // Configures the FVF vertex shader
+ void ConfigureFVFVertexShader( unsigned int flags );
+ void ConfigureCustomFVFVertexShader( unsigned int flags );
+
+ // Configures our texture indices
+ void ConfigureTextureCoordinates( unsigned int flags );
+
+ // Returns a blend value based on overbrighting
+ D3DTEXTUREOP OverbrightBlendValue( TextureStage_t stage );
+
+ // Sets the desired color and alpha op state
+ void DrawFlags( unsigned int flags );
+
+ // Computes a vertex format for the draw flags
+ VertexFormat_t FlagsToVertexFormat( int flags ) const;
+
+ // Indicates we've got a constant color specified
+ bool HasConstantColor() const;
+
+ // Configures the alpha pipe
+ void ConfigureAlphaPipe( unsigned int flags );
+
+ // returns true if we're using texture coordinates at a given stage
+ bool IsUsingTextureCoordinates( Sampler_t stage ) const;
+
+ // Recomputes the tex coord index
+ void RecomputeTexCoordIndex( TextureStage_t stage );
+
+
+ // State needed to create the snapshots
+ IMaterialSystemHardwareConfig* m_pHardwareConfig;
+
+ // Separate alpha control?
+ bool m_AlphaPipe;
+
+ // Constant color state
+ bool m_HasConstantColor;
+ bool m_HasConstantAlpha;
+
+ // Vertex color state
+ bool m_HasVertexAlpha;
+
+ // funky custom method of specifying shader state
+ bool m_CustomTextureStageState;
+
+ // Number of stages used by the custom pipeline
+ int m_CustomTextureStages;
+
+ // Number of bones...
+ int m_NumBlendVertices;
+
+ // Draw flags
+ int m_DrawFlags;
+
+ // Alpha blending...
+ D3DBLEND m_SrcBlend;
+ D3DBLEND m_DestBlend;
+ D3DBLENDOP m_BlendOp;
+
+ // GR - Separate alpha blending...
+ D3DBLEND m_SrcBlendAlpha;
+ D3DBLEND m_DestBlendAlpha;
+ D3DBLENDOP m_BlendOpAlpha;
+
+ // Alpha testing
+ D3DCMPFUNC m_AlphaFunc;
+ int m_AlphaRef;
+
+ // Stencil
+ D3DCMPFUNC m_StencilFunc;
+ int m_StencilRef;
+ int m_StencilMask;
+ DWORD m_StencilFail;
+ DWORD m_StencilZFail;
+ DWORD m_StencilPass;
+ int m_StencilWriteMask;
+
+ // The current shadow state
+ ShadowState_t m_ShadowState;
+ ShadowShaderState_t m_ShadowShaderState;
+
+ // State info stores with each texture stage
+ TextureStageState_t m_TextureStage[MAX_TEXTURE_STAGES];
+ SamplerState_t m_SamplerState[MAX_SAMPLERS];
+};
+
+
+//-----------------------------------------------------------------------------
+// Class factory
+//-----------------------------------------------------------------------------
+static CShaderShadowDX8 g_ShaderShadow;
+IShaderShadowDX8 *g_pShaderShadowDx8 = &g_ShaderShadow;
+
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CShaderShadowDX8, IShaderShadow,
+ SHADERSHADOW_INTERFACE_VERSION, g_ShaderShadow )
+
+//-----------------------------------------------------------------------------
+// Global instance
+//-----------------------------------------------------------------------------
+IShaderShadowDX8* ShaderShadow()
+{
+ return &g_ShaderShadow;
+}
+
+
+//-----------------------------------------------------------------------------
+// Constructor, destructor
+//-----------------------------------------------------------------------------
+CShaderShadowDX8::CShaderShadowDX8( ) :
+ m_DrawFlags(0), m_pHardwareConfig(0), m_HasConstantColor(false)
+{
+ memset( &m_ShadowState, 0, sizeof(m_ShadowState) );
+ memset( &m_TextureStage, 0, sizeof(m_TextureStage) );
+}
+
+CShaderShadowDX8::~CShaderShadowDX8()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Initialize render state
+//-----------------------------------------------------------------------------
+void CShaderShadowDX8::Init( )
+{
+ m_pHardwareConfig = HardwareConfig();
+
+ // Clear out the shadow state
+ memset( &m_ShadowState, 0, sizeof(m_ShadowState) );
+
+ // No funky custom methods..
+ m_CustomTextureStageState = false;
+
+ // No constant color modulation
+ m_HasConstantColor = false;
+ m_HasConstantAlpha = false;
+ m_HasVertexAlpha = false;
+
+ m_ShadowShaderState.m_ModulateConstantColor = false;
+
+ m_ShadowState.m_bDisableFogGammaCorrection = false;
+
+ // By default we're using fixed function
+ m_ShadowState.m_UsingFixedFunction = true;
+
+ // Lighting off by default
+ m_ShadowState.m_Lighting = false;
+
+ // Pixel + vertex shaders
+ m_ShadowShaderState.m_VertexShader = INVALID_SHADER;
+ m_ShadowShaderState.m_PixelShader = INVALID_SHADER;
+ m_ShadowShaderState.m_nStaticPshIndex = 0;
+ m_ShadowShaderState.m_nStaticVshIndex = 0;
+ m_ShadowShaderState.m_VertexUsage = 0;
+
+ // Drawing nothing..
+ m_DrawFlags = 0;
+
+ // No alpha control
+ m_AlphaPipe = false;
+
+ // Vertex blending
+ m_NumBlendVertices = 0;
+ m_ShadowState.m_VertexBlendEnable = false;
+
+ // NOTE: If you change these defaults, change the code in ComputeAggregateShadowState + CreateTransitionTableEntry
+ int i;
+ for (i = 0; i < MAX_TEXTURE_STAGES; ++i)
+ {
+ m_ShadowState.m_TextureStage[i].m_ColorOp = D3DTOP_DISABLE;
+ m_ShadowState.m_TextureStage[i].m_ColorArg1 = D3DTA_TEXTURE;
+ m_ShadowState.m_TextureStage[i].m_ColorArg2 = (i == 0) ? D3DTA_DIFFUSE : D3DTA_CURRENT;
+ m_ShadowState.m_TextureStage[i].m_AlphaOp = D3DTOP_DISABLE;
+ m_ShadowState.m_TextureStage[i].m_AlphaArg1 = D3DTA_TEXTURE;
+ m_ShadowState.m_TextureStage[i].m_AlphaArg2 = (i == 0) ? D3DTA_DIFFUSE : D3DTA_CURRENT;
+ m_ShadowState.m_TextureStage[i].m_TexCoordIndex = i;
+ }
+
+ for (i = 0; i < MAX_SAMPLERS; ++i)
+ {
+ m_ShadowState.m_SamplerState[i].m_TextureEnable = false;
+ m_ShadowState.m_SamplerState[i].m_SRGBReadEnable = false;
+ m_ShadowState.m_SamplerState[i].m_Fetch4Enable = false;
+#ifdef DX_TO_GL_ABSTRACTION
+ m_ShadowState.m_SamplerState[i].m_ShadowFilterEnable = false;
+#endif
+ // A *real* measure if the texture stage is being used.
+ // we sometimes have to set the shadow state to not mirror this.
+ m_SamplerState[i].m_TextureEnable = false;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the default state
+//-----------------------------------------------------------------------------
+void CShaderShadowDX8::SetDefaultState()
+{
+ DepthFunc( SHADER_DEPTHFUNC_NEAREROREQUAL );
+ EnableDepthWrites( true );
+ EnableDepthTest( true );
+ EnableColorWrites( true );
+ EnableAlphaWrites( false );
+ EnableAlphaTest( false );
+ EnableLighting( false );
+ EnableConstantColor( false );
+ EnableBlending( false );
+ BlendFunc( SHADER_BLEND_ONE, SHADER_BLEND_ZERO );
+ BlendOp( SHADER_BLEND_OP_ADD );
+ // GR - separate alpha
+ EnableBlendingSeparateAlpha( false );
+ BlendFuncSeparateAlpha( SHADER_BLEND_ONE, SHADER_BLEND_ZERO );
+ BlendOpSeparateAlpha( SHADER_BLEND_OP_ADD );
+ AlphaFunc( SHADER_ALPHAFUNC_GEQUAL, 0.7f );
+ PolyMode( SHADER_POLYMODEFACE_FRONT_AND_BACK, SHADER_POLYMODE_FILL );
+ EnableCulling( true );
+ EnableAlphaToCoverage( false );
+ EnablePolyOffset( SHADER_POLYOFFSET_DISABLE );
+ EnableVertexBlend( false );
+ EnableSpecular( false );
+ EnableSRGBWrite( false );
+ DrawFlags( SHADER_DRAW_POSITION );
+ EnableCustomPixelPipe( false );
+ CustomTextureStages( 0 );
+ EnableAlphaPipe( false );
+ EnableConstantAlpha( false );
+ EnableVertexAlpha( false );
+ SetVertexShader( NULL, 0 );
+ SetPixelShader( NULL, 0 );
+ FogMode( SHADER_FOGMODE_DISABLED );
+ DisableFogGammaCorrection( false );
+ SetDiffuseMaterialSource( SHADER_MATERIALSOURCE_MATERIAL );
+ EnableStencil( false );
+ StencilFunc( SHADER_STENCILFUNC_ALWAYS );
+ StencilPassOp( SHADER_STENCILOP_KEEP );
+ StencilFailOp( SHADER_STENCILOP_KEEP );
+ StencilDepthFailOp( SHADER_STENCILOP_KEEP );
+ StencilReference( 0 );
+ StencilMask( 0xFFFFFFFF );
+ StencilWriteMask( 0xFFFFFFFF );
+ m_ShadowShaderState.m_VertexUsage = 0;
+
+ int i;
+ int nSamplerCount = HardwareConfig()->GetSamplerCount();
+ for( i = 0; i < nSamplerCount; i++ )
+ {
+ EnableTexture( (Sampler_t)i, false );
+ EnableSRGBRead( (Sampler_t)i, false );
+ }
+
+ int nTextureStageCount = HardwareConfig()->GetTextureStageCount();
+ for( i = 0; i < nTextureStageCount; i++ )
+ {
+ EnableTexGen( (TextureStage_t)i, false );
+ OverbrightValue( (TextureStage_t)i, 1.0f );
+ EnableTextureAlpha( (TextureStage_t)i, false );
+ CustomTextureOperation( (TextureStage_t)i, SHADER_TEXCHANNEL_COLOR,
+ SHADER_TEXOP_DISABLE, SHADER_TEXARG_TEXTURE, SHADER_TEXARG_PREVIOUSSTAGE );
+ CustomTextureOperation( (TextureStage_t)i, SHADER_TEXCHANNEL_ALPHA,
+ SHADER_TEXOP_DISABLE, SHADER_TEXARG_TEXTURE, SHADER_TEXARG_PREVIOUSSTAGE );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets at the shadow state
+//-----------------------------------------------------------------------------
+const ShadowState_t &CShaderShadowDX8::GetShadowState()
+{
+ return m_ShadowState;
+}
+
+const ShadowShaderState_t &CShaderShadowDX8::GetShadowShaderState()
+{
+ return m_ShadowShaderState;
+}
+
+
+//-----------------------------------------------------------------------------
+// Depth functions...
+//-----------------------------------------------------------------------------
+void CShaderShadowDX8::DepthFunc( ShaderDepthFunc_t depthFunc )
+{
+ D3DCMPFUNC zFunc;
+
+ switch( depthFunc )
+ {
+ case SHADER_DEPTHFUNC_NEVER:
+ zFunc = D3DCMP_NEVER;
+ break;
+ case SHADER_DEPTHFUNC_NEARER:
+ zFunc = (ShaderUtil()->GetConfig().bReverseDepth ^ ReverseDepthOnX360()) ? D3DCMP_GREATER : D3DCMP_LESS;
+ break;
+ case SHADER_DEPTHFUNC_EQUAL:
+ zFunc = D3DCMP_EQUAL;
+ break;
+ case SHADER_DEPTHFUNC_NEAREROREQUAL:
+ zFunc = (ShaderUtil()->GetConfig().bReverseDepth ^ ReverseDepthOnX360()) ? D3DCMP_GREATEREQUAL : D3DCMP_LESSEQUAL;
+ break;
+ case SHADER_DEPTHFUNC_FARTHER:
+ zFunc = (ShaderUtil()->GetConfig().bReverseDepth ^ ReverseDepthOnX360()) ? D3DCMP_LESS : D3DCMP_GREATER;
+ break;
+ case SHADER_DEPTHFUNC_NOTEQUAL:
+ zFunc = D3DCMP_NOTEQUAL;
+ break;
+ case SHADER_DEPTHFUNC_FARTHEROREQUAL:
+ zFunc = (ShaderUtil()->GetConfig().bReverseDepth ^ ReverseDepthOnX360()) ? D3DCMP_LESSEQUAL : D3DCMP_GREATEREQUAL;
+ break;
+ case SHADER_DEPTHFUNC_ALWAYS:
+ zFunc = D3DCMP_ALWAYS;
+ break;
+ default:
+ zFunc = D3DCMP_ALWAYS;
+ Warning( "DepthFunc: invalid param\n" );
+ break;
+ }
+
+ m_ShadowState.m_ZFunc = zFunc;
+}
+
+void CShaderShadowDX8::EnableDepthWrites( bool bEnable )
+{
+ m_ShadowState.m_ZWriteEnable = bEnable;
+}
+
+void CShaderShadowDX8::EnableDepthTest( bool bEnable )
+{
+ m_ShadowState.m_ZEnable = bEnable ? D3DZB_TRUE : D3DZB_FALSE;
+}
+
+void CShaderShadowDX8::EnablePolyOffset( PolygonOffsetMode_t nOffsetMode )
+{
+ m_ShadowState.m_ZBias = nOffsetMode;
+}
+
+//-----------------------------------------------------------------------------
+// Color write state
+//-----------------------------------------------------------------------------
+void CShaderShadowDX8::EnableColorWrites( bool bEnable )
+{
+ if (bEnable)
+ {
+ m_ShadowState.m_ColorWriteEnable |= D3DCOLORWRITEENABLE_BLUE |
+ D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED;
+ }
+ else
+ {
+ m_ShadowState.m_ColorWriteEnable &= ~( D3DCOLORWRITEENABLE_BLUE |
+ D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED );
+ }
+}
+
+void CShaderShadowDX8::EnableAlphaWrites( bool bEnable )
+{
+ if (bEnable)
+ {
+ m_ShadowState.m_ColorWriteEnable |= D3DCOLORWRITEENABLE_ALPHA;
+ }
+ else
+ {
+ m_ShadowState.m_ColorWriteEnable &= ~D3DCOLORWRITEENABLE_ALPHA;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Alpha blending states
+//-----------------------------------------------------------------------------
+void CShaderShadowDX8::EnableBlending( bool bEnable )
+{
+ m_ShadowState.m_AlphaBlendEnable = bEnable;
+}
+
+// GR - separate alpha
+void CShaderShadowDX8::EnableBlendingSeparateAlpha( bool bEnable )
+{
+ m_ShadowState.m_SeparateAlphaBlendEnable = bEnable;
+}
+
+void CShaderShadowDX8::EnableAlphaTest( bool bEnable )
+{
+ m_ShadowState.m_AlphaTestEnable = bEnable;
+}
+
+void CShaderShadowDX8::AlphaFunc( ShaderAlphaFunc_t alphaFunc, float alphaRef /* [0-1] */ )
+{
+ D3DCMPFUNC d3dCmpFunc;
+
+ switch( alphaFunc )
+ {
+ case SHADER_ALPHAFUNC_NEVER:
+ d3dCmpFunc = D3DCMP_NEVER;
+ break;
+ case SHADER_ALPHAFUNC_LESS:
+ d3dCmpFunc = D3DCMP_LESS;
+ break;
+ case SHADER_ALPHAFUNC_EQUAL:
+ d3dCmpFunc = D3DCMP_EQUAL;
+ break;
+ case SHADER_ALPHAFUNC_LEQUAL:
+ d3dCmpFunc = D3DCMP_LESSEQUAL;
+ break;
+ case SHADER_ALPHAFUNC_GREATER:
+ d3dCmpFunc = D3DCMP_GREATER;
+ break;
+ case SHADER_ALPHAFUNC_NOTEQUAL:
+ d3dCmpFunc = D3DCMP_NOTEQUAL;
+ break;
+ case SHADER_ALPHAFUNC_GEQUAL:
+ d3dCmpFunc = D3DCMP_GREATEREQUAL;
+ break;
+ case SHADER_ALPHAFUNC_ALWAYS:
+ d3dCmpFunc = D3DCMP_ALWAYS;
+ break;
+ default:
+ Warning( "AlphaFunc: invalid param\n" );
+ return;
+ }
+
+ m_AlphaFunc = d3dCmpFunc;
+ m_AlphaRef = (int)(alphaRef * 255);
+}
+
+D3DBLEND CShaderShadowDX8::BlendFuncValue( ShaderBlendFactor_t factor ) const
+{
+ switch( factor )
+ {
+ case SHADER_BLEND_ZERO:
+ return D3DBLEND_ZERO;
+
+ case SHADER_BLEND_ONE:
+ return D3DBLEND_ONE;
+
+ case SHADER_BLEND_DST_COLOR:
+ return D3DBLEND_DESTCOLOR;
+
+ case SHADER_BLEND_ONE_MINUS_DST_COLOR:
+ return D3DBLEND_INVDESTCOLOR;
+
+ case SHADER_BLEND_SRC_ALPHA:
+ return D3DBLEND_SRCALPHA;
+
+ case SHADER_BLEND_ONE_MINUS_SRC_ALPHA:
+ return D3DBLEND_INVSRCALPHA;
+
+ case SHADER_BLEND_DST_ALPHA:
+ return D3DBLEND_DESTALPHA;
+
+ case SHADER_BLEND_ONE_MINUS_DST_ALPHA:
+ return D3DBLEND_INVDESTALPHA;
+
+ case SHADER_BLEND_SRC_ALPHA_SATURATE:
+ return D3DBLEND_SRCALPHASAT;
+
+ case SHADER_BLEND_SRC_COLOR:
+ return D3DBLEND_SRCCOLOR;
+
+ case SHADER_BLEND_ONE_MINUS_SRC_COLOR:
+ return D3DBLEND_INVSRCCOLOR;
+ }
+
+ Warning( "BlendFunc: invalid factor\n" );
+ return D3DBLEND_ONE;
+}
+
+D3DBLENDOP CShaderShadowDX8::BlendOpValue( ShaderBlendOp_t blendOp ) const
+{
+ switch( blendOp )
+ {
+ case SHADER_BLEND_OP_ADD:
+ return D3DBLENDOP_ADD;
+
+ case SHADER_BLEND_OP_SUBTRACT:
+ return D3DBLENDOP_SUBTRACT;
+
+ case SHADER_BLEND_OP_REVSUBTRACT:
+ return D3DBLENDOP_REVSUBTRACT;
+
+ case SHADER_BLEND_OP_MIN:
+ return D3DBLENDOP_MIN;
+
+ case SHADER_BLEND_OP_MAX:
+ return D3DBLENDOP_MAX;
+ }
+
+ Warning( "BlendOp: invalid op\n" );
+ return D3DBLENDOP_ADD;
+}
+
+void CShaderShadowDX8::BlendFunc( ShaderBlendFactor_t srcFactor, ShaderBlendFactor_t dstFactor )
+{
+ D3DBLEND d3dSrcFactor = BlendFuncValue( srcFactor );
+ D3DBLEND d3dDstFactor = BlendFuncValue( dstFactor );
+ m_SrcBlend = d3dSrcFactor;
+ m_DestBlend = d3dDstFactor;
+}
+
+// GR - separate alpha blend
+void CShaderShadowDX8::BlendFuncSeparateAlpha( ShaderBlendFactor_t srcFactor, ShaderBlendFactor_t dstFactor )
+{
+ D3DBLEND d3dSrcFactor = BlendFuncValue( srcFactor );
+ D3DBLEND d3dDstFactor = BlendFuncValue( dstFactor );
+ m_SrcBlendAlpha = d3dSrcFactor;
+ m_DestBlendAlpha = d3dDstFactor;
+}
+
+void CShaderShadowDX8::BlendOp( ShaderBlendOp_t blendOp )
+{
+ m_BlendOp = BlendOpValue( blendOp );
+}
+
+void CShaderShadowDX8::BlendOpSeparateAlpha( ShaderBlendOp_t blendOp )
+{
+ m_BlendOpAlpha = BlendOpValue( blendOp );
+}
+
+//-----------------------------------------------------------------------------
+// Polygon fill mode states
+//-----------------------------------------------------------------------------
+void CShaderShadowDX8::PolyMode( ShaderPolyModeFace_t face, ShaderPolyMode_t polyMode )
+{
+ // DX8 can't handle different modes on front and back faces
+// FIXME: Assert( face == SHADER_POLYMODEFACE_FRONT_AND_BACK );
+ if (face == SHADER_POLYMODEFACE_BACK)
+ return;
+
+ D3DFILLMODE fillMode;
+ switch( polyMode )
+ {
+ case SHADER_POLYMODE_POINT:
+ fillMode = D3DFILL_POINT;
+ break;
+ case SHADER_POLYMODE_LINE:
+ fillMode = D3DFILL_WIREFRAME;
+ break;
+ case SHADER_POLYMODE_FILL:
+ fillMode = D3DFILL_SOLID;
+ break;
+ default:
+ Warning( "PolyMode: invalid poly mode\n" );
+ return;
+ }
+
+ m_ShadowState.m_FillMode = fillMode;
+}
+
+
+//-----------------------------------------------------------------------------
+// Backface cull states
+//-----------------------------------------------------------------------------
+void CShaderShadowDX8::EnableCulling( bool bEnable )
+{
+ m_ShadowState.m_CullEnable = bEnable;
+}
+
+
+//-----------------------------------------------------------------------------
+// Alpha to coverage
+//-----------------------------------------------------------------------------
+void CShaderShadowDX8::EnableAlphaToCoverage( bool bEnable )
+{
+ m_ShadowState.m_EnableAlphaToCoverage = bEnable;
+}
+
+
+//-----------------------------------------------------------------------------
+// Indicates we've got a constant color specified
+//-----------------------------------------------------------------------------
+bool CShaderShadowDX8::HasConstantColor() const
+{
+ return m_HasConstantColor;
+}
+
+void CShaderShadowDX8::EnableConstantColor( bool bEnable )
+{
+ m_HasConstantColor = bEnable;
+}
+
+
+//-----------------------------------------------------------------------------
+// A simpler method of dealing with alpha modulation
+//-----------------------------------------------------------------------------
+void CShaderShadowDX8::EnableAlphaPipe( bool bEnable )
+{
+ m_AlphaPipe = bEnable;
+}
+
+void CShaderShadowDX8::EnableConstantAlpha( bool bEnable )
+{
+ m_HasConstantAlpha = bEnable;
+}
+
+void CShaderShadowDX8::EnableVertexAlpha( bool bEnable )
+{
+ m_HasVertexAlpha = bEnable;
+}
+
+void CShaderShadowDX8::EnableTextureAlpha( TextureStage_t stage, bool bEnable )
+{
+ if ( stage < m_pHardwareConfig->GetSamplerCount() )
+ {
+ m_TextureStage[stage].m_TextureAlphaEnable = bEnable;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Indicates we're going to light the model
+//-----------------------------------------------------------------------------
+void CShaderShadowDX8::EnableLighting( bool bEnable )
+{
+ m_ShadowState.m_Lighting = bEnable;
+}
+
+
+//-----------------------------------------------------------------------------
+// Enables specular lighting (lighting has also got to be enabled)
+//-----------------------------------------------------------------------------
+void CShaderShadowDX8::EnableSpecular( bool bEnable )
+{
+ m_ShadowState.m_SpecularEnable = bEnable;
+}
+
+//-----------------------------------------------------------------------------
+// Enables auto-conversion from linear to gamma space on write to framebuffer.
+//-----------------------------------------------------------------------------
+void CShaderShadowDX8::EnableSRGBWrite( bool bEnable )
+{
+ if ( m_pHardwareConfig->SupportsSRGB() )
+ {
+ m_ShadowState.m_SRGBWriteEnable = bEnable;
+ }
+ else
+ {
+ m_ShadowState.m_SRGBWriteEnable = false;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Activate/deactivate skinning
+//-----------------------------------------------------------------------------
+void CShaderShadowDX8::EnableVertexBlend( bool bEnable )
+{
+ // Activate/deactivate skinning. Indexed blending is automatically
+ // enabled if it's available for this hardware. When blending is enabled,
+ // we allocate enough room for 3 weights (max allowed)
+ if ((m_pHardwareConfig->MaxBlendMatrices() > 0) || (!bEnable))
+ {
+ m_ShadowState.m_VertexBlendEnable = bEnable;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Texturemapping state
+//-----------------------------------------------------------------------------
+void CShaderShadowDX8::EnableTexture( Sampler_t sampler, bool bEnable )
+{
+ if ( sampler < m_pHardwareConfig->GetSamplerCount() )
+ {
+ m_SamplerState[sampler].m_TextureEnable = bEnable;
+ }
+ else
+ {
+ Warning( "Attempting to bind a texture to an invalid sampler (%d)!\n", sampler );
+ }
+}
+
+void CShaderShadowDX8::EnableSRGBRead( Sampler_t sampler, bool bEnable )
+{
+ if ( !m_pHardwareConfig->SupportsSRGB() )
+ {
+ m_ShadowState.m_SamplerState[sampler].m_SRGBReadEnable = false;
+ return;
+ }
+
+ if ( sampler < m_pHardwareConfig->GetSamplerCount() )
+ {
+ m_ShadowState.m_SamplerState[sampler].m_SRGBReadEnable = bEnable;
+ }
+ else
+ {
+ Warning( "Attempting set SRGBRead state on an invalid sampler (%d)!\n", sampler );
+ }
+}
+
+void CShaderShadowDX8::SetShadowDepthFiltering( Sampler_t stage )
+{
+#ifdef DX_TO_GL_ABSTRACTION
+ if ( stage < m_pHardwareConfig->GetSamplerCount() )
+ {
+ m_ShadowState.m_SamplerState[stage].m_ShadowFilterEnable = true;
+ return;
+ }
+#else
+ if ( !m_pHardwareConfig->SupportsFetch4() )
+ {
+ m_ShadowState.m_SamplerState[stage].m_Fetch4Enable = false;
+ return;
+ }
+
+ if ( stage < m_pHardwareConfig->GetSamplerCount() )
+ {
+ m_ShadowState.m_SamplerState[stage].m_Fetch4Enable = true;
+ return;
+ }
+#endif
+
+ Warning( "Attempting set shadow filtering state on an invalid sampler (%d)!\n", stage );
+}
+
+
+//-----------------------------------------------------------------------------
+// Binds texture coordinates to a particular stage...
+//-----------------------------------------------------------------------------
+void CShaderShadowDX8::TextureCoordinate( TextureStage_t stage, int useTexCoord )
+{
+ if ( stage < m_pHardwareConfig->GetTextureStageCount() )
+ {
+ m_TextureStage[stage].m_TexCoordinate = useTexCoord;
+
+ // Need to recompute the texCoordIndex, since that's affected by this
+ RecomputeTexCoordIndex(stage);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Automatic texture coordinate generation
+//-----------------------------------------------------------------------------
+void CShaderShadowDX8::RecomputeTexCoordIndex( TextureStage_t stage )
+{
+ int texCoordIndex = m_TextureStage[stage].m_TexCoordinate;
+ if (m_TextureStage[stage].m_TexGenEnable)
+ texCoordIndex |= m_TextureStage[stage].m_TexCoordIndex;
+ m_ShadowState.m_TextureStage[stage].m_TexCoordIndex = texCoordIndex;
+}
+
+
+//-----------------------------------------------------------------------------
+// Automatic texture coordinate generation
+//-----------------------------------------------------------------------------
+void CShaderShadowDX8::EnableTexGen( TextureStage_t stage, bool bEnable )
+{
+ if ( stage >= m_pHardwareConfig->GetTextureStageCount() )
+ {
+ Assert( 0 );
+ return;
+ }
+
+ m_TextureStage[stage].m_TexGenEnable = bEnable;
+ RecomputeTexCoordIndex(stage);
+}
+
+//-----------------------------------------------------------------------------
+// Automatic texture coordinate generation
+//-----------------------------------------------------------------------------
+void CShaderShadowDX8::TexGen( TextureStage_t stage, ShaderTexGenParam_t param )
+{
+#ifdef FIXED_FUNCTION_PIPELINE
+ if ( stage >= m_pHardwareConfig->GetTextureStageCount() )
+ return;
+
+ switch( param )
+ {
+ case SHADER_TEXGENPARAM_OBJECT_LINEAR:
+ m_TextureStage[stage].m_TexCoordIndex = 0;
+ break;
+ case SHADER_TEXGENPARAM_EYE_LINEAR:
+ m_TextureStage[stage].m_TexCoordIndex = D3DTSS_TCI_CAMERASPACEPOSITION;
+ break;
+ case SHADER_TEXGENPARAM_SPHERE_MAP:
+ if ( m_pHardwareConfig->SupportsSpheremapping() )
+ {
+ m_TextureStage[stage].m_TexCoordIndex = D3DTSS_TCI_SPHEREMAP;
+ }
+ else
+ {
+ m_TextureStage[stage].m_TexCoordIndex = D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR;
+ }
+ break;
+ case SHADER_TEXGENPARAM_CAMERASPACEREFLECTIONVECTOR:
+ m_TextureStage[stage].m_TexCoordIndex = D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR;
+ break;
+ case SHADER_TEXGENPARAM_CAMERASPACENORMAL:
+ m_TextureStage[stage].m_TexCoordIndex = D3DTSS_TCI_CAMERASPACENORMAL;
+ break;
+ }
+
+ // Set the board state...
+ RecomputeTexCoordIndex(stage);
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Overbrighting
+//-----------------------------------------------------------------------------
+void CShaderShadowDX8::OverbrightValue( TextureStage_t stage, float value )
+{
+ if ( m_pHardwareConfig->SupportsOverbright() &&
+ ( stage < m_pHardwareConfig->GetTextureStageCount() ) )
+ {
+ m_TextureStage[stage].m_OverbrightVal = value;
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// alternate method of specifying per-texture unit stuff, more flexible and more complicated
+// Can be used to specify different operation per channel (alpha/color)...
+//-----------------------------------------------------------------------------
+void CShaderShadowDX8::EnableCustomPixelPipe( bool bEnable )
+{
+ m_CustomTextureStageState = bEnable;
+}
+
+void CShaderShadowDX8::CustomTextureStages( int stageCount )
+{
+ m_CustomTextureStages = stageCount;
+ Assert( stageCount <= m_pHardwareConfig->GetTextureStageCount() );
+ if ( stageCount > m_pHardwareConfig->GetTextureStageCount() )
+ stageCount = m_pHardwareConfig->GetTextureStageCount();
+}
+
+void CShaderShadowDX8::CustomTextureOperation( TextureStage_t stage,
+ ShaderTexChannel_t channel, ShaderTexOp_t op, ShaderTexArg_t arg1, ShaderTexArg_t arg2 )
+{
+ m_TextureStage[stage].m_Op[channel]= op;
+ m_TextureStage[stage].m_Arg[channel][0] = arg1;
+ m_TextureStage[stage].m_Arg[channel][1] = arg2;
+}
+
+
+//-----------------------------------------------------------------------------
+// Compute the vertex format from vertex descriptor flags
+//-----------------------------------------------------------------------------
+void CShaderShadowDX8::VertexShaderVertexFormat( unsigned int nFlags,
+ int nTexCoordCount, int* pTexCoordDimensions, int nUserDataSize )
+{
+ // Code that creates a Mesh should specify whether it contains bone weights+indices, *not* the shader.
+ Assert( ( nFlags & VERTEX_BONE_INDEX ) == 0 );
+ nFlags &= ~VERTEX_BONE_INDEX;
+
+ // This indicates we're using a vertex shader
+ nFlags |= VERTEX_FORMAT_VERTEX_SHADER;
+ m_ShadowShaderState.m_VertexUsage = MeshMgr()->ComputeVertexFormat( nFlags, nTexCoordCount,
+ pTexCoordDimensions, 0, nUserDataSize );
+ m_ShadowState.m_UsingFixedFunction = false;
+
+ // Avoid an error if vertex stream 0 is too narrow
+ if ( CVertexBufferBase::VertexFormatSize( m_ShadowShaderState.m_VertexUsage ) <= 16 )
+ {
+ // FIXME: this is only necessary because we
+ // (a) put the flex normal/position stream in ALL vertex decls
+ // (b) bind stream 0's VB to stream 2 if there is no actual flex data
+ // ...it would be far more sensible to not add stream 2 to all vertex decls.
+ static bool bComplained = false;
+ if( !bComplained )
+ {
+ Warning( "ERROR: shader asking for a too-narrow vertex format - you will see errors if running with debug D3D DLLs!\n\tPadding the vertex format with extra texcoords\n\tWill not warn again.\n" );
+ bComplained = true;
+ }
+ // All vertex formats should contain position...
+ Assert( nFlags & VERTEX_POSITION );
+ nFlags |= VERTEX_POSITION;
+ // This error should occur only if we have zero texcoords, or if we have a single, 1-D texcoord
+ Assert( ( nTexCoordCount == 0 ) ||
+ ( ( nTexCoordCount == 1 ) && pTexCoordDimensions && ( pTexCoordDimensions[0] == 1 ) ) );
+ nTexCoordCount = 1;
+ m_ShadowShaderState.m_VertexUsage = MeshMgr()->ComputeVertexFormat( nFlags, nTexCoordCount, NULL, 0, nUserDataSize );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Compute the vertex format from vertex descriptor flags
+//-----------------------------------------------------------------------------
+void CShaderShadowDX8::SetMorphFormat( MorphFormat_t flags )
+{
+ m_ShadowShaderState.m_MorphUsage = flags;
+}
+
+//-----------------------------------------------------------------------------
+// Pixel and vertex shader methods
+//-----------------------------------------------------------------------------
+void CShaderShadowDX8::SetVertexShader( const char* pFileName, int nStaticVshIndex )
+{
+ char debugLabel[500] = "";
+#ifdef DX_TO_GL_ABSTRACTION
+ Q_snprintf( debugLabel, sizeof(debugLabel), "vs-file %s vs-index %d", pFileName, nStaticVshIndex );
+#endif
+
+ m_ShadowShaderState.m_VertexShader = ShaderManager()->CreateVertexShader( pFileName, nStaticVshIndex, debugLabel );
+ m_ShadowShaderState.m_nStaticVshIndex = nStaticVshIndex;
+}
+
+void CShaderShadowDX8::SetPixelShader( const char* pFileName, int nStaticPshIndex )
+{
+ char debugLabel[500] = "";
+#ifdef DX_TO_GL_ABSTRACTION
+ Q_snprintf( debugLabel, sizeof(debugLabel), "ps-file %s ps-index %d", pFileName, nStaticPshIndex );
+#endif
+
+ m_ShadowShaderState.m_PixelShader = ShaderManager()->CreatePixelShader( pFileName, nStaticPshIndex, debugLabel );
+ m_ShadowShaderState.m_nStaticPshIndex = nStaticPshIndex;
+}
+
+
+//-----------------------------------------------------------------------------
+// NOTE: See Version 5 of this file for NVidia 8-stage shader stuff
+//-----------------------------------------------------------------------------
+inline bool CShaderShadowDX8::IsUsingTextureCoordinates( Sampler_t sampler ) const
+{
+ return m_SamplerState[sampler].m_TextureEnable;
+}
+
+inline D3DTEXTUREOP CShaderShadowDX8::OverbrightBlendValue( TextureStage_t stage )
+{
+ D3DTEXTUREOP colorop;
+ if (m_TextureStage[stage].m_OverbrightVal < 2.0F)
+ colorop = D3DTOP_MODULATE;
+ else if (m_TextureStage[stage].m_OverbrightVal < 4.0F)
+ colorop = D3DTOP_MODULATE2X;
+ else
+ colorop = D3DTOP_MODULATE4X;
+ return colorop;
+}
+
+static inline int ComputeArg( ShaderTexArg_t arg )
+{
+ switch(arg)
+ {
+ case SHADER_TEXARG_TEXTURE:
+ return D3DTA_TEXTURE;
+
+ case SHADER_TEXARG_ZERO:
+ return D3DTA_SPECULAR | D3DTA_COMPLEMENT;
+
+ case SHADER_TEXARG_ONE:
+ return D3DTA_SPECULAR;
+
+ case SHADER_TEXARG_TEXTUREALPHA:
+ return D3DTA_TEXTURE | D3DTA_ALPHAREPLICATE;
+
+ case SHADER_TEXARG_INVTEXTUREALPHA:
+ return D3DTA_TEXTURE | D3DTA_ALPHAREPLICATE | D3DTA_COMPLEMENT;
+
+ case SHADER_TEXARG_NONE:
+ case SHADER_TEXARG_VERTEXCOLOR:
+ return D3DTA_DIFFUSE;
+
+ case SHADER_TEXARG_SPECULARCOLOR:
+ return D3DTA_SPECULAR;
+
+ case SHADER_TEXARG_CONSTANTCOLOR:
+ return D3DTA_TFACTOR;
+
+ case SHADER_TEXARG_PREVIOUSSTAGE:
+ return D3DTA_CURRENT;
+ }
+
+ Assert(0);
+ return D3DTA_TEXTURE;
+}
+
+static inline D3DTEXTUREOP ComputeOp( ShaderTexOp_t op )
+{
+ switch(op)
+ {
+ case SHADER_TEXOP_MODULATE:
+ return D3DTOP_MODULATE;
+
+ case SHADER_TEXOP_MODULATE2X:
+ return D3DTOP_MODULATE2X;
+
+ case SHADER_TEXOP_MODULATE4X:
+ return D3DTOP_MODULATE4X;
+
+ case SHADER_TEXOP_SELECTARG1:
+ return D3DTOP_SELECTARG1;
+
+ case SHADER_TEXOP_SELECTARG2:
+ return D3DTOP_SELECTARG2;
+
+ case SHADER_TEXOP_ADD:
+ return D3DTOP_ADD;
+
+ case SHADER_TEXOP_SUBTRACT:
+ return D3DTOP_SUBTRACT;
+
+ case SHADER_TEXOP_ADDSIGNED2X:
+ return D3DTOP_ADDSIGNED2X;
+
+ case SHADER_TEXOP_BLEND_CONSTANTALPHA:
+ return D3DTOP_BLENDFACTORALPHA;
+
+ case SHADER_TEXOP_BLEND_PREVIOUSSTAGEALPHA:
+ return D3DTOP_BLENDCURRENTALPHA;
+
+ case SHADER_TEXOP_BLEND_TEXTUREALPHA:
+ return D3DTOP_BLENDTEXTUREALPHA;
+
+ case SHADER_TEXOP_MODULATECOLOR_ADDALPHA:
+ return D3DTOP_MODULATECOLOR_ADDALPHA;
+
+ case SHADER_TEXOP_MODULATEINVCOLOR_ADDALPHA:
+ return D3DTOP_MODULATEINVCOLOR_ADDALPHA;
+
+ case SHADER_TEXOP_DOTPRODUCT3:
+ return D3DTOP_DOTPRODUCT3;
+
+ case SHADER_TEXOP_DISABLE:
+ return D3DTOP_DISABLE;
+ }
+
+ Assert(0);
+ return D3DTOP_MODULATE;
+}
+
+void CShaderShadowDX8::ConfigureCustomFVFVertexShader( unsigned int flags )
+{
+ int i;
+ for ( i = 0; i < m_CustomTextureStages; ++i)
+ {
+ m_ShadowState.m_TextureStage[i].m_ColorArg1 = ComputeArg( m_TextureStage[i].m_Arg[0][0] );
+ m_ShadowState.m_TextureStage[i].m_ColorArg2 = ComputeArg( m_TextureStage[i].m_Arg[0][1] );
+ m_ShadowState.m_TextureStage[i].m_AlphaArg1 = ComputeArg( m_TextureStage[i].m_Arg[1][0] );
+ m_ShadowState.m_TextureStage[i].m_AlphaArg2 = ComputeArg( m_TextureStage[i].m_Arg[1][1] );
+ m_ShadowState.m_TextureStage[i].m_ColorOp = ComputeOp( m_TextureStage[i].m_Op[0] );
+ m_ShadowState.m_TextureStage[i].m_AlphaOp = ComputeOp( m_TextureStage[i].m_Op[1] );
+ }
+
+ // Deal with texture stage 1 -> n
+ for ( i = m_CustomTextureStages; i < m_pHardwareConfig->GetTextureStageCount(); ++i )
+ {
+ m_ShadowState.m_TextureStage[i].m_ColorArg1 = D3DTA_TEXTURE;
+ m_ShadowState.m_TextureStage[i].m_ColorArg2 = D3DTA_CURRENT;
+ m_ShadowState.m_TextureStage[i].m_AlphaArg1 = D3DTA_TEXTURE;
+ m_ShadowState.m_TextureStage[i].m_AlphaArg2 = D3DTA_CURRENT;
+ m_ShadowState.m_TextureStage[i].m_ColorOp = D3DTOP_DISABLE;
+ m_ShadowState.m_TextureStage[i].m_AlphaOp = D3DTOP_DISABLE;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets up the alpha texture stage state
+//-----------------------------------------------------------------------------
+void CShaderShadowDX8::ConfigureAlphaPipe( unsigned int flags )
+{
+ // Are we using color?
+ bool isUsingVertexAlpha = m_HasVertexAlpha && ((flags & SHADER_DRAW_COLOR) != 0);
+ bool isUsingConstantAlpha = m_HasConstantAlpha;
+
+ int lastTextureStage = m_pHardwareConfig->GetTextureStageCount() - 1;
+ while ( lastTextureStage >= 0 )
+ {
+ if ( m_TextureStage[lastTextureStage].m_TextureAlphaEnable )
+ break;
+ --lastTextureStage;
+ }
+
+ for ( int i = 0; i < m_pHardwareConfig->GetTextureStageCount(); ++i )
+ {
+ m_ShadowState.m_TextureStage[i].m_AlphaOp = D3DTOP_MODULATE;
+ if ( m_TextureStage[i].m_TextureAlphaEnable )
+ {
+ if (i == 0)
+ {
+ m_ShadowState.m_TextureStage[i].m_AlphaArg1 = D3DTA_TEXTURE;
+ m_ShadowState.m_TextureStage[i].m_AlphaArg2 =
+ isUsingConstantAlpha ? D3DTA_TFACTOR : D3DTA_DIFFUSE;
+ if (!isUsingConstantAlpha && !isUsingVertexAlpha)
+ m_ShadowState.m_TextureStage[i].m_AlphaOp = D3DTOP_SELECTARG1;
+ if (isUsingConstantAlpha)
+ isUsingConstantAlpha = false;
+ else if (isUsingVertexAlpha)
+ isUsingVertexAlpha = false;
+ }
+ else
+ {
+ // Deal with texture stage 0
+ m_ShadowState.m_TextureStage[i].m_AlphaArg1 = D3DTA_TEXTURE;
+ m_ShadowState.m_TextureStage[i].m_AlphaArg2 = D3DTA_CURRENT;
+ }
+ }
+ else
+ {
+ // Blat out unused stages
+ if ((i > lastTextureStage) && !isUsingVertexAlpha && !isUsingConstantAlpha)
+ {
+ m_ShadowState.m_TextureStage[i].m_AlphaArg1 = D3DTA_TEXTURE;
+ m_ShadowState.m_TextureStage[i].m_AlphaArg2 = D3DTA_CURRENT;
+ m_ShadowState.m_TextureStage[i].m_AlphaOp = D3DTOP_DISABLE;
+ continue;
+ }
+
+ // No texture coordinates; try to fold in vertex or constant alpha
+ if (i == 0)
+ {
+ m_ShadowState.m_TextureStage[i].m_AlphaArg1 = D3DTA_TFACTOR;
+ m_ShadowState.m_TextureStage[i].m_AlphaArg2 = D3DTA_DIFFUSE;
+ if (isUsingVertexAlpha)
+ {
+ m_ShadowState.m_TextureStage[i].m_AlphaOp =
+ isUsingConstantAlpha ? D3DTOP_MODULATE : D3DTOP_SELECTARG2;
+ }
+ else
+ {
+ m_ShadowState.m_TextureStage[i].m_AlphaOp = D3DTOP_SELECTARG1;
+ }
+ isUsingVertexAlpha = false;
+ isUsingConstantAlpha = false;
+ }
+ else
+ {
+ m_ShadowState.m_TextureStage[i].m_AlphaArg1 = D3DTA_CURRENT;
+ if (isUsingConstantAlpha)
+ {
+ m_ShadowState.m_TextureStage[i].m_AlphaArg2 = D3DTA_TFACTOR;
+ isUsingConstantAlpha = false;
+ }
+ else if (isUsingVertexAlpha)
+ {
+ m_ShadowState.m_TextureStage[i].m_AlphaArg2 = D3DTA_DIFFUSE;
+ isUsingVertexAlpha = false;
+ }
+ else
+ {
+ m_ShadowState.m_TextureStage[i].m_AlphaArg2 = D3DTA_DIFFUSE;
+ m_ShadowState.m_TextureStage[i].m_AlphaOp = D3DTOP_SELECTARG1;
+ }
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets up the texture stage state
+//-----------------------------------------------------------------------------
+void CShaderShadowDX8::ConfigureFVFVertexShader( unsigned int flags )
+{
+ // For non-modulation, we can't really use the path below...
+ if (m_CustomTextureStageState)
+ {
+ ConfigureCustomFVFVertexShader( flags );
+ return;
+ }
+
+ // Deal with texture stage 0
+ m_ShadowState.m_TextureStage[0].m_ColorArg1 = D3DTA_TEXTURE;
+ m_ShadowState.m_TextureStage[0].m_ColorArg2 = D3DTA_DIFFUSE;
+ m_ShadowState.m_TextureStage[0].m_AlphaArg1 = D3DTA_TEXTURE;
+ m_ShadowState.m_TextureStage[0].m_AlphaArg2 = D3DTA_DIFFUSE;
+
+ // Are we using color?
+ bool isUsingVertexColor = (flags & SHADER_DRAW_COLOR) != 0;
+ bool isUsingConstantColor = (flags & SHADER_HAS_CONSTANT_COLOR) != 0;
+
+ // Are we using texture coordinates?
+ if ( IsUsingTextureCoordinates( SHADER_SAMPLER0 ) )
+ {
+ if (isUsingVertexColor)
+ {
+ m_ShadowState.m_TextureStage[0].m_ColorOp = OverbrightBlendValue(SHADER_TEXTURE_STAGE0);
+ m_ShadowState.m_TextureStage[0].m_AlphaOp = D3DTOP_MODULATE;
+ }
+ else
+ {
+ // Just blend in the constant color here, and don't blend it in below
+ m_ShadowState.m_TextureStage[0].m_ColorArg2 = D3DTA_TFACTOR;
+ m_ShadowState.m_TextureStage[0].m_AlphaArg2 = D3DTA_TFACTOR;
+ isUsingConstantColor = false;
+
+ m_ShadowState.m_TextureStage[0].m_ColorOp = OverbrightBlendValue(SHADER_TEXTURE_STAGE0);
+ m_ShadowState.m_TextureStage[0].m_AlphaOp = D3DTOP_MODULATE;
+ }
+ }
+ else
+ {
+ // Are we using color?
+ if (isUsingVertexColor)
+ {
+ // Color, but no texture
+ if ( m_TextureStage[0].m_OverbrightVal < 2.0f )
+ {
+ // Use diffuse * constant color, if we have a constant color
+ if (isUsingConstantColor)
+ {
+ m_ShadowState.m_TextureStage[0].m_ColorArg1 = D3DTA_TFACTOR;
+ m_ShadowState.m_TextureStage[0].m_AlphaArg1 = D3DTA_TFACTOR;
+ m_ShadowState.m_TextureStage[0].m_ColorOp = OverbrightBlendValue((TextureStage_t)0);
+ m_ShadowState.m_TextureStage[0].m_AlphaOp = D3DTOP_MODULATE;
+
+ // This'll make sure we don't apply the constant color again below
+ isUsingConstantColor = false;
+ }
+ else
+ {
+ m_ShadowState.m_TextureStage[0].m_ColorOp = D3DTOP_SELECTARG2;
+ m_ShadowState.m_TextureStage[0].m_AlphaOp = D3DTOP_SELECTARG2;
+ }
+ }
+ else if (m_TextureStage[0].m_OverbrightVal < 4.0f)
+ {
+ // Produce diffuse + diffuse
+ m_ShadowState.m_TextureStage[0].m_ColorArg1 = D3DTA_DIFFUSE;
+ m_ShadowState.m_TextureStage[0].m_ColorOp = D3DTOP_ADD;
+ m_ShadowState.m_TextureStage[0].m_AlphaOp = D3DTOP_SELECTARG2;
+ }
+ else
+ {
+ // no 4x overbright yet!
+ Assert(0);
+ }
+ }
+ else
+ {
+ // No texture, no color
+ if (isUsingConstantColor)
+ {
+ m_ShadowState.m_TextureStage[0].m_ColorArg1 = D3DTA_TFACTOR;
+ m_ShadowState.m_TextureStage[0].m_AlphaArg1 = D3DTA_TFACTOR;
+ m_ShadowState.m_TextureStage[0].m_ColorOp = D3DTOP_SELECTARG1;
+ m_ShadowState.m_TextureStage[0].m_AlphaOp = D3DTOP_SELECTARG1;
+
+ // This'll make sure we don't apply the constant color again below
+ isUsingConstantColor = false;
+ }
+ else
+ {
+ // Deal with texture stage 0
+ m_ShadowState.m_TextureStage[0].m_ColorArg1 = D3DTA_TFACTOR;
+ m_ShadowState.m_TextureStage[0].m_AlphaArg1 = D3DTA_TFACTOR;
+ m_ShadowState.m_TextureStage[0].m_ColorOp = D3DTOP_SELECTARG1;
+ m_ShadowState.m_TextureStage[0].m_AlphaOp = D3DTOP_SELECTARG1;
+ }
+ }
+ }
+
+ // Deal with texture stage 1 -> n
+ int lastUsedTextureStage = 0;
+ for ( int i = 1; i < m_pHardwareConfig->GetTextureStageCount(); ++i )
+ {
+ m_ShadowState.m_TextureStage[i].m_ColorArg1 = D3DTA_TEXTURE;
+ m_ShadowState.m_TextureStage[i].m_ColorArg2 = D3DTA_CURRENT;
+ m_ShadowState.m_TextureStage[i].m_AlphaArg1 = D3DTA_TEXTURE;
+ m_ShadowState.m_TextureStage[i].m_AlphaArg2 = D3DTA_CURRENT;
+
+ // Not doing anything? Disable the stage
+ if ( !IsUsingTextureCoordinates( (Sampler_t)i ) )
+ {
+ if (m_TextureStage[i].m_OverbrightVal < 2.0f)
+ {
+ m_ShadowState.m_TextureStage[i].m_ColorOp = D3DTOP_DISABLE;
+ m_ShadowState.m_TextureStage[i].m_AlphaOp = D3DTOP_DISABLE;
+ }
+ else
+ {
+ // Here, we're modulating. Add in the constant color if we need to...
+ m_ShadowState.m_TextureStage[i].m_ColorArg1 = D3DTA_TFACTOR;
+ m_ShadowState.m_TextureStage[i].m_AlphaArg1 = D3DTA_TFACTOR;
+
+ m_ShadowState.m_TextureStage[i].m_ColorOp = OverbrightBlendValue((TextureStage_t)i);
+ m_ShadowState.m_TextureStage[i].m_AlphaOp = D3DTOP_MODULATE;
+
+ isUsingConstantColor = false;
+ lastUsedTextureStage = i;
+ }
+ }
+ else
+ {
+ // Here, we're modulating. Keep track of the last modulation stage,
+ // cause the constant color modulation comes in the stage after that
+ lastUsedTextureStage = i;
+ m_ShadowState.m_TextureStage[i].m_ColorOp = OverbrightBlendValue((TextureStage_t)i);
+ m_ShadowState.m_TextureStage[i].m_AlphaOp = D3DTOP_MODULATE;
+ }
+ }
+
+ // massive amounts of suck: gotta overbright here if we really
+ // wanted to overbright stage0 but couldn't because of the add.
+ // This isn't totally correct, but there's no way around putting it here
+ // because we can't texture out of stage2 on low or medium end hardware
+ m_ShadowShaderState.m_ModulateConstantColor = false;
+ if (isUsingConstantColor)
+ {
+ ++lastUsedTextureStage;
+
+ if (isUsingConstantColor &&
+ (lastUsedTextureStage >= m_pHardwareConfig->GetTextureStageCount()))
+ {
+ // This is the case where we'd want to modulate in a particular texture
+ // stage, but we can't because there aren't enough. In this case, we're gonna
+ // need to do the modulation in the per-vertex color.
+ m_ShadowShaderState.m_ModulateConstantColor = true;
+ }
+ else
+ {
+ AssertOnce (lastUsedTextureStage < 2);
+
+ // Here, we've got enough texture stages to do the modulation
+ m_ShadowState.m_TextureStage[lastUsedTextureStage].m_ColorArg1 = D3DTA_TFACTOR;
+ m_ShadowState.m_TextureStage[lastUsedTextureStage].m_ColorArg2 = D3DTA_CURRENT;
+ m_ShadowState.m_TextureStage[lastUsedTextureStage].m_AlphaArg1 = D3DTA_TFACTOR;
+ m_ShadowState.m_TextureStage[lastUsedTextureStage].m_AlphaArg2 = D3DTA_CURRENT;
+ m_ShadowState.m_TextureStage[lastUsedTextureStage].m_ColorOp = D3DTOP_MODULATE;
+ m_ShadowState.m_TextureStage[lastUsedTextureStage].m_AlphaOp = D3DTOP_MODULATE;
+ }
+ }
+
+ // Overwrite the alpha stuff if we asked to independently control it
+ if (m_AlphaPipe)
+ {
+ ConfigureAlphaPipe( flags );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Makes sure we report if we're getting garbage.
+//-----------------------------------------------------------------------------
+void CShaderShadowDX8::DrawFlags( unsigned int flags )
+{
+ m_DrawFlags = flags;
+ m_ShadowState.m_UsingFixedFunction = true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Compute texture coordinates
+//-----------------------------------------------------------------------------
+void CShaderShadowDX8::ConfigureTextureCoordinates( unsigned int flags )
+{
+ // default...
+ for (int i = 0; i < m_pHardwareConfig->GetTextureStageCount(); ++i)
+ {
+ TextureCoordinate( (TextureStage_t)i, i );
+ }
+
+ if (flags & SHADER_DRAW_TEXCOORD0)
+ {
+ Assert( (flags & SHADER_DRAW_LIGHTMAP_TEXCOORD0) == 0 );
+ TextureCoordinate( SHADER_TEXTURE_STAGE0, 0 );
+ }
+ else if (flags & SHADER_DRAW_LIGHTMAP_TEXCOORD0)
+ {
+ TextureCoordinate( SHADER_TEXTURE_STAGE0, 1 );
+ }
+ else if (flags & SHADER_DRAW_SECONDARY_TEXCOORD0 )
+ {
+ TextureCoordinate( SHADER_TEXTURE_STAGE0, 2 );
+ }
+
+ if (flags & SHADER_DRAW_TEXCOORD1)
+ {
+ Assert( (flags & SHADER_DRAW_LIGHTMAP_TEXCOORD1) == 0 );
+ TextureCoordinate( SHADER_TEXTURE_STAGE1, 0 );
+ }
+ else if (flags & SHADER_DRAW_LIGHTMAP_TEXCOORD1)
+ {
+ TextureCoordinate( SHADER_TEXTURE_STAGE1, 1 );
+ }
+ else if (flags & SHADER_DRAW_SECONDARY_TEXCOORD1 )
+ {
+ TextureCoordinate( SHADER_TEXTURE_STAGE1, 2 );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Converts draw flags into vertex format
+//-----------------------------------------------------------------------------
+VertexFormat_t CShaderShadowDX8::FlagsToVertexFormat( int flags ) const
+{
+ // Flags -1 occurs when there's an error condition;
+ // we'll just give em the max space and let them fill it in.
+ int formatFlags = 0;
+ int texCoordSize[VERTEX_MAX_TEXTURE_COORDINATES] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ int userDataSize = 0;
+ int numBones = 0;
+
+ // Flags -1 occurs when there's an error condition;
+ // we'll just give em the max space and let them fill it in.
+ if (flags == -1)
+ {
+ formatFlags = VERTEX_POSITION | VERTEX_NORMAL | VERTEX_COLOR |
+ VERTEX_TANGENT_S | VERTEX_TANGENT_T;
+ texCoordSize[0] = texCoordSize[1] = texCoordSize[2] = 2;
+ }
+ else
+ {
+ if (flags & SHADER_DRAW_POSITION)
+ formatFlags |= VERTEX_POSITION;
+
+ if (flags & SHADER_DRAW_NORMAL)
+ formatFlags |= VERTEX_NORMAL;
+
+ if (flags & SHADER_DRAW_COLOR)
+ formatFlags |= VERTEX_COLOR;
+
+ if( flags & SHADER_DRAW_SPECULAR )
+ formatFlags |= VERTEX_SPECULAR;
+
+ if (flags & SHADER_TEXCOORD_MASK)
+ {
+ // normal texture coords into texture 0
+ texCoordSize[0] = 2;
+ }
+
+ if (flags & SHADER_LIGHTMAP_TEXCOORD_MASK)
+ {
+ // lightmaps go into texcoord 1
+ texCoordSize[1] = 2;
+ }
+
+ if (flags & SHADER_SECONDARY_TEXCOORD_MASK)
+ {
+ // any texgen, or secondary texture coordinate is put into texcoord 2
+ texCoordSize[2] = 2;
+ }
+ }
+
+ // Hardware skinning... always store space for up to 3 bones
+ // and always assume index blend enabled if available
+ if (m_ShadowState.m_VertexBlendEnable)
+ {
+ if (HardwareConfig()->MaxBlendMatrixIndices() > 0)
+ formatFlags |= VERTEX_BONE_INDEX;
+
+ if (HardwareConfig()->MaxBlendMatrices() > 2)
+ numBones = 2; // the third bone weight is implied
+ else
+ numBones = HardwareConfig()->MaxBlendMatrices() - 1;
+ }
+
+ return MeshMgr()->ComputeVertexFormat( formatFlags, VERTEX_MAX_TEXTURE_COORDINATES,
+ texCoordSize, numBones, userDataSize );
+}
+
+
+//-----------------------------------------------------------------------------
+// Computes shadow state based on bunches of other parameters
+//-----------------------------------------------------------------------------
+void CShaderShadowDX8::ComputeAggregateShadowState( )
+{
+ unsigned int flags = 0;
+
+ // Initialize the texture stage usage; this may get changed later
+ for (int i = 0; i < m_pHardwareConfig->GetSamplerCount(); ++i)
+ {
+ m_ShadowState.m_SamplerState[i].m_TextureEnable =
+ IsUsingTextureCoordinates( (Sampler_t)i );
+
+ // Deal with the alpha pipe
+ if ( m_ShadowState.m_UsingFixedFunction && m_AlphaPipe )
+ {
+ if ( m_TextureStage[i].m_TextureAlphaEnable )
+ {
+ m_ShadowState.m_SamplerState[i].m_TextureEnable = true;
+ }
+ }
+ }
+
+ // Always use the same alpha src + dest if it's disabled
+ // NOTE: This is essential for stateblocks to work
+ if ( m_ShadowState.m_AlphaBlendEnable )
+ {
+ m_ShadowState.m_SrcBlend = m_SrcBlend;
+ m_ShadowState.m_DestBlend = m_DestBlend;
+ m_ShadowState.m_BlendOp = m_BlendOp;
+ }
+ else
+ {
+ m_ShadowState.m_SrcBlend = D3DBLEND_ONE;
+ m_ShadowState.m_DestBlend = D3DBLEND_ZERO;
+ m_ShadowState.m_BlendOp = D3DBLENDOP_ADD;
+ }
+
+ // GR
+ if (m_ShadowState.m_SeparateAlphaBlendEnable)
+ {
+ m_ShadowState.m_SrcBlendAlpha = m_SrcBlendAlpha;
+ m_ShadowState.m_DestBlendAlpha = m_DestBlendAlpha;
+ m_ShadowState.m_BlendOpAlpha = m_BlendOpAlpha;
+ }
+ else
+ {
+ m_ShadowState.m_SrcBlendAlpha = D3DBLEND_ONE;
+ m_ShadowState.m_DestBlendAlpha = D3DBLEND_ZERO;
+ m_ShadowState.m_BlendOpAlpha = D3DBLENDOP_ADD;
+ }
+
+ // Use the same func if it's disabled
+ if (m_ShadowState.m_AlphaTestEnable)
+ {
+ // If alpha test is enabled, just use the values set
+ m_ShadowState.m_AlphaFunc = m_AlphaFunc;
+ m_ShadowState.m_AlphaRef = m_AlphaRef;
+ }
+ else
+ {
+ // A default value
+ m_ShadowState.m_AlphaFunc = D3DCMP_GREATEREQUAL;
+ m_ShadowState.m_AlphaRef = 0;
+
+ // If not alpha testing and doing a standard alpha blend, force on alpha testing
+ if ( m_ShadowState.m_AlphaBlendEnable )
+ {
+ if ( ( m_ShadowState.m_SrcBlend == D3DBLEND_SRCALPHA ) && ( m_ShadowState.m_DestBlend == D3DBLEND_INVSRCALPHA ) )
+ {
+ m_ShadowState.m_AlphaFunc = D3DCMP_GREATEREQUAL;
+ m_ShadowState.m_AlphaRef = 1;
+ }
+ }
+ }
+ if ( m_ShadowState.m_UsingFixedFunction )
+ {
+ flags = m_DrawFlags;
+
+ // We need to take this bad boy into account
+ if (HasConstantColor())
+ flags |= SHADER_HAS_CONSTANT_COLOR;
+
+ // We need to take lighting into account..
+ if ( m_ShadowState.m_Lighting )
+ flags |= SHADER_DRAW_NORMAL;
+
+ if (m_ShadowState.m_Lighting)
+ flags |= SHADER_DRAW_COLOR;
+
+ // Look for inconsistency in the shadow state (can't have texgen &
+ // SHADER_DRAW_TEXCOORD or SHADER_DRAW_SECONDARY_TEXCOORD0 on the same stage)
+ if (flags & (SHADER_DRAW_TEXCOORD0 | SHADER_DRAW_SECONDARY_TEXCOORD0))
+ {
+ Assert( (m_ShadowState.m_TextureStage[0].m_TexCoordIndex & 0xFFFF0000) == 0 );
+ }
+ if (flags & (SHADER_DRAW_TEXCOORD1 | SHADER_DRAW_SECONDARY_TEXCOORD1))
+ {
+ Assert( (m_ShadowState.m_TextureStage[1].m_TexCoordIndex & 0xFFFF0000) == 0 );
+ }
+ if (flags & (SHADER_DRAW_TEXCOORD2 | SHADER_DRAW_SECONDARY_TEXCOORD2))
+ {
+ Assert( (m_ShadowState.m_TextureStage[2].m_TexCoordIndex & 0xFFFF0000) == 0 );
+ }
+ if (flags & (SHADER_DRAW_TEXCOORD3 | SHADER_DRAW_SECONDARY_TEXCOORD3))
+ {
+ Assert( (m_ShadowState.m_TextureStage[3].m_TexCoordIndex & 0xFFFF0000) == 0 );
+ }
+
+ // Vertex usage has already been set for pixel + vertex shaders
+ m_ShadowShaderState.m_VertexUsage = FlagsToVertexFormat( flags );
+
+ // Configure the texture stages
+ ConfigureFVFVertexShader(flags);
+
+#if 0
+//#ifdef _DEBUG
+ // NOTE: This must be true for stateblocks to work
+ for ( i = 0; i < m_pHardwareConfig->GetTextureStageCount(); ++i )
+ {
+ if ( m_ShadowState.m_TextureStage[i].m_ColorOp == D3DTOP_DISABLE )
+ {
+ Assert( m_ShadowState.m_TextureStage[i].m_ColorArg1 == D3DTA_TEXTURE );
+ Assert( m_ShadowState.m_TextureStage[i].m_ColorArg2 == ((i == 0) ? D3DTA_DIFFUSE : D3DTA_CURRENT) );
+ }
+
+ if ( m_ShadowState.m_TextureStage[i].m_AlphaOp == D3DTOP_DISABLE )
+ {
+ Assert( m_ShadowState.m_TextureStage[i].m_AlphaArg1 == D3DTA_TEXTURE );
+ Assert( m_ShadowState.m_TextureStage[i].m_AlphaArg2 == ((i == 0) ? D3DTA_DIFFUSE : D3DTA_CURRENT) );
+ }
+ }
+#endif
+ }
+ else
+ {
+ // Pixel shaders, disable everything so as to prevent unnecessary state changes....
+ for ( int i = 0; i < m_pHardwareConfig->GetTextureStageCount(); ++i )
+ {
+ m_ShadowState.m_TextureStage[i].m_ColorArg1 = D3DTA_TEXTURE;
+ m_ShadowState.m_TextureStage[i].m_ColorArg2 = (i == 0) ? D3DTA_DIFFUSE : D3DTA_CURRENT;
+ m_ShadowState.m_TextureStage[i].m_AlphaArg1 = D3DTA_TEXTURE;
+ m_ShadowState.m_TextureStage[i].m_AlphaArg2 = (i == 0) ? D3DTA_DIFFUSE : D3DTA_CURRENT;
+ m_ShadowState.m_TextureStage[i].m_ColorOp = D3DTOP_DISABLE;
+ m_ShadowState.m_TextureStage[i].m_AlphaOp = D3DTOP_DISABLE;
+ m_ShadowState.m_TextureStage[i].m_TexCoordIndex = i;
+ }
+ m_ShadowState.m_Lighting = false;
+ m_ShadowState.m_SpecularEnable = false;
+ m_ShadowState.m_VertexBlendEnable = false;
+ m_ShadowShaderState.m_ModulateConstantColor = false;
+ }
+
+ // Compute texture coordinates
+ ConfigureTextureCoordinates(flags);
+
+ // Alpha to coverage
+ if ( m_ShadowState.m_EnableAlphaToCoverage )
+ {
+ // Only allow this to be enabled if blending is disabled and testing is enabled
+ if ( ( m_ShadowState.m_AlphaBlendEnable == true ) || ( m_ShadowState.m_AlphaTestEnable == false ) )
+ {
+ m_ShadowState.m_EnableAlphaToCoverage = false;
+ }
+ }
+}
+
+void CShaderShadowDX8::FogMode( ShaderFogMode_t fogMode )
+{
+ Assert( fogMode >= 0 && fogMode < SHADER_FOGMODE_NUMFOGMODES );
+ m_ShadowState.m_FogMode = fogMode;
+}
+
+void CShaderShadowDX8::DisableFogGammaCorrection( bool bDisable )
+{
+ m_ShadowState.m_bDisableFogGammaCorrection = bDisable;
+}
+
+void CShaderShadowDX8::SetDiffuseMaterialSource( ShaderMaterialSource_t materialSource )
+{
+ COMPILE_TIME_ASSERT( ( int )D3DMCS_MATERIAL == ( int )SHADER_MATERIALSOURCE_MATERIAL );
+ COMPILE_TIME_ASSERT( ( int )D3DMCS_COLOR1 == ( int )SHADER_MATERIALSOURCE_COLOR1 );
+ COMPILE_TIME_ASSERT( ( int )D3DMCS_COLOR2 == ( int )SHADER_MATERIALSOURCE_COLOR2 );
+ Assert( materialSource == SHADER_MATERIALSOURCE_MATERIAL ||
+ materialSource == SHADER_MATERIALSOURCE_COLOR1 ||
+ materialSource == SHADER_MATERIALSOURCE_COLOR2 );
+ m_ShadowState.m_DiffuseMaterialSource = ( D3DMATERIALCOLORSOURCE )materialSource;
+}
diff --git a/materialsystem/shaderapidx9/shadershadowdx8.h b/materialsystem/shaderapidx9/shadershadowdx8.h
new file mode 100644
index 0000000..09b16ae
--- /dev/null
+++ b/materialsystem/shaderapidx9/shadershadowdx8.h
@@ -0,0 +1,176 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#ifndef SHADERSHADOWDX8_H
+#define SHADERSHADOWDX8_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "togl/rendermechanism.h"
+#include "locald3dtypes.h"
+#include "shaderapi/ishadershadow.h"
+
+class IShaderAPIDX8;
+
+
+//-----------------------------------------------------------------------------
+// Important enumerations
+//-----------------------------------------------------------------------------
+enum
+{
+ MAX_SAMPLERS = 16,
+ MAX_TEXTURE_STAGES = 16,
+};
+
+
+//-----------------------------------------------------------------------------
+// A structure maintaining the shadowed board state
+//-----------------------------------------------------------------------------
+struct TextureStageShadowState_t
+{
+ // State shadowing affects these
+ D3DTEXTUREOP m_ColorOp;
+ int m_ColorArg1;
+ int m_ColorArg2;
+ D3DTEXTUREOP m_AlphaOp;
+ int m_AlphaArg1;
+ int m_AlphaArg2;
+ int m_TexCoordIndex;
+};
+
+struct SamplerShadowState_t
+{
+ bool m_TextureEnable : 1;
+ bool m_SRGBReadEnable : 1;
+ bool m_Fetch4Enable : 1;
+ bool m_ShadowFilterEnable : 1;
+};
+
+struct ShadowState_t
+{
+ // Depth buffering state
+ D3DCMPFUNC m_ZFunc;
+ D3DZBUFFERTYPE m_ZEnable;
+
+ // Write enable
+ DWORD m_ColorWriteEnable;
+
+ // Fill mode
+ D3DFILLMODE m_FillMode;
+
+ // Alpha state
+ D3DBLEND m_SrcBlend;
+ D3DBLEND m_DestBlend;
+ D3DBLENDOP m_BlendOp;
+
+ // Separate alpha blend state
+ D3DBLEND m_SrcBlendAlpha;
+ D3DBLEND m_DestBlendAlpha;
+ D3DBLENDOP m_BlendOpAlpha;
+
+ D3DCMPFUNC m_AlphaFunc;
+ int m_AlphaRef;
+
+ // Texture stage state
+ TextureStageShadowState_t m_TextureStage[MAX_TEXTURE_STAGES];
+
+ // Sampler state
+ SamplerShadowState_t m_SamplerState[MAX_SAMPLERS];
+
+ ShaderFogMode_t m_FogMode;
+
+ D3DMATERIALCOLORSOURCE m_DiffuseMaterialSource;
+
+ unsigned char m_ZWriteEnable:1;
+ unsigned char m_ZBias:2;
+ // Cull State?
+ unsigned char m_CullEnable:1;
+ // Lighting in hardware?
+ unsigned char m_Lighting:1;
+ unsigned char m_SpecularEnable:1;
+ unsigned char m_AlphaBlendEnable:1;
+ unsigned char m_AlphaTestEnable:1;
+
+ // Fixed function?
+ unsigned char m_UsingFixedFunction:1;
+ // Vertex blending?
+ unsigned char m_VertexBlendEnable:1;
+ // Auto-convert from linear to gamma upon writing to the frame buffer?
+ unsigned char m_SRGBWriteEnable:1;
+ // Seperate Alpha Blend?
+ unsigned char m_SeparateAlphaBlendEnable:1;
+ // Stencil?
+ unsigned char m_StencilEnable:1;
+
+ unsigned char m_bDisableFogGammaCorrection:1;
+
+ unsigned char m_EnableAlphaToCoverage:1;
+
+ unsigned char m_Reserved : 1;
+ unsigned short m_nReserved2;
+};
+
+
+//-----------------------------------------------------------------------------
+// These are part of the "shadow" since they describe the shading algorithm
+// but aren't actually captured in the state transition table
+// because it would produce too many transitions
+//-----------------------------------------------------------------------------
+struct ShadowShaderState_t
+{
+ // The vertex + pixel shader group to use...
+ VertexShader_t m_VertexShader;
+ PixelShader_t m_PixelShader;
+
+ // The static vertex + pixel shader indices
+ int m_nStaticVshIndex;
+ int m_nStaticPshIndex;
+
+ // Vertex data used by this snapshot
+ // Note that the vertex format actually used will be the
+ // aggregate of the vertex formats used by all snapshots in a material
+ VertexFormat_t m_VertexUsage;
+
+ // Morph data used by this snapshot
+ // Note that the morph format actually used will be the
+ // aggregate of the morph formats used by all snapshots in a material
+ MorphFormat_t m_MorphUsage;
+
+ // Modulate constant color into the vertex color
+ bool m_ModulateConstantColor;
+
+ bool m_nReserved[3];
+};
+
+
+//-----------------------------------------------------------------------------
+// The shader setup API
+//-----------------------------------------------------------------------------
+abstract_class IShaderShadowDX8 : public IShaderShadow
+{
+public:
+ // Initializes it
+ virtual void Init() = 0;
+
+ // Gets at the shadow state
+ virtual ShadowState_t const& GetShadowState() = 0;
+ virtual ShadowShaderState_t const& GetShadowShaderState() = 0;
+
+ // This must be called right before taking a snapshot
+ virtual void ComputeAggregateShadowState( ) = 0;
+
+ // Class factory methods
+ static IShaderShadowDX8* Create( IShaderAPIDX8* pShaderAPIDX8 );
+ static void Destroy( IShaderShadowDX8* pShaderShadow );
+};
+
+extern IShaderShadowDX8 *g_pShaderShadowDx8;
+
+#endif // SHADERSHADOWDX8_H
diff --git a/materialsystem/shaderapidx9/stubd3ddevice.h b/materialsystem/shaderapidx9/stubd3ddevice.h
new file mode 100644
index 0000000..a97f015
--- /dev/null
+++ b/materialsystem/shaderapidx9/stubd3ddevice.h
@@ -0,0 +1,809 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef STUBD3DDEVICE_H
+#define STUBD3DDEVICE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#ifdef STUBD3D
+
+#include "locald3dtypes.h"
+#include "filesystem.h"
+
+#ifdef USE_FOPEN
+#include <stdio.h>
+#define FPRINTF fprintf
+#else
+#define FPRINTF s_pFileSystem->FPrintf
+#endif
+
+#ifdef USE_FOPEN
+
+static FILE *s_FileHandle;
+
+#else
+
+static IFileSystem *s_pFileSystem;
+static FileHandle_t s_FileHandle;
+
+#endif
+
+
+
+class CStubD3DTexture : public IDirect3DTexture8
+{
+private:
+ IDirect3DTexture8 *m_pTexture;
+ IDirect3DDevice8 *m_pDevice;
+
+public:
+ CStubD3DTexture( IDirect3DTexture8 *pTexture, IDirect3DDevice8 *pDevice )
+ {
+ m_pTexture = pTexture;
+ m_pDevice = pDevice;
+ }
+
+ /*** IUnknown methods ***/
+ HRESULT __stdcall QueryInterface(REFIID riid, void** ppvObj)
+ {
+ FPRINTF( s_FileHandle, "IDirect3DTexture8::QueryInterface\n" );
+ return m_pTexture->QueryInterface( riid, ppvObj );
+ }
+
+ ULONG __stdcall AddRef()
+ {
+ FPRINTF( s_FileHandle, "IDirect3DTexture8::AddRef\n" );
+ return m_pTexture->AddRef();
+ }
+
+ ULONG __stdcall Release()
+ {
+ FPRINTF( s_FileHandle, "IDirect3DTexture8::Release\n" );
+ return m_pTexture->Release();
+ }
+
+ /*** IDirect3DBaseTexture8 methods ***/
+ HRESULT __stdcall GetDevice( IDirect3DDevice8** ppDevice )
+ {
+ FPRINTF( s_FileHandle, "IDirect3DTexture8::GetDevice\n" );
+#if 0
+ *ppDevice = m_pDevice;
+ return D3D_OK;
+#else
+ return m_pTexture->GetDevice( ppDevice );
+#endif
+ }
+
+ HRESULT __stdcall SetPrivateData( REFGUID refguid,CONST void* pData,DWORD SizeOfData,DWORD Flags)
+ {
+ FPRINTF( s_FileHandle, "IDirect3DTexture8::SetPrivateData\n" );
+ return m_pTexture->SetPrivateData( refguid, pData, SizeOfData, Flags );
+ }
+
+ HRESULT __stdcall GetPrivateData( REFGUID refguid,void* pData,DWORD* pSizeOfData )
+ {
+ FPRINTF( s_FileHandle, "IDirect3DTexture8::GetPrivateData\n" );
+ return m_pTexture->GetPrivateData( refguid, pData, pSizeOfData );
+ }
+
+ HRESULT __stdcall FreePrivateData( REFGUID refguid )
+ {
+ FPRINTF( s_FileHandle, "IDirect3DTexture8::GetPrivateData\n" );
+ return m_pTexture->FreePrivateData( refguid );
+ }
+
+ DWORD __stdcall SetPriority( DWORD PriorityNew )
+ {
+ FPRINTF( s_FileHandle, "IDirect3DTexture8::SetPriority\n" );
+ return m_pTexture->SetPriority( PriorityNew );
+ }
+
+ DWORD __stdcall GetPriority()
+ {
+ FPRINTF( s_FileHandle, "IDirect3DTexture8::GetPriority\n" );
+ return m_pTexture->GetPriority();
+ }
+
+ void __stdcall PreLoad()
+ {
+ FPRINTF( s_FileHandle, "IDirect3DTexture8::PreLoad\n" );
+ m_pTexture->PreLoad();
+ }
+
+ D3DRESOURCETYPE __stdcall GetType()
+ {
+ FPRINTF( s_FileHandle, "IDirect3DTexture8::GetType\n" );
+ return m_pTexture->GetType();
+ }
+
+ DWORD __stdcall SetLOD( DWORD LODNew )
+ {
+ FPRINTF( s_FileHandle, "IDirect3DTexture8::SetLOD\n" );
+ return m_pTexture->SetLOD( LODNew );
+ }
+
+ DWORD __stdcall GetLOD()
+ {
+ FPRINTF( s_FileHandle, "IDirect3DTexture8::GetLOD\n" );
+ return m_pTexture->GetLOD();
+ }
+
+ DWORD __stdcall GetLevelCount()
+ {
+ FPRINTF( s_FileHandle, "IDirect3DTexture8::GetLevelCount\n" );
+ return m_pTexture->GetLevelCount();
+ }
+
+ HRESULT __stdcall GetLevelDesc(UINT Level,D3DSURFACE_DESC *pDesc)
+ {
+ FPRINTF( s_FileHandle, "IDirect3DTexture8::GetLevelCount\n" );
+ return m_pTexture->GetLevelDesc( Level, pDesc );
+ }
+
+ HRESULT __stdcall GetSurfaceLevel(UINT Level,IDirect3DSurface8** ppSurfaceLevel)
+ {
+ FPRINTF( s_FileHandle, "IDirect3DTexture8::GetSurfaceLevel\n" );
+ return m_pTexture->GetSurfaceLevel( Level, ppSurfaceLevel );
+ }
+
+ HRESULT __stdcall LockRect(UINT Level,D3DLOCKED_RECT* pLockedRect,CONST RECT* pRect,DWORD Flags)
+ {
+ FPRINTF( s_FileHandle, "IDirect3DTexture8::LockRect\n" );
+ return m_pTexture->LockRect( Level, pLockedRect, pRect, Flags );
+ }
+
+ HRESULT __stdcall UnlockRect(UINT Level)
+ {
+ FPRINTF( s_FileHandle, "IDirect3DTexture8::UnlockRect\n" );
+ return m_pTexture->UnlockRect( Level );
+ }
+
+ HRESULT __stdcall AddDirtyRect( CONST RECT* pDirtyRect )
+ {
+ FPRINTF( s_FileHandle, "IDirect3DTexture8::AddDirtyRect\n" );
+ return m_pTexture->AddDirtyRect( pDirtyRect );
+ }
+};
+
+class CStubD3DDevice : public IDirect3DDevice8
+{
+public:
+ CStubD3DDevice( IDirect3DDevice8 *pD3DDevice, IFileSystem *pFileSystem )
+ {
+ Assert( pD3DDevice );
+ m_pD3DDevice = pD3DDevice;
+#ifdef USE_FOPEN
+ s_FileHandle = fopen( "stubd3d.txt", "w" );
+#else
+ Assert( pFileSystem );
+ s_pFileSystem = pFileSystem;
+ s_FileHandle = pFileSystem->Open( "stubd3d.txt", "w" );
+#endif
+ }
+
+ ~CStubD3DDevice()
+ {
+#ifdef USE_FOPEN
+ fclose( s_FileHandle );
+#else
+ s_pFileSystem->Close( s_FileHandle );
+#endif
+ }
+
+private:
+ IDirect3DDevice8 *m_pD3DDevice;
+
+public:
+ /*** IUnknown methods ***/
+ HRESULT __stdcall QueryInterface(REFIID riid, void** ppvObj)
+ {
+ FPRINTF( s_FileHandle, "QueryInterface\n" );
+ return m_pD3DDevice->QueryInterface( riid, ppvObj );
+ }
+
+ ULONG __stdcall AddRef()
+ {
+ FPRINTF( s_FileHandle, "AddRef\n" );
+ return m_pD3DDevice->AddRef();
+ }
+
+ ULONG __stdcall Release()
+ {
+ FPRINTF( s_FileHandle, "Release\n" );
+ return m_pD3DDevice->Release();
+ delete this;
+ }
+
+ /*** IDirect3DDevice8 methods ***/
+ HRESULT __stdcall TestCooperativeLevel()
+ {
+ FPRINTF( s_FileHandle, "TestCooperativeLevel\n" );
+ return m_pD3DDevice->TestCooperativeLevel();
+ }
+
+ UINT __stdcall GetAvailableTextureMem()
+ {
+ FPRINTF( s_FileHandle, "GetAvailableTextureMem\n" );
+ return m_pD3DDevice->GetAvailableTextureMem();
+ }
+
+ HRESULT __stdcall ResourceManagerDiscardBytes(DWORD Bytes)
+ {
+ FPRINTF( s_FileHandle, "ResourceManagerDiscardBytes\n" );
+ return m_pD3DDevice->ResourceManagerDiscardBytes( Bytes );
+ }
+
+ HRESULT __stdcall GetDirect3D(IDirect3D8** ppD3D8)
+ {
+ FPRINTF( s_FileHandle, "GetDirect3D\n" );
+ return m_pD3DDevice->GetDirect3D( ppD3D8 );
+ }
+
+ HRESULT __stdcall GetDeviceCaps(D3DCAPS8* pCaps)
+ {
+ FPRINTF( s_FileHandle, "GetDeviceCaps\n" );
+ return m_pD3DDevice->GetDeviceCaps( pCaps );
+ }
+
+ HRESULT __stdcall GetDisplayMode(D3DDISPLAYMODE* pMode)
+ {
+ FPRINTF( s_FileHandle, "GetDisplayMode\n" );
+ return m_pD3DDevice->GetDisplayMode( pMode );
+ }
+
+ HRESULT __stdcall GetCreationParameters(D3DDEVICE_CREATION_PARAMETERS *pParameters)
+ {
+ FPRINTF( s_FileHandle, "GetCreationParameters\n" );
+ return m_pD3DDevice->GetCreationParameters( pParameters );
+ }
+
+ HRESULT __stdcall SetCursorProperties(UINT XHotSpot,UINT YHotSpot,IDirect3DSurface8* pCursorBitmap)
+ {
+ FPRINTF( s_FileHandle, "SetCursorProperties\n" );
+ return m_pD3DDevice->SetCursorProperties( XHotSpot, YHotSpot, pCursorBitmap );
+ }
+
+ void __stdcall SetCursorPosition(UINT XScreenSpace,UINT YScreenSpace,DWORD Flags)
+ {
+ FPRINTF( s_FileHandle, "SetCursorPosition\n" );
+ m_pD3DDevice->SetCursorPosition( XScreenSpace, YScreenSpace, Flags );
+ }
+
+ BOOL __stdcall ShowCursor(BOOL bShow)
+ {
+ FPRINTF( s_FileHandle, "ShowCursor\n" );
+ return m_pD3DDevice->ShowCursor( bShow );
+ }
+
+ HRESULT __stdcall CreateAdditionalSwapChain(D3DPRESENT_PARAMETERS* pPresentationParameters,IDirect3DSwapChain8** pSwapChain)
+ {
+ FPRINTF( s_FileHandle, "CreateAdditionalSwapChain\n" );
+ return m_pD3DDevice->CreateAdditionalSwapChain( pPresentationParameters, pSwapChain );
+ }
+
+ HRESULT __stdcall Reset(D3DPRESENT_PARAMETERS* pPresentationParameters)
+ {
+ FPRINTF( s_FileHandle, "Reset\n" );
+ return m_pD3DDevice->Reset( pPresentationParameters );
+ }
+
+ HRESULT __stdcall Present(CONST RECT* pSourceRect,CONST RECT* pDestRect,HWND hDestWindowOverride,CONST RGNDATA* pDirtyRegion)
+ {
+ FPRINTF( s_FileHandle, "Present\n" );
+ return m_pD3DDevice->Present( pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion );
+ }
+
+ HRESULT __stdcall GetBackBuffer(UINT BackBuffer,D3DBACKBUFFER_TYPE Type,IDirect3DSurface8** ppBackBuffer)
+ {
+ FPRINTF( s_FileHandle, "GetBackBuffer\n" );
+ return m_pD3DDevice->GetBackBuffer( BackBuffer, Type, ppBackBuffer );
+ }
+
+ HRESULT __stdcall GetRasterStatus(D3DRASTER_STATUS* pRasterStatus)
+ {
+ FPRINTF( s_FileHandle, "GetRasterStatus\n" );
+ return m_pD3DDevice->GetRasterStatus( pRasterStatus );
+ }
+
+ void __stdcall SetGammaRamp(DWORD Flags,CONST D3DGAMMARAMP* pRamp)
+ {
+ FPRINTF( s_FileHandle, "SetGammaRamp\n" );
+ m_pD3DDevice->SetGammaRamp( Flags, pRamp );
+ }
+
+ void __stdcall GetGammaRamp(D3DGAMMARAMP* pRamp)
+ {
+ FPRINTF( s_FileHandle, "GetGammaRamp\n" );
+ m_pD3DDevice->GetGammaRamp( pRamp );
+ }
+
+ HRESULT __stdcall CreateTexture(UINT Width,UINT Height,UINT Levels,DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,IDirect3DTexture8** ppTexture)
+ {
+ FPRINTF( s_FileHandle, "CreateTexture\n" );
+#if 0
+ HRESULT ret = m_pD3DDevice->CreateTexture( Width, Height, Levels, Usage, Format, Pool, ppTexture );
+ if( ret == D3D_OK )
+ {
+ *ppTexture = new CStubD3DTexture( *ppTexture, this );
+ return ret;
+ }
+ else
+ {
+ return ret;
+ }
+#else
+ return m_pD3DDevice->CreateTexture( Width, Height, Levels, Usage, Format, Pool, ppTexture );
+#endif
+ }
+
+ HRESULT __stdcall CreateVolumeTexture(UINT Width,UINT Height,UINT Depth,UINT Levels,DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,IDirect3DVolumeTexture8** ppVolumeTexture)
+ {
+ FPRINTF( s_FileHandle, "CreateVolumeTexture\n" );
+ return m_pD3DDevice->CreateVolumeTexture( Width, Height, Depth, Levels, Usage, Format, Pool, ppVolumeTexture );
+ }
+
+ HRESULT __stdcall CreateCubeTexture(UINT EdgeLength,UINT Levels,DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,IDirect3DCubeTexture8** ppCubeTexture)
+ {
+ FPRINTF( s_FileHandle, "CreateCubeTexture\n" );
+ return m_pD3DDevice->CreateCubeTexture( EdgeLength, Levels, Usage, Format, Pool, ppCubeTexture );
+ }
+
+ HRESULT __stdcall CreateVertexBuffer(UINT Length,DWORD Usage,DWORD FVF,D3DPOOL Pool,IDirect3DVertexBuffer8** ppVertexBuffer)
+ {
+ FPRINTF( s_FileHandle, "CreateVertexBuffer\n" );
+ return m_pD3DDevice->CreateVertexBuffer( Length, Usage, FVF, Pool, ppVertexBuffer );
+ }
+
+ HRESULT __stdcall CreateIndexBuffer(UINT Length,DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,IDirect3DIndexBuffer8** ppIndexBuffer)
+ {
+ FPRINTF( s_FileHandle, "CreateIndexBuffer\n" );
+ return m_pD3DDevice->CreateIndexBuffer( Length, Usage, Format, Pool, ppIndexBuffer );
+ }
+
+ HRESULT __stdcall CreateRenderTarget(UINT Width,UINT Height,D3DFORMAT Format,D3DMULTISAMPLE_TYPE MultiSample,BOOL Lockable,IDirect3DSurface8** ppSurface)
+ {
+ FPRINTF( s_FileHandle, "CreateRenderTarget\n" );
+ return m_pD3DDevice->CreateRenderTarget( Width, Height, Format, MultiSample, Lockable, ppSurface );
+ }
+
+ HRESULT __stdcall CreateDepthStencilSurface(UINT Width,UINT Height,D3DFORMAT Format,D3DMULTISAMPLE_TYPE MultiSample,IDirect3DSurface8** ppSurface)
+ {
+ FPRINTF( s_FileHandle, "CreateDepthStencilSurface\n" );
+ return m_pD3DDevice->CreateDepthStencilSurface( Width, Height, Format, MultiSample, ppSurface );
+ }
+
+ HRESULT __stdcall CreateImageSurface(UINT Width,UINT Height,D3DFORMAT Format,IDirect3DSurface8** ppSurface)
+ {
+ FPRINTF( s_FileHandle, "CreateImageSurface\n" );
+ return m_pD3DDevice->CreateImageSurface( Width, Height, Format, ppSurface );
+ }
+
+ HRESULT __stdcall CopyRects(IDirect3DSurface8* pSourceSurface,CONST RECT* pSourceRectsArray,UINT cRects,IDirect3DSurface8* pDestinationSurface,CONST POINT* pDestPointsArray)
+ {
+ FPRINTF( s_FileHandle, "CopyRects\n" );
+ return m_pD3DDevice->CopyRects( pSourceSurface, pSourceRectsArray, cRects, pDestinationSurface, pDestPointsArray );
+ }
+
+ HRESULT __stdcall UpdateTexture(IDirect3DBaseTexture8* pSourceTexture,IDirect3DBaseTexture8* pDestinationTexture)
+ {
+ FPRINTF( s_FileHandle, "UpdateTexture\n" );
+ return m_pD3DDevice->UpdateTexture( pSourceTexture, pDestinationTexture );
+ }
+
+ HRESULT __stdcall GetFrontBuffer(IDirect3DSurface8* pDestSurface)
+ {
+ FPRINTF( s_FileHandle, "GetFrontBuffer\n" );
+ return m_pD3DDevice->GetFrontBuffer( pDestSurface );
+ }
+
+ HRESULT __stdcall SetRenderTarget(IDirect3DSurface8* pRenderTarget,IDirect3DSurface8* pNewZStencil)
+ {
+ FPRINTF( s_FileHandle, "SetRenderTarget\n" );
+ return m_pD3DDevice->SetRenderTarget( pRenderTarget, pNewZStencil );
+ }
+
+ HRESULT __stdcall GetRenderTarget(IDirect3DSurface8** ppRenderTarget)
+ {
+ FPRINTF( s_FileHandle, "GetRenderTarget\n" );
+ return m_pD3DDevice->GetRenderTarget( ppRenderTarget );
+ }
+
+ HRESULT __stdcall GetDepthStencilSurface(IDirect3DSurface8** ppZStencilSurface)
+ {
+ FPRINTF( s_FileHandle, "GetDepthStencilSurface\n" );
+ return m_pD3DDevice->GetDepthStencilSurface( ppZStencilSurface );
+ }
+
+ HRESULT __stdcall BeginScene( void )
+ {
+ FPRINTF( s_FileHandle, "BeginScene\n" );
+ return m_pD3DDevice->BeginScene();
+ }
+
+ HRESULT __stdcall EndScene()
+ {
+ FPRINTF( s_FileHandle, "EndScene\n" );
+ return m_pD3DDevice->EndScene();
+ }
+
+ HRESULT __stdcall Clear(DWORD Count,CONST D3DRECT* pRects,DWORD Flags,D3DCOLOR Color,float Z,DWORD Stencil)
+ {
+ FPRINTF( s_FileHandle, "Clear\n" );
+ return m_pD3DDevice->Clear( Count, pRects, Flags, Color, Z, Stencil );
+ }
+
+ HRESULT __stdcall SetTransform(D3DTRANSFORMSTATETYPE State,CONST D3DMATRIX* pMatrix)
+ {
+ FPRINTF( s_FileHandle, "SetTransform\n" );
+ return m_pD3DDevice->SetTransform( State, pMatrix );
+ }
+
+ HRESULT __stdcall GetTransform(D3DTRANSFORMSTATETYPE State,D3DMATRIX* pMatrix)
+ {
+ FPRINTF( s_FileHandle, "GetTransform\n" );
+ return m_pD3DDevice->GetTransform( State, pMatrix );
+ }
+
+ HRESULT __stdcall MultiplyTransform(D3DTRANSFORMSTATETYPE transformState,CONST D3DMATRIX* pMatrix)
+ {
+ FPRINTF( s_FileHandle, "MultiplyTransform\n" );
+ return m_pD3DDevice->MultiplyTransform( transformState, pMatrix );
+ }
+
+ HRESULT __stdcall SetViewport(CONST D3DVIEWPORT8* pViewport)
+ {
+ FPRINTF( s_FileHandle, "SetViewport\n" );
+ return m_pD3DDevice->SetViewport( pViewport );
+ }
+
+ HRESULT __stdcall GetViewport(D3DVIEWPORT8* pViewport)
+ {
+ FPRINTF( s_FileHandle, "GetViewport\n" );
+ return m_pD3DDevice->GetViewport( pViewport );
+ }
+
+ HRESULT __stdcall SetMaterial(CONST D3DMATERIAL8* pMaterial)
+ {
+ FPRINTF( s_FileHandle, "SetMaterial\n" );
+ return m_pD3DDevice->SetMaterial( pMaterial );
+ }
+
+ HRESULT __stdcall GetMaterial(D3DMATERIAL8* pMaterial)
+ {
+ FPRINTF( s_FileHandle, "GetMaterial\n" );
+ return m_pD3DDevice->GetMaterial( pMaterial );
+ }
+
+ HRESULT __stdcall SetLight(DWORD Index,CONST D3DLIGHT8* pLight)
+ {
+ FPRINTF( s_FileHandle, "SetLight\n" );
+ return m_pD3DDevice->SetLight( Index, pLight );
+ }
+
+ HRESULT __stdcall GetLight(DWORD Index,D3DLIGHT8* pLight)
+ {
+ FPRINTF( s_FileHandle, "GetLight\n" );
+ return m_pD3DDevice->GetLight( Index, pLight );
+ }
+
+ HRESULT __stdcall LightEnable(DWORD Index,BOOL Enable)
+ {
+ FPRINTF( s_FileHandle, "LightEnable\n" );
+ return m_pD3DDevice->LightEnable( Index, Enable );
+ }
+
+ HRESULT __stdcall GetLightEnable(DWORD Index,BOOL* pEnable)
+ {
+ FPRINTF( s_FileHandle, "GetLightEnable\n" );
+ return m_pD3DDevice->GetLightEnable( Index, pEnable );
+ }
+
+ HRESULT __stdcall SetClipPlane(DWORD Index,CONST float* pPlane)
+ {
+ FPRINTF( s_FileHandle, "SetClipPlane\n" );
+ return m_pD3DDevice->SetClipPlane( Index, pPlane );
+ }
+
+ HRESULT __stdcall GetClipPlane(DWORD Index,float* pPlane)
+ {
+ FPRINTF( s_FileHandle, "GetClipPlane\n" );
+ return m_pD3DDevice->GetClipPlane( Index, pPlane );
+ }
+
+ HRESULT __stdcall SetRenderState(D3DRENDERSTATETYPE State,DWORD Value)
+ {
+ FPRINTF( s_FileHandle, "SetRenderState\n" );
+ return m_pD3DDevice->SetRenderState( State, Value );
+ }
+
+ HRESULT __stdcall GetRenderState(D3DRENDERSTATETYPE State,DWORD* pValue)
+ {
+ FPRINTF( s_FileHandle, "GetRenderState\n" );
+ return m_pD3DDevice->GetRenderState( State, pValue );
+ }
+
+ HRESULT __stdcall BeginStateBlock(void)
+ {
+ FPRINTF( s_FileHandle, "BeginStateBlock\n" );
+ return m_pD3DDevice->BeginStateBlock();
+ }
+
+ HRESULT __stdcall EndStateBlock(DWORD* pToken)
+ {
+ FPRINTF( s_FileHandle, "EndStateBlock\n" );
+ return m_pD3DDevice->EndStateBlock( pToken );
+ }
+
+ HRESULT __stdcall ApplyStateBlock(DWORD Token)
+ {
+ FPRINTF( s_FileHandle, "ApplyStateBlock\n" );
+ return m_pD3DDevice->ApplyStateBlock( Token );
+ }
+
+ HRESULT __stdcall CaptureStateBlock(DWORD Token)
+ {
+ FPRINTF( s_FileHandle, "CaptureStateBlock\n" );
+ return m_pD3DDevice->CaptureStateBlock( Token );
+ }
+
+ HRESULT __stdcall DeleteStateBlock(DWORD Token)
+ {
+ FPRINTF( s_FileHandle, "DeleteStateBlock\n" );
+ return m_pD3DDevice->DeleteStateBlock( Token );
+ }
+
+ HRESULT __stdcall CreateStateBlock(D3DSTATEBLOCKTYPE Type,DWORD* pToken)
+ {
+ FPRINTF( s_FileHandle, "CreateStateBlock\n" );
+ return m_pD3DDevice->CreateStateBlock( Type, pToken );
+ }
+
+ HRESULT __stdcall SetClipStatus(CONST D3DCLIPSTATUS8* pClipStatus)
+ {
+ FPRINTF( s_FileHandle, "SetClipStatus\n" );
+ return m_pD3DDevice->SetClipStatus( pClipStatus );
+ }
+
+ HRESULT __stdcall GetClipStatus(D3DCLIPSTATUS8* pClipStatus)
+ {
+ FPRINTF( s_FileHandle, "GetClipStatus\n" );
+ return m_pD3DDevice->GetClipStatus( pClipStatus );
+ }
+
+ HRESULT __stdcall GetTexture(DWORD Stage,IDirect3DBaseTexture8** ppTexture)
+ {
+ FPRINTF( s_FileHandle, "GetTexture\n" );
+ return m_pD3DDevice->GetTexture( Stage, ppTexture );
+ }
+
+ HRESULT __stdcall SetTexture(DWORD Stage,IDirect3DBaseTexture8* pTexture)
+ {
+ FPRINTF( s_FileHandle, "SetTexture\n" );
+ return m_pD3DDevice->SetTexture( Stage, pTexture );
+ }
+
+ HRESULT __stdcall GetTextureStageState(DWORD Stage,D3DTEXTURESTAGESTATETYPE Type,DWORD* pValue)
+ {
+ FPRINTF( s_FileHandle, "GetTextureStageState\n" );
+ return m_pD3DDevice->GetTextureStageState( Stage, Type, pValue );
+ }
+
+ HRESULT __stdcall SetTextureStageState(DWORD Stage,D3DTEXTURESTAGESTATETYPE Type,DWORD Value)
+ {
+ FPRINTF( s_FileHandle, "SetTextureStageState\n" );
+ return m_pD3DDevice->SetTextureStageState( Stage, Type, Value );
+ }
+
+ HRESULT __stdcall ValidateDevice(DWORD* pNumPasses)
+ {
+ FPRINTF( s_FileHandle, "ValidateDevice\n" );
+#if 0
+ return m_pD3DDevice->ValidateDevice( pNumPasses );
+#else
+ return D3D_OK;
+#endif
+ }
+
+ HRESULT __stdcall GetInfo(DWORD DevInfoID,void* pDevInfoStruct,DWORD DevInfoStructSize)
+ {
+ FPRINTF( s_FileHandle, "GetInfo\n" );
+ return m_pD3DDevice->GetInfo( DevInfoID, pDevInfoStruct, DevInfoStructSize );
+ }
+
+ HRESULT __stdcall SetPaletteEntries(UINT PaletteNumber,CONST PALETTEENTRY* pEntries)
+ {
+ FPRINTF( s_FileHandle, "SetPaletteEntries\n" );
+ return m_pD3DDevice->SetPaletteEntries( PaletteNumber, pEntries );
+ }
+
+ HRESULT __stdcall GetPaletteEntries(UINT PaletteNumber,PALETTEENTRY* pEntries)
+ {
+ FPRINTF( s_FileHandle, "GetPaletteEntries\n" );
+ return m_pD3DDevice->GetPaletteEntries( PaletteNumber, pEntries );
+ }
+
+ HRESULT __stdcall SetCurrentTexturePalette(UINT PaletteNumber)
+ {
+ FPRINTF( s_FileHandle, "SetCurrentTexturePalette\n" );
+ return m_pD3DDevice->SetCurrentTexturePalette( PaletteNumber );
+ }
+
+ HRESULT __stdcall GetCurrentTexturePalette(UINT *PaletteNumber)
+ {
+ FPRINTF( s_FileHandle, "GetCurrentTexturePalette\n" );
+ return m_pD3DDevice->GetCurrentTexturePalette( PaletteNumber );
+ }
+
+ HRESULT __stdcall DrawPrimitive(D3DPRIMITIVETYPE PrimitiveType,UINT StartVertex,UINT PrimitiveCount)
+ {
+ FPRINTF( s_FileHandle, "DrawPrimitive\n" );
+ return m_pD3DDevice->DrawPrimitive( PrimitiveType, StartVertex, PrimitiveCount );
+ }
+
+ HRESULT __stdcall DrawIndexedPrimitive(D3DPRIMITIVETYPE primitiveType,UINT minIndex,UINT NumVertices,UINT startIndex,UINT primCount)
+ {
+ FPRINTF( s_FileHandle, "DrawIndexedPrimitive\n" );
+ return m_pD3DDevice->DrawIndexedPrimitive( primitiveType,minIndex,NumVertices,startIndex,primCount );
+ }
+
+ HRESULT __stdcall DrawPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType,UINT PrimitiveCount,CONST void* pVertexStreamZeroData,UINT VertexStreamZeroStride)
+ {
+ FPRINTF( s_FileHandle, "DrawPrimitiveUP\n" );
+ return m_pD3DDevice->DrawPrimitiveUP( PrimitiveType, PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride );
+ }
+
+ HRESULT __stdcall DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType,UINT MinVertexIndex,UINT NumVertexIndices,UINT PrimitiveCount,CONST void* pIndexData,D3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,UINT VertexStreamZeroStride)
+ {
+ FPRINTF( s_FileHandle, "DrawIndexedPrimitiveUP\n" );
+ return m_pD3DDevice->DrawIndexedPrimitiveUP( PrimitiveType, MinVertexIndex, NumVertexIndices, PrimitiveCount, pIndexData, IndexDataFormat,pVertexStreamZeroData, VertexStreamZeroStride );
+ }
+
+ HRESULT __stdcall ProcessVertices(UINT SrcStartIndex,UINT DestIndex,UINT VertexCount,IDirect3DVertexBuffer8* pDestBuffer,DWORD Flags)
+ {
+ FPRINTF( s_FileHandle, "ProcessVertices\n" );
+ return m_pD3DDevice->ProcessVertices( SrcStartIndex, DestIndex, VertexCount, pDestBuffer, Flags );
+ }
+
+ HRESULT __stdcall CreateVertexShader(CONST DWORD* pDeclaration,CONST DWORD* pFunction,DWORD* pHandle,DWORD Usage)
+ {
+ FPRINTF( s_FileHandle, "CreateVertexShader\n" );
+ return m_pD3DDevice->CreateVertexShader( pDeclaration, pFunction, pHandle, Usage );
+ }
+
+ HRESULT __stdcall SetVertexShader(DWORD Handle)
+ {
+ FPRINTF( s_FileHandle, "SetVertexShader\n" );
+ return m_pD3DDevice->SetVertexShader( Handle );
+ }
+
+ HRESULT __stdcall GetVertexShader(DWORD* pHandle)
+ {
+ FPRINTF( s_FileHandle, "GetVertexShader\n" );
+ return m_pD3DDevice->GetVertexShader( pHandle );
+ }
+
+ HRESULT __stdcall DeleteVertexShader(DWORD Handle)
+ {
+ FPRINTF( s_FileHandle, "DeleteVertexShader\n" );
+ return m_pD3DDevice->DeleteVertexShader( Handle );
+ }
+
+ HRESULT __stdcall SetVertexShaderConstant(DWORD Register,CONST void* pConstantData,DWORD ConstantCount)
+ {
+ FPRINTF( s_FileHandle, "SetVertexShaderConstant\n" );
+ return m_pD3DDevice->SetVertexShaderConstant( Register, pConstantData, ConstantCount );
+ }
+
+ HRESULT __stdcall GetVertexShaderConstant(DWORD Register,void* pConstantData,DWORD ConstantCount)
+ {
+ FPRINTF( s_FileHandle, "GetVertexShaderConstant\n" );
+ return m_pD3DDevice->GetVertexShaderConstant( Register, pConstantData, ConstantCount );
+ }
+
+ HRESULT __stdcall GetVertexShaderDeclaration(DWORD Handle,void* pData,DWORD* pSizeOfData)
+ {
+ FPRINTF( s_FileHandle, "GetVertexShaderDeclaration\n" );
+ return m_pD3DDevice->GetVertexShaderDeclaration( Handle, pData, pSizeOfData );
+ }
+
+ HRESULT __stdcall GetVertexShaderFunction(DWORD Handle,void* pData,DWORD* pSizeOfData)
+ {
+ FPRINTF( s_FileHandle, "GetVertexShaderFunction\n" );
+ return m_pD3DDevice->GetVertexShaderFunction( Handle, pData, pSizeOfData );
+ }
+
+ HRESULT __stdcall SetStreamSource(UINT StreamNumber,IDirect3DVertexBuffer8* pStreamData,UINT Stride)
+ {
+ FPRINTF( s_FileHandle, "SetStreamSource\n" );
+ return m_pD3DDevice->SetStreamSource( StreamNumber, pStreamData, Stride );
+ }
+
+ HRESULT __stdcall GetStreamSource(UINT StreamNumber,IDirect3DVertexBuffer8** ppStreamData,UINT* pStride)
+ {
+ FPRINTF( s_FileHandle, "GetStreamSource\n" );
+ return m_pD3DDevice->GetStreamSource( StreamNumber, ppStreamData, pStride );
+ }
+
+ HRESULT __stdcall SetIndices(IDirect3DIndexBuffer8* pIndexData,UINT BaseVertexIndex)
+ {
+ FPRINTF( s_FileHandle, "SetIndices\n" );
+ return m_pD3DDevice->SetIndices( pIndexData, BaseVertexIndex );
+ }
+
+ HRESULT __stdcall GetIndices(IDirect3DIndexBuffer8** ppIndexData,UINT* pBaseVertexIndex)
+ {
+ FPRINTF( s_FileHandle, "GetIndices\n" );
+ return m_pD3DDevice->GetIndices( ppIndexData, pBaseVertexIndex );
+ }
+
+ HRESULT __stdcall CreatePixelShader(CONST DWORD* pFunction,DWORD* pHandle)
+ {
+ FPRINTF( s_FileHandle, "CreatePixelShader\n" );
+ return m_pD3DDevice->CreatePixelShader( pFunction, pHandle );
+ }
+
+ HRESULT __stdcall SetPixelShader(DWORD Handle)
+ {
+ FPRINTF( s_FileHandle, "SetPixelShader\n" );
+ return m_pD3DDevice->SetPixelShader( Handle );
+ }
+
+ HRESULT __stdcall GetPixelShader(DWORD* pHandle)
+ {
+ FPRINTF( s_FileHandle, "GetPixelShader\n" );
+ return m_pD3DDevice->GetPixelShader( pHandle );
+ }
+
+ HRESULT __stdcall DeletePixelShader(DWORD Handle)
+ {
+ FPRINTF( s_FileHandle, "DeletePixelShader\n" );
+ return m_pD3DDevice->DeletePixelShader( Handle );
+ }
+
+ HRESULT __stdcall SetPixelShaderConstant(DWORD Register,CONST void* pConstantData,DWORD ConstantCount)
+ {
+ FPRINTF( s_FileHandle, "SetPixelShaderConstant\n" );
+ return m_pD3DDevice->SetPixelShaderConstant( Register, pConstantData, ConstantCount );
+ }
+
+ HRESULT __stdcall GetPixelShaderConstant(DWORD Register,void* pConstantData,DWORD ConstantCount)
+ {
+ FPRINTF( s_FileHandle, "GetPixelShaderConstant\n" );
+ return m_pD3DDevice->GetPixelShaderConstant( Register, pConstantData, ConstantCount );
+ }
+
+ HRESULT __stdcall GetPixelShaderFunction(DWORD Handle,void* pData,DWORD* pSizeOfData)
+ {
+ FPRINTF( s_FileHandle, "GetPixelShaderFunction\n" );
+ return m_pD3DDevice->GetPixelShaderFunction( Handle, pData, pSizeOfData );
+ }
+
+ HRESULT __stdcall DrawRectPatch(UINT Handle,CONST float* pNumSegs,CONST D3DRECTPATCH_INFO* pRectPatchInfo)
+ {
+ FPRINTF( s_FileHandle, "DrawRectPatch\n" );
+ return m_pD3DDevice->DrawRectPatch( Handle, pNumSegs, pRectPatchInfo );
+ }
+
+ HRESULT __stdcall DrawTriPatch(UINT Handle,CONST float* pNumSegs,CONST D3DTRIPATCH_INFO* pTriPatchInfo)
+ {
+ FPRINTF( s_FileHandle, "DrawTriPatch\n" );
+ return m_pD3DDevice->DrawTriPatch( Handle, pNumSegs, pTriPatchInfo );
+ }
+
+ HRESULT __stdcall DeletePatch(UINT Handle)
+ {
+ FPRINTF( s_FileHandle, "DeletePatch\n" );
+ return m_pD3DDevice->DeletePatch( Handle );
+ }
+};
+
+#endif // STUBD3D
+
+#endif // STUBD3DDEVICE_H
+
diff --git a/materialsystem/shaderapidx9/texturedx8.cpp b/materialsystem/shaderapidx9/texturedx8.cpp
new file mode 100644
index 0000000..d4dbede
--- /dev/null
+++ b/materialsystem/shaderapidx9/texturedx8.cpp
@@ -0,0 +1,1545 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#define DISABLE_PROTECTED_THINGS
+#include "locald3dtypes.h"
+#include "texturedx8.h"
+#include "shaderapidx8_global.h"
+#include "colorformatdx8.h"
+#include "shaderapi/ishaderutil.h"
+#include "materialsystem/imaterialsystem.h"
+#include "utlvector.h"
+#include "recording.h"
+#include "shaderapi/ishaderapi.h"
+#include "filesystem.h"
+#include "locald3dtypes.h"
+#include "textureheap.h"
+#include "tier1/utlbuffer.h"
+#include "tier1/callqueue.h"
+#include "tier0/vprof.h"
+#include "vtf/vtf.h"
+#include "tier0/icommandline.h"
+
+#include "tier0/memdbgon.h"
+
+#ifdef _WIN32
+#pragma warning (disable:4189 4701)
+#endif
+
+static int s_TextureCount = 0;
+static bool s_bTestingVideoMemorySize = false;
+
+//-----------------------------------------------------------------------------
+// Stats...
+//-----------------------------------------------------------------------------
+
+int TextureCount()
+{
+ return s_TextureCount;
+}
+
+static bool IsVolumeTexture( IDirect3DBaseTexture* pBaseTexture )
+{
+ if ( !pBaseTexture )
+ {
+ return false;
+ }
+
+ return ( pBaseTexture->GetType() == D3DRTYPE_VOLUMETEXTURE );
+}
+
+static HRESULT GetLevelDesc( IDirect3DBaseTexture* pBaseTexture, UINT level, D3DSURFACE_DESC* pDesc )
+{
+ MEM_ALLOC_D3D_CREDIT();
+
+ if ( !pBaseTexture )
+ {
+ return ( HRESULT )-1;
+ }
+
+ HRESULT hr;
+ switch( pBaseTexture->GetType() )
+ {
+ case D3DRTYPE_TEXTURE:
+ hr = ( ( IDirect3DTexture * )pBaseTexture )->GetLevelDesc( level, pDesc );
+ break;
+ case D3DRTYPE_CUBETEXTURE:
+ hr = ( ( IDirect3DCubeTexture * )pBaseTexture )->GetLevelDesc( level, pDesc );
+ break;
+ default:
+ return ( HRESULT )-1;
+ }
+ return hr;
+}
+
+static HRESULT GetSurfaceFromTexture( IDirect3DBaseTexture* pBaseTexture, UINT level,
+ D3DCUBEMAP_FACES cubeFaceID, IDirect3DSurface** ppSurfLevel )
+{
+ MEM_ALLOC_D3D_CREDIT();
+
+ if ( !pBaseTexture )
+ {
+ return ( HRESULT )-1;
+ }
+
+ HRESULT hr;
+
+ switch( pBaseTexture->GetType() )
+ {
+ case D3DRTYPE_TEXTURE:
+ hr = ( ( IDirect3DTexture * )pBaseTexture )->GetSurfaceLevel( level, ppSurfLevel );
+ break;
+ case D3DRTYPE_CUBETEXTURE:
+ if (cubeFaceID !=0)
+ {
+ //Debugger();
+ }
+
+ hr = ( ( IDirect3DCubeTexture * )pBaseTexture )->GetCubeMapSurface( cubeFaceID, level, ppSurfLevel );
+ break;
+ default:
+ Assert(0);
+ return ( HRESULT )-1;
+ }
+ return hr;
+}
+
+//-----------------------------------------------------------------------------
+// Gets the image format of a texture
+//-----------------------------------------------------------------------------
+static ImageFormat GetImageFormat( IDirect3DBaseTexture* pTexture )
+{
+ MEM_ALLOC_D3D_CREDIT();
+
+ if ( pTexture )
+ {
+ HRESULT hr;
+ if ( !IsVolumeTexture( pTexture ) )
+ {
+ D3DSURFACE_DESC desc;
+ hr = GetLevelDesc( pTexture, 0, &desc );
+ if ( !FAILED( hr ) )
+ return ImageLoader::D3DFormatToImageFormat( desc.Format );
+ }
+ else
+ {
+ D3DVOLUME_DESC desc;
+ IDirect3DVolumeTexture *pVolumeTexture = static_cast<IDirect3DVolumeTexture*>( pTexture );
+ hr = pVolumeTexture->GetLevelDesc( 0, &desc );
+ if ( !FAILED( hr ) )
+ return ImageLoader::D3DFormatToImageFormat( desc.Format );
+ }
+ }
+
+ // Bogus baby!
+ return (ImageFormat)-1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Allocates the D3DTexture
+//-----------------------------------------------------------------------------
+IDirect3DBaseTexture* CreateD3DTexture( int width, int height, int nDepth,
+ ImageFormat dstFormat, int numLevels, int nCreationFlags, char *debugLabel ) // OK to skip the last param
+{
+ if ( nDepth <= 0 )
+ {
+ nDepth = 1;
+ }
+
+ bool isCubeMap = ( nCreationFlags & TEXTURE_CREATE_CUBEMAP ) != 0;
+ bool bIsRenderTarget = ( nCreationFlags & TEXTURE_CREATE_RENDERTARGET ) != 0;
+ bool bManaged = ( nCreationFlags & TEXTURE_CREATE_MANAGED ) != 0;
+ bool bSysmem = ( nCreationFlags & TEXTURE_CREATE_SYSMEM ) != 0;
+ bool bIsDepthBuffer = ( nCreationFlags & TEXTURE_CREATE_DEPTHBUFFER ) != 0;
+ bool isDynamic = ( nCreationFlags & TEXTURE_CREATE_DYNAMIC ) != 0;
+ bool bAutoMipMap = ( nCreationFlags & TEXTURE_CREATE_AUTOMIPMAP ) != 0;
+ bool bVertexTexture = ( nCreationFlags & TEXTURE_CREATE_VERTEXTEXTURE ) != 0;
+ bool bAllowNonFilterable = ( nCreationFlags & TEXTURE_CREATE_UNFILTERABLE_OK ) != 0;
+ bool bVolumeTexture = ( nDepth > 1 );
+ bool bIsFallback = ( nCreationFlags & TEXTURE_CREATE_FALLBACK ) != 0;
+ bool bNoD3DBits = ( nCreationFlags & TEXTURE_CREATE_NOD3DMEMORY ) != 0;
+ bool bSRGB = (nCreationFlags & TEXTURE_CREATE_SRGB) != 0; // for Posix/GL only
+
+ // NOTE: This function shouldn't be used for creating depth buffers!
+ Assert( !bIsDepthBuffer );
+
+ D3DFORMAT d3dFormat = D3DFMT_UNKNOWN;
+
+ D3DPOOL pool = bManaged ? D3DPOOL_MANAGED : D3DPOOL_DEFAULT;
+ if ( bSysmem )
+ pool = D3DPOOL_SYSTEMMEM;
+
+ if ( IsX360() )
+ {
+ // 360 does not support vertex textures
+ // 360 render target creation path is for the target as a texture source (NOT the EDRAM version)
+ // use normal texture format rules
+ Assert( !bVertexTexture );
+ if ( !bVertexTexture )
+ {
+ d3dFormat = ImageLoader::ImageFormatToD3DFormat( FindNearestSupportedFormat( dstFormat, false, false, false ) );
+ }
+ }
+ else
+ {
+ d3dFormat = ImageLoader::ImageFormatToD3DFormat( FindNearestSupportedFormat( dstFormat, bVertexTexture, bIsRenderTarget, bAllowNonFilterable ) );
+ }
+
+ if ( d3dFormat == D3DFMT_UNKNOWN )
+ {
+ Warning( "ShaderAPIDX8::CreateD3DTexture: Invalid color format!\n" );
+ Assert( 0 );
+ return 0;
+ }
+
+ IDirect3DBaseTexture* pBaseTexture = NULL;
+ IDirect3DTexture* pD3DTexture = NULL;
+ IDirect3DCubeTexture* pD3DCubeTexture = NULL;
+ IDirect3DVolumeTexture* pD3DVolumeTexture = NULL;
+ HRESULT hr = S_OK;
+ DWORD usage = 0;
+
+ if ( bIsRenderTarget )
+ {
+ usage |= D3DUSAGE_RENDERTARGET;
+ }
+ if ( isDynamic )
+ {
+ usage |= D3DUSAGE_DYNAMIC;
+ }
+ if ( bAutoMipMap )
+ {
+ usage |= D3DUSAGE_AUTOGENMIPMAP;
+ }
+
+#ifdef DX_TO_GL_ABSTRACTION
+ {
+ if (bSRGB)
+ {
+ usage |= D3DUSAGE_TEXTURE_SRGB; // does not exist in real DX9... just for GL to know that this is an SRGB tex
+ }
+ }
+#endif
+
+ if ( isCubeMap )
+ {
+#if !defined( _X360 )
+ hr = Dx9Device()->CreateCubeTexture(
+ width,
+ numLevels,
+ usage,
+ d3dFormat,
+ pool,
+ &pD3DCubeTexture,
+ NULL
+ #if defined( DX_TO_GL_ABSTRACTION )
+ , debugLabel // tex create funcs take extra arg for debug name on GL
+ #endif
+ );
+#else
+ pD3DCubeTexture = g_TextureHeap.AllocCubeTexture( width, numLevels, usage, d3dFormat, bIsFallback, bNoD3DBits );
+#endif
+ pBaseTexture = pD3DCubeTexture;
+ }
+ else if ( bVolumeTexture )
+ {
+#if !defined( _X360 )
+ hr = Dx9Device()->CreateVolumeTexture(
+ width,
+ height,
+ nDepth,
+ numLevels,
+ usage,
+ d3dFormat,
+ pool,
+ &pD3DVolumeTexture,
+ NULL
+ #if defined( DX_TO_GL_ABSTRACTION )
+ , debugLabel // tex create funcs take extra arg for debug name on GL
+ #endif
+ );
+#else
+ Assert( !bIsFallback && !bNoD3DBits );
+ pD3DVolumeTexture = g_TextureHeap.AllocVolumeTexture( width, height, nDepth, numLevels, usage, d3dFormat );
+#endif
+ pBaseTexture = pD3DVolumeTexture;
+ }
+ else
+ {
+#if !defined( _X360 )
+ // Override usage and managed params if using special hardware shadow depth map formats...
+ if ( ( d3dFormat == NVFMT_RAWZ ) || ( d3dFormat == NVFMT_INTZ ) ||
+ ( d3dFormat == D3DFMT_D16 ) || ( d3dFormat == D3DFMT_D24S8 ) ||
+ ( d3dFormat == ATIFMT_D16 ) || ( d3dFormat == ATIFMT_D24S8 ) )
+ {
+ // Not putting D3DUSAGE_RENDERTARGET here causes D3D debug spew later, but putting the flag causes this create to fail...
+ usage = D3DUSAGE_DEPTHSTENCIL;
+ bManaged = false;
+ }
+
+ // Override managed param if using special null texture format
+ if ( d3dFormat == NVFMT_NULL )
+ {
+ bManaged = false;
+ }
+
+ hr = Dx9Device()->CreateTexture(
+ width,
+ height,
+ numLevels,
+ usage,
+ d3dFormat,
+ pool,
+ &pD3DTexture,
+ NULL
+ #if defined( DX_TO_GL_ABSTRACTION )
+ , debugLabel // tex create funcs take extra arg for debug name on GL
+ #endif
+ );
+
+#else
+ pD3DTexture = g_TextureHeap.AllocTexture( width, height, numLevels, usage, d3dFormat, bIsFallback, bNoD3DBits );
+#endif
+ pBaseTexture = pD3DTexture;
+ }
+
+ if ( FAILED( hr ) )
+ {
+#ifdef ENABLE_NULLREF_DEVICE_SUPPORT
+ if( CommandLine()->FindParm( "-nulldevice" ) )
+ {
+ Warning( "ShaderAPIDX8::CreateD3DTexture: Null device used. Texture not created.\n" );
+ return 0;
+ }
+#endif
+
+ switch ( hr )
+ {
+ case D3DERR_INVALIDCALL:
+ Warning( "ShaderAPIDX8::CreateD3DTexture: D3DERR_INVALIDCALL\n" );
+ break;
+ case D3DERR_OUTOFVIDEOMEMORY:
+ // This conditional is here so that we don't complain when testing
+ // how much video memory we have. . this is kinda gross.
+ if ( !s_bTestingVideoMemorySize )
+ {
+ Warning( "ShaderAPIDX8::CreateD3DTexture: D3DERR_OUTOFVIDEOMEMORY\n" );
+ }
+ break;
+ case E_OUTOFMEMORY:
+ Warning( "ShaderAPIDX8::CreateD3DTexture: E_OUTOFMEMORY\n" );
+ break;
+ default:
+ break;
+ }
+ return 0;
+ }
+
+#ifdef MEASURE_DRIVER_ALLOCATIONS
+ int nMipCount = numLevels;
+ if ( !nMipCount )
+ {
+ while ( width > 1 || height > 1 )
+ {
+ width >>= 1;
+ height >>= 1;
+ ++nMipCount;
+ }
+ }
+
+ int nMemUsed = nMipCount * 1.1f * 1024;
+ if ( isCubeMap )
+ {
+ nMemUsed *= 6;
+ }
+
+ VPROF_INCREMENT_GROUP_COUNTER( "texture count", COUNTER_GROUP_NO_RESET, 1 );
+ VPROF_INCREMENT_GROUP_COUNTER( "texture driver mem", COUNTER_GROUP_NO_RESET, nMemUsed );
+ VPROF_INCREMENT_GROUP_COUNTER( "total driver mem", COUNTER_GROUP_NO_RESET, nMemUsed );
+#endif
+
+ ++s_TextureCount;
+
+ return pBaseTexture;
+}
+
+
+//-----------------------------------------------------------------------------
+// Texture destruction
+//-----------------------------------------------------------------------------
+void ReleaseD3DTexture( IDirect3DBaseTexture* pD3DTex )
+{
+ int ref = pD3DTex->Release();
+ Assert( ref == 0 );
+}
+
+void DestroyD3DTexture( IDirect3DBaseTexture* pD3DTex )
+{
+ if ( pD3DTex )
+ {
+#ifdef MEASURE_DRIVER_ALLOCATIONS
+ D3DRESOURCETYPE type = pD3DTex->GetType();
+ int nMipCount = pD3DTex->GetLevelCount();
+ if ( type == D3DRTYPE_CUBETEXTURE )
+ {
+ nMipCount *= 6;
+ }
+ int nMemUsed = nMipCount * 1.1f * 1024;
+ VPROF_INCREMENT_GROUP_COUNTER( "texture count", COUNTER_GROUP_NO_RESET, -1 );
+ VPROF_INCREMENT_GROUP_COUNTER( "texture driver mem", COUNTER_GROUP_NO_RESET, -nMemUsed );
+ VPROF_INCREMENT_GROUP_COUNTER( "total driver mem", COUNTER_GROUP_NO_RESET, -nMemUsed );
+#endif
+
+#if !defined( _X360 )
+ CMatRenderContextPtr pRenderContext( materials );
+ ICallQueue *pCallQueue;
+ if ( ( pCallQueue = pRenderContext->GetCallQueue() ) != NULL )
+ {
+ pCallQueue->QueueCall( ReleaseD3DTexture, pD3DTex );
+ }
+ else
+ {
+ ReleaseD3DTexture( pD3DTex );
+ }
+#else
+ g_TextureHeap.FreeTexture( pD3DTex );
+#endif
+ --s_TextureCount;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pTex -
+// Output : int
+//-----------------------------------------------------------------------------
+int GetD3DTextureRefCount( IDirect3DBaseTexture *pTex )
+{
+ if ( !pTex )
+ return 0;
+
+ pTex->AddRef();
+ int ref = pTex->Release();
+
+ return ref;
+}
+
+//-----------------------------------------------------------------------------
+// See version 13 for a function that converts a texture to a mipmap (ConvertToMipmap)
+//-----------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------
+// Lock, unlock a texture...
+//-----------------------------------------------------------------------------
+
+static RECT s_LockedSrcRect;
+static D3DLOCKED_RECT s_LockedRect;
+#ifdef DBGFLAG_ASSERT
+static bool s_bInLock = false;
+#endif
+
+bool LockTexture( ShaderAPITextureHandle_t bindId, int copy, IDirect3DBaseTexture* pTexture, int level,
+ D3DCUBEMAP_FACES cubeFaceID, int xOffset, int yOffset, int width, int height, bool bDiscard,
+ CPixelWriter& writer )
+{
+ Assert( !s_bInLock );
+
+ IDirect3DSurface* pSurf;
+ HRESULT hr = GetSurfaceFromTexture( pTexture, level, cubeFaceID, &pSurf );
+ if ( FAILED( hr ) )
+ return false;
+
+ s_LockedSrcRect.left = xOffset;
+ s_LockedSrcRect.right = xOffset + width;
+ s_LockedSrcRect.top = yOffset;
+ s_LockedSrcRect.bottom = yOffset + height;
+
+ unsigned int flags = D3DLOCK_NOSYSLOCK;
+ flags |= bDiscard ? D3DLOCK_DISCARD : 0;
+ RECORD_COMMAND( DX8_LOCK_TEXTURE, 6 );
+ RECORD_INT( bindId );
+ RECORD_INT( copy );
+ RECORD_INT( level );
+ RECORD_INT( cubeFaceID );
+ RECORD_STRUCT( &s_LockedSrcRect, sizeof(s_LockedSrcRect) );
+ RECORD_INT( flags );
+
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "D3DLockTexture" );
+
+ hr = pSurf->LockRect( &s_LockedRect, &s_LockedSrcRect, flags );
+ pSurf->Release();
+
+ if ( FAILED( hr ) )
+ return false;
+
+ writer.SetPixelMemory( GetImageFormat(pTexture), s_LockedRect.pBits, s_LockedRect.Pitch );
+
+#ifdef DBGFLAG_ASSERT
+ s_bInLock = true;
+#endif
+ return true;
+}
+
+void UnlockTexture( ShaderAPITextureHandle_t bindId, int copy, IDirect3DBaseTexture* pTexture, int level,
+ D3DCUBEMAP_FACES cubeFaceID )
+{
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
+
+ Assert( s_bInLock );
+
+ IDirect3DSurface* pSurf;
+ HRESULT hr = GetSurfaceFromTexture( pTexture, level, cubeFaceID, &pSurf );
+ if (FAILED(hr))
+ return;
+
+#ifdef RECORD_TEXTURES
+ int width = s_LockedSrcRect.right - s_LockedSrcRect.left;
+ int height = s_LockedSrcRect.bottom - s_LockedSrcRect.top;
+ int imageFormatSize = ImageLoader::SizeInBytes( GetImageFormat( pTexture ) );
+ Assert( imageFormatSize != 0 );
+ int validDataBytesPerRow = imageFormatSize * width;
+ int storeSize = validDataBytesPerRow * height;
+ static CUtlVector< unsigned char > tmpMem;
+ if( tmpMem.Size() < storeSize )
+ {
+ tmpMem.AddMultipleToTail( storeSize - tmpMem.Size() );
+ }
+ unsigned char *pDst = tmpMem.Base();
+ unsigned char *pSrc = ( unsigned char * )s_LockedRect.pBits;
+ RECORD_COMMAND( DX8_SET_TEXTURE_DATA, 3 );
+ RECORD_INT( validDataBytesPerRow );
+ RECORD_INT( height );
+ int i;
+ for( i = 0; i < height; i++ )
+ {
+ memcpy( pDst, pSrc, validDataBytesPerRow );
+ pDst += validDataBytesPerRow;
+ pSrc += s_LockedRect.Pitch;
+ }
+ RECORD_STRUCT( tmpMem.Base(), storeSize );
+#endif // RECORD_TEXTURES
+
+ RECORD_COMMAND( DX8_UNLOCK_TEXTURE, 4 );
+ RECORD_INT( bindId );
+ RECORD_INT( copy );
+ RECORD_INT( level );
+ RECORD_INT( cubeFaceID );
+
+ hr = pSurf->UnlockRect();
+ pSurf->Release();
+#ifdef DBGFLAG_ASSERT
+ s_bInLock = false;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Compute texture size based on compression
+//-----------------------------------------------------------------------------
+
+static inline int DetermineGreaterPowerOfTwo( int val )
+{
+ int num = 1;
+ while (val > num)
+ {
+ num <<= 1;
+ }
+
+ return num;
+}
+
+inline int DeterminePowerOfTwo( int val )
+{
+ int pow = 0;
+ while ((val & 0x1) == 0x0)
+ {
+ val >>= 1;
+ ++pow;
+ }
+
+ return pow;
+}
+
+
+//-----------------------------------------------------------------------------
+// Blit in bits
+//-----------------------------------------------------------------------------
+// NOTE: IF YOU CHANGE THIS, CHANGE THE VERSION IN PLAYBACK.CPP!!!!
+// OPTIMIZE??: could lock the texture directly instead of the surface in dx9.
+#if !defined( _X360 )
+static void BlitSurfaceBits( TextureLoadInfo_t &info, int xOffset, int yOffset, int srcStride )
+{
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
+
+ // Get the level of the texture we want to write into
+ IDirect3DSurface* pTextureLevel;
+
+ if (info.m_CubeFaceID !=0)
+ {
+ //Debugger();
+ }
+
+
+ HRESULT hr = GetSurfaceFromTexture( info.m_pTexture, info.m_nLevel, info.m_CubeFaceID, &pTextureLevel );
+ if ( FAILED( hr ) )
+ return;
+
+ RECT srcRect;
+ RECT *pSrcRect = NULL;
+ D3DLOCKED_RECT lockedRect;
+
+ srcRect.left = xOffset;
+ srcRect.right = xOffset + info.m_nWidth;
+ srcRect.top = yOffset;
+ srcRect.bottom = yOffset + info.m_nHeight;
+
+#if defined( SHADERAPIDX9 ) && !defined( _X360 ) && !defined( DX_TO_GL_ABSTRACTION )
+ if ( !info.m_bTextureIsLockable )
+ {
+ // Copy from system memory to video memory using D3D9Device->UpdateSurface
+ bool bSuccess = false;
+
+ D3DSURFACE_DESC desc;
+ Verify( pTextureLevel->GetDesc( &desc ) == S_OK );
+ ImageFormat dstFormat = ImageLoader::D3DFormatToImageFormat( desc.Format );
+ D3DFORMAT dstFormatD3D = ImageLoader::ImageFormatToD3DFormat( dstFormat );
+
+ IDirect3DSurface* pSrcSurface = NULL;
+ bool bCopyBitsToSrcSurface = true;
+
+#if defined(IS_WINDOWS_PC) && defined(SHADERAPIDX9)
+ // D3D9Ex fast path: create a texture wrapping our own system memory buffer
+ // if the source and destination formats are exactly the same and the stride
+ // is tightly packed. no locking/blitting required.
+ // NOTE: the fast path does not work on sub-4x4 DXT compressed textures.
+ extern bool g_ShaderDeviceUsingD3D9Ex;
+ if ( g_ShaderDeviceUsingD3D9Ex &&
+ ( info.m_SrcFormat == dstFormat || ( info.m_SrcFormat == IMAGE_FORMAT_DXT1_ONEBITALPHA && dstFormat == IMAGE_FORMAT_DXT1 ) ) &&
+ ( !ImageLoader::IsCompressed( dstFormat ) || (info.m_nWidth >= 4 || info.m_nHeight >= 4) ) )
+ {
+ if ( srcStride == 0 || srcStride == info.m_nWidth * ImageLoader::SizeInBytes( info.m_SrcFormat ) )
+ {
+ IDirect3DTexture9* pTempTex = NULL;
+ if ( Dx9Device()->CreateTexture( info.m_nWidth, info.m_nHeight, 1, 0, dstFormatD3D, D3DPOOL_SYSTEMMEM, &pTempTex, (HANDLE*) &info.m_pSrcData ) == S_OK )
+ {
+ IDirect3DSurface* pTempSurf = NULL;
+ if ( pTempTex->GetSurfaceLevel( 0, &pTempSurf ) == S_OK )
+ {
+ pSrcSurface = pTempSurf;
+ bCopyBitsToSrcSurface = false;
+ }
+ pTempTex->Release();
+ }
+ }
+ }
+#endif
+
+ // If possible to create a texture of this size, create a temporary texture in
+ // system memory and then use the UpdateSurface method to copy between textures.
+ if ( !pSrcSurface && ( g_pHardwareConfig->Caps().m_SupportsNonPow2Textures ||
+ ( IsPowerOfTwo( info.m_nWidth ) && IsPowerOfTwo( info.m_nHeight ) ) ) )
+ {
+ int tempW = info.m_nWidth, tempH = info.m_nHeight, mip = 0;
+ if ( info.m_nLevel > 0 && ( ( tempW | tempH ) & 3 ) && ImageLoader::IsCompressed( dstFormat ) )
+ {
+ // Loading lower mip levels of DXT compressed textures is sort of tricky
+ // because we can't create textures that aren't multiples of 4, and we can't
+ // pass subrectangles of DXT textures into UpdateSurface. Create a temporary
+ // texture which is 1 or 2 mip levels larger and then lock the appropriate
+ // mip level to grab its correctly-dimensioned surface. -henryg 11/18/2011
+ mip = ( info.m_nLevel > 1 && ( ( tempW | tempH ) & 1 ) ) ? 2 : 1;
+ tempW <<= mip;
+ tempH <<= mip;
+ }
+
+ IDirect3DTexture9* pTempTex = NULL;
+ IDirect3DSurface* pTempSurf = NULL;
+ if ( Dx9Device()->CreateTexture( tempW, tempH, mip+1, 0, dstFormatD3D, D3DPOOL_SYSTEMMEM, &pTempTex, NULL ) == S_OK )
+ {
+ if ( pTempTex->GetSurfaceLevel( mip, &pTempSurf ) == S_OK )
+ {
+ pSrcSurface = pTempSurf;
+ bCopyBitsToSrcSurface = true;
+ }
+ pTempTex->Release();
+ }
+ }
+
+ // Create an offscreen surface if the texture path wasn't an option.
+ if ( !pSrcSurface )
+ {
+ IDirect3DSurface* pTempSurf = NULL;
+ if ( Dx9Device()->CreateOffscreenPlainSurface( info.m_nWidth, info.m_nHeight, dstFormatD3D, D3DPOOL_SYSTEMMEM, &pTempSurf, NULL ) == S_OK )
+ {
+ pSrcSurface = pTempSurf;
+ bCopyBitsToSrcSurface = true;
+ }
+ }
+
+ // Lock and fill the surface
+ if ( bCopyBitsToSrcSurface && pSrcSurface )
+ {
+ if ( pSrcSurface->LockRect( &lockedRect, NULL, D3DLOCK_NOSYSLOCK ) == S_OK )
+ {
+ unsigned char *pImage = (unsigned char *)lockedRect.pBits;
+ ShaderUtil()->ConvertImageFormat( info.m_pSrcData, info.m_SrcFormat,
+ pImage, dstFormat, info.m_nWidth, info.m_nHeight, srcStride, lockedRect.Pitch );
+ pSrcSurface->UnlockRect();
+ }
+ else
+ {
+ // Lock failed.
+ pSrcSurface->Release();
+ pSrcSurface = NULL;
+ }
+ }
+
+ // Perform the UpdateSurface call that blits between system and video memory
+ if ( pSrcSurface )
+ {
+ POINT pt = { xOffset, yOffset };
+ bSuccess = ( Dx9Device()->UpdateSurface( pSrcSurface, NULL, pTextureLevel, &pt ) == S_OK );
+ pSrcSurface->Release();
+ }
+
+ if ( !bSuccess )
+ {
+ Warning( "CShaderAPIDX8::BlitTextureBits: couldn't lock texture rect or use UpdateSurface\n" );
+ }
+
+ pTextureLevel->Release();
+ return;
+ }
+#endif
+
+ Assert( info.m_bTextureIsLockable );
+
+#ifndef RECORD_TEXTURES
+ RECORD_COMMAND( DX8_LOCK_TEXTURE, 6 );
+ RECORD_INT( info.m_TextureHandle );
+ RECORD_INT( info.m_nCopy );
+ RECORD_INT( info.m_nLevel );
+ RECORD_INT( info.m_CubeFaceID );
+ RECORD_STRUCT( &srcRect, sizeof(srcRect) );
+ RECORD_INT( D3DLOCK_NOSYSLOCK );
+#endif
+
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - D3DLockRect", __FUNCTION__ );
+
+ // lock the region (could be the full surface or less)
+ if ( FAILED( pTextureLevel->LockRect( &lockedRect, &srcRect, D3DLOCK_NOSYSLOCK ) ) )
+ {
+ Warning( "CShaderAPIDX8::BlitTextureBits: couldn't lock texture rect\n" );
+ pTextureLevel->Release();
+ return;
+ }
+ }
+
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - ConvertImageFormat", __FUNCTION__ );
+
+ // garymcthack : need to make a recording command for this.
+ ImageFormat dstFormat = GetImageFormat( info.m_pTexture );
+ unsigned char *pImage = (unsigned char *)lockedRect.pBits;
+ ShaderUtil()->ConvertImageFormat( info.m_pSrcData, info.m_SrcFormat,
+ pImage, dstFormat, info.m_nWidth, info.m_nHeight, srcStride, lockedRect.Pitch );
+ }
+
+#ifndef RECORD_TEXTURES
+ RECORD_COMMAND( DX8_UNLOCK_TEXTURE, 4 );
+ RECORD_INT( info.m_TextureHandle );
+ RECORD_INT( info.m_nCopy );
+ RECORD_INT( info.m_nLevel );
+ RECORD_INT( info.m_CubeFaceID );
+#endif
+
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - UnlockRect", __FUNCTION__ );
+
+ if ( FAILED( pTextureLevel->UnlockRect() ) )
+ {
+ Warning( "CShaderAPIDX8::BlitTextureBits: couldn't unlock texture rect\n" );
+ pTextureLevel->Release();
+ return;
+ }
+ }
+
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - pTextureLevel->Release", __FUNCTION__ );
+ pTextureLevel->Release();
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// Puts 2D texture data into 360 gpu memory.
+//-----------------------------------------------------------------------------
+#if defined( _X360 )
+static void BlitSurfaceBits( TextureLoadInfo_t &info, int xOffset, int yOffset, int srcStride )
+{
+ // xbox textures are NOT backed in gpu memory contiguously
+ // stride details are critical - see [Xbox 360 Texture Storage]
+ // a d3dformat identifier on the xbox is tiled, the same d3dformat on the pc is expected linear to the app
+ // we purposely hide the tiling here, otherwise much confusion for the pc
+ // the *entire* target must be un-tiled *only* before any *subrect* blitting linear work
+ // the *entire* target must then be re-tiled after the *subrect* blit
+ // procedural textures require this to subrect blit their new portions correctly
+ // the tiling dance can be avoided if the source and target match in tiled state during a full rect blit
+
+ if ( info.m_bSrcIsTiled )
+ {
+ // not supporting subrect blitting from a tiled source
+ Assert( 0 );
+ return;
+ }
+
+ CUtlBuffer formatConvertMemory;
+ unsigned char *pSrcData = info.m_pSrcData;
+
+ ImageFormat dstFormat = GetImageFormat( info.m_pTexture );
+ if ( dstFormat != info.m_SrcFormat )
+ {
+ if ( !info.m_bCanConvertFormat )
+ {
+ // texture is expected to be in target format
+ // not supporting conversion of a tiled source
+ Assert( 0 );
+ return;
+ }
+
+ int srcSize = ImageLoader::GetMemRequired( info.m_nWidth, info.m_nHeight, 1, info.m_SrcFormat, false );
+ int dstSize = ImageLoader::GetMemRequired( info.m_nWidth, info.m_nHeight, 1, dstFormat, false );
+ formatConvertMemory.EnsureCapacity( dstSize );
+
+ // due to format conversion, source is in non-native order
+ ImageLoader::PreConvertSwapImageData( (unsigned char*)info.m_pSrcData, srcSize, info.m_SrcFormat, info.m_nWidth, srcStride );
+
+ // slow conversion operation
+ if ( !ShaderUtil()->ConvertImageFormat(
+ info.m_pSrcData,
+ info.m_SrcFormat,
+ (unsigned char*)formatConvertMemory.Base(),
+ dstFormat,
+ info.m_nWidth,
+ info.m_nHeight,
+ srcStride,
+ 0 ) )
+ {
+ // conversion failed
+ Assert( 0 );
+ return;
+ }
+
+ // due to format conversion, source must have been in non-native order
+ ImageLoader::PostConvertSwapImageData( (unsigned char*)formatConvertMemory.Base(), dstSize, dstFormat );
+
+ pSrcData = (unsigned char*)formatConvertMemory.Base();
+ }
+
+ // get the top mip level info (needed for proper sub mip access)
+ XGTEXTURE_DESC baseDesc;
+ XGGetTextureDesc( info.m_pTexture, 0, &baseDesc );
+ bool bDstIsTiled = XGIsTiledFormat( baseDesc.Format ) == TRUE;
+
+ // get the target mip level info
+ XGTEXTURE_DESC mipDesc;
+ XGGetTextureDesc( info.m_pTexture, info.m_nLevel, &mipDesc );
+ bool bFullSurfBlit = ( mipDesc.Width == (unsigned)info.m_nWidth && mipDesc.Height == (unsigned)info.m_nHeight );
+
+ // get the mip level of the texture we want to write into
+ IDirect3DSurface* pTextureLevel;
+ HRESULT hr = GetSurfaceFromTexture( info.m_pTexture, info.m_nLevel, info.m_CubeFaceID, &pTextureLevel );
+ if ( FAILED( hr ) )
+ {
+ Warning( "CShaderAPIDX8::BlitTextureBits: GetSurfaceFromTexture() failure\n" );
+ return;
+ }
+
+ CUtlBuffer scratchMemory;
+ D3DLOCKED_RECT lockedRect;
+
+ hr = pTextureLevel->LockRect( &lockedRect, NULL, D3DLOCK_NOSYSLOCK );
+ if ( FAILED( hr ) )
+ {
+ Warning( "CShaderAPIDX8::BlitTextureBits: couldn't lock texture rect\n" );
+ goto cleanUp;
+ }
+ unsigned char *pTargetImage = (unsigned char *)lockedRect.pBits;
+
+ POINT p;
+ p.x = xOffset;
+ p.y = yOffset;
+
+ RECT r;
+ r.left = 0;
+ r.top = 0;
+ r.right = info.m_nWidth;
+ r.bottom = info.m_nHeight;
+
+ int blockSize = mipDesc.Width/mipDesc.WidthInBlocks;
+ if ( !srcStride )
+ {
+ srcStride = (mipDesc.Width/blockSize)*mipDesc.BytesPerBlock;
+ }
+
+ // subrect blitting path
+ if ( !bDstIsTiled )
+ {
+ // Copy the subrect without conversion
+ hr = XGCopySurface(
+ pTargetImage,
+ mipDesc.RowPitch,
+ mipDesc.Width,
+ mipDesc.Height,
+ mipDesc.Format,
+ &p,
+ pSrcData,
+ srcStride,
+ mipDesc.Format,
+ &r,
+ 0,
+ 0 );
+ if ( FAILED( hr ) )
+ {
+ Warning( "CShaderAPIDX8::BlitTextureBits: failed subrect copy\n" );
+ goto cleanUp;
+ }
+ }
+ else
+ {
+ int tileFlags = 0;
+ if ( !( mipDesc.Flags & XGTDESC_PACKED ) )
+ tileFlags |= XGTILE_NONPACKED;
+ if ( mipDesc.Flags & XGTDESC_BORDERED )
+ tileFlags |= XGTILE_BORDER;
+
+ // tile the temp store back into the target surface
+ XGTileTextureLevel(
+ baseDesc.Width,
+ baseDesc.Height,
+ info.m_nLevel,
+ XGGetGpuFormat( baseDesc.Format ),
+ tileFlags,
+ pTargetImage,
+ &p,
+ pSrcData,
+ srcStride,
+ &r );
+ }
+
+ hr = pTextureLevel->UnlockRect();
+ if ( FAILED( hr ) )
+ {
+ Warning( "CShaderAPIDX8::BlitTextureBits: couldn't unlock texture rect\n" );
+ goto cleanUp;
+ }
+
+cleanUp:
+ pTextureLevel->Release();
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// Blit in bits
+//-----------------------------------------------------------------------------
+#if !defined( _X360 )
+static void BlitVolumeBits( TextureLoadInfo_t &info, int xOffset, int yOffset, int srcStride )
+{
+ D3DBOX srcBox;
+ D3DLOCKED_BOX lockedBox;
+ srcBox.Left = xOffset;
+ srcBox.Right = xOffset + info.m_nWidth;
+ srcBox.Top = yOffset;
+ srcBox.Bottom = yOffset + info.m_nHeight;
+ srcBox.Front = info.m_nZOffset;
+ srcBox.Back = info.m_nZOffset + 1;
+
+#ifndef RECORD_TEXTURES
+ RECORD_COMMAND( DX8_LOCK_TEXTURE, 6 );
+ RECORD_INT( info.m_TextureHandle );
+ RECORD_INT( info.m_nCopy );
+ RECORD_INT( info.m_nLevel );
+ RECORD_INT( info.m_CubeFaceID );
+ RECORD_STRUCT( &srcRect, sizeof(srcRect) );
+ RECORD_INT( D3DLOCK_NOSYSLOCK );
+#endif
+
+ IDirect3DVolumeTexture *pVolumeTexture = static_cast<IDirect3DVolumeTexture*>( info.m_pTexture );
+ if ( FAILED( pVolumeTexture->LockBox( info.m_nLevel, &lockedBox, &srcBox, D3DLOCK_NOSYSLOCK ) ) )
+ {
+ Warning( "BlitVolumeBits: couldn't lock volume texture rect\n" );
+ return;
+ }
+
+ // garymcthack : need to make a recording command for this.
+ ImageFormat dstFormat = GetImageFormat( info.m_pTexture );
+ unsigned char *pImage = (unsigned char *)lockedBox.pBits;
+ ShaderUtil()->ConvertImageFormat( info.m_pSrcData, info.m_SrcFormat,
+ pImage, dstFormat, info.m_nWidth, info.m_nHeight, srcStride, lockedBox.RowPitch );
+
+#ifndef RECORD_TEXTURES
+ RECORD_COMMAND( DX8_UNLOCK_TEXTURE, 4 );
+ RECORD_INT( info.m_TextureHandle );
+ RECORD_INT( info.m_nCopy );
+ RECORD_INT( info.m_nLevel );
+ RECORD_INT( info.m_CubeFaceID );
+#endif
+
+ if ( FAILED( pVolumeTexture->UnlockBox( info.m_nLevel ) ) )
+ {
+ Warning( "BlitVolumeBits: couldn't unlock volume texture rect\n" );
+ return;
+ }
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// Puts 3D texture data into 360 gpu memory.
+// Does not support any subvolume or slice blitting.
+//-----------------------------------------------------------------------------
+#if defined( _X360 )
+static void BlitVolumeBits( TextureLoadInfo_t &info, int xOffset, int yOffset, int srcStride )
+{
+ if ( xOffset || yOffset || info.m_nZOffset || srcStride )
+ {
+ // not supporting any subvolume blitting
+ // the entire volume per mip must be blitted
+ Assert( 0 );
+ return;
+ }
+
+ ImageFormat dstFormat = GetImageFormat( info.m_pTexture );
+ if ( dstFormat != info.m_SrcFormat )
+ {
+ // texture is expected to be in target format
+ // not supporting conversion
+ Assert( 0 );
+ return;
+ }
+
+ // get the top mip level info (needed for proper sub mip access)
+ XGTEXTURE_DESC baseDesc;
+ XGGetTextureDesc( info.m_pTexture, 0, &baseDesc );
+ bool bDstIsTiled = XGIsTiledFormat( baseDesc.Format ) == TRUE;
+ if ( info.m_bSrcIsTiled && !bDstIsTiled )
+ {
+ // not supporting a tiled source into an untiled target
+ Assert( 0 );
+ return;
+ }
+
+ // get the mip level info
+ XGTEXTURE_DESC mipDesc;
+ XGGetTextureDesc( info.m_pTexture, info.m_nLevel, &mipDesc );
+ bool bFullSurfBlit = ( mipDesc.Width == (unsigned int)info.m_nWidth && mipDesc.Height == (unsigned int)info.m_nHeight );
+
+ if ( !bFullSurfBlit )
+ {
+ // not supporting subrect blitting
+ Assert( 0 );
+ return;
+ }
+
+ D3DLOCKED_BOX lockedBox;
+
+ // get the mip level of the volume we want to write into
+ IDirect3DVolumeTexture *pVolumeTexture = static_cast<IDirect3DVolumeTexture*>( info.m_pTexture );
+ HRESULT hr = pVolumeTexture->LockBox( info.m_nLevel, &lockedBox, NULL, D3DLOCK_NOSYSLOCK );
+ if ( FAILED( hr ) )
+ {
+ Warning( "CShaderAPIDX8::BlitVolumeBits: Couldn't lock volume box\n" );
+ return;
+ }
+
+ unsigned char *pSrcData = info.m_pSrcData;
+ unsigned char *pTargetImage = (unsigned char *)lockedBox.pBits;
+
+ int tileFlags = 0;
+ if ( !( mipDesc.Flags & XGTDESC_PACKED ) )
+ tileFlags |= XGTILE_NONPACKED;
+ if ( mipDesc.Flags & XGTDESC_BORDERED )
+ tileFlags |= XGTILE_BORDER;
+
+ if ( !info.m_bSrcIsTiled && bDstIsTiled )
+ {
+ // tile the source directly into the target surface
+ XGTileVolumeTextureLevel(
+ baseDesc.Width,
+ baseDesc.Height,
+ baseDesc.Depth,
+ info.m_nLevel,
+ XGGetGpuFormat( baseDesc.Format ),
+ tileFlags,
+ pTargetImage,
+ NULL,
+ pSrcData,
+ mipDesc.RowPitch,
+ mipDesc.SlicePitch,
+ NULL );
+ }
+ else if ( !info.m_bSrcIsTiled && !bDstIsTiled )
+ {
+ // not implemented yet
+ Assert( 0 );
+ }
+ else
+ {
+ // not implemented yet
+ Assert( 0 );
+ }
+
+ hr = pVolumeTexture->UnlockBox( info.m_nLevel );
+ if ( FAILED( hr ) )
+ {
+ Warning( "CShaderAPIDX8::BlitVolumeBits: couldn't unlock volume box\n" );
+ return;
+ }
+}
+#endif
+
+// FIXME: How do I blit from D3DPOOL_SYSTEMMEM to D3DPOOL_MANAGED? I used to use CopyRects for this. UpdateSurface doesn't work because it can't blit to anything besides D3DPOOL_DEFAULT.
+// We use this only in the case where we need to create a < 4x4 miplevel for a compressed texture. We end up creating a 4x4 system memory texture, and blitting it into the proper miplevel.
+// 6) LockRects should be used for copying between SYSTEMMEM and
+// MANAGED. For such a small copy, you'd avoid a significant
+// amount of overhead from the old CopyRects code. Ideally, you
+// should just lock the bottom of MANAGED and generate your
+// sub-4x4 data there.
+
+// NOTE: IF YOU CHANGE THIS, CHANGE THE VERSION IN PLAYBACK.CPP!!!!
+static void BlitTextureBits( TextureLoadInfo_t &info, int xOffset, int yOffset, int srcStride )
+{
+#ifdef RECORD_TEXTURES
+ RECORD_COMMAND( DX8_BLIT_TEXTURE_BITS, 14 );
+ RECORD_INT( info.m_TextureHandle );
+ RECORD_INT( info.m_nCopy );
+ RECORD_INT( info.m_nLevel );
+ RECORD_INT( info.m_CubeFaceID );
+ RECORD_INT( xOffset );
+ RECORD_INT( yOffset );
+ RECORD_INT( info.m_nZOffset );
+ RECORD_INT( info.m_nWidth );
+ RECORD_INT( info.m_nHeight );
+ RECORD_INT( info.m_SrcFormat );
+ RECORD_INT( srcStride );
+ RECORD_INT( GetImageFormat( info.m_pTexture ) );
+ // strides are in bytes.
+ int srcDataSize;
+ if ( srcStride == 0 )
+ {
+ srcDataSize = ImageLoader::GetMemRequired( info.m_nWidth, info.m_nHeight, 1, info.m_SrcFormat, false );
+ }
+ else
+ {
+ srcDataSize = srcStride * info.m_nHeight;
+ }
+ RECORD_INT( srcDataSize );
+ RECORD_STRUCT( info.m_pSrcData, srcDataSize );
+#endif // RECORD_TEXTURES
+
+ if ( !IsVolumeTexture( info.m_pTexture ) )
+ {
+ Assert( info.m_nZOffset == 0 );
+ BlitSurfaceBits( info, xOffset, yOffset, srcStride );
+ }
+ else
+ {
+ BlitVolumeBits( info, xOffset, yOffset, srcStride );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Texture image upload
+//-----------------------------------------------------------------------------
+void LoadTexture( TextureLoadInfo_t &info )
+{
+ MEM_ALLOC_D3D_CREDIT();
+
+ Assert( info.m_pSrcData );
+ Assert( info.m_pTexture );
+
+#ifdef _DEBUG
+ ImageFormat format = GetImageFormat( info.m_pTexture );
+ Assert( (format != -1) && (format == FindNearestSupportedFormat( format, false, false, false )) );
+#endif
+
+ // Copy in the bits...
+ BlitTextureBits( info, 0, 0, 0 );
+}
+
+void LoadVolumeTextureFromVTF( TextureLoadInfo_t &info, IVTFTexture* pVTF, int iVTFFrame )
+{
+ if ( !info.m_pTexture || info.m_pTexture->GetType() != D3DRTYPE_VOLUMETEXTURE )
+ {
+ Assert( 0 );
+ return;
+ }
+
+ IDirect3DVolumeTexture9 *pVolTex = static_cast<IDirect3DVolumeTexture*>( info.m_pTexture );
+
+ D3DVOLUME_DESC desc;
+ if ( pVolTex->GetLevelDesc( 0, &desc ) != S_OK )
+ {
+ Warning( "LoadVolumeTextureFromVTF: couldn't get texture level description\n" );
+ return;
+ }
+
+ int iMipCount = pVolTex->GetLevelCount();
+ if ( pVTF->Depth() != (int)desc.Depth || pVTF->Width() != (int)desc.Width || pVTF->Height() != (int)desc.Height || pVTF->MipCount() < iMipCount )
+ {
+ Warning( "LoadVolumeTextureFromVTF: VTF dimensions do not match texture\n" );
+ return;
+ }
+
+ TextureLoadInfo_t sliceInfo = info;
+
+#if !defined( _X360 ) && !defined( DX_TO_GL_ABSTRACTION )
+ IDirect3DVolumeTexture9 *pStagingTexture = NULL;
+ if ( !info.m_bTextureIsLockable )
+ {
+ IDirect3DVolumeTexture9 *pTemp;
+ if ( Dx9Device()->CreateVolumeTexture( desc.Width, desc.Height, desc.Depth, iMipCount, 0, desc.Format, D3DPOOL_SYSTEMMEM, &pTemp, NULL ) != S_OK )
+ {
+ Warning( "LoadVolumeTextureFromVTF: failed to create temporary staging texture\n" );
+ return;
+ }
+ sliceInfo.m_pTexture = static_cast<IDirect3DBaseTexture*>( pTemp );
+ sliceInfo.m_bTextureIsLockable = true;
+ pStagingTexture = pTemp;
+ }
+#endif
+
+ for ( int iMip = 0; iMip < iMipCount; ++iMip )
+ {
+ int w, h, d;
+ pVTF->ComputeMipLevelDimensions( iMip, &w, &h, &d );
+ sliceInfo.m_nLevel = iMip;
+ sliceInfo.m_nWidth = w;
+ sliceInfo.m_nHeight = h;
+ for ( int iSlice = 0; iSlice < d; ++iSlice )
+ {
+ sliceInfo.m_nZOffset = iSlice;
+ sliceInfo.m_pSrcData = pVTF->ImageData( iVTFFrame, 0, iMip, 0, 0, iSlice );
+ BlitTextureBits( sliceInfo, 0, 0, 0 );
+ }
+ }
+
+#if !defined( _X360 ) && !defined( DX_TO_GL_ABSTRACTION )
+ if ( pStagingTexture )
+ {
+ if ( Dx9Device()->UpdateTexture( pStagingTexture, pVolTex ) != S_OK )
+ {
+ Warning( "LoadVolumeTextureFromVTF: volume UpdateTexture failed\n" );
+ }
+ pStagingTexture->Release();
+ }
+#endif
+}
+
+void LoadCubeTextureFromVTF( TextureLoadInfo_t &info, IVTFTexture* pVTF, int iVTFFrame )
+{
+ if ( !info.m_pTexture || info.m_pTexture->GetType() != D3DRTYPE_CUBETEXTURE )
+ {
+ Assert( 0 );
+ return;
+ }
+
+ IDirect3DCubeTexture9 *pCubeTex = static_cast<IDirect3DCubeTexture9*>( info.m_pTexture );
+
+ D3DSURFACE_DESC desc;
+ if ( pCubeTex->GetLevelDesc( 0, &desc ) != S_OK )
+ {
+ Warning( "LoadCubeTextureFromVTF: couldn't get texture level description\n" );
+ return;
+ }
+
+ int iMipCount = pCubeTex->GetLevelCount();
+ if ( pVTF->Depth() != 1 || pVTF->Width() != (int)desc.Width || pVTF->Height() != (int)desc.Height || pVTF->FaceCount() < 6 || pVTF->MipCount() < iMipCount )
+ {
+ Warning( "LoadCubeTextureFromVTF: VTF dimensions do not match texture\n" );
+ return;
+ }
+
+ TextureLoadInfo_t faceInfo = info;
+
+#if !defined( _X360 ) && !defined( DX_TO_GL_ABSTRACTION )
+ IDirect3DCubeTexture9 *pStagingTexture = NULL;
+ if ( !info.m_bTextureIsLockable )
+ {
+ IDirect3DCubeTexture9 *pTemp;
+ if ( Dx9Device()->CreateCubeTexture( desc.Width, iMipCount, 0, desc.Format, D3DPOOL_SYSTEMMEM, &pTemp, NULL ) != S_OK )
+ {
+ Warning( "LoadCubeTextureFromVTF: failed to create temporary staging texture\n" );
+ return;
+ }
+ faceInfo.m_pTexture = static_cast<IDirect3DBaseTexture*>( pTemp );
+ faceInfo.m_bTextureIsLockable = true;
+ pStagingTexture = pTemp;
+ }
+#endif
+
+ for ( int iMip = 0; iMip < iMipCount; ++iMip )
+ {
+ int w, h, d;
+ pVTF->ComputeMipLevelDimensions( iMip, &w, &h, &d );
+ faceInfo.m_nLevel = iMip;
+ faceInfo.m_nWidth = w;
+ faceInfo.m_nHeight = h;
+ for ( int iFace = 0; iFace < 6; ++iFace )
+ {
+ faceInfo.m_CubeFaceID = (D3DCUBEMAP_FACES) iFace;
+ faceInfo.m_pSrcData = pVTF->ImageData( iVTFFrame, iFace, iMip );
+ BlitTextureBits( faceInfo, 0, 0, 0 );
+ }
+ }
+
+#if !defined( _X360 ) && !defined( DX_TO_GL_ABSTRACTION )
+ if ( pStagingTexture )
+ {
+ if ( Dx9Device()->UpdateTexture( pStagingTexture, pCubeTex ) != S_OK )
+ {
+ Warning( "LoadCubeTextureFromVTF: cube UpdateTexture failed\n" );
+ }
+ pStagingTexture->Release();
+ }
+#endif
+}
+
+void LoadTextureFromVTF( TextureLoadInfo_t &info, IVTFTexture* pVTF, int iVTFFrame )
+{
+ TM_ZONE_DEFAULT( TELEMETRY_LEVEL0 );
+
+ if ( !info.m_pTexture || info.m_pTexture->GetType() != D3DRTYPE_TEXTURE )
+ {
+ Assert( 0 );
+ return;
+ }
+
+ IDirect3DTexture9 *pTex = static_cast<IDirect3DTexture9*>( info.m_pTexture );
+
+ D3DSURFACE_DESC desc;
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - GetLevelDesc", __FUNCTION__ );
+ if ( pTex->GetLevelDesc( 0, &desc ) != S_OK )
+ {
+ Warning( "LoadTextureFromVTF: couldn't get texture level description\n" );
+ return;
+ }
+ }
+
+ int iMipCount = pTex->GetLevelCount();
+ if ( pVTF->Depth() != 1 || pVTF->Width() != (int)desc.Width || pVTF->Height() != (int)desc.Height || pVTF->MipCount() < iMipCount || pVTF->FaceCount() <= (int)info.m_CubeFaceID )
+ {
+ Warning( "LoadTextureFromVTF: VTF dimensions do not match texture\n" );
+ return;
+ }
+
+ // Info may have a cube face ID if we are falling back to 2D sphere map support
+ TextureLoadInfo_t mipInfo = info;
+ int iVTFFaceNum = info.m_CubeFaceID;
+ mipInfo.m_CubeFaceID = (D3DCUBEMAP_FACES)0;
+
+#if !defined( _X360 ) && !defined( DX_TO_GL_ABSTRACTION )
+ // If blitting more than one mip level of an unlockable texture, create a temporary
+ // texture for all mip levels only call UpdateTexture once. For textures with
+ // only a single mip level, fall back on the support in BlitSurfaceBits. -henryg
+ IDirect3DTexture9 *pStagingTexture = NULL;
+ if ( !info.m_bTextureIsLockable && iMipCount > 1 )
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - CreateSysmemTexture", __FUNCTION__ );
+
+ IDirect3DTexture9 *pTemp;
+ if ( Dx9Device()->CreateTexture( desc.Width, desc.Height, iMipCount, 0, desc.Format, D3DPOOL_SYSTEMMEM, &pTemp, NULL ) != S_OK )
+ {
+ Warning( "LoadTextureFromVTF: failed to create temporary staging texture\n" );
+ return;
+ }
+
+ mipInfo.m_pTexture = static_cast<IDirect3DBaseTexture*>( pTemp );
+ mipInfo.m_bTextureIsLockable = true;
+ pStagingTexture = pTemp;
+ }
+#endif
+
+ // Get the clamped resolutions from the VTF, then apply any clamping we've done from the higher level code.
+ // (For example, we chop off the bottom of the mipmap pyramid at 32x32--that is reflected in iMipCount, so
+ // honor that here).
+ int finest = 0, coarsest = 0;
+ pVTF->GetMipmapRange( &finest, &coarsest );
+ finest = Min( finest, iMipCount - 1 );
+ coarsest = Min( coarsest, iMipCount - 1 );
+ Assert( finest <= coarsest && coarsest < iMipCount );
+
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - BlitTextureBits", __FUNCTION__ );
+ for ( int iMip = finest; iMip <= coarsest; ++iMip )
+ {
+ int w, h, d;
+ pVTF->ComputeMipLevelDimensions( iMip, &w, &h, &d );
+ mipInfo.m_nLevel = iMip;
+ mipInfo.m_nWidth = w;
+ mipInfo.m_nHeight = h;
+ mipInfo.m_pSrcData = pVTF->ImageData( iVTFFrame, iVTFFaceNum, iMip );
+
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - BlitTextureBits - %d", __FUNCTION__, iMip );
+
+ BlitTextureBits( mipInfo, 0, 0, 0 );
+ }
+ }
+
+#if !defined( _X360 ) && !defined( DX_TO_GL_ABSTRACTION )
+ if ( pStagingTexture )
+ {
+ if ( ( coarsest - finest + 1 ) == iMipCount )
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - UpdateTexture", __FUNCTION__ );
+ if ( Dx9Device()->UpdateTexture( pStagingTexture, pTex ) != S_OK )
+ {
+ Warning( "LoadTextureFromVTF: UpdateTexture failed\n" );
+ }
+ }
+ else
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - UpdateSurface", __FUNCTION__ );
+
+ for ( int mip = finest; mip <= coarsest; ++mip )
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - UpdateSurface - %d", __FUNCTION__, mip );
+
+ IDirect3DSurface9 *pSrcSurf = NULL,
+ *pDstSurf = NULL;
+
+ if ( pStagingTexture->GetSurfaceLevel( mip, &pSrcSurf ) != S_OK )
+ Warning( "LoadTextureFromVTF: couldn't get surface level %d for system surface\n", mip );
+
+ if ( pTex->GetSurfaceLevel( mip, &pDstSurf ) != S_OK )
+ Warning( "LoadTextureFromVTF: couldn't get surface level %d for dest surface\n", mip );
+
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - UpdateSurface - Call ", __FUNCTION__, mip );
+ if ( !pSrcSurf || !pDstSurf || Dx9Device()->UpdateSurface( pSrcSurf, NULL, pDstSurf, NULL ) != S_OK )
+ Warning( "LoadTextureFromVTF: surface update failed.\n" );
+ }
+
+ if ( pSrcSurf )
+ pSrcSurf->Release();
+
+ if ( pDstSurf )
+ pDstSurf->Release();
+ }
+ }
+
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - Cleanup", __FUNCTION__ );
+ pStagingTexture->Release();
+ }
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Upload to a sub-piece of a texture
+//-----------------------------------------------------------------------------
+void LoadSubTexture( TextureLoadInfo_t &info, int xOffset, int yOffset, int srcStride )
+{
+ Assert( info.m_pSrcData );
+ Assert( info.m_pTexture );
+
+#if defined( _X360 )
+ // xboxissue - not supporting subrect swizzling
+ Assert( !info.m_bSrcIsTiled );
+#endif
+
+#ifdef _DEBUG
+ ImageFormat format = GetImageFormat( info.m_pTexture );
+ Assert( (format == FindNearestSupportedFormat(format, false, false, false )) && (format != -1) );
+#endif
+
+ // Copy in the bits...
+ BlitTextureBits( info, xOffset, yOffset, srcStride );
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the size of texture memory, in MB
+//-----------------------------------------------------------------------------
+// Helps with startup time.. we don't use the texture memory size for anything anyways
+#define DONT_CHECK_MEM
+
+int ComputeTextureMemorySize( const GUID &nDeviceGUID, D3DDEVTYPE deviceType )
+{
+#if defined( _X360 )
+ return 0;
+#elif defined( DONT_CHECK_MEM )
+ return (deviceType == D3DDEVTYPE_REF) ? (64 * 1024 * 1024) : 102236160;
+#else
+
+ FileHandle_t file = g_pFullFileSystem->Open( "vidcfg.bin", "rb", "EXECUTABLE_PATH" );
+ if ( file )
+ {
+ GUID deviceId;
+ int texSize;
+ g_pFullFileSystem->Read( &deviceId, sizeof(deviceId), file );
+ g_pFullFileSystem->Read( &texSize, sizeof(texSize), file );
+ g_pFullFileSystem->Close( file );
+ if ( nDeviceGUID == deviceId )
+ {
+ return texSize;
+ }
+ }
+ // How much texture memory?
+ if (deviceType == D3DDEVTYPE_REF)
+ return 64 * 1024 * 1024;
+
+ // Sadly, the only way to compute texture memory size
+ // is to allocate a crapload of textures until we can't any more
+ ImageFormat fmt = FindNearestSupportedFormat( IMAGE_FORMAT_BGR565, false, false, false );
+ int textureSize = ShaderUtil()->GetMemRequired( 256, 256, 1, fmt, false );
+
+ int totalSize = 0;
+ CUtlVector< IDirect3DBaseTexture* > textures;
+
+ s_bTestingVideoMemorySize = true;
+ while (true)
+ {
+ RECORD_COMMAND( DX8_CREATE_TEXTURE, 7 );
+ RECORD_INT( textures.Count() );
+ RECORD_INT( 256 );
+ RECORD_INT( 256 );
+ RECORD_INT( ImageLoader::ImageFormatToD3DFormat(fmt) );
+ RECORD_INT( 1 );
+ RECORD_INT( false );
+ RECORD_INT( 1 );
+
+ IDirect3DBaseTexture* pTex = CreateD3DTexture( 256, 256, 1, fmt, 1, 0 );
+ if (!pTex)
+ break;
+ totalSize += textureSize;
+
+ textures.AddToTail( pTex );
+ }
+ s_bTestingVideoMemorySize = false;
+
+ // Free all the temp textures
+ for (int i = textures.Size(); --i >= 0; )
+ {
+ RECORD_COMMAND( DX8_DESTROY_TEXTURE, 1 );
+ RECORD_INT( i );
+
+ DestroyD3DTexture( textures[i] );
+ }
+
+ file = g_pFullFileSystem->Open( "vidcfg.bin", "wb", "EXECUTABLE_PATH" );
+ if ( file )
+ {
+ g_pFullFileSystem->Write( &nDeviceGUID, sizeof(GUID), file );
+ g_pFullFileSystem->Write( &totalSize, sizeof(totalSize), file );
+ g_pFullFileSystem->Close( file );
+ }
+
+ return totalSize;
+#endif
+}
diff --git a/materialsystem/shaderapidx9/texturedx8.h b/materialsystem/shaderapidx9/texturedx8.h
new file mode 100644
index 0000000..2901798
--- /dev/null
+++ b/materialsystem/shaderapidx9/texturedx8.h
@@ -0,0 +1,110 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#ifndef TEXTUREDX8_H
+#define TEXTUREDX8_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "togl/rendermechanism.h"
+#include "bitmap/imageformat.h"
+#include "locald3dtypes.h"
+#include "shaderapi/ishaderapi.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class CPixelWriter;
+
+
+//-----------------------------------------------------------------------------
+// Returns the size of texture memory
+//-----------------------------------------------------------------------------
+int ComputeTextureMemorySize( const GUID &nDeviceId, D3DDEVTYPE deviceType );
+
+
+//-----------------------------------------------------------------------------
+// Texture creation
+//-----------------------------------------------------------------------------
+IDirect3DBaseTexture *CreateD3DTexture( int width, int height, int depth,
+ ImageFormat dstFormat, int numLevels, int creationFlags, char *debugLabel=NULL ); // OK to not-supply the last param
+
+
+//-----------------------------------------------------------------------------
+// Texture destruction
+//-----------------------------------------------------------------------------
+void DestroyD3DTexture( IDirect3DBaseTexture *pTex );
+
+int GetD3DTextureRefCount( IDirect3DBaseTexture *pTex );
+
+
+//-----------------------------------------------------------------------------
+// Texture heap methods
+//-----------------------------------------------------------------------------
+#if defined( _X360 )
+void SetD3DTextureImmobile( IDirect3DBaseTexture *pTex, bool bImmobile );
+void CompactTextureHeap();
+#endif
+
+//-----------------------------------------------------------------------------
+// Stats...
+//-----------------------------------------------------------------------------
+int TextureCount();
+
+
+//-----------------------------------------------------------------------------
+// Info for texture loading
+//-----------------------------------------------------------------------------
+struct TextureLoadInfo_t
+{
+ ShaderAPITextureHandle_t m_TextureHandle;
+ int m_nCopy;
+ IDirect3DBaseTexture *m_pTexture;
+ int m_nLevel;
+ D3DCUBEMAP_FACES m_CubeFaceID;
+ int m_nWidth;
+ int m_nHeight;
+ int16 m_nZOffset; // What z-slice of the volume texture are we loading?
+#if defined( _X360 )
+ bool m_bSrcIsTiled; // format may not be, but data could be
+ bool m_bCanConvertFormat; // allow format conversion
+#else
+ bool m_bTextureIsLockable;
+#endif
+ ImageFormat m_SrcFormat;
+ unsigned char *m_pSrcData;
+};
+
+
+//-----------------------------------------------------------------------------
+// Texture image upload
+//-----------------------------------------------------------------------------
+void LoadTexture( TextureLoadInfo_t &info );
+void LoadTextureFromVTF( TextureLoadInfo_t &info, IVTFTexture* pVTF, int iVTFFrame );
+void LoadCubeTextureFromVTF( TextureLoadInfo_t &info, IVTFTexture* pVTF, int iVTFFrame );
+void LoadVolumeTextureFromVTF( TextureLoadInfo_t &info, IVTFTexture* pVTF, int iVTFFrame );
+
+//-----------------------------------------------------------------------------
+// Upload to a sub-piece of a texture
+//-----------------------------------------------------------------------------
+void LoadSubTexture( TextureLoadInfo_t &info, int xOffset, int yOffset, int srcStride );
+
+//-----------------------------------------------------------------------------
+// Lock, unlock a texture...
+//-----------------------------------------------------------------------------
+bool LockTexture( ShaderAPITextureHandle_t textureHandle, int copy, IDirect3DBaseTexture* pTexture, int level,
+ D3DCUBEMAP_FACES cubeFaceID, int xOffset, int yOffset, int width, int height, bool bDiscard,
+ CPixelWriter& writer );
+
+void UnlockTexture( ShaderAPITextureHandle_t textureHandle, int copy, IDirect3DBaseTexture* pTexture, int level,
+ D3DCUBEMAP_FACES cubeFaceID );
+
+#endif // TEXTUREDX8_H \ No newline at end of file
diff --git a/materialsystem/shaderapidx9/textureheap.cpp b/materialsystem/shaderapidx9/textureheap.cpp
new file mode 100644
index 0000000..b2c9a66
--- /dev/null
+++ b/materialsystem/shaderapidx9/textureheap.cpp
@@ -0,0 +1,1258 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "tier1/mempool.h"
+#include "tier1/convar.h"
+#include "tier1/utlmap.h"
+#include "shaderapidx8.h"
+#include "texturedx8.h"
+#include "textureheap.h"
+#include "shaderapidx8_global.h"
+
+#include "tier0/memdbgon.h"
+
+#define USE_STANDARD_ALLOCATOR
+#ifdef USE_STANDARD_ALLOCATOR
+#define UseStandardAllocator() (true)
+#elif !defined(_RETAIL)
+bool g_bUseStandardAllocator = false;
+bool UseStandardAllocator()
+{
+ static bool bReadCommandLine;
+ if ( !bReadCommandLine )
+ {
+ bReadCommandLine = true;
+ const char *pStr = Plat_GetCommandLine();
+ if ( pStr )
+ {
+ char tempStr[512];
+ Q_strncpy( tempStr, pStr, sizeof( tempStr ) - 1 );
+ tempStr[ sizeof( tempStr ) - 1 ] = 0;
+ _strlwr( tempStr );
+
+ if ( strstr( tempStr, "-notextureheap" ) )
+ g_bUseStandardAllocator = true;
+ }
+ }
+ return g_bUseStandardAllocator;
+}
+#else
+#define UseStandardAllocator() (false)
+#endif
+
+#if !defined( _RELEASE ) && !defined( _RETAIL )
+#define StrongAssert( expr ) if ( (expr) ) ; else { DebuggerBreak(); }
+#else
+#define StrongAssert( expr ) ((void)0)
+#endif
+
+//-----------------------------------------------------------------------------
+// Get Texture HW base
+//-----------------------------------------------------------------------------
+void *GetD3DTextureBasePtr( IDirect3DBaseTexture* pTex )
+{
+ // assumes base and mips are contiguous
+ return (void *)( (unsigned int)pTex->Format.BaseAddress << 12 );
+}
+
+class CD3DTextureAllocator
+{
+public:
+ static void *Alloc( int bytes )
+ {
+ DWORD attributes = MAKE_XALLOC_ATTRIBUTES(
+ 0,
+ false,
+ TRUE,
+ FALSE,
+ eXALLOCAllocatorId_D3D,
+ XALLOC_PHYSICAL_ALIGNMENT_4K,
+ XALLOC_MEMPROTECT_WRITECOMBINE,
+ FALSE,
+ XALLOC_MEMTYPE_PHYSICAL );
+ m_nTotalAllocations++;
+ m_nTotalSize += AlignValue( bytes, 4096 );
+ return XMemAlloc( bytes, attributes );
+ }
+
+ static void Free( void *p )
+ {
+ DWORD attributes = MAKE_XALLOC_ATTRIBUTES(
+ 0,
+ false,
+ TRUE,
+ FALSE,
+ eXALLOCAllocatorId_D3D,
+ XALLOC_PHYSICAL_ALIGNMENT_4K,
+ XALLOC_MEMPROTECT_WRITECOMBINE,
+ FALSE,
+ XALLOC_MEMTYPE_PHYSICAL );
+ m_nTotalAllocations--;
+ m_nTotalSize -= XMemSize( p, attributes );
+ XMemFree( p, attributes );
+ }
+
+ static int GetAllocations()
+ {
+ return m_nTotalAllocations;
+ }
+
+ static int GetSize()
+ {
+ return m_nTotalSize;
+ }
+
+ static int m_nTotalSize;
+ static int m_nTotalAllocations;
+};
+
+int CD3DTextureAllocator::m_nTotalSize;
+int CD3DTextureAllocator::m_nTotalAllocations;
+
+enum TextureAllocator_t
+{
+ TA_DEFAULT,
+ TA_MIXED,
+ TA_UNKNOWN,
+};
+
+struct THBaseInfo
+{
+ TextureAllocator_t m_fAllocator;
+ int m_TextureSize; // stored for delayed allocations
+};
+
+struct THInfo_t : public THBaseInfo
+{
+ // Mixed heap info
+ int nLogicalBytes;
+ int nBytes;
+ bool bFree:1;
+ bool bNonTexture:1;
+
+ THInfo_t *pPrev, *pNext;
+};
+
+struct THFreeBlock_t
+{
+ THInfo_t heapInfo;
+ THFreeBlock_t *pPrevFree, *pNextFree;
+};
+
+class CXboxTexture : public IDirect3DTexture, public THInfo_t
+{
+public:
+ CXboxTexture()
+ : bImmobile(false)
+ {
+ }
+
+ bool bImmobile;
+ bool CanRelocate() { return ( !bImmobile && !IsBusy() ); }
+};
+
+class CXboxCubeTexture : public IDirect3DCubeTexture, public THBaseInfo
+{
+};
+
+class CXboxVolumeTexture : public IDirect3DVolumeTexture, public THBaseInfo
+{
+};
+
+
+void SetD3DTextureImmobile( IDirect3DBaseTexture *pTexture, bool bImmobile )
+{
+ if ( pTexture->GetType() == D3DRTYPE_TEXTURE )
+ {
+ (( CXboxTexture *)pTexture)->bImmobile = bImmobile;
+ }
+}
+
+CXboxTexture *GetTexture( THInfo_t *pInfo )
+{
+ if ( !pInfo->bFree && !pInfo->bNonTexture )
+ {
+ return (CXboxTexture *)((byte *)pInfo - offsetof( CXboxTexture, m_fAllocator ));
+ }
+ return NULL;
+}
+
+inline THFreeBlock_t *GetFreeBlock( THInfo_t *pInfo )
+{
+ if ( pInfo->bFree )
+ {
+ return (THFreeBlock_t *)((byte *)pInfo - offsetof( THFreeBlock_t, heapInfo ));
+ }
+ return NULL;
+}
+
+class CMixedTextureHeap
+{
+ enum
+ {
+ SIZE_ALIGNMENT = XBOX_HDD_SECTORSIZE,
+ MIN_BLOCK_SIZE = 1024,
+ };
+public:
+
+ CMixedTextureHeap() :
+ m_nLogicalBytes( 0 ),
+ m_nActualBytes( 0 ),
+ m_nAllocs( 0 ),
+ m_nOldBytes( 0 ),
+ m_nNonTextureAllocs( 0 ),
+ m_nBytesTotal( 0 ),
+ m_pBase( NULL ),
+ m_pFirstFree( NULL )
+ {
+ }
+
+ void Init()
+ {
+ extern ConVar mat_texturecachesize;
+ MEM_ALLOC_CREDIT_("CMixedTextureHeap");
+
+ m_nBytesTotal = ( mat_texturecachesize.GetInt() * 1024 * 1024 );
+#if 0
+ m_nBytesTotal = AlignValue( m_nBytesTotal, SIZE_ALIGNMENT );
+ m_pBase = CD3DTextureAllocator::Alloc( m_nBytesTotal );
+#else
+ m_nBytesTotal = AlignValue( m_nBytesTotal, 16*1024*1024 );
+ m_pBase = XPhysicalAlloc( m_nBytesTotal, MAXULONG_PTR, 4096, PAGE_READWRITE | PAGE_WRITECOMBINE | MEM_16MB_PAGES );
+#endif
+ m_pFirstFree = (THFreeBlock_t *)m_pBase;
+
+
+ m_pFirstFree->heapInfo.bFree = true;
+ m_pFirstFree->heapInfo.bNonTexture = false;
+ m_pFirstFree->heapInfo.nBytes = m_nBytesTotal;
+ m_pFirstFree->heapInfo.pNext = NULL;
+ m_pFirstFree->heapInfo.pPrev = NULL;
+ m_pFirstFree->pNextFree = NULL;
+ m_pFirstFree->pPrevFree = NULL;
+
+ m_pLastFree = m_pFirstFree;
+ }
+
+ void *Alloc( int bytes, THInfo_t *pInfo, bool bNonTexture = false )
+ {
+ pInfo->nBytes = AlignValue( bytes, SIZE_ALIGNMENT );
+
+ if ( !m_pBase )
+ {
+ Init();
+ }
+
+ if ( bNonTexture && m_nNonTextureAllocs == 0 )
+ {
+ Compact();
+ }
+
+ void *p = FindBlock( pInfo );
+
+ if ( !p )
+ {
+ p = ExpandToFindBlock( pInfo );
+ }
+
+ if ( p )
+ {
+ pInfo->nLogicalBytes = bytes;
+ pInfo->bNonTexture = bNonTexture;
+ m_nLogicalBytes += bytes;
+ if ( !IsRetail() )
+ {
+ m_nOldBytes += AlignValue( bytes, 4096 );
+ }
+ m_nActualBytes += pInfo->nBytes;
+ m_nAllocs++;
+
+ if ( bNonTexture )
+ {
+ m_nNonTextureAllocs++;
+ }
+ }
+ return p;
+ }
+
+ void Free( void *p, THInfo_t *pInfo )
+ {
+ if ( !p )
+ {
+ return;
+ }
+
+ if ( !IsRetail() )
+ {
+ m_nOldBytes -= AlignValue( pInfo->nLogicalBytes, 4096 );
+ }
+
+ if ( pInfo->bNonTexture )
+ {
+ m_nNonTextureAllocs--;
+ }
+
+ m_nLogicalBytes -= pInfo->nLogicalBytes;
+ m_nAllocs--;
+ m_nActualBytes -= pInfo->nBytes;
+
+ THFreeBlock_t *pFree = (THFreeBlock_t *)p;
+ pFree->heapInfo = *pInfo;
+ pFree->heapInfo.bFree = true;
+
+ AddToBlocksList( &pFree->heapInfo, pFree->heapInfo.pPrev, pFree->heapInfo.pNext );
+
+ pFree = MergeLeft( pFree );
+ pFree = MergeRight( pFree );
+
+ AddToFreeList( pFree );
+
+ if ( pInfo->bNonTexture && m_nNonTextureAllocs == 0 )
+ {
+ Compact();
+ }
+ }
+
+ int Size( void *p, THInfo_t *pInfo )
+ {
+ return AlignValue( pInfo->nBytes, SIZE_ALIGNMENT );
+ }
+
+ bool IsOwner( void *p )
+ {
+ return ( m_pBase && p >= m_pBase && p < (byte *)m_pBase + m_nBytesTotal );
+ }
+
+ //-----------------------------------------------------
+
+ void *FindBlock( THInfo_t *pInfo )
+ {
+ THFreeBlock_t *pCurrent = m_pFirstFree;
+
+ int nBytesDesired = pInfo->nBytes;
+
+ // Find the first block big enough to hold, then split it if appropriate
+ while ( pCurrent && pCurrent->heapInfo.nBytes < nBytesDesired )
+ {
+ pCurrent = pCurrent->pNextFree;
+ }
+
+ if ( pCurrent )
+ {
+ return ClaimBlock( pCurrent, pInfo );
+ }
+
+ return NULL;
+ }
+
+ void AddToFreeList( THFreeBlock_t *pFreeBlock )
+ {
+ if ( !IsRetail() )
+ {
+ pFreeBlock->heapInfo.nLogicalBytes = 0;
+ }
+
+ if ( m_pFirstFree )
+ {
+ THFreeBlock_t *pPrev = NULL;
+ THFreeBlock_t *pNext = m_pFirstFree;
+
+ int nBytes = pFreeBlock->heapInfo.nBytes;
+
+ while ( pNext && pNext->heapInfo.nBytes < nBytes )
+ {
+ pPrev = pNext;
+ pNext = pNext->pNextFree;
+ }
+
+ pFreeBlock->pPrevFree = pPrev;
+ pFreeBlock->pNextFree = pNext;
+
+ if ( pPrev )
+ {
+ pPrev->pNextFree = pFreeBlock;
+ }
+ else
+ {
+ m_pFirstFree = pFreeBlock;
+ }
+
+ if ( pNext )
+ {
+ pNext->pPrevFree = pFreeBlock;
+ }
+ else
+ {
+ m_pLastFree = pFreeBlock;
+ }
+ }
+ else
+ {
+ pFreeBlock->pPrevFree = pFreeBlock->pNextFree = NULL;
+ m_pLastFree = m_pFirstFree = pFreeBlock;
+ }
+ }
+
+ void RemoveFromFreeList( THFreeBlock_t *pFreeBlock )
+ {
+ if ( m_pFirstFree == pFreeBlock )
+ {
+ m_pFirstFree = m_pFirstFree->pNextFree;
+ }
+ else if ( pFreeBlock->pPrevFree )
+ {
+ pFreeBlock->pPrevFree->pNextFree = pFreeBlock->pNextFree;
+ }
+
+ if ( m_pLastFree == pFreeBlock )
+ {
+ m_pLastFree = pFreeBlock->pPrevFree;
+ }
+ else if ( pFreeBlock->pNextFree )
+ {
+ pFreeBlock->pNextFree->pPrevFree = pFreeBlock->pPrevFree;
+ }
+
+ pFreeBlock->pPrevFree = pFreeBlock->pNextFree = NULL;
+ }
+
+ THFreeBlock_t *GetLastFree()
+ {
+ return m_pLastFree;
+ }
+
+ void AddToBlocksList( THInfo_t *pBlock, THInfo_t *pPrev, THInfo_t *pNext )
+ {
+ if ( pPrev )
+ {
+ pPrev->pNext = pBlock;
+ }
+
+ if ( pNext)
+ {
+ pNext->pPrev = pBlock;
+ }
+
+ pBlock->pPrev = pPrev;
+ pBlock->pNext = pNext;
+ }
+
+ void RemoveFromBlocksList( THInfo_t *pBlock )
+ {
+ if ( pBlock->pPrev )
+ {
+ pBlock->pPrev->pNext = pBlock->pNext;
+ }
+
+ if ( pBlock->pNext )
+ {
+ pBlock->pNext->pPrev = pBlock->pPrev;
+ }
+ }
+
+ //-----------------------------------------------------
+
+ void *ClaimBlock( THFreeBlock_t *pFreeBlock, THInfo_t *pInfo )
+ {
+ RemoveFromFreeList( pFreeBlock );
+
+ int nBytesDesired = pInfo->nBytes;
+ int nBytesRemainder = pFreeBlock->heapInfo.nBytes - nBytesDesired;
+ *pInfo = pFreeBlock->heapInfo;
+ pInfo->bFree = false;
+ pInfo->bNonTexture = false;
+ if ( nBytesRemainder >= MIN_BLOCK_SIZE )
+ {
+ pInfo->nBytes = nBytesDesired;
+
+ THFreeBlock_t *pRemainder = (THFreeBlock_t *)(((byte *)(pFreeBlock)) + nBytesDesired);
+ pRemainder->heapInfo.bFree = true;
+ pRemainder->heapInfo.nBytes = nBytesRemainder;
+
+ AddToBlocksList( &pRemainder->heapInfo, pInfo, pInfo->pNext );
+ AddToFreeList( pRemainder );
+ }
+ AddToBlocksList( pInfo, pInfo->pPrev, pInfo->pNext );
+ return pFreeBlock;
+ }
+
+ THFreeBlock_t *MergeLeft( THFreeBlock_t *pFree )
+ {
+ THInfo_t *pPrev = pFree->heapInfo.pPrev;
+ if ( pPrev && pPrev->bFree )
+ {
+ pPrev->nBytes += pFree->heapInfo.nBytes;
+ RemoveFromBlocksList( &pFree->heapInfo );
+ pFree = GetFreeBlock( pPrev );
+ RemoveFromFreeList( pFree );
+ }
+ return pFree;
+ }
+
+ THFreeBlock_t *MergeRight( THFreeBlock_t *pFree )
+ {
+ THInfo_t *pNext = pFree->heapInfo.pNext;
+ if ( pNext && pNext->bFree )
+ {
+ pFree->heapInfo.nBytes += pNext->nBytes;
+ RemoveFromBlocksList( pNext );
+ RemoveFromFreeList( GetFreeBlock( pNext ) );
+ }
+ return pFree;
+ }
+
+ //-----------------------------------------------------
+
+ bool GetExpansionList( THFreeBlock_t *pFreeBlock, THInfo_t **ppStart, THInfo_t **ppEnd, int depth = 1 )
+ {
+ THInfo_t *pStart;
+ THInfo_t *pEnd;
+ int i;
+
+ pStart = &pFreeBlock->heapInfo;
+ pEnd = &pFreeBlock->heapInfo;
+
+ if ( m_nNonTextureAllocs > 0 )
+ {
+ return false;
+ }
+
+ // Walk backwards to start of expansion
+ i = depth;
+ while ( i > 0 && pStart->pPrev)
+ {
+ THInfo_t *pScan = pStart->pPrev;
+
+ while ( i > 0 && pScan && !pScan->bFree && GetTexture( pScan )->CanRelocate() )
+ {
+ pScan = pScan->pPrev;
+ i--;
+ }
+
+ if ( !pScan || !pScan->bFree )
+ {
+ break;
+ }
+
+ pStart = pScan;
+ }
+
+ // Walk forwards to start of expansion
+ i = depth;
+ while ( i > 0 && pEnd->pNext)
+ {
+ THInfo_t *pScan = pStart->pNext;
+
+ while ( i > 0 && pScan && !pScan->bFree && GetTexture( pScan )->CanRelocate() )
+ {
+ pScan = pScan->pNext;
+ i--;
+ }
+
+ if ( !pScan || !pScan->bFree )
+ {
+ break;
+ }
+
+ pEnd = pScan;
+ }
+
+ *ppStart = pStart;
+ *ppEnd = pEnd;
+
+ return ( pStart != pEnd );
+ }
+
+ THFreeBlock_t *CompactExpansionList( THInfo_t *pStart, THInfo_t *pEnd )
+ {
+// X360TBD:
+Assert( 0 );
+return NULL;
+#if 0
+#ifdef TH_PARANOID
+ Validate();
+#endif
+ StrongAssert( pStart->bFree );
+ StrongAssert( pEnd->bFree );
+ byte *pNextBlock = (byte *)pStart;
+
+ THInfo_t *pTextureBlock = pStart;
+ THInfo_t *pLastBlock = pStart->pPrev;
+
+ while ( pTextureBlock != pEnd )
+ {
+ CXboxTexture *pTexture = GetTexture( pTextureBlock );
+ // If it's a texture, move it and thread it on. Otherwise, discard it
+ if ( pTexture )
+ {
+ void *pTextureBits = GetD3DTextureBasePtr( pTexture );
+ int nBytes = pTextureBlock->nBytes;
+
+ if ( pNextBlock + nBytes <= pTextureBits)
+ {
+ memcpy( pNextBlock, pTextureBits, nBytes );
+ }
+ else
+ {
+ memmove( pNextBlock, pTextureBits, nBytes );
+ }
+
+ pTexture->Data = 0;
+ pTexture->Register( pNextBlock );
+
+ pNextBlock += nBytes;
+ if ( pLastBlock)
+ {
+ pLastBlock->pNext = pTextureBlock;
+ }
+ pTextureBlock->pPrev = pLastBlock;
+ pLastBlock = pTextureBlock;
+ }
+ else
+ {
+ StrongAssert( pTextureBlock->bFree );
+ RemoveFromFreeList( GetFreeBlock( pTextureBlock ) );
+ }
+ pTextureBlock = pTextureBlock->pNext;
+ }
+
+ RemoveFromFreeList( GetFreeBlock( pEnd ) );
+
+ // Make a new block and fix up the block lists
+ THFreeBlock_t *pFreeBlock = (THFreeBlock_t *)pNextBlock;
+ pFreeBlock->heapInfo.pPrev = pLastBlock;
+ pLastBlock->pNext = &pFreeBlock->heapInfo;
+ pFreeBlock->heapInfo.pNext = pEnd->pNext;
+ if ( pEnd->pNext )
+ {
+ pEnd->pNext->pPrev = &pFreeBlock->heapInfo;
+ }
+ pFreeBlock->heapInfo.bFree = true;
+ pFreeBlock->heapInfo.nBytes = ( (byte *)pEnd - pNextBlock ) + pEnd->nBytes;
+
+ AddToFreeList( pFreeBlock );
+
+#ifdef TH_PARANOID
+ Validate();
+#endif
+ return pFreeBlock;
+#endif
+ }
+
+ THFreeBlock_t *ExpandBlock( THFreeBlock_t *pFreeBlock, int depth = 1 )
+ {
+ THInfo_t *pStart;
+ THInfo_t *pEnd;
+
+ if ( GetExpansionList( pFreeBlock, &pStart, &pEnd, depth ) )
+ {
+ return CompactExpansionList( pStart, pEnd );
+ }
+
+ return pFreeBlock;
+ }
+
+ THFreeBlock_t *ExpandBlockToFit( THFreeBlock_t *pFreeBlock, unsigned bytes )
+ {
+ if ( pFreeBlock )
+ {
+ THInfo_t *pStart;
+ THInfo_t *pEnd;
+
+ if ( GetExpansionList( pFreeBlock, &pStart, &pEnd, 2 ) )
+ {
+ unsigned sum = 0;
+ THInfo_t *pCurrent = pStart;
+ while( pCurrent != pEnd->pNext )
+ {
+ if ( pCurrent->bFree )
+ {
+ sum += pCurrent->nBytes;
+ }
+ pCurrent = pCurrent->pNext;
+ }
+
+ if ( sum >= bytes )
+ {
+ pFreeBlock = CompactExpansionList( pStart, pEnd );
+ }
+ }
+ }
+
+ return pFreeBlock;
+ }
+
+ void *ExpandToFindBlock( THInfo_t *pInfo )
+ {
+ THFreeBlock_t *pFreeBlock = ExpandBlockToFit( GetLastFree(), pInfo->nBytes );
+ if ( pFreeBlock && pFreeBlock->heapInfo.nBytes >= pInfo->nBytes )
+ {
+ return ClaimBlock( pFreeBlock, pInfo );
+ }
+ return NULL;
+ }
+
+ void Compact()
+ {
+ if ( m_nNonTextureAllocs > 0 )
+ {
+ return;
+ }
+
+ for (;;)
+ {
+ THFreeBlock_t *pCurrent = m_pFirstFree;
+ THFreeBlock_t *pNew;
+ while ( pCurrent )
+ {
+ int nBytesOld = pCurrent->heapInfo.nBytes;
+ pNew = ExpandBlock( pCurrent, 999999 );
+
+ if ( pNew != pCurrent || pNew->heapInfo.nBytes != nBytesOld )
+ {
+#ifdef TH_PARANOID
+ Validate();
+#endif
+ break;
+ }
+
+#ifdef TH_PARANOID
+ pNew = ExpandBlock( pCurrent, 999999 );
+ StrongAssert( pNew == pCurrent && pNew->heapInfo.nBytes == nBytesOld );
+#endif
+
+ pCurrent = pCurrent->pNextFree;
+ }
+
+ if ( !pCurrent )
+ {
+ break;
+ }
+ }
+ }
+
+ void Validate()
+ {
+ if ( !m_pFirstFree )
+ {
+ return;
+ }
+
+ if ( m_nNonTextureAllocs > 0 )
+ {
+ return;
+ }
+
+ THInfo_t *pLast = NULL;
+ THInfo_t *pInfo = &m_pFirstFree->heapInfo;
+
+ while ( pInfo->pPrev )
+ {
+ pInfo = pInfo->pPrev;
+ }
+
+ void *pNextExpectedAddress = m_pBase;
+
+ while ( pInfo )
+ {
+ byte *pCurrentAddress = (byte *)(( pInfo->bFree ) ? GetFreeBlock( pInfo ) : GetD3DTextureBasePtr( GetTexture( pInfo ) ) );
+ StrongAssert( pCurrentAddress == pNextExpectedAddress );
+ StrongAssert( pInfo->pPrev == pLast );
+ pNextExpectedAddress = pCurrentAddress + pInfo->nBytes;
+ pLast = pInfo;
+ pInfo = pInfo->pNext;
+ }
+
+ THFreeBlock_t *pFree = m_pFirstFree;
+ THFreeBlock_t *pLastFree = NULL;
+ int nBytesHeap = XPhysicalSize( m_pBase );
+
+ while ( pFree )
+ {
+ StrongAssert( pFree->pPrevFree == pLastFree );
+ StrongAssert( (void *)pFree >= m_pBase && (void *)pFree < (byte *)m_pBase + nBytesHeap );
+ StrongAssert( !pFree->pPrevFree || ( (void *)pFree->pPrevFree >= m_pBase && (void *)pFree->pPrevFree < (byte *)m_pBase + nBytesHeap ) );
+ StrongAssert( !pFree->pNextFree || ( (void *)pFree->pNextFree >= m_pBase && (void *)pFree->pNextFree < (byte *)m_pBase + nBytesHeap ) );
+ StrongAssert( !pFree->pPrevFree || pFree->pPrevFree->heapInfo.nBytes <= pFree->heapInfo.nBytes );
+ pLastFree = pFree;
+ pFree = pFree->pNextFree;
+ }
+ }
+
+ //-----------------------------------------------------
+
+ THFreeBlock_t *m_pFirstFree;
+ THFreeBlock_t *m_pLastFree;
+ void *m_pBase;
+
+ int m_nLogicalBytes;
+ int m_nActualBytes;
+ int m_nAllocs;
+ int m_nOldBytes;
+ int m_nNonTextureAllocs;
+ int m_nBytesTotal;
+};
+
+//-----------------------------------------------------------------------------
+
+inline TextureAllocator_t GetTextureAllocator( IDirect3DBaseTexture9 *pTexture )
+{
+ return ( pTexture->GetType() == D3DRTYPE_CUBETEXTURE ) ? (( CXboxCubeTexture *)pTexture)->m_fAllocator : (( CXboxTexture *)pTexture)->m_fAllocator;
+}
+
+//-----------------------------------------------------------------------------
+
+CMixedTextureHeap g_MixedTextureHeap;
+
+CON_COMMAND( mat_texture_heap_stats, "" )
+{
+ if ( UseStandardAllocator() )
+ {
+ Msg( "Texture heap stats: (Standard Allocator)\n" );
+ Msg( "Allocations:%d Size:%d\n", CD3DTextureAllocator::GetAllocations(), CD3DTextureAllocator::GetSize() );
+ }
+ else
+ {
+ Msg( "Texture heap stats:\n" );
+ Msg( " Mixed textures: %dk/%dk allocated in %d textures\n", g_MixedTextureHeap.m_nLogicalBytes/1024, g_MixedTextureHeap.m_nActualBytes/1024, g_MixedTextureHeap.m_nAllocs );
+ float oldFootprint = g_MixedTextureHeap.m_nOldBytes;
+ float newFootprint = g_MixedTextureHeap.m_nActualBytes;
+ Msg( "\n Old: %.3fmb, New: %.3fmb\n", oldFootprint / (1024.0*1024.0), newFootprint / (1024.0*1024.0) );
+ }
+}
+
+CON_COMMAND( mat_texture_heap_compact, "" )
+{
+ Msg( "Validating texture heap...\n" );
+ g_MixedTextureHeap.Validate();
+ Msg( "Compacting texture heap...\n" );
+ unsigned oldLargest = ( g_MixedTextureHeap.GetLastFree() ) ? g_MixedTextureHeap.GetLastFree()->heapInfo.nBytes : 0;
+ g_MixedTextureHeap.Compact();
+ unsigned newLargest = ( g_MixedTextureHeap.GetLastFree() ) ? g_MixedTextureHeap.GetLastFree()->heapInfo.nBytes : 0;
+
+ Msg( "\n Old largest block: %.3fk, New largest block: %.3fk\n\n", oldLargest / 1024.0, newLargest / 1024.0 );
+
+ Msg( "Validating texture heap...\n" );
+ g_MixedTextureHeap.Validate();
+ Msg( "Done.\n" );
+}
+
+//-----------------------------------------------------------------------------
+// Nasty back doors
+//-----------------------------------------------------------------------------
+
+void CompactTextureHeap()
+{
+ unsigned oldLargest = ( g_MixedTextureHeap.GetLastFree() ) ? g_MixedTextureHeap.GetLastFree()->heapInfo.nBytes : 0;
+ g_MixedTextureHeap.Compact();
+ unsigned newLargest = ( g_MixedTextureHeap.GetLastFree() ) ? g_MixedTextureHeap.GetLastFree()->heapInfo.nBytes : 0;
+
+ DevMsg( "Compacted texture heap. Old largest block: %.3fk, New largest block: %.3fk\n", oldLargest / 1024.0, newLargest / 1024.0 );
+}
+
+CTextureHeap g_TextureHeap;
+
+//-----------------------------------------------------------------------------
+// Build and alloc a texture resource
+//-----------------------------------------------------------------------------
+IDirect3DTexture *CTextureHeap::AllocTexture( int width, int height, int levels, DWORD usage, D3DFORMAT d3dFormat, bool bFallback, bool bNoD3DMemory )
+{
+ CXboxTexture* pD3DTexture = new CXboxTexture;
+
+ // create a texture with contiguous mips and packed tails
+ DWORD dwTextureSize = XGSetTextureHeaderEx(
+ width,
+ height,
+ levels,
+ usage,
+ d3dFormat,
+ 0,
+ 0,
+ 0,
+ XGHEADER_CONTIGUOUS_MIP_OFFSET,
+ 0,
+ pD3DTexture,
+ NULL,
+ NULL );
+
+ // based on "Xbox 360 Texture Storage"
+ // can truncate the terminal tile using packed tails
+ // the terminal tile must be at 32x32 or 16x16 packed
+ if ( width == height && levels != 0 )
+ {
+ int terminalWidth = width >> (levels - 1);
+ if ( d3dFormat == D3DFMT_DXT1 )
+ {
+ if ( terminalWidth <= 32 )
+ {
+ dwTextureSize -= 4*1024;
+ }
+ }
+ else if ( d3dFormat == D3DFMT_DXT5 )
+ {
+ if ( terminalWidth == 32 )
+ {
+ dwTextureSize -= 8*1024;
+ }
+ else if ( terminalWidth <= 16 )
+ {
+ dwTextureSize -= 12*1024;
+ }
+ }
+ }
+
+ pD3DTexture->m_TextureSize = dwTextureSize;
+
+ if ( !bFallback && bNoD3DMemory )
+ {
+ pD3DTexture->m_fAllocator = TA_UNKNOWN;
+ return pD3DTexture;
+ }
+
+ void *pBuffer;
+ if ( UseStandardAllocator() )
+ {
+ MEM_ALLOC_CREDIT_( __FILE__ ": Standard D3D" );
+ pBuffer = CD3DTextureAllocator::Alloc( dwTextureSize );
+ pD3DTexture->m_fAllocator = TA_DEFAULT;
+ }
+ else
+ {
+ MEM_ALLOC_CREDIT_( __FILE__ ": Mixed texture" );
+ pBuffer = g_MixedTextureHeap.Alloc( dwTextureSize, pD3DTexture );
+ if ( pBuffer )
+ {
+ pD3DTexture->m_fAllocator = TA_MIXED;
+ }
+ else
+ {
+ g_MixedTextureHeap.Compact();
+ pBuffer = g_MixedTextureHeap.Alloc( dwTextureSize, pD3DTexture );
+ if ( pBuffer )
+ {
+ pD3DTexture->m_fAllocator = TA_MIXED;
+ }
+ else
+ {
+ pBuffer = CD3DTextureAllocator::Alloc( dwTextureSize );
+ pD3DTexture->m_fAllocator = TA_DEFAULT;
+ }
+ }
+ }
+
+ if ( !pBuffer )
+ {
+ delete pD3DTexture;
+ return NULL;
+ }
+
+ XGOffsetResourceAddress( pD3DTexture, pBuffer );
+
+ return pD3DTexture;
+}
+
+//-----------------------------------------------------------------------------
+// Build and alloc a cube texture resource
+//-----------------------------------------------------------------------------
+IDirect3DCubeTexture *CTextureHeap::AllocCubeTexture( int width, int levels, DWORD usage, D3DFORMAT d3dFormat, bool bFallback, bool bNoD3DMemory )
+{
+ CXboxCubeTexture* pD3DCubeTexture = new CXboxCubeTexture;
+
+ // create a cube texture with contiguous mips and packed tails
+ DWORD dwTextureSize = XGSetCubeTextureHeaderEx(
+ width,
+ levels,
+ usage,
+ d3dFormat,
+ 0,
+ 0,
+ 0,
+ XGHEADER_CONTIGUOUS_MIP_OFFSET,
+ pD3DCubeTexture,
+ NULL,
+ NULL );
+ pD3DCubeTexture->m_TextureSize = dwTextureSize;
+
+ if ( !bFallback && bNoD3DMemory )
+ {
+ pD3DCubeTexture->m_fAllocator = TA_UNKNOWN;
+ return pD3DCubeTexture;
+ }
+
+ void *pBits;
+ if ( UseStandardAllocator() )
+ {
+ MEM_ALLOC_CREDIT_( __FILE__ ": Cubemap standard D3D" );
+ pBits = CD3DTextureAllocator::Alloc( dwTextureSize );
+ pD3DCubeTexture->m_fAllocator = TA_DEFAULT;
+ }
+ else
+ {
+ // @todo: switch to texture heap
+ MEM_ALLOC_CREDIT_( __FILE__ ": Odd sized cubemap textures" );
+ // Really only happens with environment map
+ pBits = CD3DTextureAllocator::Alloc( dwTextureSize );
+ pD3DCubeTexture->m_fAllocator = TA_DEFAULT;
+ }
+
+ if ( !pBits )
+ {
+ delete pD3DCubeTexture;
+ return NULL;
+ }
+
+ XGOffsetResourceAddress( pD3DCubeTexture, pBits );
+
+ return pD3DCubeTexture;
+}
+
+//-----------------------------------------------------------------------------
+// Allocate an Volume Texture
+//-----------------------------------------------------------------------------
+IDirect3DVolumeTexture *CTextureHeap::AllocVolumeTexture( int width, int height, int depth, int levels, DWORD usage, D3DFORMAT d3dFormat )
+{
+ CXboxVolumeTexture *pD3DVolumeTexture = new CXboxVolumeTexture;
+
+ // create a cube texture with contiguous mips and packed tails
+ DWORD dwTextureSize = XGSetVolumeTextureHeaderEx(
+ width,
+ height,
+ depth,
+ levels,
+ usage,
+ d3dFormat,
+ 0,
+ 0,
+ 0,
+ XGHEADER_CONTIGUOUS_MIP_OFFSET,
+ pD3DVolumeTexture,
+ NULL,
+ NULL );
+
+ void *pBits;
+
+ MEM_ALLOC_CREDIT_( __FILE__ ": Volume standard D3D" );
+
+ pBits = CD3DTextureAllocator::Alloc( dwTextureSize );
+ pD3DVolumeTexture->m_fAllocator = TA_DEFAULT;
+ pD3DVolumeTexture->m_TextureSize = dwTextureSize;
+
+ if ( !pBits )
+ {
+ delete pD3DVolumeTexture;
+ return NULL;
+ }
+
+ XGOffsetResourceAddress( pD3DVolumeTexture, pBits );
+
+ return pD3DVolumeTexture;
+}
+
+//-----------------------------------------------------------------------------
+// Get current backbuffer multisample type (used in AllocRenderTargetSurface() )
+//-----------------------------------------------------------------------------
+D3DMULTISAMPLE_TYPE CTextureHeap::GetBackBufferMultiSampleType()
+{
+ int backWidth, backHeight;
+ ShaderAPI()->GetBackBufferDimensions( backWidth, backHeight );
+
+ // 2xMSAA at 640x480 and 848x480 are the only supported multisample mode on 360 (2xMSAA for 720p would
+ // use predicated tiling, which would require a rewrite of *all* our render target code)
+ // FIXME: shuffle the EDRAM surfaces to allow 4xMSAA for standard def
+ // (they would overlap & trash each other with the current allocation scheme)
+ D3DMULTISAMPLE_TYPE backBufferMultiSampleType = g_pShaderDevice->IsAAEnabled() ? D3DMULTISAMPLE_2_SAMPLES : D3DMULTISAMPLE_NONE;
+ Assert( ( g_pShaderDevice->IsAAEnabled() == false ) || (backHeight == 480) );
+
+ return backBufferMultiSampleType;
+}
+
+//-----------------------------------------------------------------------------
+// Allocate an EDRAM surface
+//-----------------------------------------------------------------------------
+IDirect3DSurface *CTextureHeap::AllocRenderTargetSurface( int width, int height, D3DFORMAT d3dFormat, bool bMultiSample, int base )
+{
+ // render target surfaces don't need to exist simultaneously
+ // force their allocations to overlap at the end of back buffer and zbuffer
+ // this should leave 3MB (of 10) free assuming 1280x720 (and 5MB with 640x480@2xMSAA)
+ D3DMULTISAMPLE_TYPE backBufferMultiSampleType = GetBackBufferMultiSampleType();
+ D3DMULTISAMPLE_TYPE multiSampleType = bMultiSample ? backBufferMultiSampleType : D3DMULTISAMPLE_NONE;
+ if ( base < 0 )
+ {
+ int backWidth, backHeight;
+ ShaderAPI()->GetBackBufferDimensions( backWidth, backHeight );
+ D3DFORMAT backBufferFormat = ImageLoader::ImageFormatToD3DFormat( g_pShaderDevice->GetBackBufferFormat() );
+ base = 2*XGSurfaceSize( backWidth, backHeight, backBufferFormat, backBufferMultiSampleType );
+ }
+
+ D3DSURFACE_PARAMETERS surfParameters;
+ surfParameters.Base = base;
+ surfParameters.ColorExpBias = 0;
+
+ if ( ( d3dFormat == D3DFMT_D24FS8 ) || ( d3dFormat == D3DFMT_D24S8 ) || ( d3dFormat == D3DFMT_D16 ) )
+ {
+ surfParameters.HierarchicalZBase = 0;
+ if ( ( surfParameters.HierarchicalZBase + XGHierarchicalZSize( width, height, multiSampleType ) ) > GPU_HIERARCHICAL_Z_TILES )
+ {
+ // overflow, can't hold the tiles so disable
+ surfParameters.HierarchicalZBase = 0xFFFFFFFF;
+ }
+ }
+ else
+ {
+ // not using
+ surfParameters.HierarchicalZBase = 0xFFFFFFFF;
+ }
+
+ HRESULT hr;
+ IDirect3DSurface9 *pSurface = NULL;
+ hr = Dx9Device()->CreateRenderTarget( width, height, d3dFormat, multiSampleType, 0, FALSE, &pSurface, &surfParameters );
+ Assert( !FAILED( hr ) );
+
+ return pSurface;
+}
+
+//-----------------------------------------------------------------------------
+// Perform the real d3d allocation, returns true if succesful, false otherwise.
+// Only valid for a texture created with no d3d bits, otherwise no-op.
+//-----------------------------------------------------------------------------
+bool CTextureHeap::AllocD3DMemory( IDirect3DBaseTexture *pD3DTexture )
+{
+ if ( !pD3DTexture )
+ {
+ return false;
+ }
+
+ if ( pD3DTexture->GetType() == D3DRTYPE_SURFACE )
+ {
+ // there are no d3d bits for a surface
+ return false;
+ }
+
+ void *pBits = GetD3DTextureBasePtr( pD3DTexture );
+ if ( pBits )
+ {
+ // already have d3d bits
+ return true;
+ }
+
+ if ( pD3DTexture->GetType() == D3DRTYPE_TEXTURE )
+ {
+ MEM_ALLOC_CREDIT_( __FILE__ ": Standard D3D" );
+ pBits = CD3DTextureAllocator::Alloc( ((CXboxTexture *)pD3DTexture)->m_TextureSize );
+ ((CXboxTexture *)pD3DTexture)->m_fAllocator = TA_DEFAULT;
+ XGOffsetResourceAddress( (CXboxTexture *)pD3DTexture, pBits );
+ return true;
+ }
+ else if ( pD3DTexture->GetType() == D3DRTYPE_CUBETEXTURE )
+ {
+ MEM_ALLOC_CREDIT_( __FILE__ ": Cubemap standard D3D" );
+ pBits = CD3DTextureAllocator::Alloc( ((CXboxCubeTexture *)pD3DTexture)->m_TextureSize );
+ ((CXboxCubeTexture *)pD3DTexture)->m_fAllocator = TA_DEFAULT;
+ XGOffsetResourceAddress( (CXboxCubeTexture *)pD3DTexture, pBits );
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Release the allocated store
+//-----------------------------------------------------------------------------
+void CTextureHeap::FreeTexture( IDirect3DBaseTexture *pD3DTexture )
+{
+ if ( !pD3DTexture )
+ {
+ return;
+ }
+
+ if ( pD3DTexture->GetType() == D3DRTYPE_SURFACE )
+ {
+ // texture heap doesn't own render target surfaces
+ // allow callers to call through for less higher level detection
+ int ref = ((IDirect3DSurface*)pD3DTexture)->Release();
+ Assert( ref == 0 );
+ ref = ref; // Quiet "unused variable" warning in release
+ return;
+ }
+ else
+ {
+ byte *pBits = (byte *)GetD3DTextureBasePtr( pD3DTexture );
+ if ( pBits )
+ {
+ switch ( GetTextureAllocator( pD3DTexture ) )
+ {
+ case TA_DEFAULT:
+ CD3DTextureAllocator::Free( pBits );
+ break;
+
+ case TA_MIXED:
+ g_MixedTextureHeap.Free( pBits, ((CXboxTexture *)pD3DTexture) );
+ break;
+ }
+ }
+ }
+
+ if ( pD3DTexture->GetType() == D3DRTYPE_TEXTURE )
+ {
+ delete (CXboxTexture *)pD3DTexture;
+ }
+ else if ( pD3DTexture->GetType() == D3DRTYPE_VOLUMETEXTURE )
+ {
+ delete (CXboxVolumeTexture *)pD3DTexture;
+ }
+ else if ( pD3DTexture->GetType() == D3DRTYPE_CUBETEXTURE )
+ {
+ delete (CXboxCubeTexture *)pD3DTexture;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Returns the allocated footprint
+//-----------------------------------------------------------------------------
+int CTextureHeap::GetSize( IDirect3DBaseTexture *pD3DTexture )
+{
+ if( pD3DTexture == NULL )
+ return 0;
+
+ if ( pD3DTexture->GetType() == D3DRTYPE_SURFACE )
+ {
+ D3DSURFACE_DESC surfaceDesc;
+ HRESULT hr = ((IDirect3DSurface*)pD3DTexture)->GetDesc( &surfaceDesc );
+ Assert( !FAILED( hr ) );
+ hr = hr; // Quiet "unused variable" warning in release
+
+ int size = ImageLoader::GetMemRequired(
+ surfaceDesc.Width,
+ surfaceDesc.Height,
+ 0,
+ ImageLoader::D3DFormatToImageFormat( surfaceDesc.Format ),
+ false );
+
+ return size;
+ }
+ else if ( pD3DTexture->GetType() == D3DRTYPE_TEXTURE )
+ {
+ return ((CXboxTexture *)pD3DTexture)->m_TextureSize;
+ }
+ else if ( pD3DTexture->GetType() == D3DRTYPE_CUBETEXTURE )
+ {
+ return ((CXboxCubeTexture *)pD3DTexture)->m_TextureSize;
+ }
+ else if ( pD3DTexture->GetType() == D3DRTYPE_VOLUMETEXTURE )
+ {
+ return ((CXboxVolumeTexture *)pD3DTexture)->m_TextureSize;
+ }
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Crunch the pools
+//-----------------------------------------------------------------------------
+void CTextureHeap::Compact()
+{
+ g_MixedTextureHeap.Compact();
+}
diff --git a/materialsystem/shaderapidx9/textureheap.h b/materialsystem/shaderapidx9/textureheap.h
new file mode 100644
index 0000000..ceeb3a9
--- /dev/null
+++ b/materialsystem/shaderapidx9/textureheap.h
@@ -0,0 +1,42 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#ifndef TEXTUREHEAP_H
+#define TEXTUREHEAP_H
+
+#if defined( _X360 )
+
+#include "locald3dtypes.h"
+
+class CTextureHeap
+{
+public:
+ IDirect3DTexture *AllocTexture( int width, int height, int levels, DWORD usage, D3DFORMAT format, bool bFallback, bool bNoD3DMemory );
+ IDirect3DCubeTexture *AllocCubeTexture( int width, int levels, DWORD usage, D3DFORMAT format, bool bFallback, bool bNoD3DMemory );
+ IDirect3DVolumeTexture *AllocVolumeTexture( int width, int height, int depth, int levels, DWORD usage, D3DFORMAT format );
+ IDirect3DSurface *AllocRenderTargetSurface( int width, int height, D3DFORMAT format, bool bMultiSample = false , int base = -1);
+
+ // Perform the real d3d allocation, returns true if succesful, false otherwise.
+ // Only valid for a texture created with no d3d bits, otherwise no-op.
+ bool AllocD3DMemory( IDirect3DBaseTexture *pTexture );
+
+ // Release header and d3d bits.
+ void FreeTexture( IDirect3DBaseTexture *pTexture );
+
+ // Returns the amount of memory needed or allocated for the texture.
+ int GetSize( IDirect3DBaseTexture *pTexture );
+
+ // Crunch the heap.
+ void Compact();
+
+ // Get current backbuffer multisample type
+ D3DMULTISAMPLE_TYPE GetBackBufferMultiSampleType();
+};
+
+extern CTextureHeap g_TextureHeap;
+
+#endif
+#endif // TEXTUREHEAP_H
diff --git a/materialsystem/shaderapidx9/vertexdecl.cpp b/materialsystem/shaderapidx9/vertexdecl.cpp
new file mode 100644
index 0000000..3d70dbc
--- /dev/null
+++ b/materialsystem/shaderapidx9/vertexdecl.cpp
@@ -0,0 +1,576 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#undef PROTECTED_THINGS_ENABLE
+#include "vertexdecl.h" // this includes <windows.h> inside the dx headers
+#define PROTECTED_THINGS_ENABLE
+#include "materialsystem/imaterialsystemhardwareconfig.h"
+#include "shaderapidx8_global.h"
+#include "tier0/dbg.h"
+#include "utlrbtree.h"
+#include "recording.h"
+#include "tier1/strtools.h"
+#include "tier0/vprof.h"
+#include "materialsystem/imesh.h"
+#include "shaderdevicedx8.h"
+
+// NOTE: This has to be the last file included!
+#include "tier0/memdbgon.h"
+
+//-----------------------------------------------------------------------------
+// Computes the DX8 vertex specification
+//-----------------------------------------------------------------------------
+static const char *DeclTypeToString( BYTE type )
+{
+ switch( type )
+ {
+ case D3DDECLTYPE_FLOAT1:
+ return "D3DDECLTYPE_FLOAT1";
+ case D3DDECLTYPE_FLOAT2:
+ return "D3DDECLTYPE_FLOAT2";
+ case D3DDECLTYPE_FLOAT3:
+ return "D3DDECLTYPE_FLOAT3";
+ case D3DDECLTYPE_FLOAT4:
+ return "D3DDECLTYPE_FLOAT4";
+ case D3DDECLTYPE_D3DCOLOR:
+ return "D3DDECLTYPE_D3DCOLOR";
+ case D3DDECLTYPE_UBYTE4:
+ return "D3DDECLTYPE_UBYTE4";
+ case D3DDECLTYPE_SHORT2:
+ return "D3DDECLTYPE_SHORT2";
+ case D3DDECLTYPE_SHORT4:
+ return "D3DDECLTYPE_SHORT4";
+ case D3DDECLTYPE_UBYTE4N:
+ return "D3DDECLTYPE_UBYTE4N";
+ case D3DDECLTYPE_SHORT2N:
+ return "D3DDECLTYPE_SHORT2N";
+ case D3DDECLTYPE_SHORT4N:
+ return "D3DDECLTYPE_SHORT4N";
+ case D3DDECLTYPE_USHORT2N:
+ return "D3DDECLTYPE_USHORT2N";
+ case D3DDECLTYPE_USHORT4N:
+ return "D3DDECLTYPE_USHORT4N";
+ case D3DDECLTYPE_UDEC3:
+ return "D3DDECLTYPE_UDEC3";
+ case D3DDECLTYPE_DEC3N:
+ return "D3DDECLTYPE_DEC3N";
+ case D3DDECLTYPE_FLOAT16_2:
+ return "D3DDECLTYPE_FLOAT16_2";
+ case D3DDECLTYPE_FLOAT16_4:
+ return "D3DDECLTYPE_FLOAT16_4";
+ default:
+ Assert( 0 );
+ return "ERROR";
+ }
+}
+
+static const char *DeclMethodToString( BYTE method )
+{
+ switch( method )
+ {
+ case D3DDECLMETHOD_DEFAULT:
+ return "D3DDECLMETHOD_DEFAULT";
+ case D3DDECLMETHOD_PARTIALU:
+ return "D3DDECLMETHOD_PARTIALU";
+ case D3DDECLMETHOD_PARTIALV:
+ return "D3DDECLMETHOD_PARTIALV";
+ case D3DDECLMETHOD_CROSSUV:
+ return "D3DDECLMETHOD_CROSSUV";
+ case D3DDECLMETHOD_UV:
+ return "D3DDECLMETHOD_UV";
+ case D3DDECLMETHOD_LOOKUP:
+ return "D3DDECLMETHOD_LOOKUP";
+ case D3DDECLMETHOD_LOOKUPPRESAMPLED:
+ return "D3DDECLMETHOD_LOOKUPPRESAMPLED";
+ default:
+ Assert( 0 );
+ return "ERROR";
+ }
+}
+
+static const char *DeclUsageToString( BYTE usage )
+{
+ switch( usage )
+ {
+ case D3DDECLUSAGE_POSITION:
+ return "D3DDECLUSAGE_POSITION";
+ case D3DDECLUSAGE_BLENDWEIGHT:
+ return "D3DDECLUSAGE_BLENDWEIGHT";
+ case D3DDECLUSAGE_BLENDINDICES:
+ return "D3DDECLUSAGE_BLENDINDICES";
+ case D3DDECLUSAGE_NORMAL:
+ return "D3DDECLUSAGE_NORMAL";
+ case D3DDECLUSAGE_PSIZE:
+ return "D3DDECLUSAGE_PSIZE";
+ case D3DDECLUSAGE_COLOR:
+ return "D3DDECLUSAGE_COLOR";
+ case D3DDECLUSAGE_TEXCOORD:
+ return "D3DDECLUSAGE_TEXCOORD";
+ case D3DDECLUSAGE_TANGENT:
+ return "D3DDECLUSAGE_TANGENT";
+ case D3DDECLUSAGE_BINORMAL:
+ return "D3DDECLUSAGE_BINORMAL";
+ case D3DDECLUSAGE_TESSFACTOR:
+ return "D3DDECLUSAGE_TESSFACTOR";
+// case D3DDECLUSAGE_POSITIONTL:
+// return "D3DDECLUSAGE_POSITIONTL";
+ default:
+ Assert( 0 );
+ return "ERROR";
+ }
+}
+
+static D3DDECLTYPE VertexElementToDeclType( VertexElement_t element, VertexCompressionType_t compressionType )
+{
+ Detect_VertexElement_t_Changes( element );
+
+ if ( compressionType == VERTEX_COMPRESSION_ON )
+ {
+ // Compressed-vertex element sizes
+ switch ( element )
+ {
+#if ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_SEPARATETANGENTS_SHORT2 )
+ case VERTEX_ELEMENT_NORMAL: return D3DDECLTYPE_SHORT2;
+ case VERTEX_ELEMENT_USERDATA4: return D3DDECLTYPE_SHORT2;
+#else //( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 )
+ case VERTEX_ELEMENT_NORMAL: return D3DDECLTYPE_UBYTE4;
+ case VERTEX_ELEMENT_USERDATA4: return D3DDECLTYPE_UBYTE4;
+#endif
+ case VERTEX_ELEMENT_BONEWEIGHTS1: return D3DDECLTYPE_SHORT2;
+ case VERTEX_ELEMENT_BONEWEIGHTS2: return D3DDECLTYPE_SHORT2;
+ default:
+ break;
+ }
+ }
+
+ // Uncompressed-vertex element sizes
+ switch ( element )
+ {
+ case VERTEX_ELEMENT_POSITION: return D3DDECLTYPE_FLOAT3;
+ case VERTEX_ELEMENT_NORMAL: return D3DDECLTYPE_FLOAT3;
+ case VERTEX_ELEMENT_COLOR: return D3DDECLTYPE_D3DCOLOR;
+ case VERTEX_ELEMENT_SPECULAR: return D3DDECLTYPE_D3DCOLOR;
+ case VERTEX_ELEMENT_TANGENT_S: return D3DDECLTYPE_FLOAT3;
+ case VERTEX_ELEMENT_TANGENT_T: return D3DDECLTYPE_FLOAT3;
+ case VERTEX_ELEMENT_WRINKLE:
+ // Wrinkle is packed into Position.W, it is not specified as a separate vertex element
+ Assert( 0 );
+ return D3DDECLTYPE_UNUSED;
+#if !defined( _X360 )
+ case VERTEX_ELEMENT_BONEINDEX: return D3DDECLTYPE_D3DCOLOR;
+#else
+ // UBYTE4 comes in as [0,255] in the shader, which is ideal for bone indices
+ // (unfortunately, UBYTE4 is not universally supported on PC DX8 GPUs)
+ case VERTEX_ELEMENT_BONEINDEX: return D3DDECLTYPE_UBYTE4;
+#endif
+ case VERTEX_ELEMENT_BONEWEIGHTS1: return D3DDECLTYPE_FLOAT1;
+ case VERTEX_ELEMENT_BONEWEIGHTS2: return D3DDECLTYPE_FLOAT2;
+ case VERTEX_ELEMENT_BONEWEIGHTS3: return D3DDECLTYPE_FLOAT3;
+ case VERTEX_ELEMENT_BONEWEIGHTS4: return D3DDECLTYPE_FLOAT4;
+ case VERTEX_ELEMENT_USERDATA1: return D3DDECLTYPE_FLOAT1;
+ case VERTEX_ELEMENT_USERDATA2: return D3DDECLTYPE_FLOAT2;
+ case VERTEX_ELEMENT_USERDATA3: return D3DDECLTYPE_FLOAT3;
+ case VERTEX_ELEMENT_USERDATA4: return D3DDECLTYPE_FLOAT4;
+ case VERTEX_ELEMENT_TEXCOORD1D_0: return D3DDECLTYPE_FLOAT1;
+ case VERTEX_ELEMENT_TEXCOORD1D_1: return D3DDECLTYPE_FLOAT1;
+ case VERTEX_ELEMENT_TEXCOORD1D_2: return D3DDECLTYPE_FLOAT1;
+ case VERTEX_ELEMENT_TEXCOORD1D_3: return D3DDECLTYPE_FLOAT1;
+ case VERTEX_ELEMENT_TEXCOORD1D_4: return D3DDECLTYPE_FLOAT1;
+ case VERTEX_ELEMENT_TEXCOORD1D_5: return D3DDECLTYPE_FLOAT1;
+ case VERTEX_ELEMENT_TEXCOORD1D_6: return D3DDECLTYPE_FLOAT1;
+ case VERTEX_ELEMENT_TEXCOORD1D_7: return D3DDECLTYPE_FLOAT1;
+ case VERTEX_ELEMENT_TEXCOORD2D_0: return D3DDECLTYPE_FLOAT2;
+ case VERTEX_ELEMENT_TEXCOORD2D_1: return D3DDECLTYPE_FLOAT2;
+ case VERTEX_ELEMENT_TEXCOORD2D_2: return D3DDECLTYPE_FLOAT2;
+ case VERTEX_ELEMENT_TEXCOORD2D_3: return D3DDECLTYPE_FLOAT2;
+ case VERTEX_ELEMENT_TEXCOORD2D_4: return D3DDECLTYPE_FLOAT2;
+ case VERTEX_ELEMENT_TEXCOORD2D_5: return D3DDECLTYPE_FLOAT2;
+ case VERTEX_ELEMENT_TEXCOORD2D_6: return D3DDECLTYPE_FLOAT2;
+ case VERTEX_ELEMENT_TEXCOORD2D_7: return D3DDECLTYPE_FLOAT2;
+ case VERTEX_ELEMENT_TEXCOORD3D_0: return D3DDECLTYPE_FLOAT3;
+ case VERTEX_ELEMENT_TEXCOORD3D_1: return D3DDECLTYPE_FLOAT3;
+ case VERTEX_ELEMENT_TEXCOORD3D_2: return D3DDECLTYPE_FLOAT3;
+ case VERTEX_ELEMENT_TEXCOORD3D_3: return D3DDECLTYPE_FLOAT3;
+ case VERTEX_ELEMENT_TEXCOORD3D_4: return D3DDECLTYPE_FLOAT3;
+ case VERTEX_ELEMENT_TEXCOORD3D_5: return D3DDECLTYPE_FLOAT3;
+ case VERTEX_ELEMENT_TEXCOORD3D_6: return D3DDECLTYPE_FLOAT3;
+ case VERTEX_ELEMENT_TEXCOORD3D_7: return D3DDECLTYPE_FLOAT3;
+ case VERTEX_ELEMENT_TEXCOORD4D_0: return D3DDECLTYPE_FLOAT4;
+ case VERTEX_ELEMENT_TEXCOORD4D_1: return D3DDECLTYPE_FLOAT4;
+ case VERTEX_ELEMENT_TEXCOORD4D_2: return D3DDECLTYPE_FLOAT4;
+ case VERTEX_ELEMENT_TEXCOORD4D_3: return D3DDECLTYPE_FLOAT4;
+ case VERTEX_ELEMENT_TEXCOORD4D_4: return D3DDECLTYPE_FLOAT4;
+ case VERTEX_ELEMENT_TEXCOORD4D_5: return D3DDECLTYPE_FLOAT4;
+ case VERTEX_ELEMENT_TEXCOORD4D_6: return D3DDECLTYPE_FLOAT4;
+ case VERTEX_ELEMENT_TEXCOORD4D_7: return D3DDECLTYPE_FLOAT4;
+ default:
+ Assert(0);
+ return D3DDECLTYPE_UNUSED;
+ };
+}
+
+void PrintVertexDeclaration( const D3DVERTEXELEMENT9 *pDecl )
+{
+ int i;
+ static D3DVERTEXELEMENT9 declEnd = D3DDECL_END();
+ for ( i = 0; ; i++ )
+ {
+ if ( memcmp( &pDecl[i], &declEnd, sizeof( declEnd ) ) == 0 )
+ {
+ Warning( "D3DDECL_END\n" );
+ break;
+ }
+ Msg( "%d: Stream: %d, Offset: %d, Type: %s, Method: %s, Usage: %s, UsageIndex: %d\n",
+ i, ( int )pDecl[i].Stream, ( int )pDecl[i].Offset,
+ DeclTypeToString( pDecl[i].Type ),
+ DeclMethodToString( pDecl[i].Method ),
+ DeclUsageToString( pDecl[i].Usage ),
+ ( int )pDecl[i].UsageIndex );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Converts format to a vertex decl
+//-----------------------------------------------------------------------------
+void ComputeVertexSpec( VertexFormat_t fmt, D3DVERTEXELEMENT9 *pDecl, bool bStaticLit, bool bUsingFlex, bool bUsingMorph )
+{
+ int i = 0;
+ int offset = 0;
+
+ VertexCompressionType_t compressionType = CompressionType( fmt );
+
+ if ( IsX360() )
+ {
+ // On 360, there's a performance penalty for reading more than 2 streams in the vertex shader
+ // (we don't do this yet, but we should be aware if we start doing it)
+#ifdef _DEBUG
+ int numStreams = 1 + ( bStaticLit ? 1 : 0 ) + ( bUsingFlex ? 1 : 0 ) + ( bUsingMorph ? 1 : 0 );
+ Assert( numStreams <= 2 );
+#endif
+ }
+
+ if ( fmt & VERTEX_POSITION )
+ {
+ pDecl[i].Stream = 0;
+ pDecl[i].Offset = offset;
+ pDecl[i].Method = D3DDECLMETHOD_DEFAULT;
+ pDecl[i].Usage = D3DDECLUSAGE_POSITION;
+ pDecl[i].UsageIndex = 0;
+ pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_POSITION, compressionType );
+ offset += GetVertexElementSize( VERTEX_ELEMENT_POSITION, compressionType );
+ ++i;
+ }
+
+ int numBones = NumBoneWeights(fmt);
+ if ( numBones > 0 )
+ {
+ pDecl[i].Stream = 0;
+ pDecl[i].Offset = offset;
+ pDecl[i].Method = D3DDECLMETHOD_DEFAULT;
+ pDecl[i].Usage = D3DDECLUSAGE_BLENDWEIGHT;
+ pDecl[i].UsageIndex = 0;
+
+ // Always exactly two weights
+ pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_BONEWEIGHTS2, compressionType );
+ offset += GetVertexElementSize( VERTEX_ELEMENT_BONEWEIGHTS2, compressionType );
+ ++i;
+ }
+
+ if ( fmt & VERTEX_BONE_INDEX )
+ {
+ // this isn't FVF!!!!!
+ pDecl[i].Stream = 0;
+ pDecl[i].Offset = offset;
+ pDecl[i].Method = D3DDECLMETHOD_DEFAULT;
+ pDecl[i].Usage = D3DDECLUSAGE_BLENDINDICES;
+ pDecl[i].UsageIndex = 0;
+ pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_BONEINDEX, compressionType );
+ offset += GetVertexElementSize( VERTEX_ELEMENT_BONEINDEX, compressionType );
+ ++i;
+ }
+
+ int normalOffset = -1;
+ if ( fmt & VERTEX_NORMAL )
+ {
+ pDecl[i].Stream = 0;
+ pDecl[i].Offset = offset;
+ normalOffset = offset;
+ pDecl[i].Method = D3DDECLMETHOD_DEFAULT;
+ pDecl[i].Usage = D3DDECLUSAGE_NORMAL;
+ pDecl[i].UsageIndex = 0;
+ pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_NORMAL, compressionType );
+ offset += GetVertexElementSize( VERTEX_ELEMENT_NORMAL, compressionType );
+ ++i;
+ }
+
+ if ( fmt & VERTEX_COLOR )
+ {
+ pDecl[i].Stream = 0;
+ pDecl[i].Offset = offset;
+ pDecl[i].Method = D3DDECLMETHOD_DEFAULT;
+ pDecl[i].Usage = D3DDECLUSAGE_COLOR;
+ pDecl[i].UsageIndex = 0;
+ pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_COLOR, compressionType );
+ offset += GetVertexElementSize( VERTEX_ELEMENT_COLOR, compressionType );
+ ++i;
+ }
+
+ if ( fmt & VERTEX_SPECULAR )
+ {
+ Assert( !bStaticLit );
+ pDecl[i].Stream = 0;
+ pDecl[i].Offset = offset;
+ pDecl[i].Method = D3DDECLMETHOD_DEFAULT;
+ pDecl[i].Usage = D3DDECLUSAGE_COLOR;
+ pDecl[i].UsageIndex = 1; // SPECULAR goes in the second COLOR slot
+ pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_SPECULAR, compressionType );
+ offset += GetVertexElementSize( VERTEX_ELEMENT_SPECULAR, compressionType );
+ ++i;
+ }
+
+ VertexElement_t texCoordDimensions[4] = { VERTEX_ELEMENT_TEXCOORD1D_0,
+ VERTEX_ELEMENT_TEXCOORD2D_0,
+ VERTEX_ELEMENT_TEXCOORD3D_0,
+ VERTEX_ELEMENT_TEXCOORD4D_0 };
+ for ( int j = 0; j < VERTEX_MAX_TEXTURE_COORDINATES; ++j )
+ {
+ int nCoordSize = TexCoordSize( j, fmt );
+ if ( nCoordSize <= 0 )
+ continue;
+ Assert( nCoordSize <= 4 );
+
+ pDecl[i].Stream = 0;
+ pDecl[i].Offset = offset;
+ pDecl[i].Method = D3DDECLMETHOD_DEFAULT;
+ pDecl[i].Usage = D3DDECLUSAGE_TEXCOORD;
+ pDecl[i].UsageIndex = j;
+ VertexElement_t texCoordElement = (VertexElement_t)( texCoordDimensions[ nCoordSize - 1 ] + j );
+ pDecl[i].Type = VertexElementToDeclType( texCoordElement, compressionType );
+ offset += GetVertexElementSize( texCoordElement, compressionType );
+ ++i;
+ }
+
+ if ( fmt & VERTEX_TANGENT_S )
+ {
+ pDecl[i].Stream = 0;
+ pDecl[i].Offset = offset;
+ pDecl[i].Method = D3DDECLMETHOD_DEFAULT;
+ pDecl[i].Usage = D3DDECLUSAGE_TANGENT;
+ pDecl[i].UsageIndex = 0;
+ // NOTE: this is currently *not* compressed
+ pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_TANGENT_S, compressionType );
+ offset += GetVertexElementSize( VERTEX_ELEMENT_TANGENT_S, compressionType );
+ ++i;
+ }
+
+ if ( fmt & VERTEX_TANGENT_T )
+ {
+ pDecl[i].Stream = 0;
+ pDecl[i].Offset = offset;
+ pDecl[i].Method = D3DDECLMETHOD_DEFAULT;
+ pDecl[i].Usage = D3DDECLUSAGE_BINORMAL;
+ pDecl[i].UsageIndex = 0;
+ // NOTE: this is currently *not* compressed
+ pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_TANGENT_T, compressionType );
+ offset += GetVertexElementSize( VERTEX_ELEMENT_TANGENT_T, compressionType );
+ ++i;
+ }
+
+ int userDataSize = UserDataSize(fmt);
+ if ( userDataSize > 0 )
+ {
+ Assert( userDataSize == 4 ); // This is actually only ever used for tangents
+ pDecl[i].Stream = 0;
+ if ( ( compressionType == VERTEX_COMPRESSION_ON ) &&
+ ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) )
+ {
+ // FIXME: Normals and tangents are packed together into a single UBYTE4 element,
+ // so just point this back at the same data while we're testing UBYTE4 out.
+ pDecl[i].Offset = normalOffset;
+ }
+ else
+ {
+ pDecl[i].Offset = offset;
+ }
+ pDecl[i].Method = D3DDECLMETHOD_DEFAULT;
+ pDecl[i].Usage = D3DDECLUSAGE_TANGENT;
+ pDecl[i].UsageIndex = 0;
+ VertexElement_t userDataElement = (VertexElement_t)( VERTEX_ELEMENT_USERDATA1 + ( userDataSize - 1 ) );
+ pDecl[i].Type = VertexElementToDeclType( userDataElement, compressionType );
+ offset += GetVertexElementSize( userDataElement, compressionType );
+ ++i;
+ }
+
+ if ( bStaticLit )
+ {
+ // force stream 1 to have specular color in it, which is used for baked static lighting
+ pDecl[i].Stream = 1;
+ pDecl[i].Offset = 0;
+ pDecl[i].Method = D3DDECLMETHOD_DEFAULT;
+ pDecl[i].Usage = D3DDECLUSAGE_COLOR;
+ pDecl[i].UsageIndex = 1; // SPECULAR goes into the second COLOR slot
+ pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_SPECULAR, compressionType );
+ ++i;
+ }
+
+ if ( HardwareConfig()->SupportsVertexAndPixelShaders() )
+ {
+ // FIXME: There needs to be a better way of doing this
+ // In 2.0b, assume position is 4d, storing wrinkle in pos.w.
+ bool bUseWrinkle = HardwareConfig()->SupportsPixelShaders_2_b();
+
+ // Force stream 2 to have flex deltas in it
+ pDecl[i].Stream = 2;
+ pDecl[i].Offset = 0;
+ pDecl[i].Method = D3DDECLMETHOD_DEFAULT;
+ pDecl[i].Usage = D3DDECLUSAGE_POSITION;
+ pDecl[i].UsageIndex = 1;
+ // FIXME: unify this with VertexElementToDeclType():
+ pDecl[i].Type = bUseWrinkle ? D3DDECLTYPE_FLOAT4 : D3DDECLTYPE_FLOAT3;
+ ++i;
+
+ int normalOffset = GetVertexElementSize( VERTEX_ELEMENT_POSITION, compressionType );
+ if ( bUseWrinkle )
+ {
+ normalOffset += GetVertexElementSize( VERTEX_ELEMENT_WRINKLE, compressionType );
+ }
+
+ // Normal deltas
+ pDecl[i].Stream = 2;
+ pDecl[i].Offset = normalOffset;
+ pDecl[i].Method = D3DDECLMETHOD_DEFAULT;
+ pDecl[i].Usage = D3DDECLUSAGE_NORMAL;
+ pDecl[i].UsageIndex = 1;
+ // NOTE: this is currently *not* compressed
+ pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_NORMAL, VERTEX_COMPRESSION_NONE );
+ ++i;
+ }
+
+ if ( bUsingMorph )
+ {
+ // force stream 3 to have vertex index in it, which is used for doing vertex texture reads
+ pDecl[i].Stream = 3;
+ pDecl[i].Offset = 0;
+ pDecl[i].Method = D3DDECLMETHOD_DEFAULT;
+ pDecl[i].Usage = D3DDECLUSAGE_POSITION;
+ pDecl[i].UsageIndex = 2;
+ pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_USERDATA1, compressionType );
+ ++i;
+ }
+
+ static D3DVERTEXELEMENT9 declEnd = D3DDECL_END();
+ pDecl[i] = declEnd;
+
+ //PrintVertexDeclaration( pDecl );
+}
+
+//-----------------------------------------------------------------------------
+// Gets the declspec associated with a vertex format
+//-----------------------------------------------------------------------------
+struct VertexDeclLookup_t
+{
+ enum LookupFlags_t
+ {
+ STATIC_LIT = 0x1,
+ USING_MORPH = 0x2,
+ USING_FLEX = 0x4,
+ };
+
+ VertexFormat_t m_VertexFormat;
+ int m_nFlags;
+ IDirect3DVertexDeclaration9 *m_pDecl;
+
+ bool operator==( const VertexDeclLookup_t &src ) const
+ {
+ return ( m_VertexFormat == src.m_VertexFormat ) && ( m_nFlags == src.m_nFlags );
+ }
+};
+
+
+//-----------------------------------------------------------------------------
+// Dictionary of vertex decls
+// FIXME: stick this in the class?
+// FIXME: Does anything cause this to get flushed?
+//-----------------------------------------------------------------------------
+static bool VertexDeclLessFunc( const VertexDeclLookup_t &src1, const VertexDeclLookup_t &src2 )
+{
+ if ( src1.m_nFlags == src2.m_nFlags )
+ return src1.m_VertexFormat < src2.m_VertexFormat;
+
+ return ( src1.m_nFlags < src2.m_nFlags );
+}
+
+static CUtlRBTree<VertexDeclLookup_t, int> s_VertexDeclDict( 0, 256, VertexDeclLessFunc );
+
+//-----------------------------------------------------------------------------
+// Gets the declspec associated with a vertex format
+//-----------------------------------------------------------------------------
+IDirect3DVertexDeclaration9 *FindOrCreateVertexDecl( VertexFormat_t fmt, bool bStaticLit, bool bUsingFlex, bool bUsingMorph )
+{
+ MEM_ALLOC_D3D_CREDIT();
+
+ VertexDeclLookup_t lookup;
+ lookup.m_VertexFormat = fmt;
+ lookup.m_nFlags = 0;
+ if ( bStaticLit )
+ {
+ lookup.m_nFlags |= VertexDeclLookup_t::STATIC_LIT;
+ }
+ if ( bUsingMorph )
+ {
+ lookup.m_nFlags |= VertexDeclLookup_t::USING_MORPH;
+ }
+ if ( bUsingFlex )
+ {
+ lookup.m_nFlags |= VertexDeclLookup_t::USING_FLEX;
+ }
+
+ int i = s_VertexDeclDict.Find( lookup );
+ if ( i != s_VertexDeclDict.InvalidIndex() )
+ {
+ // found
+ return s_VertexDeclDict[i].m_pDecl;
+ }
+
+ D3DVERTEXELEMENT9 decl[32];
+ ComputeVertexSpec( fmt, decl, bStaticLit, bUsingFlex, bUsingMorph );
+
+ HRESULT hr =
+ Dx9Device()->CreateVertexDeclaration( decl, &lookup.m_pDecl );
+
+ // NOTE: can't record until we have m_pDecl!
+ RECORD_COMMAND( DX8_CREATE_VERTEX_DECLARATION, 2 );
+ RECORD_INT( ( int )lookup.m_pDecl );
+ RECORD_STRUCT( decl, sizeof( decl ) );
+ COMPILE_TIME_ASSERT( sizeof( decl ) == sizeof( D3DVERTEXELEMENT9 ) * 32 );
+
+ Assert( hr == D3D_OK );
+ if ( hr != D3D_OK )
+ {
+ Warning( " ERROR: failed to create vertex decl for vertex format 0x%08llX! You'll probably see messed-up mesh rendering - to diagnose, build shaderapidx9.dll in debug.\n", fmt );
+ }
+
+ s_VertexDeclDict.Insert( lookup );
+ return lookup.m_pDecl;
+}
+
+
+//-----------------------------------------------------------------------------
+// Clears out all declspecs
+//-----------------------------------------------------------------------------
+void ReleaseAllVertexDecl()
+{
+ int i = s_VertexDeclDict.FirstInorder();
+ while ( i != s_VertexDeclDict.InvalidIndex() )
+ {
+ if ( s_VertexDeclDict[i].m_pDecl )
+ s_VertexDeclDict[i].m_pDecl->Release();
+ i = s_VertexDeclDict.NextInorder( i );
+ }
+}
+
diff --git a/materialsystem/shaderapidx9/vertexdecl.h b/materialsystem/shaderapidx9/vertexdecl.h
new file mode 100644
index 0000000..d275fdb
--- /dev/null
+++ b/materialsystem/shaderapidx9/vertexdecl.h
@@ -0,0 +1,32 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#ifndef VERTEXDECL_H
+#define VERTEXDECL_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "locald3dtypes.h"
+#include "materialsystem/imaterial.h"
+
+
+//-----------------------------------------------------------------------------
+// Gets the declspec associated with a vertex format
+//-----------------------------------------------------------------------------
+IDirect3DVertexDeclaration9 *FindOrCreateVertexDecl( VertexFormat_t fmt, bool bStaticLit, bool bUsingFlex, bool bUsingMorph );
+
+//-----------------------------------------------------------------------------
+// Clears out all declspecs
+//-----------------------------------------------------------------------------
+void ReleaseAllVertexDecl( );
+
+
+#endif // VERTEXDECL_H
+
diff --git a/materialsystem/shaderapidx9/vertexshaderdx8.cpp b/materialsystem/shaderapidx9/vertexshaderdx8.cpp
new file mode 100644
index 0000000..b3f1063
--- /dev/null
+++ b/materialsystem/shaderapidx9/vertexshaderdx8.cpp
@@ -0,0 +1,3783 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Vertex/Pixel Shaders
+//
+//===========================================================================//
+#define DISABLE_PROTECTED_THINGS
+#if ( defined(_WIN32) && !defined( _X360 ) )
+#elif POSIX
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#define closesocket close
+#define WSAGetLastError() errno
+#undef SOCKET
+typedef int SOCKET;
+#define SOCKET_ERROR (-1)
+#define SD_SEND 0x01
+#define INVALID_SOCKET (~0)
+#endif
+
+#include "togl/rendermechanism.h"
+#include "vertexshaderdx8.h"
+#include "tier1/utlsymbol.h"
+#include "tier1/utlvector.h"
+#include "tier1/utldict.h"
+#include "tier1/utllinkedlist.h"
+#include "tier1/utlbuffer.h"
+#include "tier1/UtlStringMap.h"
+#include "locald3dtypes.h"
+#include "shaderapidx8_global.h"
+#include "recording.h"
+#include "tier0/vprof.h"
+#include "materialsystem/imaterialsystem.h"
+#include "materialsystem/imaterialsystemhardwareconfig.h"
+#include "KeyValues.h"
+#include "shaderapidx8.h"
+#include "materialsystem/IShader.h"
+#include "IShaderSystem.h"
+#include "tier0/fasttimer.h"
+#include <sys/stat.h>
+#include <time.h>
+#include <stdlib.h>
+#include "filesystem.h"
+#include "convar.h"
+#include "materialsystem/shader_vcs_version.h"
+#include "tier1/lzmaDecoder.h"
+#include "tier1/utlmap.h"
+
+#include "datacache/idatacache.h"
+#include "tier1/diff.h"
+#include "shaderdevicedx8.h"
+#include "filesystem/IQueuedLoader.h"
+#include "tier2/tier2.h"
+#include "shaderapi/ishaderutil.h"
+#include "tier0/icommandline.h"
+
+#include "Color.h"
+#include "tier0/dbg.h"
+
+#ifdef REMOTE_DYNAMIC_SHADER_COMPILE
+
+# if defined (POSIX)
+
+# include <sys/types.h>
+# include <sys/socket.h>
+
+# else
+
+# include <winsock2.h>
+# include <ws2tcpip.h>
+
+# endif
+
+#endif
+
+// NOTE: This has to be the last file included!
+#include "tier0/memdbgon.h"
+
+
+// It currently includes windows.h and we don't want that.
+#ifdef USE_ACTUAL_DX
+
+#include "../utils/bzip2/bzlib.h"
+
+#else
+
+int BZ2_bzBuffToBuffDecompress(
+ char* dest,
+ unsigned int* destLen,
+ char* source,
+ unsigned int sourceLen,
+ int small,
+ int verbosity
+ )
+{
+ return 0;
+}
+
+#endif
+
+static ConVar mat_remoteshadercompile( "mat_remoteshadercompile", "127.0.0.1", FCVAR_CHEAT );
+
+//#define PROFILE_SHADER_CREATE
+
+//#define NO_AMBIENT_CUBE
+#define MAX_BONES 3
+
+// debugging aid
+#define MAX_SHADER_HISTORY 16
+
+#if !defined( _X360 )
+#define SHADER_FNAME_EXTENSION ".vcs"
+#else
+#define SHADER_FNAME_EXTENSION ".360.vcs"
+#endif
+
+#ifdef DYNAMIC_SHADER_COMPILE
+volatile static char s_ShaderCompileString[]="dynamic_shader_compile_is_on";
+#endif
+
+#ifdef DYNAMIC_SHADER_COMPILE
+static void MatFlushShaders( void );
+#endif
+
+// D3D to OpenGL translator
+//static D3DToGL_ASM sg_D3DToOpenGLTranslator; // Remove the _ASM to switch to the new translator
+//static D3DToGL sg_NewD3DToOpenGLTranslator; // Remove the _ASM to switch to the new translator
+
+static const char *GetLightTypeName( VertexShaderLightTypes_t type )
+{
+ static const char *s_VertexShaderLightTypeNames[] =
+ {
+ "LIGHT_NONE",
+ "LIGHT_SPOT",
+ "LIGHT_POINT",
+ "LIGHT_DIRECTIONAL",
+ "LIGHT_STATIC",
+ "LIGHT_AMBIENTCUBE",
+ };
+ return s_VertexShaderLightTypeNames[type+1];
+}
+
+#ifdef PROFILE_SHADER_CREATE
+static FILE *GetDebugFileHandle( void )
+{
+ static FILE *fp = NULL;
+ if( !fp )
+ {
+ fp = fopen( "shadercreate.txt", "w" );
+ Assert( fp );
+ }
+ return fp;
+}
+#endif // PROFILE_SHADER_CREATE
+
+#ifdef DX_TO_GL_ABSTRACTION
+ // mat_autoload_glshaders instructs the engine to load a cached shader table at startup
+ // it will try for glshaders.cfg first, then fall back to glbaseshaders.cfg if not found
+ConVar mat_autoload_glshaders( "mat_autoload_glshaders", "1" );
+
+ // mat_autosave_glshaders instructs the engine to save out the shader table at key points
+ // to the filename glshaders.cfg
+ //
+ConVar mat_autosave_glshaders( "mat_autosave_glshaders", "1" );
+
+
+#endif
+//-----------------------------------------------------------------------------
+// Explicit instantiation of shader buffer implementation
+//-----------------------------------------------------------------------------
+template class CShaderBuffer< ID3DXBuffer >;
+
+
+//-----------------------------------------------------------------------------
+// Used to find unique shaders
+//-----------------------------------------------------------------------------
+#ifdef MEASURE_DRIVER_ALLOCATIONS
+static CUtlMap< CRC32_t, int, int > s_UniqueVS( 0, 0, DefLessFunc( CRC32_t ) );
+static CUtlMap< CRC32_t, int, int > s_UniquePS( 0, 0, DefLessFunc( CRC32_t ) );
+static CUtlMap< IDirect3DVertexShader9*, CRC32_t, int > s_VSLookup( 0, 0, DefLessFunc( IDirect3DVertexShader9* ) );
+static CUtlMap< IDirect3DPixelShader9*, CRC32_t, int > s_PSLookup( 0, 0, DefLessFunc( IDirect3DPixelShader9* ) );
+#endif
+
+static int s_NumPixelShadersCreated = 0;
+static int s_NumVertexShadersCreated = 0;
+
+static void RegisterVS( const void* pShaderBits, int nShaderSize, IDirect3DVertexShader9* pShader )
+{
+#ifdef MEASURE_DRIVER_ALLOCATIONS
+ CRC32_t crc;
+ CRC32_Init( &crc );
+ CRC32_ProcessBuffer( &crc, pShaderBits, nShaderSize );
+ CRC32_Final( &crc );
+
+ s_VSLookup.Insert( pShader, crc );
+
+ int nIndex = s_UniqueVS.Find( crc );
+ if ( nIndex != s_UniqueVS.InvalidIndex() )
+ {
+ ++s_UniqueVS[nIndex];
+ }
+ else
+ {
+ int nMemUsed = 23 * 1024;
+ s_UniqueVS.Insert( crc, 1 );
+ VPROF_INCREMENT_GROUP_COUNTER( "unique vs count", COUNTER_GROUP_NO_RESET, 1 );
+ VPROF_INCREMENT_GROUP_COUNTER( "vs driver mem", COUNTER_GROUP_NO_RESET, nMemUsed );
+ VPROF_INCREMENT_GROUP_COUNTER( "total driver mem", COUNTER_GROUP_NO_RESET, nMemUsed );
+ }
+#endif
+}
+
+static void RegisterPS( const void* pShaderBits, int nShaderSize, IDirect3DPixelShader9* pShader )
+{
+#ifdef MEASURE_DRIVER_ALLOCATIONS
+ CRC32_t crc;
+ CRC32_Init( &crc );
+ CRC32_ProcessBuffer( &crc, pShaderBits, nShaderSize );
+ CRC32_Final( &crc );
+
+ s_PSLookup.Insert( pShader, crc );
+
+ int nIndex = s_UniquePS.Find( crc );
+ if ( nIndex != s_UniquePS.InvalidIndex() )
+ {
+ ++s_UniquePS[nIndex];
+ }
+ else
+ {
+ int nMemUsed = 400;
+ s_UniquePS.Insert( crc, 1 );
+ VPROF_INCREMENT_GROUP_COUNTER( "unique ps count", COUNTER_GROUP_NO_RESET, 1 );
+ VPROF_INCREMENT_GROUP_COUNTER( "ps driver mem", COUNTER_GROUP_NO_RESET, nMemUsed );
+ VPROF_INCREMENT_GROUP_COUNTER( "total driver mem", COUNTER_GROUP_NO_RESET, nMemUsed );
+ }
+#endif
+}
+
+static void UnregisterVS( IDirect3DVertexShader9* pShader )
+{
+#ifdef MEASURE_DRIVER_ALLOCATIONS
+ int nCRCIndex = s_VSLookup.Find( pShader );
+ if ( nCRCIndex == s_VSLookup.InvalidIndex() )
+ return;
+
+ CRC32_t crc = s_VSLookup[nCRCIndex];
+ s_VSLookup.RemoveAt( nCRCIndex );
+
+ int nIndex = s_UniqueVS.Find( crc );
+ if ( nIndex != s_UniqueVS.InvalidIndex() )
+ {
+ if ( --s_UniqueVS[nIndex] <= 0 )
+ {
+ int nMemUsed = 23 * 1024;
+ VPROF_INCREMENT_GROUP_COUNTER( "unique vs count", COUNTER_GROUP_NO_RESET, -1 );
+ VPROF_INCREMENT_GROUP_COUNTER( "vs driver mem", COUNTER_GROUP_NO_RESET, -nMemUsed );
+ VPROF_INCREMENT_GROUP_COUNTER( "total driver mem", COUNTER_GROUP_NO_RESET, -nMemUsed );
+ s_UniqueVS.Remove( nIndex );
+ }
+ }
+#endif
+}
+
+static void UnregisterPS( IDirect3DPixelShader9* pShader )
+{
+#ifdef MEASURE_DRIVER_ALLOCATIONS
+ int nCRCIndex = s_PSLookup.Find( pShader );
+ if ( nCRCIndex == s_PSLookup.InvalidIndex() )
+ return;
+
+ CRC32_t crc = s_PSLookup[nCRCIndex];
+ s_PSLookup.RemoveAt( nCRCIndex );
+
+ int nIndex = s_UniquePS.Find( crc );
+ if ( nIndex != s_UniquePS.InvalidIndex() )
+ {
+ if ( --s_UniquePS[nIndex] <= 0 )
+ {
+ int nMemUsed = 400;
+ VPROF_INCREMENT_GROUP_COUNTER( "unique ps count", COUNTER_GROUP_NO_RESET, -1 );
+ VPROF_INCREMENT_GROUP_COUNTER( "ps driver mem", COUNTER_GROUP_NO_RESET, -nMemUsed );
+ VPROF_INCREMENT_GROUP_COUNTER( "total driver mem", COUNTER_GROUP_NO_RESET, -nMemUsed );
+ s_UniquePS.Remove( nIndex );
+ }
+ }
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// The lovely low-level dx call to create a vertex shader
+//-----------------------------------------------------------------------------
+static HardwareShader_t CreateD3DVertexShader( DWORD *pByteCode, int numBytes, const char *pShaderName, char *debugLabel = NULL )
+{
+ MEM_ALLOC_D3D_CREDIT();
+
+ if ( !pByteCode )
+ {
+ Assert( 0 );
+ return INVALID_HARDWARE_SHADER;
+ }
+
+ // Compute the vertex specification
+ HardwareShader_t hShader;
+
+ #ifdef DX_TO_GL_ABSTRACTION
+ HRESULT hr = Dx9Device()->CreateVertexShader( pByteCode, (IDirect3DVertexShader9 **)&hShader, pShaderName, debugLabel );
+ #else
+ if ( IsEmulatingGL() )
+ {
+ DWORD dwVersion = D3DXGetShaderVersion( pByteCode );
+ REFERENCE( dwVersion );
+ Assert ( D3DSHADER_VERSION_MAJOR( dwVersion ) == 2 );
+ }
+
+ #if defined(_X360) || !defined(DX_TO_GL_ABSTRACTION)
+ HRESULT hr = Dx9Device()->CreateVertexShader( pByteCode, (IDirect3DVertexShader9 **)&hShader );
+ #else
+ HRESULT hr = Dx9Device()->CreateVertexShader( pByteCode, (IDirect3DVertexShader9 **)&hShader, pShaderName );
+#endif
+
+ #endif
+
+ // NOTE: This isn't recorded before the CreateVertexShader because
+ // we don't know the value of shader until after the CreateVertexShader.
+ RECORD_COMMAND( DX8_CREATE_VERTEX_SHADER, 3 );
+ RECORD_INT( ( int )hShader ); // hack hack hack
+ RECORD_INT( numBytes );
+ RECORD_STRUCT( pByteCode, numBytes );
+
+ if ( FAILED( hr ) )
+ {
+ Assert( 0 );
+ hShader = INVALID_HARDWARE_SHADER;
+ }
+ else
+ {
+ s_NumVertexShadersCreated++;
+ RegisterVS( pByteCode, numBytes, (IDirect3DVertexShader9 *)hShader );
+ }
+ return hShader;
+}
+
+static void PatchPixelShaderForAtiMsaaHack(DWORD *pShader, DWORD dwTexCoordMask)
+{
+ if ( IsPC() )
+ {
+ bool bIsSampler, bIsTexCoord;
+
+ // Should be able to patch only ps2.0
+ if (*pShader != 0xFFFF0200)
+ return;
+
+ pShader++;
+
+ while (pShader)
+ {
+ switch (*pShader & D3DSI_OPCODE_MASK)
+ {
+ case D3DSIO_COMMENT:
+ // Process comment
+ pShader = pShader + (*pShader >> 16) + 1;
+ break;
+
+ case D3DSIO_END:
+ // End of shader
+ return;
+
+ case D3DSIO_DCL:
+ bIsSampler = (*(pShader + 1) & D3DSP_TEXTURETYPE_MASK) != D3DSTT_UNKNOWN;
+ bIsTexCoord = (((*(pShader + 2) & D3DSP_REGTYPE_MASK) >> D3DSP_REGTYPE_SHIFT) +
+ ((*(pShader + 2) & D3DSP_REGTYPE_MASK2) >> D3DSP_REGTYPE_SHIFT2)) == D3DSPR_TEXTURE;
+
+ if (!bIsSampler && bIsTexCoord)
+ {
+ DWORD dwTexCoord = *(pShader + 2) & D3DSP_REGNUM_MASK;
+ DWORD mask = 0x01;
+ for (DWORD i = 0; i < 16; i++)
+ {
+ if (((dwTexCoordMask & mask) == mask) && (dwTexCoord == i))
+ {
+ // If found -- patch and get out
+ // *(pShader + 2) |= D3DSPDM_PARTIALPRECISION;
+ *(pShader + 2) |= D3DSPDM_MSAMPCENTROID;
+ break;
+ }
+ mask <<= 1;
+ }
+ }
+ // Intentionally fall through...
+
+ default:
+ // Skip instruction
+ pShader = pShader + ((*pShader & D3DSI_INSTLENGTH_MASK) >> D3DSI_INSTLENGTH_SHIFT) + 1;
+ }
+ }
+ }
+}
+
+static ConVar mat_force_ps_patch( "mat_force_ps_patch", "0" );
+static ConVar mat_disable_ps_patch( "mat_disable_ps_patch", "0", FCVAR_ALLOWED_IN_COMPETITIVE );
+
+//-----------------------------------------------------------------------------
+// The lovely low-level dx call to create a pixel shader
+//-----------------------------------------------------------------------------
+static HardwareShader_t CreateD3DPixelShader( DWORD *pByteCode, unsigned int nCentroidMask, int numBytes, const char* pShaderName, char *debugLabel = NULL )
+{
+ MEM_ALLOC_D3D_CREDIT();
+
+ if ( !pByteCode )
+ return INVALID_HARDWARE_SHADER;
+
+ if ( IsPC() && nCentroidMask &&
+ ( HardwareConfig()->NeedsATICentroidHack() ||
+ mat_force_ps_patch.GetInt() ) )
+ {
+ if ( !mat_disable_ps_patch.GetInt() )
+ {
+ PatchPixelShaderForAtiMsaaHack( pByteCode, nCentroidMask );
+ }
+ }
+
+ HardwareShader_t shader;
+ #if defined( DX_TO_GL_ABSTRACTION )
+ #if defined( OSX )
+ HRESULT hr = Dx9Device()->CreatePixelShader( pByteCode, ( IDirect3DPixelShader ** )&shader, pShaderName, debugLabel );
+ #else
+ HRESULT hr = Dx9Device()->CreatePixelShader( pByteCode, ( IDirect3DPixelShader ** )&shader, pShaderName, debugLabel, &nCentroidMask );
+ #endif
+ #else
+ if ( IsEmulatingGL() )
+ {
+ DWORD dwVersion;
+ dwVersion = D3DXGetShaderVersion( pByteCode );
+ Assert ( D3DSHADER_VERSION_MAJOR( dwVersion ) == 2 );
+ }
+#if defined(_X360) || !defined(DX_TO_GL_ABSTRACTION)
+ HRESULT hr = Dx9Device()->CreatePixelShader( pByteCode, ( IDirect3DPixelShader ** )&shader );
+#else
+ HRESULT hr = Dx9Device()->CreatePixelShader( pByteCode, ( IDirect3DPixelShader ** )&shader, pShaderName );
+ #endif
+ #endif
+
+ // NOTE: We have to do this after creating the pixel shader since we don't know
+ // lookup.m_PixelShader yet!!!!!!!
+ RECORD_COMMAND( DX8_CREATE_PIXEL_SHADER, 3 );
+ RECORD_INT( ( int )shader ); // hack hack hack
+ RECORD_INT( numBytes );
+ RECORD_STRUCT( pByteCode, numBytes );
+
+ if ( FAILED( hr ) )
+ {
+ Assert(0);
+ shader = INVALID_HARDWARE_SHADER;
+ }
+ else
+ {
+ s_NumPixelShadersCreated++;
+ RegisterPS( pByteCode, numBytes, ( IDirect3DPixelShader9* )shader );
+ }
+
+ return shader;
+}
+
+template<class T> int BinarySearchCombos( uint32 nStaticComboID, int nCombos, T const *pRecords )
+{
+ // Use binary search - data is sorted
+ int nLowerIdx = 1;
+ int nUpperIdx = nCombos;
+ for (;;)
+ {
+ if ( nUpperIdx < nLowerIdx )
+ return -1;
+
+ int nMiddleIndex = ( nLowerIdx + nUpperIdx ) / 2;
+ uint32 nProbe = pRecords[nMiddleIndex-1].m_nStaticComboID;
+ if ( nStaticComboID < nProbe )
+ {
+ nUpperIdx = nMiddleIndex - 1;
+ }
+ else
+ {
+ if ( nStaticComboID > nProbe )
+ nLowerIdx = nMiddleIndex + 1;
+ else
+ return nMiddleIndex - 1;
+ }
+ }
+}
+
+inline int FindShaderStaticCombo( uint32 nStaticComboID, const ShaderHeader_t& header, StaticComboRecord_t *pRecords )
+{
+ if ( header.m_nVersion < 5 )
+ return -1;
+
+ return BinarySearchCombos( nStaticComboID, header.m_nNumStaticCombos, pRecords );
+}
+
+// cache redundant i/o fetched components of the vcs files
+struct ShaderFileCache_t
+{
+ CUtlSymbol m_Name;
+ CUtlSymbol m_Filename;
+ ShaderHeader_t m_Header;
+ bool m_bVertexShader;
+
+ // valid for diff version only - contains the microcode used as the reference for diff algorithm
+ CUtlBuffer m_ReferenceCombo;
+
+ // valid for ver5 only - contains the directory
+ CUtlVector< StaticComboRecord_t > m_StaticComboRecords;
+ CUtlVector< StaticComboAliasRecord_t > m_StaticComboDupRecords;
+
+ ShaderFileCache_t()
+ {
+ // invalid until version established
+ m_Header.m_nVersion = 0;
+ }
+
+ bool IsValid() const
+ {
+ return m_Header.m_nVersion != 0;
+ }
+
+ bool IsOldVersion() const
+ {
+ return m_Header.m_nVersion < 5;
+ }
+
+ int IsVersion6() const
+ {
+ return ( m_Header.m_nVersion == 6 );
+ }
+
+ int FindCombo( uint32 nStaticComboID )
+ {
+ int nSearchAliases = BinarySearchCombos( nStaticComboID, m_StaticComboDupRecords.Count(), m_StaticComboDupRecords.Base() );
+ if ( nSearchAliases != -1 )
+ nStaticComboID = m_StaticComboDupRecords[nSearchAliases].m_nSourceStaticCombo;
+ return FindShaderStaticCombo( nStaticComboID, m_Header, m_StaticComboRecords.Base() );
+ }
+
+ bool operator==( const ShaderFileCache_t& a ) const
+ {
+ return m_Name == a.m_Name && m_bVertexShader == a.m_bVertexShader;
+ }
+};
+
+
+//-----------------------------------------------------------------------------
+// Vertex + pixel shader manager
+//-----------------------------------------------------------------------------
+class CShaderManager : public IShaderManager
+{
+public:
+ CShaderManager();
+ virtual ~CShaderManager();
+
+ // Methods of IShaderManager
+ virtual void Init();
+ virtual void Shutdown();
+ virtual IShaderBuffer *CompileShader( const char *pProgram, size_t nBufLen, const char *pShaderVersion );
+ virtual VertexShaderHandle_t CreateVertexShader( IShaderBuffer* pShaderBuffer );
+ virtual void DestroyVertexShader( VertexShaderHandle_t hShader );
+ virtual PixelShaderHandle_t CreatePixelShader( IShaderBuffer* pShaderBuffer );
+ virtual void DestroyPixelShader( PixelShaderHandle_t hShader );
+ virtual VertexShader_t CreateVertexShader( const char *pVertexShaderFile, int nStaticVshIndex = 0, char *debugLabel = NULL );
+ virtual PixelShader_t CreatePixelShader( const char *pPixelShaderFile, int nStaticPshIndex = 0, char *debugLabel = NULL );
+ virtual void SetVertexShader( VertexShader_t shader );
+ virtual void SetPixelShader( PixelShader_t shader );
+ virtual void BindVertexShader( VertexShaderHandle_t shader );
+ virtual void BindPixelShader( PixelShaderHandle_t shader );
+ virtual void *GetCurrentVertexShader();
+ virtual void *GetCurrentPixelShader();
+ virtual void ResetShaderState();
+ void FlushShaders();
+ virtual void ClearVertexAndPixelShaderRefCounts();
+ virtual void PurgeUnusedVertexAndPixelShaders();
+ void SpewVertexAndPixelShaders();
+ const char *GetActiveVertexShaderName();
+ const char *GetActivePixelShaderName();
+ bool CreateDynamicCombos_Ver4( void *pContext, uint8 *pComboBuffer );
+ bool CreateDynamicCombos_Ver5( void *pContext, uint8 *pComboBuffer, char *debugLabel = NULL );
+
+#if defined( DX_TO_GL_ABSTRACTION )
+ virtual void DoStartupShaderPreloading();
+#endif
+
+ static void QueuedLoaderCallback( void *pContext, void *pContext2, const void *pData, int nSize, LoaderError_t loaderError );
+
+private:
+ typedef CUtlFixedLinkedList< IDirect3DVertexShader9* >::IndexType_t VertexShaderIndex_t;
+ typedef CUtlFixedLinkedList< IDirect3DPixelShader9* >::IndexType_t PixelShaderIndex_t;
+
+ struct ShaderStaticCombos_t
+ {
+ int m_nCount;
+
+ // Can't use CUtlVector here since you CUtlLinkedList<CUtlVector<>> doesn't work.
+ HardwareShader_t *m_pHardwareShaders;
+ struct ShaderCreationData_t
+ {
+ CUtlVector<uint8> ByteCode;
+ uint32 iCentroidMask;
+ };
+
+ ShaderCreationData_t *m_pCreationData;
+ };
+
+ struct ShaderLookup_t
+ {
+ CUtlSymbol m_Name;
+ int m_nStaticIndex;
+ ShaderStaticCombos_t m_ShaderStaticCombos;
+ DWORD m_Flags;
+ int m_nRefCount;
+ unsigned int m_hShaderFileCache;
+
+ // for queued loading, bias an aligned optimal buffer forward to correct location
+ int m_nDataOffset;
+
+ // diff version, valid during load only
+ ShaderDictionaryEntry_t *m_pComboDictionary;
+
+ ShaderLookup_t()
+ {
+ m_Flags = 0;
+ m_nRefCount = 0;
+ m_ShaderStaticCombos.m_nCount = 0;
+ m_ShaderStaticCombos.m_pHardwareShaders = 0;
+ m_ShaderStaticCombos.m_pCreationData = 0;
+ m_pComboDictionary = NULL;
+ }
+ void IncRefCount()
+ {
+ m_nRefCount++;
+ }
+ bool operator==( const ShaderLookup_t& a ) const
+ {
+ return m_Name == a.m_Name && m_nStaticIndex == a.m_nStaticIndex;
+ }
+ };
+
+#ifdef DYNAMIC_SHADER_COMPILE
+ struct Combo_t
+ {
+ CUtlSymbol m_ComboName;
+ int m_nMin;
+ int m_nMax;
+ };
+
+ struct ShaderCombos_t
+ {
+ CUtlVector<Combo_t> m_StaticCombos;
+ CUtlVector<Combo_t> m_DynamicCombos;
+ int GetNumDynamicCombos( void ) const
+ {
+ int combos = 1;
+ int i;
+ for( i = 0; i < m_DynamicCombos.Count(); i++ )
+ {
+ combos *= ( m_DynamicCombos[i].m_nMax - m_DynamicCombos[i].m_nMin + 1 );
+ }
+ return combos;
+ }
+ int GetNumStaticCombos( void ) const
+ {
+ int combos = 1;
+ int i;
+ for( i = 0; i < m_StaticCombos.Count(); i++ )
+ {
+ combos *= ( m_StaticCombos[i].m_nMax - m_StaticCombos[i].m_nMin + 1 );
+ }
+ return combos;
+ }
+ };
+#endif
+
+private:
+ void CreateStaticShaders();
+ void DestroyStaticShaders();
+
+#if defined ( DYNAMIC_SHADER_COMPILE ) && defined( REMOTE_DYNAMIC_SHADER_COMPILE )
+ void InitRemoteShaderCompile();
+ void DeinitRemoteShaderCompile();
+#endif
+
+ // The low-level dx call to set the vertex shader state
+ void SetVertexShaderState( HardwareShader_t shader, DataCacheHandle_t hCachedShader = DC_INVALID_HANDLE );
+
+ // The low-level dx call to set the pixel shader state
+ void SetPixelShaderState( HardwareShader_t shader, DataCacheHandle_t hCachedShader = DC_INVALID_HANDLE );
+
+ // Destroys all shaders
+ void DestroyAllShaders();
+
+ // Destroy a particular vertex shader
+ void DestroyVertexShader( VertexShader_t shader );
+ // Destroy a particular pixel shader
+ void DestroyPixelShader( PixelShader_t shader );
+
+ bool LoadAndCreateShaders( ShaderLookup_t &lookup, bool bVertexShader, char *debugLabel = NULL );
+ FileHandle_t OpenFileAndLoadHeader( const char *pFileName, ShaderHeader_t *pHeader );
+
+#ifdef DYNAMIC_SHADER_COMPILE
+ bool LoadAndCreateShaders_Dynamic( ShaderLookup_t &lookup, bool bVertexShader );
+ const ShaderCombos_t *FindOrCreateShaderCombos( const char *pShaderName );
+ HardwareShader_t CompileShader( const char *pShaderName, int nStaticIndex, int nDynamicIndex, bool bVertexShader );
+#endif
+
+ void DisassembleShader( ShaderLookup_t *pLookup, int dynamicCombo, uint8 *pByteCode );
+ void WriteTranslatedFile( ShaderLookup_t *pLookup, int dynamicCombo, char *pFileContents, char *pFileExtension );
+
+ // DX_TO_GL_ABSTRACTION only, no-op otherwise
+
+ void SaveShaderCache( char *cacheName ); // query GLM pair cache for all active shader pairs and write them to disk in named file
+ bool LoadShaderCache( char *cacheName ); // read named file, establish compiled shader sets for each vertex+static and pixel+static, then link pairs as listed in table
+ // return true on success, false if file not found
+
+ // old void WarmShaderCache();
+
+ CUtlFixedLinkedList< ShaderLookup_t > m_VertexShaderDict;
+ CUtlFixedLinkedList< ShaderLookup_t > m_PixelShaderDict;
+
+ CUtlSymbolTable m_ShaderSymbolTable;
+
+#ifdef DYNAMIC_SHADER_COMPILE
+ typedef HRESULT (__stdcall *ShaderCompileFromFileFunc_t)( LPCSTR pSrcFile, CONST D3DXMACRO* pDefines,
+ LPD3DXINCLUDE pInclude, LPCSTR pFunctionName, LPCSTR pProfile, DWORD Flags,
+ LPD3DXBUFFER* ppShader, LPD3DXBUFFER * ppErrorMsgs, LPD3DXCONSTANTTABLE * ppConstantTable );
+ CUtlStringMap<ShaderCombos_t> m_ShaderNameToCombos;
+ CSysModule *m_pShaderCompiler30;
+ ShaderCompileFromFileFunc_t m_ShaderCompileFileFunc30;
+#endif
+
+ // The current vertex and pixel shader
+ HardwareShader_t m_HardwareVertexShader;
+ HardwareShader_t m_HardwarePixelShader;
+
+ CUtlFixedLinkedList< IDirect3DVertexShader9* > m_RawVertexShaderDict;
+ CUtlFixedLinkedList< IDirect3DPixelShader9* > m_RawPixelShaderDict;
+
+ CUtlFixedLinkedList< ShaderFileCache_t > m_ShaderFileCache;
+
+ // false, creates during init.
+ // true, creates on access, helps reduce d3d memory for tools, but causes i/o hitches.
+ bool m_bCreateShadersOnDemand;
+
+#if defined( _DEBUG )
+ // for debugging (can't resolve UtlSym)
+ // need some history because 360 d3d has rips related to sequencing
+ char vshDebugName[MAX_SHADER_HISTORY][64];
+ int vshDebugIndex;
+ char pshDebugName[MAX_SHADER_HISTORY][64];
+ int pshDebugIndex;
+#endif
+
+#if defined ( DYNAMIC_SHADER_COMPILE ) && defined( REMOTE_DYNAMIC_SHADER_COMPILE )
+ SOCKET m_RemoteShaderCompileSocket;
+#endif
+
+};
+
+
+//-----------------------------------------------------------------------------
+// Singleton accessor
+//-----------------------------------------------------------------------------
+static CShaderManager s_ShaderManager;
+IShaderManager *g_pShaderManager = &s_ShaderManager;
+
+//-----------------------------------------------------------------------------
+// Constructor, destructor
+//-----------------------------------------------------------------------------
+CShaderManager::CShaderManager() :
+ m_ShaderSymbolTable( 0, 32, true /* caseInsensitive */ ),
+ m_VertexShaderDict( 32 ),
+ m_PixelShaderDict( 32 ),
+ m_ShaderFileCache( 32 )
+{
+ m_bCreateShadersOnDemand = false;
+
+#ifdef DYNAMIC_SHADER_COMPILE
+ m_pShaderCompiler30 = 0;
+ m_ShaderCompileFileFunc30 = 0;
+#ifdef REMOTE_DYNAMIC_SHADER_COMPILE
+ m_RemoteShaderCompileSocket = INVALID_SOCKET;
+#endif
+#endif
+
+#ifdef _DEBUG
+ vshDebugIndex = 0;
+ pshDebugIndex = 0;
+#endif
+}
+
+CShaderManager::~CShaderManager()
+{
+#if defined ( DYNAMIC_SHADER_COMPILE ) && defined( REMOTE_DYNAMIC_SHADER_COMPILE )
+ DeinitRemoteShaderCompile();
+#endif
+}
+
+#define REMOTE_SHADER_COMPILE_PORT "20000"
+
+#if defined ( DYNAMIC_SHADER_COMPILE ) && defined( REMOTE_DYNAMIC_SHADER_COMPILE )
+void CShaderManager::InitRemoteShaderCompile()
+{
+ DeinitRemoteShaderCompile();
+
+ int nResult = 0;
+ #ifdef _WIN32
+ WSADATA wsaData;
+ nResult = WSAStartup( 0x101, &wsaData );
+ if ( nResult != 0 )
+ {
+ Warning( "CShaderManager::Init - Could not init socket for remote dynamic shader compilation\n" );
+ }
+ #endif
+
+ struct addrinfo hints;
+ ZeroMemory( &hints, sizeof(hints) );
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ // Resolve the server address and port
+ struct addrinfo *result = NULL;
+ nResult = getaddrinfo( mat_remoteshadercompile.GetString(), REMOTE_SHADER_COMPILE_PORT, &hints, &result );
+ if ( nResult != 0 )
+ {
+ Warning( "getaddrinfo failed: %d\n", nResult );
+ #ifdef _WIN32
+ WSACleanup();
+ #endif
+ Assert( 0 );
+ }
+
+ // Attempt to connect to an address until one succeeds
+ for( struct addrinfo *ptr = result; ptr != NULL; ptr = ptr->ai_next )
+ {
+ // Create a SOCKET for connecting to remote shader compilation server
+ m_RemoteShaderCompileSocket = socket( ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol );
+ if ( m_RemoteShaderCompileSocket == INVALID_SOCKET )
+ {
+ Warning( "Error at socket(): %ld\n", WSAGetLastError() );
+ freeaddrinfo( result );
+ #ifdef _WIN32
+ WSACleanup();
+ #endif
+ Assert( 0 );
+ continue;
+ }
+
+ // Connect to server.
+ nResult = connect( m_RemoteShaderCompileSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
+ if ( nResult == SOCKET_ERROR )
+ {
+ closesocket( m_RemoteShaderCompileSocket );
+ m_RemoteShaderCompileSocket = INVALID_SOCKET;
+ continue;
+ }
+ break;
+ }
+
+ freeaddrinfo( result );
+
+ if ( m_RemoteShaderCompileSocket == INVALID_SOCKET )
+ {
+ Warning( "Unable to connect to remote shader compilation server!\n" );
+ #ifdef _WIN32
+ WSACleanup();
+ #endif
+ Assert ( 0 );
+ }
+}
+
+void CShaderManager::DeinitRemoteShaderCompile()
+{
+ if ( m_RemoteShaderCompileSocket != INVALID_SOCKET )
+ {
+ if ( shutdown( m_RemoteShaderCompileSocket, SD_SEND ) == SOCKET_ERROR )
+ {
+ Warning( "Remote shader compilation shutdown failed: %d\n", WSAGetLastError() );
+ }
+ closesocket( m_RemoteShaderCompileSocket );
+ m_RemoteShaderCompileSocket = INVALID_SOCKET;
+ }
+}
+#endif // defined ( DYNAMIC_SHADER_COMPILE ) && defined( REMOTE_DYNAMIC_SHADER_COMPILE )
+
+//-----------------------------------------------------------------------------
+// Initialization, shutdown
+//-----------------------------------------------------------------------------
+void CShaderManager::Init()
+{
+ // incompatible with the 360, violates loading system
+ // only used by PC to help tools reduce d3d footprint
+ m_bCreateShadersOnDemand = IsPC() && ( ShaderUtil()->InEditorMode() || CommandLine()->CheckParm( "-shadersondemand" ) );
+
+#ifdef DYNAMIC_SHADER_COMPILE
+ if( !IsX360() )
+ {
+
+#ifdef REMOTE_DYNAMIC_SHADER_COMPILE
+ InitRemoteShaderCompile();
+#else // REMOTE_DYNAMIC_SHADER_COMPILE
+
+#ifdef _DEBUG
+ m_pShaderCompiler30 = Sys_LoadModule( "d3dx9d_33.dll" );
+#endif
+ if (!m_pShaderCompiler30)
+ {
+ m_pShaderCompiler30 = Sys_LoadModule( "d3dx9_33.dll" );
+ }
+
+ if ( m_pShaderCompiler30 )
+ {
+ m_ShaderCompileFileFunc30 = (ShaderCompileFromFileFunc_t)GetProcAddress( (HMODULE)m_pShaderCompiler30, "D3DXCompileShaderFromFileA" );
+ }
+
+#endif
+
+ }
+#endif // DYNAMIC_SHADER_COMPILE
+
+ CreateStaticShaders();
+}
+
+void CShaderManager::Shutdown()
+{
+#ifdef DYNAMIC_SHADER_COMPILE
+ if ( m_pShaderCompiler30 )
+ {
+ Sys_UnloadModule( m_pShaderCompiler30 );
+ m_pShaderCompiler30 = 0;
+ m_ShaderCompileFileFunc30 = 0;
+ }
+#endif
+
+#ifdef DX_TO_GL_ABSTRACTION
+ if (mat_autosave_glshaders.GetInt())
+ {
+ SaveShaderCache("glshaders.cfg");
+ }
+#endif
+
+ DestroyAllShaders();
+ DestroyStaticShaders();
+}
+
+
+//-----------------------------------------------------------------------------
+// Compiles shaders
+//-----------------------------------------------------------------------------
+IShaderBuffer *CShaderManager::CompileShader( const char *pProgram, size_t nBufLen, const char *pShaderVersion )
+{
+ int nCompileFlags = D3DXSHADER_AVOID_FLOW_CONTROL;
+
+#ifdef _DEBUG
+ nCompileFlags |= D3DXSHADER_DEBUG;
+#endif
+
+ LPD3DXBUFFER pCompiledShader, pErrorMessages;
+ HRESULT hr = D3DXCompileShader( pProgram, nBufLen,
+ NULL, NULL, "main", pShaderVersion, nCompileFlags,
+ &pCompiledShader, &pErrorMessages, NULL );
+
+ if ( FAILED( hr ) )
+ {
+ if ( pErrorMessages )
+ {
+ const char *pErrorMessage = (const char *)pErrorMessages->GetBufferPointer();
+ Warning( "Shader compilation failed! Reported the following errors:\n%s\n", pErrorMessage );
+ pErrorMessages->Release();
+ }
+ return NULL;
+ }
+
+ // NOTE: This uses small block heap allocator; so I'm not going
+ // to bother creating a memory pool.
+ CShaderBuffer< ID3DXBuffer > *pShaderBuffer = new CShaderBuffer< ID3DXBuffer >( pCompiledShader );
+ if ( pErrorMessages )
+ {
+ pErrorMessages->Release();
+ }
+
+ return pShaderBuffer;
+}
+
+
+VertexShaderHandle_t CShaderManager::CreateVertexShader( IShaderBuffer* pShaderBuffer )
+{
+ // Create the vertex shader
+ IDirect3DVertexShader9 *pVertexShader = NULL;
+
+#if defined(_X360) || !defined(DX_TO_GL_ABSTRACTION)
+ HRESULT hr = Dx9Device()->CreateVertexShader( (const DWORD*)pShaderBuffer->GetBits(), &pVertexShader );
+#else
+ HRESULT hr = Dx9Device()->CreateVertexShader( (const DWORD*)pShaderBuffer->GetBits(), &pVertexShader, NULL );
+#endif
+
+ if ( FAILED( hr ) || !pVertexShader )
+ return VERTEX_SHADER_HANDLE_INVALID;
+
+ s_NumVertexShadersCreated++;
+ RegisterVS( pShaderBuffer->GetBits(), pShaderBuffer->GetSize(), pVertexShader );
+
+ // Insert the shader into the dictionary of shaders
+ VertexShaderIndex_t i = m_RawVertexShaderDict.AddToTail( pVertexShader );
+ return (VertexShaderHandle_t)i;
+}
+
+void CShaderManager::DestroyVertexShader( VertexShaderHandle_t hShader )
+{
+ if ( hShader == VERTEX_SHADER_HANDLE_INVALID )
+ return;
+
+ VertexShaderIndex_t i = (VertexShaderIndex_t)hShader;
+ IDirect3DVertexShader9 *pVertexShader = m_RawVertexShaderDict[ i ];
+
+ UnregisterVS( pVertexShader );
+
+ VerifyEquals( (int)pVertexShader->Release(), 0 );
+ m_RawVertexShaderDict.Remove( i );
+}
+
+PixelShaderHandle_t CShaderManager::CreatePixelShader( IShaderBuffer* pShaderBuffer )
+{
+ // Create the vertex shader
+ IDirect3DPixelShader9 *pPixelShader = NULL;
+#if defined(_X360) || !defined(DX_TO_GL_ABSTRACTION)
+ HRESULT hr = Dx9Device()->CreatePixelShader( (const DWORD*)pShaderBuffer->GetBits(), &pPixelShader );
+#else
+ HRESULT hr = Dx9Device()->CreatePixelShader( (const DWORD*)pShaderBuffer->GetBits(), &pPixelShader, NULL );
+#endif
+
+ if ( FAILED( hr ) || !pPixelShader )
+ return PIXEL_SHADER_HANDLE_INVALID;
+
+ s_NumPixelShadersCreated++;
+
+ RegisterPS( pShaderBuffer->GetBits(), pShaderBuffer->GetSize(), pPixelShader );
+
+ // Insert the shader into the dictionary of shaders
+ PixelShaderIndex_t i = m_RawPixelShaderDict.AddToTail( pPixelShader );
+ return (PixelShaderHandle_t)i;
+}
+
+void CShaderManager::DestroyPixelShader( PixelShaderHandle_t hShader )
+{
+ if ( hShader == PIXEL_SHADER_HANDLE_INVALID )
+ return;
+
+ PixelShaderIndex_t i = (PixelShaderIndex_t)hShader;
+ IDirect3DPixelShader9 *pPixelShader = m_RawPixelShaderDict[ i ];
+
+ UnregisterPS( pPixelShader );
+
+ VerifyEquals( (int)pPixelShader->Release(), 0 );
+ m_RawPixelShaderDict.Remove( i );
+}
+
+
+//-----------------------------------------------------------------------------
+// Globals
+//-----------------------------------------------------------------------------
+HardwareShader_t s_pIllegalMaterialPS = INVALID_HARDWARE_SHADER;
+
+//-----------------------------------------------------------------------------
+// Static methods
+//-----------------------------------------------------------------------------
+void CShaderManager::CreateStaticShaders()
+{
+ MEM_ALLOC_D3D_CREDIT();
+
+ if ( !HardwareConfig()->SupportsVertexAndPixelShaders() )
+ {
+ return;
+ }
+
+ if ( IsPC() )
+ {
+ // GR - hack for illegal materials
+ const DWORD psIllegalMaterial[] =
+ {
+ #ifdef DX_TO_GL_ABSTRACTION
+ // Use a PS 2.0 binary shader on DX_TO_GL_ABSTRACTION
+ 0xffff0200, 0x05000051, 0xa00f0000, 0x3f800000,
+ 0x00000000, 0x3f800000, 0x3f800000, 0x02000001,
+ 0x800f0000, 0xa0e40000, 0x02000001, 0x800f0800,
+ 0x80e40000, 0x0000ffff
+ #else
+ 0xffff0101, 0x00000051, 0xa00f0000, 0x00000000, 0x3f800000, 0x00000000,
+ 0x3f800000, 0x00000001, 0x800f0000, 0xa0e40000, 0x0000ffff
+ #endif
+ };
+ // create default shader
+#if defined(_X360) || !defined(DX_TO_GL_ABSTRACTION)
+ Dx9Device()->CreatePixelShader( psIllegalMaterial, ( IDirect3DPixelShader9 ** )&s_pIllegalMaterialPS );
+#else
+ Dx9Device()->CreatePixelShader( psIllegalMaterial, ( IDirect3DPixelShader9 ** )&s_pIllegalMaterialPS, NULL );
+#endif
+ }
+}
+
+void CShaderManager::DestroyStaticShaders()
+{
+ // GR - invalid material hack
+ // destroy internal shader
+ if ( s_pIllegalMaterialPS != INVALID_HARDWARE_SHADER )
+ {
+ ( ( IDirect3DPixelShader9 * )s_pIllegalMaterialPS )->Release();
+ s_pIllegalMaterialPS = INVALID_HARDWARE_SHADER;
+ }
+}
+
+#ifdef DYNAMIC_SHADER_COMPILE
+static const char *GetShaderSourcePath( void )
+{
+ static char shaderDir[MAX_PATH];
+ // GR - just in case init this...
+ static bool bHaveShaderDir = false;
+ if( !bHaveShaderDir )
+ {
+ bHaveShaderDir = true;
+# if ( defined( DYNAMIC_SHADER_COMPILE_CUSTOM_PATH ) )
+ {
+ Q_strncpy( shaderDir, DYNAMIC_SHADER_COMPILE_CUSTOM_PATH, MAX_PATH );
+ }
+# else
+ {
+# if ( defined( _X360 ) )
+ {
+ char hostName[128] = "";
+ const char *pHostName = CommandLine()->ParmValue( "-host" );
+ if ( !pHostName )
+ {
+ // the 360 machine name must be <HostPC>_360
+ DWORD length = sizeof( hostName );
+ DmGetXboxName( hostName, &length );
+ char *p = strstr( hostName, "_360" );
+ *p = '\0';
+ pHostName = hostName;
+ }
+
+ Q_snprintf( shaderDir, MAX_PATH, "net:\\smb\\%s\\stdshaders", pHostName );
+ }
+# else
+ {
+ Q_strncpy( shaderDir, __FILE__, MAX_PATH );
+ Q_StripFilename( shaderDir );
+ Q_StripLastDir( shaderDir, MAX_PATH );
+ Q_strncat( shaderDir, "stdshaders", MAX_PATH, COPY_ALL_CHARACTERS );
+ }
+# endif
+ }
+# endif
+ }
+ return shaderDir;
+}
+#endif
+
+#ifdef DYNAMIC_SHADER_COMPILE
+const CShaderManager::ShaderCombos_t *CShaderManager::FindOrCreateShaderCombos( const char *pShaderName )
+{
+ if( m_ShaderNameToCombos.Defined( pShaderName ) )
+ {
+ return &m_ShaderNameToCombos[pShaderName];
+ }
+ ShaderCombos_t &combos = m_ShaderNameToCombos[pShaderName];
+ char filename[MAX_PATH];
+ // try the vsh dir first.
+ Q_strncpy( filename, GetShaderSourcePath(), MAX_PATH );
+ Q_strncat( filename, "\\", MAX_PATH, COPY_ALL_CHARACTERS );
+ Q_strncat( filename, pShaderName, MAX_PATH, COPY_ALL_CHARACTERS );
+ Q_strncat( filename, ".vsh", MAX_PATH, COPY_ALL_CHARACTERS );
+ CUtlInplaceBuffer bffr( 0, 0, CUtlInplaceBuffer::TEXT_BUFFER );
+
+ bool bOpenResult = g_pFullFileSystem->ReadFile( filename, NULL, bffr );
+
+ if ( bOpenResult )
+ {
+ NULL;
+ }
+ else
+ {
+ // try the fxc dir.
+ Q_strncpy( filename, GetShaderSourcePath(), MAX_PATH );
+ Q_strncat( filename, "\\", MAX_PATH, COPY_ALL_CHARACTERS );
+ Q_strncat( filename, pShaderName, MAX_PATH, COPY_ALL_CHARACTERS );
+ Q_strncat( filename, ".fxc", MAX_PATH, COPY_ALL_CHARACTERS );
+ bOpenResult = g_pFullFileSystem->ReadFile( filename, NULL, bffr );
+
+ if ( !bOpenResult )
+ {
+ // Maybe this is a specific version [20 & 20b] -> [2x]
+ if ( Q_strlen( pShaderName ) >= 3 )
+ {
+ char *pszEndFilename = filename + strlen( filename );
+ if ( !Q_stricmp( pszEndFilename - 6, "30.fxc" ) )
+ {
+ // Total hack. Who knows what builds that 30 shader?
+ strcpy( pszEndFilename - 6, "20b.fxc" );
+ bOpenResult = g_pFullFileSystem->ReadFile( filename, NULL, bffr );
+ if ( !bOpenResult )
+ {
+ strcpy( pszEndFilename - 6, "2x.fxc" );
+ bOpenResult = g_pFullFileSystem->ReadFile( filename, NULL, bffr );
+ }
+ if ( !bOpenResult )
+ {
+ strcpy( pszEndFilename - 6, "20.fxc" );
+ bOpenResult = g_pFullFileSystem->ReadFile( filename, NULL, bffr );
+ }
+ }
+ else
+ {
+ if ( !stricmp( pszEndFilename - 6, "20.fxc" ) )
+ {
+ pszEndFilename[ -5 ] = 'x';
+ }
+ else if ( !stricmp( pszEndFilename - 7, "20b.fxc" ) )
+ {
+ strcpy( pszEndFilename - 7, "2x.fxc" );
+ --pszEndFilename;
+ }
+ else if ( !stricmp( pszEndFilename - 6, "11.fxc" ) )
+ {
+ strcpy( pszEndFilename - 6, "xx.fxc" );
+ }
+
+ bOpenResult = g_pFullFileSystem->ReadFile( filename, NULL, bffr );
+ if ( !bOpenResult )
+ {
+ if ( !stricmp( pszEndFilename - 6, "2x.fxc" ) )
+ {
+ pszEndFilename[ -6 ] = 'x';
+ bOpenResult = g_pFullFileSystem->ReadFile( filename, NULL, bffr );
+ }
+ }
+ }
+ }
+ }
+
+ if ( !bOpenResult )
+ {
+ Assert( 0 );
+ return NULL;
+ }
+ }
+
+ while( char *line = bffr.InplaceGetLinePtr() )
+ {
+ // dear god perl is better at this kind of shit!
+ int begin = 0;
+ int end = 0;
+
+ // check if the line starts with '//'
+ if( line[0] != '/' || line[1] != '/' )
+ {
+ continue;
+ }
+
+ // Check if line intended for platform lines
+ if( IsX360() )
+ {
+ if ( Q_stristr( line, "[PC]" ) )
+ continue;
+ }
+ else
+ {
+ if ( Q_stristr( line, "[360]" ) || Q_stristr( line, "[XBOX]" ) )
+ continue;
+ }
+
+ // Skip any lines intended for other shader version
+ if ( Q_stristr( pShaderName, "_ps20" ) && !Q_stristr( pShaderName, "_ps20b" ) &&
+ Q_stristr( line, "[ps" ) && !Q_stristr( line, "[ps20]" ) )
+ continue;
+ if ( Q_stristr( pShaderName, "_ps20b" ) &&
+ Q_stristr( line, "[ps" ) && !Q_stristr( line, "[ps20b]" ) )
+ continue;
+ if ( Q_stristr( pShaderName, "_ps30" ) &&
+ Q_stristr( line, "[ps" ) && !Q_stristr( line, "[ps30]" ) )
+ continue;
+ if ( Q_stristr( pShaderName, "_vs20" ) &&
+ Q_stristr( line, "[vs" ) && !Q_stristr( line, "[vs20]" ) )
+ continue;
+ if ( Q_stristr( pShaderName, "_vs30" ) &&
+ Q_stristr( line, "[vs" ) && !Q_stristr( line, "[vs30]" ) )
+ continue;
+
+ char *pScan = &line[2];
+ while( *pScan == ' ' || *pScan == '\t' )
+ {
+ pScan++;
+ }
+
+ bool bDynamic;
+ if( Q_strncmp( pScan, "DYNAMIC", 7 ) == 0 )
+ {
+ bDynamic = true;
+ pScan += 7;
+ }
+ else if( Q_strncmp( pScan, "STATIC", 6 ) == 0 )
+ {
+ bDynamic = false;
+ pScan += 6;
+ }
+ else
+ {
+ continue;
+ }
+
+ // skip whitespace
+ while( *pScan == ' ' || *pScan == '\t' )
+ {
+ pScan++;
+ }
+
+ // check for colon
+ if( *pScan != ':' )
+ {
+ continue;
+ }
+ pScan++;
+
+ // skip whitespace
+ while( *pScan == ' ' || *pScan == '\t' )
+ {
+ pScan++;
+ }
+
+ // check for quote
+ if( *pScan != '\"' )
+ {
+ continue;
+ }
+ pScan++;
+
+ char *pBeginningOfName = pScan;
+ while( 1 )
+ {
+ if( *pScan == '\0' )
+ {
+ break;
+ }
+ if( *pScan == '\"' )
+ {
+ break;
+ }
+ pScan++;
+ }
+
+ if( *pScan == '\0' )
+ {
+ continue;
+ }
+
+ // must have hit a quote. .done with string.
+ // slam a NULL at the end quote of the string so that we have the string at pBeginningOfName.
+ *pScan = '\0';
+ pScan++;
+
+ // skip whitespace
+ while( *pScan == ' ' || *pScan == '\t' )
+ {
+ pScan++;
+ }
+
+ // check for quote
+ if( *pScan != '\"' )
+ {
+ continue;
+ }
+ pScan++;
+
+ // make sure that we have a number after the quote.
+ if( !isdigit( *pScan ) )
+ {
+ continue;
+ }
+
+ while( isdigit( *pScan ) )
+ {
+ begin = begin * 10 + ( *pScan - '0' );
+ pScan++;
+ }
+
+ if( pScan[0] != '.' || pScan[1] != '.' )
+ {
+ continue;
+ }
+ pScan += 2;
+
+ // make sure that we have a number
+ if( !isdigit( *pScan ) )
+ {
+ continue;
+ }
+
+ while( isdigit( *pScan ) )
+ {
+ end = end * 10 + ( *pScan - '0' );
+ pScan++;
+ }
+
+ if( pScan[0] != '\"' )
+ {
+ continue;
+ }
+
+ // sweet freaking jesus. .done parsing the line.
+// char buf[1024];
+// sprintf( buf, "\"%s\" \"%s\" %d %d\n", bDynamic ? "DYNAMIC" : "STATIC", pBeginningOfName, begin, end );
+// Plat_DebugString( buf );
+
+ Combo_t *pCombo = NULL;
+ if( bDynamic )
+ {
+ pCombo = &combos.m_DynamicCombos[combos.m_DynamicCombos.AddToTail()];
+ }
+ else
+ {
+ pCombo = &combos.m_StaticCombos[combos.m_StaticCombos.AddToTail()];
+ }
+
+ pCombo->m_ComboName = m_ShaderSymbolTable.AddString( pBeginningOfName );
+ pCombo->m_nMin = begin;
+ pCombo->m_nMax = end;
+ }
+
+ return &combos;
+}
+#endif // DYNAMIC_SHADER_COMPILE
+
+#ifdef DYNAMIC_SHADER_COMPILE
+#ifndef DX_TO_GL_ABSTRACTION
+//-----------------------------------------------------------------------------
+// Used to deal with include files
+//-----------------------------------------------------------------------------
+class CDxInclude : public ID3DXInclude
+{
+public:
+ CDxInclude( const char *pMainFileName );
+
+#if defined( _X360 )
+ virtual HRESULT WINAPI Open( D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID * ppData, UINT * pBytes, LPSTR pFullPath, DWORD cbFullPath );
+#else
+ STDMETHOD(Open)(THIS_ D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID *ppData, UINT *pBytes);
+#endif
+
+ STDMETHOD(Close)(THIS_ LPCVOID pData);
+
+private:
+ char m_pBasePath[MAX_PATH];
+
+#if defined( _X360 )
+ char m_pFullPath[MAX_PATH];
+#endif
+};
+
+CDxInclude::CDxInclude( const char *pMainFileName )
+{
+ Q_ExtractFilePath( pMainFileName, m_pBasePath, sizeof(m_pBasePath) );
+}
+
+
+#if defined( _X360 )
+HRESULT CDxInclude::Open( D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID * ppData, UINT * pBytes, LPSTR pFullPath, DWORD cbFullPath )
+#else
+HRESULT CDxInclude::Open( D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID * ppData, UINT * pBytes )
+#endif
+{
+ char pTemp[MAX_PATH];
+ if ( !Q_IsAbsolutePath( pFileName ) && ( IncludeType == D3DXINC_LOCAL ) )
+ {
+ Q_ComposeFileName( m_pBasePath, pFileName, pTemp, sizeof(pTemp) );
+ pFileName = pTemp;
+ }
+
+ CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
+ if ( !g_pFullFileSystem->ReadFile( pFileName, NULL, buf ) )
+ return E_FAIL;
+
+ *pBytes = buf.TellMaxPut();
+ void *pMem = malloc( *pBytes );
+ memcpy( pMem, buf.Base(), *pBytes );
+ *ppData = pMem;
+
+# if ( defined( _X360 ) )
+ {
+ Q_ComposeFileName( m_pBasePath, pFileName, m_pFullPath, sizeof(m_pFullPath) );
+ pFullPath = m_pFullPath;
+ cbFullPath = MAX_PATH;
+ }
+# endif
+
+ return S_OK;
+}
+
+HRESULT CDxInclude::Close( LPCVOID pData )
+{
+ void *pMem = const_cast<void*>( pData );
+ free( pMem );
+ return S_OK;
+}
+#endif // not DX_TO_GL_ABSTRACTION
+
+static const char *FileNameToShaderModel( const char *pShaderName, bool bVertexShader )
+{
+ // Figure out the shader model
+ const char *pShaderModel = NULL;
+ if( bVertexShader )
+ {
+ if( Q_stristr( pShaderName, "vs20" ) )
+ {
+ pShaderModel = "vs_2_0";
+ bVertexShader = true;
+ }
+ else if( Q_stristr( pShaderName, "vs11" ) )
+ {
+ pShaderModel = "vs_1_1";
+ bVertexShader = true;
+ }
+ else if( Q_stristr( pShaderName, "vs14" ) )
+ {
+ pShaderModel = "vs_1_1";
+ bVertexShader = true;
+ }
+ else if( Q_stristr( pShaderName, "vs30" ) )
+ {
+ pShaderModel = "vs_3_0";
+ bVertexShader = true;
+ }
+ else
+ {
+#ifdef _DEBUG
+ Error( "Failed dynamic shader compiled\nBuild shaderapidx9.dll in debug to find problem\n" );
+#else
+ Assert( 0 );
+#endif
+ }
+ }
+ else
+ {
+ if( Q_stristr( pShaderName, "ps20b" ) )
+ {
+ pShaderModel = "ps_2_b";
+ }
+ else if( Q_stristr( pShaderName, "ps20" ) )
+ {
+ pShaderModel = "ps_2_0";
+ }
+ else if( Q_stristr( pShaderName, "ps11" ) )
+ {
+ pShaderModel = "ps_1_1";
+ }
+ else if( Q_stristr( pShaderName, "ps14" ) )
+ {
+ pShaderModel = "ps_1_4";
+ }
+ else if( Q_stristr( pShaderName, "ps30" ) )
+ {
+ pShaderModel = "ps_3_0";
+ }
+ else
+ {
+#ifdef _DEBUG
+ Error( "Failed dynamic shader compiled\nBuild shaderapidx9.dll in debug to find problem\n" );
+#else
+ Assert( 0 );
+#endif
+ }
+ }
+ return pShaderModel;
+}
+#endif
+
+#ifdef DYNAMIC_SHADER_COMPILE
+
+#if defined( _X360 )
+static ConVar mat_flushshaders_generate_updbs( "mat_flushshaders_generate_updbs", "0", 0, "Generates UPDBs whenever you flush shaders." );
+#endif
+
+HardwareShader_t CShaderManager::CompileShader( const char *pShaderName,
+ int nStaticIndex, int nDynamicIndex, bool bVertexShader )
+{
+ VPROF_BUDGET( "CompileShader", "CompileShader" );
+ Assert( m_ShaderNameToCombos.Defined( pShaderName ) );
+ if( !m_ShaderNameToCombos.Defined( pShaderName ) )
+ {
+ return INVALID_HARDWARE_SHADER;
+ }
+ const ShaderCombos_t &combos = m_ShaderNameToCombos[pShaderName];
+#ifdef _DEBUG
+ int numStaticCombos = combos.GetNumStaticCombos();
+ int numDynamicCombos = combos.GetNumDynamicCombos();
+#endif
+ Assert( nStaticIndex % numDynamicCombos == 0 );
+ Assert( ( nStaticIndex % numDynamicCombos ) >= 0 && ( nStaticIndex % numDynamicCombos ) < numStaticCombos );
+ Assert( nDynamicIndex >= 0 && nDynamicIndex < numDynamicCombos );
+
+# ifdef DYNAMIC_SHADER_COMPILE_VERBOSE
+
+ //Warning( "Compiling %s %s\n\tdynamic:", bVertexShader ? "vsh" : "psh", pShaderName );
+ Warning( "Compiling " );
+ if ( bVertexShader )
+ ConColorMsg( Color( 0, 255, 0, 255 ), "vsh - %s ", pShaderName );
+ else
+ ConColorMsg( Color( 0, 255, 255, 255 ), "psh - %s ", pShaderName );
+ Warning( "\n\tdynamic:" );
+
+# endif
+
+ CUtlVector<D3DXMACRO> macros;
+ // plus 1 for null termination, plus 1 for #define SHADER_MODEL_*, and plus 1 for #define _X360 on 360
+ macros.SetCount( combos.m_DynamicCombos.Count() + combos.m_StaticCombos.Count() + 2 + ( IsX360() ? 1 : 0 ) );
+
+ int nCombo = nStaticIndex + nDynamicIndex;
+ int macroIndex = 0;
+ int i;
+ for( i = 0; i < combos.m_DynamicCombos.Count(); i++ )
+ {
+ int countForCombo = combos.m_DynamicCombos[i].m_nMax - combos.m_DynamicCombos[i].m_nMin + 1;
+ int val = nCombo % countForCombo + combos.m_DynamicCombos[i].m_nMin;
+ nCombo /= countForCombo;
+ macros[macroIndex].Name = m_ShaderSymbolTable.String( combos.m_DynamicCombos[i].m_ComboName );
+ char buf[16];
+ sprintf( buf, "%d", val );
+ CUtlSymbol valSymbol( buf );
+ macros[macroIndex].Definition = valSymbol.String();
+# ifdef DYNAMIC_SHADER_COMPILE_VERBOSE
+ Warning( " %s=%s", macros[macroIndex].Name, macros[macroIndex].Definition );
+# endif
+ macroIndex++;
+ }
+
+# ifdef DYNAMIC_SHADER_COMPILE_VERBOSE
+ Warning( "\n\tstatic:" );
+# endif
+ for( i = 0; i < combos.m_StaticCombos.Count(); i++ )
+ {
+ int countForCombo = combos.m_StaticCombos[i].m_nMax - combos.m_StaticCombos[i].m_nMin + 1;
+ int val = nCombo % countForCombo + combos.m_StaticCombos[i].m_nMin;
+ nCombo /= countForCombo;
+ macros[macroIndex].Name = m_ShaderSymbolTable.String( combos.m_StaticCombos[i].m_ComboName );
+ char buf[16];
+ sprintf( buf, "%d", val );
+ CUtlSymbol valSymbol( buf );
+ macros[macroIndex].Definition = valSymbol.String();
+# ifdef DYNAMIC_SHADER_COMPILE_VERBOSE
+ Warning( " %s=%s", macros[macroIndex].Name, macros[macroIndex].Definition );
+# endif
+ macroIndex++;
+ }
+
+# ifdef DYNAMIC_SHADER_COMPILE_VERBOSE
+ Warning( "\n" );
+# endif
+
+ char filename[MAX_PATH];
+ Q_strncpy( filename, GetShaderSourcePath(), MAX_PATH );
+ Q_strncat( filename, "\\", MAX_PATH, COPY_ALL_CHARACTERS );
+ Q_strncat( filename, pShaderName, MAX_PATH, COPY_ALL_CHARACTERS );
+ Q_strncat( filename, ".fxc", MAX_PATH, COPY_ALL_CHARACTERS );
+
+ const char *pShaderModel = FileNameToShaderModel( pShaderName, bVertexShader );
+
+ // define the shader model
+ char shaderModelDefineString[1024];
+ Q_snprintf( shaderModelDefineString, 1024, "SHADER_MODEL_%s", pShaderModel );
+ Q_strupr( shaderModelDefineString );
+ macros[macroIndex].Name = shaderModelDefineString;
+ macros[macroIndex].Definition = "1";
+ macroIndex++;
+
+ char x360DefineString[1024];
+ if( IsX360() )
+ {
+ Q_snprintf( x360DefineString, 1024, "_X360", pShaderModel );
+ Q_strupr( x360DefineString );
+ macros[macroIndex].Name = x360DefineString;
+ macros[macroIndex].Definition = "1";
+ macroIndex++;
+ }
+
+ // NULL terminate.
+ macros[macroIndex].Name = NULL;
+ macros[macroIndex].Definition = NULL;
+
+ // Instead of erroring out, infinite-loop on shader compilation
+ // (i.e. give developers a chance to fix the shader code w/out restarting the game)
+#ifndef _DEBUG
+ int retriesLeft = 20;
+retry_compile:
+#endif
+
+ // Try and open the file to see if it exists
+ FileHandle_t fp = g_pFullFileSystem->Open( filename, "r" );
+
+ if ( fp == FILESYSTEM_INVALID_HANDLE )
+ {
+ // Maybe this is a specific version [20 & 20b] -> [2x]
+ if ( strlen( pShaderName ) >= 3 )
+ {
+ char *pszEndFilename = filename + strlen( filename );
+ if ( !Q_stricmp( pszEndFilename - 6, "30.fxc" ) )
+ {
+ strcpy( pszEndFilename - 6, "20b.fxc" );
+ fp = g_pFullFileSystem->Open( filename, "r" );
+ if ( fp == FILESYSTEM_INVALID_HANDLE )
+ {
+ strcpy( pszEndFilename - 6, "2x.fxc" );
+ fp = g_pFullFileSystem->Open( filename, "r" );
+ }
+ if ( fp == FILESYSTEM_INVALID_HANDLE )
+ {
+ strcpy( pszEndFilename - 6, "20.fxc" );
+ fp = g_pFullFileSystem->Open( filename, "r" );
+ }
+ }
+ else
+ {
+ if ( !Q_stricmp( pszEndFilename - 6, "20.fxc" ) )
+ {
+ pszEndFilename[ -5 ] = 'x';
+ fp = g_pFullFileSystem->Open( filename, "r" );
+ }
+ else if ( !Q_stricmp( pszEndFilename - 7, "20b.fxc" ) )
+ {
+ strcpy( pszEndFilename - 7, "2x.fxc" );
+ fp = g_pFullFileSystem->Open( filename, "r" );
+ }
+ else if ( !stricmp( pszEndFilename - 6, "11.fxc" ) )
+ {
+ strcpy( pszEndFilename - 6, "xx.fxc" );
+ fp = g_pFullFileSystem->Open( filename, "r" );
+ }
+
+ if ( fp == FILESYSTEM_INVALID_HANDLE )
+ {
+ if ( !stricmp( pszEndFilename - 6, "2x.fxc" ) )
+ {
+ pszEndFilename[ -6 ] = 'x';
+ fp = g_pFullFileSystem->Open( filename, "r" );
+ }
+ }
+ }
+ }
+ }
+
+ if ( fp != FILESYSTEM_INVALID_HANDLE )
+ {
+ g_pFullFileSystem->Close( fp );
+ }
+
+#ifdef REMOTE_DYNAMIC_SHADER_COMPILE
+ #define SEND_BUF_SIZE 40000
+ #define RECV_BUF_SIZE 40000
+
+ // Remotely-compiled shader code
+ uint32 *pRemotelyCompiledShader = NULL;
+ uint32 nRemotelyCompiledShaderLength = 0;
+
+ if ( m_RemoteShaderCompileSocket == INVALID_SOCKET )
+ {
+ InitRemoteShaderCompile();
+ }
+
+ // In this case, we're going to use a remote service to do our compiling
+ if ( m_RemoteShaderCompileSocket != INVALID_SOCKET )
+ {
+ // Build up command list for remote shader compiler
+ char pSendbuf[SEND_BUF_SIZE], pRecvbuf[RECV_BUF_SIZE], pFixedFilename[MAX_PATH], buf[MAX_PATH];
+ V_FixupPathName( pFixedFilename, MAX_PATH, filename );
+ V_FileBase( pFixedFilename, buf, MAX_PATH ); // Just find base filename
+ V_strncat( buf, ".fxc", MAX_PATH );
+ V_snprintf( pSendbuf, SEND_BUF_SIZE, "%s\n", buf );
+ V_strncat( pSendbuf, pShaderModel, SEND_BUF_SIZE );
+ V_strncat( pSendbuf, "\n", SEND_BUF_SIZE );
+ V_snprintf( buf, MAX_PATH, "%d\n", macros.Count() );
+ V_strncat( pSendbuf, buf, SEND_BUF_SIZE );
+ for ( int i=0; i < macros.Count(); i++ )
+ {
+ V_snprintf( buf, MAX_PATH, "%s\n%s\n", macros[i].Name, macros[i].Definition );
+ V_strncat( pSendbuf, buf, SEND_BUF_SIZE );
+ }
+ V_strncat( pSendbuf, "", SEND_BUF_SIZE );
+
+ // Send commands to remote shader compiler
+ int nResult = send( m_RemoteShaderCompileSocket, pSendbuf, (int)strlen( pSendbuf ), 0 );
+ if ( nResult == SOCKET_ERROR )
+ {
+ Warning( "send failed: %d\n", WSAGetLastError() );
+ DeinitRemoteShaderCompile();
+ }
+
+ if ( m_RemoteShaderCompileSocket != INVALID_SOCKET )
+ {
+ // Block here until we get a result back from the server
+ nResult = recv( m_RemoteShaderCompileSocket, pRecvbuf, RECV_BUF_SIZE, 0 );
+ if ( nResult == 0 )
+ {
+ Warning( "Connection closed\n" );
+ DeinitRemoteShaderCompile();
+ }
+ else if ( nResult < 0 )
+ {
+ Warning( "recv failed: %d\n", WSAGetLastError() );
+ DeinitRemoteShaderCompile();
+ }
+
+ if ( m_RemoteShaderCompileSocket != INVALID_SOCKET )
+ {
+ // Grab the first 32 bits, which tell us what the rest of the data is
+ uint32 nCompileResultCode;
+ memcpy( &nCompileResultCode, pRecvbuf, sizeof( nCompileResultCode ) );
+
+ // If is zero, we have an error, so the rest of the data is a text string from the compiler
+ if ( nCompileResultCode == 0x00000000 )
+ {
+ Warning( "Remote shader compile error: %s\n", pRecvbuf+4 );
+ }
+ else // we have an actual binary shader blob coming back
+ {
+ nRemotelyCompiledShaderLength = nCompileResultCode;
+ pRemotelyCompiledShader = (uint32 *) pRecvbuf;
+ pRemotelyCompiledShader++;
+ }
+ }
+ }
+ } // End using remote compile service
+#endif // REMOTE_DYNAMIC_SHADER_COMPILE
+
+#if defined( DYNAMIC_SHADER_COMPILE )
+ bool bShadersNeedFlush = false;
+#endif
+
+#if defined( DYNAMIC_SHADER_COMPILE ) && !defined( REMOTE_DYNAMIC_SHADER_COMPILE )
+ LPD3DXBUFFER pShader = NULL;
+ LPD3DXBUFFER pErrorMessages = NULL;
+ HRESULT hr = S_OK;
+ bool b30Shader = !Q_stricmp( pShaderModel, "vs_3_0" ) || !Q_stricmp( pShaderModel, "ps_3_0" );
+
+ if ( m_ShaderCompileFileFunc30 && b30Shader )
+ {
+ CDxInclude dxInclude( filename );
+ hr = m_ShaderCompileFileFunc30( filename, macros.Base(), &dxInclude,
+ "main", pShaderModel, 0 /* DWORD Flags */, &pShader, &pErrorMessages, NULL /* LPD3DXCONSTANTTABLE *ppConstantTable */ );
+ }
+ else
+ {
+# if ( !defined( _X360 ) )
+ {
+ if ( b30Shader )
+ {
+ Warning( "Compiling with a stale version of d3dx. Should have d3d9x_33.dll installed (Apr 2007)\n" );
+ }
+ hr = D3DXCompileShaderFromFile( filename, macros.Base(), NULL /* LPD3DXINCLUDE */,
+ "main", pShaderModel, 0 /* DWORD Flags */, &pShader, &pErrorMessages, NULL /* LPD3DXCONSTANTTABLE *ppConstantTable */ );
+
+
+#ifdef REMOTE_DYNAMIC_SHADER_COMPILE
+ // If we're using the remote compiling service, let's double-check against a local compile
+ if ( ( m_RemoteShaderCompileSocket != INVALID_SOCKET ) && pRemotelyCompiledShader )
+ {
+ if ( ( memcmp( pRemotelyCompiledShader, pShader->GetBufferPointer(), pShader->GetBufferSize() ) != 0 ) ||
+ ( pShader->GetBufferSize() != nRemotelyCompiledShaderLength) )
+ {
+ Warning( "Remote and local shaders don't match!\n" );
+ return INVALID_HARDWARE_SHADER;
+ }
+ }
+#endif // REMOTE_DYNAMIC_SHADER_COMPILE
+
+ }
+# else
+ {
+ D3DXSHADER_COMPILE_PARAMETERS compileParams;
+ memset( &compileParams, 0, sizeof( compileParams ) );
+
+ char pUPDBOutputFile[MAX_PATH] = ""; //where we write the file
+ char pUPDBPIXLookup[MAX_PATH] = ""; //where PIX (on a pc) looks for the file
+
+ compileParams.Flags |= D3DXSHADEREX_OPTIMIZE_UCODE;
+
+ if( mat_flushshaders_generate_updbs.GetBool() )
+ {
+ //UPDB generation for PIX debugging
+ compileParams.Flags |= D3DXSHADEREX_GENERATE_UPDB;
+ compileParams.UPDBPath = pUPDBPIXLookup;
+
+ Q_snprintf( pUPDBOutputFile, MAX_PATH, "%s\\UPDB_X360\\%s_S%d_D%d.updb", GetShaderSourcePath(), pShaderName, nStaticIndex, nDynamicIndex );
+
+ //replace "net:\smb" with another "\" turning the xbox network address format into the pc network address format
+ V_strcpy_safe( pUPDBPIXLookup, &pUPDBOutputFile[7] );
+ pUPDBPIXLookup[0] = '\\';
+ }
+
+ hr = D3DXCompileShaderFromFileEx( filename, macros.Base(), NULL /* LPD3DXINCLUDE */,
+ "main", pShaderModel, 0 /* DWORD Flags */, &pShader, &pErrorMessages, NULL /* LPD3DXCONSTANTTABLE *ppConstantTable */, &compileParams );
+
+ if( (pUPDBOutputFile[0] != '\0') && compileParams.pUPDBBuffer ) //Did we generate a updb?
+ {
+ CUtlBuffer outbuffer;
+ DWORD dataSize = compileParams.pUPDBBuffer->GetBufferSize();
+ outbuffer.EnsureCapacity( dataSize );
+ memcpy( outbuffer.Base(), compileParams.pUPDBBuffer->GetBufferPointer(), dataSize );
+ outbuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, dataSize );
+ g_pFullFileSystem->WriteFile( pUPDBOutputFile, NULL, outbuffer );
+
+ compileParams.pUPDBBuffer->Release();
+ }
+ }
+# endif
+ }
+
+ if ( hr != D3D_OK )
+ {
+ const char *pErrorMessageString = ( const char * )pErrorMessages->GetBufferPointer();
+ Plat_DebugString( pErrorMessageString );
+ Plat_DebugString( "\n" );
+
+#ifndef _DEBUG
+ if ( retriesLeft-- > 0 )
+ {
+ DevMsg( 0, "Failed dynamic shader compiled - fix the shader while the debugger is at the breakpoint, then continue\n" );
+ DebuggerBreakIfDebugging();
+#if defined( DYNAMIC_SHADER_COMPILE )
+ bShadersNeedFlush = true;
+#endif
+ goto retry_compile;
+ }
+ if( !IsX360() ) //errors make the 360 puke and die. We have a better solution for this particular error
+ Error( "Failed dynamic shader compile\nBuild shaderapidx9.dll in debug to find problem\n" );
+#else
+ Assert( 0 );
+
+#endif // _DEBUG
+
+ return INVALID_HARDWARE_SHADER;
+ }
+ else
+#endif // #if defined( DYNAMIC_SHADER_COMPILE ) && !defined( REMOTE_DYNAMIC_SHADER_COMPILE )
+
+ {
+#ifdef DYNAMIC_SHADER_COMPILE_WRITE_ASSEMBLY
+ // enable to dump the disassembly for shader validation
+ char exampleCommandLine[2048];
+ Q_strncpy( exampleCommandLine, "// Run from stdshaders\n// ..\\..\\dx9sdk\\utilities\\fxc.exe ", sizeof( exampleCommandLine ) );
+ int i;
+ for( i = 0; macros[i].Name; i++ )
+ {
+ Q_strncat( exampleCommandLine, "/D", sizeof( exampleCommandLine ) );
+ Q_strncat( exampleCommandLine, macros[i].Name, sizeof( exampleCommandLine ) );
+ Q_strncat( exampleCommandLine, "=", sizeof( exampleCommandLine ) );
+ Q_strncat( exampleCommandLine, macros[i].Definition, sizeof( exampleCommandLine ) );
+ Q_strncat( exampleCommandLine, " ", sizeof( exampleCommandLine ) );
+ }
+
+ Q_strncat( exampleCommandLine, "/T", sizeof( exampleCommandLine ) );
+ Q_strncat( exampleCommandLine, pShaderModel, sizeof( exampleCommandLine ) );
+ Q_strncat( exampleCommandLine, " ", sizeof( exampleCommandLine ) );
+ Q_strncat( exampleCommandLine, filename, sizeof( exampleCommandLine ) );
+ Q_strncat( exampleCommandLine, "\n", sizeof( exampleCommandLine ) );
+
+ ID3DXBuffer *pd3dxBuffer;
+ HRESULT hr;
+ hr = D3DXDisassembleShader( ( DWORD* )pShader->GetBufferPointer(), false, NULL, &pd3dxBuffer );
+ Assert( hr == D3D_OK );
+ CUtlBuffer tempBuffer;
+ tempBuffer.SetBufferType( true, false );
+ int exampleCommandLineLength = strlen( exampleCommandLine );
+ tempBuffer.EnsureCapacity( pd3dxBuffer->GetBufferSize() + exampleCommandLineLength );
+ memcpy( tempBuffer.Base(), exampleCommandLine, exampleCommandLineLength );
+ memcpy( ( char * )tempBuffer.Base() + exampleCommandLineLength, pd3dxBuffer->GetBufferPointer(), pd3dxBuffer->GetBufferSize() );
+ tempBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, pd3dxBuffer->GetBufferSize() + exampleCommandLineLength );
+ char filename[MAX_PATH];
+ sprintf( filename, "%s_%d_%d.asm", pShaderName, nStaticIndex, nDynamicIndex );
+ g_pFullFileSystem->WriteFile( filename, "DEFAULT_WRITE_PATH", tempBuffer );
+#endif
+
+#ifdef REMOTE_DYNAMIC_SHADER_COMPILE
+ if ( bVertexShader )
+ {
+ return CreateD3DVertexShader( ( DWORD * )pRemotelyCompiledShader, nRemotelyCompiledShaderLength, pShaderName );
+ }
+ else
+ {
+ return CreateD3DPixelShader( ( DWORD * )pRemotelyCompiledShader, 0, nRemotelyCompiledShaderLength, pShaderName ); // hack hack hack! need to get centroid info from the source
+ }
+#else // local compile, not remote
+ if ( bVertexShader )
+ {
+ return CreateD3DVertexShader( ( DWORD * )pShader->GetBufferPointer(), pShader->GetBufferSize(), pShaderName );
+ }
+ else
+ {
+ return CreateD3DPixelShader( ( DWORD * )pShader->GetBufferPointer(), 0, pShader->GetBufferSize(), pShaderName ); // hack hack hack! need to get centroid info from the source
+ }
+#endif
+
+#if defined( DYNAMIC_SHADER_COMPILE )
+ // We keep up with whether we hit a compile error above. If we did, then we likely need to recompile everything again since we could have changed global code.
+ if ( bShadersNeedFlush )
+ {
+ MatFlushShaders();
+ }
+#endif
+ }
+
+#ifndef REMOTE_DYNAMIC_SHADER_COMPILE
+ if ( pShader )
+ {
+ pShader->Release();
+ }
+#endif
+
+#if defined( DYNAMIC_SHADER_COMPILE ) && !defined( REMOTE_DYNAMIC_SHADER_COMPILE )
+ if ( pErrorMessages )
+ {
+ pErrorMessages->Release();
+ }
+#endif
+
+}
+#endif
+
+#ifdef DYNAMIC_SHADER_COMPILE
+bool CShaderManager::LoadAndCreateShaders_Dynamic( ShaderLookup_t &lookup, bool bVertexShader )
+{
+ const char *pName = m_ShaderSymbolTable.String( lookup.m_Name );
+ const ShaderCombos_t *pCombos = FindOrCreateShaderCombos( pName );
+ if ( !pCombos )
+ {
+ return false;
+ }
+
+ int numDynamicCombos = pCombos->GetNumDynamicCombos();
+ lookup.m_ShaderStaticCombos.m_pHardwareShaders = new HardwareShader_t[numDynamicCombos];
+ lookup.m_ShaderStaticCombos.m_nCount = numDynamicCombos;
+ lookup.m_ShaderStaticCombos.m_pCreationData = new ShaderStaticCombos_t::ShaderCreationData_t[numDynamicCombos];
+
+ int i;
+ for( i = 0; i < numDynamicCombos; i++ )
+ {
+ lookup.m_ShaderStaticCombos.m_pHardwareShaders[i] = INVALID_HARDWARE_SHADER;
+ }
+ return true;
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// Open the shader file, optionally gets the header
+//-----------------------------------------------------------------------------
+FileHandle_t CShaderManager::OpenFileAndLoadHeader( const char *pFileName, ShaderHeader_t *pHeader )
+{
+ FileHandle_t fp = g_pFullFileSystem->Open( pFileName, "rb", "GAME" );
+ if ( fp == FILESYSTEM_INVALID_HANDLE )
+ {
+ return FILESYSTEM_INVALID_HANDLE;
+ }
+
+ if ( pHeader )
+ {
+ // read the header
+ g_pFullFileSystem->Read( pHeader, sizeof( ShaderHeader_t ), fp );
+
+ switch ( pHeader->m_nVersion )
+ {
+ case 4:
+ // version with combos done as diffs vs a reference combo
+ // vsh/psh or older fxc
+ break;
+
+ case 5:
+ case 6:
+ // version with optimal dictionary and compressed combo block
+ break;
+
+ default:
+ Assert( 0 );
+ Warning( "Shader %s is the wrong version %d, expecting %d\n", pFileName, pHeader->m_nVersion, SHADER_VCS_VERSION_NUMBER );
+ g_pFullFileSystem->Close( fp );
+ return FILESYSTEM_INVALID_HANDLE;
+ }
+ }
+
+ return fp;
+}
+
+//---------------------------------------------------------------------------------------------------------
+// Writes text files named for looked-up shaders. Used by GL shader translator to dump code for debugging
+//---------------------------------------------------------------------------------------------------------
+void CShaderManager::WriteTranslatedFile( ShaderLookup_t *pLookup, int dynamicCombo, char *pFileContents, char *pFileExtension )
+{
+ const char *pName = m_ShaderSymbolTable.String( pLookup->m_Name );
+ int nNumChars = V_strlen( pFileContents );
+
+ CUtlBuffer tempBuffer;
+ tempBuffer.SetBufferType( true, false );
+ tempBuffer.EnsureCapacity( nNumChars );
+ memcpy( ( char * )tempBuffer.Base(), pFileContents, nNumChars );
+ tempBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, nNumChars );
+
+ char filename[MAX_PATH];
+ sprintf( filename, "%s_%d_%d.%s", pName, pLookup->m_nStaticIndex, dynamicCombo, pFileExtension );
+ g_pFullFileSystem->WriteFile( filename, "DEFAULT_WRITE_PATH", tempBuffer );
+}
+
+//-----------------------------------------------------------------------------
+// Disassemble a shader for debugging. Writes .asm files.
+//-----------------------------------------------------------------------------
+void CShaderManager::DisassembleShader( ShaderLookup_t *pLookup, int dynamicCombo, uint8 *pByteCode )
+{
+#if defined( WRITE_ASSEMBLY )
+ const char *pName = m_ShaderSymbolTable.String( pLookup->m_Name );
+
+ ID3DXBuffer *pd3dxBuffer;
+ HRESULT hr;
+ hr = D3DXDisassembleShader( (DWORD*)pByteCode, false, NULL, &pd3dxBuffer );
+ Assert( hr == D3D_OK );
+
+ CUtlBuffer tempBuffer;
+ tempBuffer.SetBufferType( true, false );
+ tempBuffer.EnsureCapacity( pd3dxBuffer->GetBufferSize() );
+ memcpy( ( char * )tempBuffer.Base(), pd3dxBuffer->GetBufferPointer(), pd3dxBuffer->GetBufferSize() );
+ tempBuffer.SeekPut( CUtlBuffer::SEEK_CURRENT, pd3dxBuffer->GetBufferSize() );
+
+ char filename[MAX_PATH];
+ sprintf( filename, "%s_%d_%d.asm", pName, pLookup->m_nStaticIndex, dynamicCombo );
+ g_pFullFileSystem->WriteFile( filename, "DEFAULT_WRITE_PATH", tempBuffer );
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Create dynamic combos
+//-----------------------------------------------------------------------------
+bool CShaderManager::CreateDynamicCombos_Ver4( void *pContext, uint8 *pComboBuffer )
+{
+ ShaderLookup_t* pLookup = (ShaderLookup_t *)pContext;
+
+ ShaderFileCache_t *pFileCache = &m_ShaderFileCache[pLookup->m_hShaderFileCache];
+ ShaderHeader_t *pHeader = &pFileCache->m_Header;
+
+ int nReferenceComboSizeForDiffs = ((ShaderHeader_t_v4 *)pHeader)->m_nDiffReferenceSize;
+
+ uint8 *pReferenceShader = NULL;
+ uint8 *pDiffOutputBuffer = NULL;
+ if ( nReferenceComboSizeForDiffs )
+ {
+ // reference combo is *always* the largest combo, so safe worst case size for uncompression buffer
+ pReferenceShader = (uint8 *)pFileCache->m_ReferenceCombo.Base();
+ pDiffOutputBuffer = (uint8 *)_alloca( nReferenceComboSizeForDiffs );
+ }
+
+ // build this shader's dynamic combos
+ bool bOK = true;
+ int nStartingOffset = 0;
+ for ( int i = 0; i < pHeader->m_nDynamicCombos; i++ )
+ {
+ if ( pLookup->m_pComboDictionary[i].m_Offset == -1 )
+ {
+ // skipped
+ continue;
+ }
+
+ if ( !nStartingOffset )
+ {
+ nStartingOffset = pLookup->m_pComboDictionary[i].m_Offset;
+ }
+
+ // offsets better be sequentially ascending
+ Assert( nStartingOffset <= pLookup->m_pComboDictionary[i].m_Offset );
+
+ if ( pLookup->m_pComboDictionary[i].m_Size <= 0 )
+ {
+ // skipped
+ continue;
+ }
+
+ // get the right byte code from the monolithic buffer
+ uint8 *pByteCode = (uint8 *)pComboBuffer + pLookup->m_nDataOffset + pLookup->m_pComboDictionary[i].m_Offset - nStartingOffset;
+ int nByteCodeSize = pLookup->m_pComboDictionary[i].m_Size;
+
+ if ( pReferenceShader )
+ {
+ // reference combo better be the largest combo, otherwise memory corruption
+ Assert( nReferenceComboSizeForDiffs >= nByteCodeSize );
+
+ // use the differencing algorithm to recover the full shader
+ int nOriginalSize;
+ ApplyDiffs(
+ pReferenceShader,
+ pByteCode,
+ nReferenceComboSizeForDiffs,
+ nByteCodeSize,
+ nOriginalSize,
+ pDiffOutputBuffer,
+ nReferenceComboSizeForDiffs );
+
+ pByteCode = pDiffOutputBuffer;
+ nByteCodeSize = nOriginalSize;
+ }
+
+#if defined( WRITE_ASSEMBLY )
+ DisassembleShader( pLookup, i, pByteCode );
+#endif
+ HardwareShader_t hardwareShader = INVALID_HARDWARE_SHADER;
+
+ if ( IsPC() && m_bCreateShadersOnDemand )
+ {
+ // cache the code off for later
+ pLookup->m_ShaderStaticCombos.m_pCreationData[i].ByteCode.SetSize( nByteCodeSize );
+ V_memcpy( pLookup->m_ShaderStaticCombos.m_pCreationData[i].ByteCode.Base(), pByteCode, nByteCodeSize );
+ pLookup->m_ShaderStaticCombos.m_pCreationData[i].iCentroidMask = pFileCache->m_bVertexShader ? 0 : pHeader->m_nCentroidMask;
+ }
+ else
+ {
+ const char *pShaderName = m_ShaderSymbolTable.String( pLookup->m_Name );
+ if ( pFileCache->m_bVertexShader )
+ {
+ hardwareShader = CreateD3DVertexShader( reinterpret_cast< DWORD *>( pByteCode ), nByteCodeSize, pShaderName );
+ }
+ else
+ {
+ hardwareShader = CreateD3DPixelShader( reinterpret_cast< DWORD *>( pByteCode ), pHeader->m_nCentroidMask, nByteCodeSize, pShaderName );
+ }
+
+ if ( hardwareShader == INVALID_HARDWARE_SHADER )
+ {
+ Assert( 0 );
+ bOK = false;
+ break;
+ }
+ }
+ pLookup->m_ShaderStaticCombos.m_pHardwareShaders[i] = hardwareShader;
+ }
+
+ delete [] pLookup->m_pComboDictionary;
+ pLookup->m_pComboDictionary = NULL;
+
+ return bOK;
+}
+
+//-----------------------------------------------------------------------------
+// Create dynamic combos
+//-----------------------------------------------------------------------------
+static uint32 NextULONG( uint8 * &pData )
+{
+ // handle unaligned read
+ uint32 nRet;
+ memcpy( &nRet, pData, sizeof( nRet ) );
+ pData += sizeof( nRet );
+ return nRet;
+}
+
+
+bool CShaderManager::CreateDynamicCombos_Ver5( void *pContext, uint8 *pComboBuffer, char *debugLabel )
+{
+ ShaderLookup_t* pLookup = (ShaderLookup_t *)pContext;
+ ShaderFileCache_t *pFileCache = &m_ShaderFileCache[pLookup->m_hShaderFileCache];
+ uint8 *pCompressedShaders = pComboBuffer + pLookup->m_nDataOffset;
+
+ uint8 *pUnpackBuffer = new uint8[MAX_SHADER_UNPACKED_BLOCK_SIZE];
+
+ char *debugLabelPtr = debugLabel; // can be moved to point at something else if need be
+
+ // now, loop through all blocks
+ bool bOK = true;
+ while ( bOK )
+ {
+ uint32 nBlockSize = NextULONG( pCompressedShaders );
+ if ( nBlockSize == 0xffffffff )
+ {
+ // any more blocks?
+ break;
+ }
+
+ switch( nBlockSize & 0xc0000000 )
+ {
+ case 0: // bzip2
+ {
+ // uncompress
+ uint32 nOutsize = MAX_SHADER_UNPACKED_BLOCK_SIZE;
+ int nRslt = BZ2_bzBuffToBuffDecompress(
+ reinterpret_cast<char *>( pUnpackBuffer ),
+ &nOutsize,
+ reinterpret_cast<char *>( pCompressedShaders ),
+ nBlockSize, 1, 0 );
+ if ( nRslt < 0 )
+ {
+ // errors are negative for bzip
+ Assert( 0 );
+ Warning( "BZIP Error (%d) decompressing shader", nRslt );
+ bOK = false;
+ }
+
+ pCompressedShaders += nBlockSize;
+ nBlockSize = nOutsize; // how much data there is
+ }
+ break;
+
+ case 0x80000000: // uncompressed
+ {
+ // not compressed, as is
+ nBlockSize &= 0x3fffffff;
+ memcpy( pUnpackBuffer, pCompressedShaders, nBlockSize );
+ pCompressedShaders += nBlockSize;
+ }
+ break;
+
+ case 0x40000000: // lzma compressed
+ {
+ nBlockSize &= 0x3fffffff;
+
+ size_t nOutsize = CLZMA::Uncompress(
+ reinterpret_cast<uint8 *>( pCompressedShaders ),
+ pUnpackBuffer );
+ pCompressedShaders += nBlockSize;
+ nBlockSize = nOutsize; // how much data there is
+ }
+ break;
+
+ default:
+ {
+ Assert( 0 );
+ Error(" unrecognized shader compression type = file corrupt?");
+ bOK = false;
+ }
+ }
+
+ uint8 *pReadPtr = pUnpackBuffer;
+ while ( pReadPtr < pUnpackBuffer+nBlockSize )
+ {
+ uint32 nCombo_ID = NextULONG( pReadPtr );
+ uint32 nShaderSize = NextULONG( pReadPtr );
+
+#if defined( WRITE_ASSEMBLY )
+ DisassembleShader( pLookup, nCombo_ID, pReadPtr );
+#endif
+ HardwareShader_t hardwareShader = INVALID_HARDWARE_SHADER;
+
+ int iIndex = nCombo_ID;
+ if ( iIndex >= pLookup->m_nStaticIndex )
+ iIndex -= pLookup->m_nStaticIndex; // ver5 stores combos as full combo, ver6 as dynamic combo # only
+ if ( IsPC() && m_bCreateShadersOnDemand )
+ {
+ // cache the code off for later
+ pLookup->m_ShaderStaticCombos.m_pCreationData[iIndex].ByteCode.SetSize( nShaderSize );
+ V_memcpy( pLookup->m_ShaderStaticCombos.m_pCreationData[iIndex].ByteCode.Base(), pReadPtr, nShaderSize );
+ pLookup->m_ShaderStaticCombos.m_pCreationData[iIndex].iCentroidMask = pFileCache->m_bVertexShader ? 0 : pFileCache->m_Header.m_nCentroidMask;
+ }
+ else
+ {
+ const char *pShaderName = m_ShaderSymbolTable.String( pLookup->m_Name );
+
+ if ( pFileCache->m_bVertexShader )
+ {
+#if 0
+ // this is all test code
+ CUtlBuffer bufGLCode( 1000, 50000, CUtlBuffer::TEXT_BUFFER );
+ CUtlBuffer bufNewGLCode( 1000, 50000, CUtlBuffer::TEXT_BUFFER );
+ CUtlBuffer bufGLSLCode( 1000, 50000, CUtlBuffer::TEXT_BUFFER );
+ bool bVertexShader;
+
+ uint32 nOptions = 0;
+ nOptions |= D3DToGL_OptionUseEnvParams;
+ nOptions |= D3DToGL_OptionDoFixupZ;
+ nOptions |= D3DToGL_OptionDoFixupY;
+ //options |= D3DToGL_OptionSpew;
+
+// sg_D3DToOpenGLTranslator.TranslateShader( (uint32 *) pReadPtr, (char *)bufGLCode.Base(), bufGLCode.Size(), &bVertexShader, nOptions, -1, debugLabel );
+// sg_NewD3DToOpenGLTranslator.TranslateShader( (uint32 *) pReadPtr, &bufNewGLCode, &bVertexShader, nOptions, -1, debugLabel );
+
+
+// bool bDumpGLSL = false;
+// if ( !stricmp( "vs-file vertexlit_and_unlit_generic_bump_vs20 vs-index 144", debugLabel ) && ( iIndex == 0 ) )
+// {
+// DisassembleShader( pLookup, iIndex, pReadPtr ); // Direct3D
+// bDumpGLSL = true;
+// }
+
+
+ // GLSL options
+ nOptions |= D3DToGL_OptionGLSL; // | D3DToGL_AddHexComments | D3DToGL_PutHexCommentsAfterLines;
+ if ( !IsOSX() )
+ {
+ nOptions |= D3DToGL_OptionAllowStaticControlFlow;
+ }
+ sg_NewD3DToOpenGLTranslator.TranslateShader( (uint32 *) pReadPtr, &bufGLSLCode, &bVertexShader, nOptions, -1, 0, debugLabel );
+ Assert( bVertexShader );
+
+ // Test to make sure these are identical
+// if ( bDumpGLSL )//V_strcmp( (char *)bufGLCode.Base(), (char *)bufNewGLCode.Base() ) )
+// {
+// WriteTranslatedFile( pLookup, iIndex, (char *)bufGLCode.Base(), "avp" ); // Old
+// WriteTranslatedFile( pLookup, iIndex, (char *)bufNewGLCode.Base(), "avp2" ); // New
+ WriteTranslatedFile( pLookup, iIndex, (char *)bufGLSLCode.Base(), "glsl_v" ); // GLSL
+// DisassembleShader( pLookup, iIndex, pReadPtr ); // Direct3D
+// }
+
+ #if defined( WRITE_ASSEMBLY )
+ WriteTranslatedFile( pLookup, iIndex, (char *)bufGLCode.Base(), "avp" );
+ #endif
+#endif // 0
+
+#ifdef DX_TO_GL_ABSTRACTION
+ // munge the debug label a bit to aid in decoding... catenate the iIndex on the end
+ char temp[1024];
+ sprintf(temp, "%s vs-combo %d", (debugLabel)?debugLabel:"none", iIndex );
+ debugLabelPtr = temp;
+#endif
+ // pass binary code to d3d interface, on GL it will invoke the translator back to asm
+ hardwareShader = CreateD3DVertexShader( reinterpret_cast< DWORD *>( pReadPtr ), nShaderSize, pShaderName, debugLabelPtr );
+ }
+ else
+ {
+#if 0
+ // this is all test code
+// CUtlBuffer bufGLCode( 1000, 50000, CUtlBuffer::TEXT_BUFFER );
+// CUtlBuffer bufNewGLCode( 1000, 50000, CUtlBuffer::TEXT_BUFFER );
+ CUtlBuffer bufGLSLCode( 1000, 50000, CUtlBuffer::TEXT_BUFFER );
+ bool bVertexShader;
+
+
+ uint32 nOptions = D3DToGL_OptionUseEnvParams;
+
+// sg_D3DToOpenGLTranslator.TranslateShader( (uint32 *) pReadPtr, (char *)bufGLCode.Base(), bufGLCode.Size(), &bVertexShader, D3DToGL_OptionUseEnvParams, -1, debugLabel );
+// sg_NewD3DToOpenGLTranslator.TranslateShader( (uint32 *) pReadPtr, &bufNewGLCode, &bVertexShader, D3DToGL_OptionUseEnvParams, -1, debugLabel );
+
+ // GLSL options
+ nOptions |= D3DToGL_OptionGLSL;// | D3DToGL_OptionSRGBWriteSuffix | D3DToGL_AddHexComments | D3DToGL_PutHexCommentsAfterLines;
+ if ( !IsOSX() )
+ {
+ nOptions |= D3DToGL_OptionAllowStaticControlFlow;
+ }
+ sg_NewD3DToOpenGLTranslator.TranslateShader( (uint32 *) pReadPtr, &bufGLSLCode, &bVertexShader, nOptions, -1, 0, debugLabel );
+
+ Assert( !bVertexShader );
+
+ // Test to make sure these are identical
+// if ( V_strcmp( (char *)bufGLCode.Base(), (char *)bufNewGLCode.Base() ) )
+// {
+// WriteTranslatedFile( pLookup, iIndex, (char *)bufGLCode.Base(), "afp" ); // Old
+// WriteTranslatedFile( pLookup, iIndex, (char *)bufNewGLCode.Base(), "afp2" ); // New
+ WriteTranslatedFile( pLookup, iIndex, (char *)bufGLSLCode.Base(), "glsl_p" ); // GLSL
+// DisassembleShader( pLookup, iIndex, pReadPtr ); // Direct3D
+// }
+
+ #if defined( WRITE_ASSEMBLY )
+ WriteTranslatedFile( pLookup, iIndex, (char *)bufGLCode.Base(), "afp" );
+ #endif
+#endif // 0
+
+#ifdef DX_TO_GL_ABSTRACTION
+ // munge the debug label a bit to aid in decoding... catenate the iIndex on the end
+ char temp[1024];
+ sprintf(temp, "%s ps-combo %d", (debugLabel)?debugLabel:"", iIndex );
+ debugLabelPtr = temp;
+#endif
+
+ // pass binary code to d3d interface, on GL it will invoke the translator back to asm
+ hardwareShader = CreateD3DPixelShader( reinterpret_cast< DWORD *>( pReadPtr ), pFileCache->m_Header.m_nCentroidMask, nShaderSize, pShaderName, debugLabelPtr );
+ }
+ if ( hardwareShader == INVALID_HARDWARE_SHADER )
+ {
+ Warning( "failed to create shader\n" );
+ Assert( 0 );
+ bOK = false;
+ break;
+ }
+ }
+ pLookup->m_ShaderStaticCombos.m_pHardwareShaders[iIndex] = hardwareShader;
+ pReadPtr += nShaderSize;
+ }
+ }
+
+ delete[] pUnpackBuffer;
+
+ return bOK;
+}
+
+//-----------------------------------------------------------------------------
+// Static method, called by thread, don't call anything non-threadsafe from handler!!!
+//-----------------------------------------------------------------------------
+void CShaderManager::QueuedLoaderCallback( void *pContext, void *pContext2, const void *pData, int nSize, LoaderError_t loaderError )
+{
+ ShaderLookup_t* pLookup = (ShaderLookup_t *)pContext;
+
+ bool bOK = ( loaderError == LOADERERROR_NONE );
+ if ( bOK )
+ {
+ if ( pContext2 )
+ {
+ // presence denotes diff version
+ bOK = s_ShaderManager.CreateDynamicCombos_Ver4( pContext, (uint8 *)pData );
+ }
+ else
+ {
+ bOK = s_ShaderManager.CreateDynamicCombos_Ver5( pContext, (uint8 *)pData );
+ }
+ }
+ if ( !bOK )
+ {
+ pLookup->m_Flags |= SHADER_FAILED_LOAD;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Loads all shaders
+//-----------------------------------------------------------------------------
+bool CShaderManager::LoadAndCreateShaders( ShaderLookup_t &lookup, bool bVertexShader, char *debugLabel )
+{
+ const char *pName = m_ShaderSymbolTable.String( lookup.m_Name );
+
+ // find it in the cache
+ // a cache hit prevents costly i/o for static components, i.e. header, ref combo, etc.
+ ShaderFileCache_t fileCacheLookup;
+ fileCacheLookup.m_Name = lookup.m_Name;
+ fileCacheLookup.m_bVertexShader = bVertexShader;
+ int fileCacheIndex = m_ShaderFileCache.Find( fileCacheLookup );
+ if ( fileCacheIndex == m_ShaderFileCache.InvalidIndex() )
+ {
+ // not found, create a new entry
+ fileCacheIndex = m_ShaderFileCache.AddToTail();
+ }
+
+ lookup.m_hShaderFileCache = fileCacheIndex;
+
+ // fetch from cache
+ ShaderFileCache_t *pFileCache = &m_ShaderFileCache[fileCacheIndex];
+ ShaderHeader_t *pHeader = &pFileCache->m_Header;
+
+ FileHandle_t hFile = FILESYSTEM_INVALID_HANDLE;
+ if ( pFileCache->IsValid() )
+ {
+ // using cached header, just open file, no read of header needed
+ hFile = OpenFileAndLoadHeader( m_ShaderSymbolTable.String( pFileCache->m_Filename ), NULL );
+ if ( hFile == FILESYSTEM_INVALID_HANDLE )
+ {
+ // shouldn't happen
+ Assert( 0 );
+ return false;
+ }
+ }
+ else
+ {
+ V_memset( pHeader, 0, sizeof( ShaderHeader_t ) );
+
+ // try the vsh/psh dir first
+ char filename[MAX_PATH];
+ Q_snprintf( filename, MAX_PATH, "shaders\\%s\\%s" SHADER_FNAME_EXTENSION, bVertexShader ? "vsh" : "psh", pName );
+ hFile = OpenFileAndLoadHeader( filename, pHeader );
+ if ( hFile == FILESYSTEM_INVALID_HANDLE )
+ {
+#ifdef DYNAMIC_SHADER_COMPILE
+ // Dynamically compile if it's HLSL.
+ if ( LoadAndCreateShaders_Dynamic( lookup, bVertexShader ) )
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+#endif
+ // next, try the fxc dir
+ Q_snprintf( filename, MAX_PATH, "shaders\\fxc\\%s" SHADER_FNAME_EXTENSION, pName );
+ hFile = OpenFileAndLoadHeader( filename, pHeader );
+ if ( hFile == FILESYSTEM_INVALID_HANDLE )
+ {
+ lookup.m_Flags |= SHADER_FAILED_LOAD;
+ Warning( "Couldn't load %s shader %s\n", bVertexShader ? "vertex" : "pixel", pName );
+ return false;
+ }
+ }
+
+ lookup.m_Flags = pHeader->m_nFlags;
+
+ pFileCache->m_Name = lookup.m_Name;
+ pFileCache->m_Filename = m_ShaderSymbolTable.AddString( filename );
+ pFileCache->m_bVertexShader = bVertexShader;
+
+ if ( pFileCache->IsOldVersion() )
+ {
+ int referenceComboSize = ((ShaderHeader_t_v4 *)pHeader)->m_nDiffReferenceSize;
+ if ( referenceComboSize )
+ {
+ // cache the reference combo
+ pFileCache->m_ReferenceCombo.EnsureCapacity( referenceComboSize );
+ g_pFullFileSystem->Read( pFileCache->m_ReferenceCombo.Base(), referenceComboSize, hFile );
+ }
+ }
+ else
+ {
+ // cache the dictionary
+ pFileCache->m_StaticComboRecords.EnsureCount( pHeader->m_nNumStaticCombos );
+ g_pFullFileSystem->Read( pFileCache->m_StaticComboRecords.Base(), pHeader->m_nNumStaticCombos * sizeof( StaticComboRecord_t ), hFile );
+ if ( pFileCache->IsVersion6() )
+ {
+ // read static combo alias records
+ int nNumDups;
+ g_pFullFileSystem->Read( &nNumDups, sizeof( nNumDups ), hFile );
+ if ( nNumDups )
+ {
+ pFileCache->m_StaticComboDupRecords.EnsureCount( nNumDups );
+ g_pFullFileSystem->Read( pFileCache->m_StaticComboDupRecords.Base(), nNumDups * sizeof( StaticComboAliasRecord_t ), hFile );
+ }
+ }
+
+ }
+ }
+
+ // FIXME: should make lookup and ShaderStaticCombos_t are pool allocated.
+ int i;
+ lookup.m_ShaderStaticCombos.m_nCount = pHeader->m_nDynamicCombos;
+ lookup.m_ShaderStaticCombos.m_pHardwareShaders = new HardwareShader_t[pHeader->m_nDynamicCombos];
+ if ( IsPC() && m_bCreateShadersOnDemand )
+ {
+ lookup.m_ShaderStaticCombos.m_pCreationData = new ShaderStaticCombos_t::ShaderCreationData_t[pHeader->m_nDynamicCombos];
+ }
+ for ( i = 0; i < pHeader->m_nDynamicCombos; i++ )
+ {
+ lookup.m_ShaderStaticCombos.m_pHardwareShaders[i] = INVALID_HARDWARE_SHADER;
+ }
+
+ int nStartingOffset = 0;
+ int nEndingOffset = 0;
+
+ if ( pFileCache->IsOldVersion() )
+ {
+ int nDictionaryOffset = sizeof( ShaderHeader_t ) + ((ShaderHeader_t_v4 *)pHeader)->m_nDiffReferenceSize;
+
+ // read in shader's dynamic combos directory
+ lookup.m_pComboDictionary = new ShaderDictionaryEntry_t[pHeader->m_nDynamicCombos];
+ g_pFullFileSystem->Seek( hFile, nDictionaryOffset + lookup.m_nStaticIndex * sizeof( ShaderDictionaryEntry_t ), FILESYSTEM_SEEK_HEAD );
+ g_pFullFileSystem->Read( lookup.m_pComboDictionary, pHeader->m_nDynamicCombos * sizeof( ShaderDictionaryEntry_t ), hFile );
+
+ // want single read of all this shader's dynamic combos into a target buffer
+ // shaders are written sequentially, determine starting offset and length
+ for ( i = 0; i < pHeader->m_nDynamicCombos; i++ )
+ {
+ if ( lookup.m_pComboDictionary[i].m_Offset == -1 )
+ {
+ // skipped
+ continue;
+ }
+
+ // ensure offsets are in fact sequentially ascending
+ Assert( lookup.m_pComboDictionary[i].m_Offset >= nStartingOffset && lookup.m_pComboDictionary[i].m_Size >= 0 );
+
+ if ( !nStartingOffset )
+ {
+ nStartingOffset = lookup.m_pComboDictionary[i].m_Offset;
+ }
+ nEndingOffset = lookup.m_pComboDictionary[i].m_Offset + lookup.m_pComboDictionary[i].m_Size;
+ }
+ if ( !nStartingOffset )
+ {
+ g_pFullFileSystem->Close( hFile );
+ Warning( "Shader '%s' - All dynamic combos skipped. This is bad!\n", m_ShaderSymbolTable.String( pFileCache->m_Filename ) );
+ return false;
+ }
+ }
+ else
+ {
+ int nStaticComboIdx = pFileCache->FindCombo( lookup.m_nStaticIndex / pFileCache->m_Header.m_nDynamicCombos );
+ if ( nStaticComboIdx == -1 )
+ {
+ g_pFullFileSystem->Close( hFile );
+ lookup.m_Flags |= SHADER_FAILED_LOAD;
+ Warning( "Shader '%s' - Couldn't load combo %d of shader (dyn=%d)\n", m_ShaderSymbolTable.String( pFileCache->m_Filename ), lookup.m_nStaticIndex, pFileCache->m_Header.m_nDynamicCombos );
+ return false;
+ }
+
+ nStartingOffset = pFileCache->m_StaticComboRecords[nStaticComboIdx].m_nFileOffset;
+ nEndingOffset = pFileCache->m_StaticComboRecords[nStaticComboIdx+1].m_nFileOffset;
+ }
+
+ // align offsets for unbuffered optimal i/o - fastest i/o possible
+ unsigned nOffsetAlign, nSizeAlign, nBufferAlign;
+ g_pFullFileSystem->GetOptimalIOConstraints( hFile, &nOffsetAlign, &nSizeAlign, &nBufferAlign );
+ unsigned int nAlignedOffset = AlignValue( ( nStartingOffset - nOffsetAlign ) + 1, nOffsetAlign );
+ unsigned int nAlignedBytesToRead = AlignValue( nEndingOffset - nAlignedOffset, nSizeAlign );
+
+ // used for adjusting provided buffer to actual data
+ lookup.m_nDataOffset = nStartingOffset - nAlignedOffset;
+
+ bool bOK = true;
+ if ( IsX360() && g_pQueuedLoader->IsMapLoading() )
+ {
+ LoaderJob_t loaderJob;
+ loaderJob.m_pFilename = m_ShaderSymbolTable.String( pFileCache->m_Filename );
+ loaderJob.m_pPathID = "GAME";
+ loaderJob.m_pCallback = QueuedLoaderCallback;
+ loaderJob.m_pContext = (void *)&lookup;
+ loaderJob.m_pContext2 = (void *)pFileCache->IsOldVersion();
+ loaderJob.m_Priority = LOADERPRIORITY_DURINGPRELOAD;
+ loaderJob.m_nBytesToRead = nAlignedBytesToRead;
+ loaderJob.m_nStartOffset = nAlignedOffset;
+ g_pQueuedLoader->AddJob( &loaderJob );
+ }
+ else
+ {
+ //printf("\n CShaderManager::LoadAndCreateShaders - reading %d bytes from file offset %d", nAlignedBytesToRead, nAlignedOffset);
+ // single optimal read of all dynamic combos into monolithic buffer
+ uint8 *pOptimalBuffer = (uint8 *)g_pFullFileSystem->AllocOptimalReadBuffer( hFile, nAlignedBytesToRead, nAlignedOffset );
+ g_pFullFileSystem->Seek( hFile, nAlignedOffset, FILESYSTEM_SEEK_HEAD );
+ g_pFullFileSystem->Read( pOptimalBuffer, nAlignedBytesToRead, hFile );
+
+ if ( pFileCache->IsOldVersion() )
+ {
+ bOK = CreateDynamicCombos_Ver4( &lookup, pOptimalBuffer );
+ }
+ else
+ {
+ bOK = CreateDynamicCombos_Ver5( &lookup, pOptimalBuffer, debugLabel );
+ }
+
+ g_pFullFileSystem->FreeOptimalReadBuffer( pOptimalBuffer );
+ }
+
+ g_pFullFileSystem->Close( hFile );
+
+ if ( !bOK )
+ {
+ lookup.m_Flags |= SHADER_FAILED_LOAD;
+ }
+
+ return bOK;
+}
+
+
+//----------------------------------------------------------------------------------old code
+
+#if 0
+
+ // Set this convar internally to build or add to the shader cache file
+ // We really only expect this to work on DX_TO_GL_ABSTRACTION
+ ConVar mat_cacheshaders( "mat_cacheshaders", "0", FCVAR_DEVELOPMENTONLY );
+
+ #define SHADER_CACHE_FILE "shader_cache.cfg"
+ #define PROGRAM_CACHE_FILE "program_cache.cfg"
+
+ static void WriteToShaderCache( const char *pShaderName, const int nIndex )
+ {
+#ifndef DX_TO_GL_ABSTRACTION
+ return;
+#endif
+
+ KeyValues *pShaderCache = new KeyValues( "shadercache" );
+ // we don't load anything, it starts empty.. pShaderCache->LoadFromFile( g_pFullFileSystem, SHADER_CACHE_FILE, "MOD" );
+
+ if ( !pShaderCache )
+ {
+ Warning( "Could not write to shader cache file!\n" );
+ return;
+ }
+
+ // Subkey for specific shader
+ KeyValues *pShaderKey = pShaderCache->FindKey( pShaderName, true );
+ Assert( pShaderKey );
+
+ bool bFound = false;
+ int nKeys = 0;
+ char szIndex[8];
+ FOR_EACH_VALUE( pShaderKey, pValues )
+ {
+ if ( pValues->GetInt() == nIndex )
+ {
+ bFound = true;
+ }
+ nKeys++;
+ }
+
+ if ( !bFound )
+ {
+ V_snprintf( szIndex, 8, "%d", nKeys );
+ pShaderKey->SetInt( szIndex, nIndex );
+ }
+
+ pShaderCache->SaveToFile( g_pFullFileSystem, SHADER_CACHE_FILE, "MOD" );
+ pShaderCache->deleteThis();
+ }
+
+void CShaderManager::WarmShaderCache()
+ {
+#ifndef DX_TO_GL_ABSTRACTION
+ return;
+#endif
+
+ // Don't access the cache if we're building it!
+ if ( mat_cacheshaders.GetBool() )
+ return;
+
+ // Don't warm the cache if we're just going to monkey with the shaders anyway
+ #ifdef DYNAMIC_SHADER_COMPILE
+ return;
+ #endif
+
+ double st = Sys_FloatTime();
+
+
+ //
+ // First we warm SHADERS ===============================================
+ //
+
+ KeyValues *pShaderCache = new KeyValues( "shadercache" );
+ pShaderCache->LoadFromFile( g_pFullFileSystem, SHADER_CACHE_FILE, "MOD" );
+
+ if ( !pShaderCache )
+ {
+ Warning( "Could not find shader cache file!\n" );
+ return;
+ }
+
+ // Run through each shader in the cache
+ FOR_EACH_SUBKEY( pShaderCache, pShaderKey )
+ {
+ const char *pShaderName = pShaderKey->GetName();
+ bool bVertexShader = Q_stristr( pShaderName, "_vs20" ) || Q_stristr( pShaderName, "_vs30" );
+
+ FOR_EACH_VALUE( pShaderKey, pValue )
+ {
+ char temp[1024];
+ int staticIndex = pValue->GetInt();
+
+ if ( bVertexShader )
+ {
+ V_snprintf( temp, sizeof(temp), "vs-file %s vs-index %d", pShaderName, staticIndex );
+ CreateVertexShader( pShaderName, staticIndex, temp );
+ }
+ else
+ {
+ V_snprintf( temp, sizeof(temp), "ps-file %s ps-index %d", pShaderName, staticIndex );
+ CreatePixelShader( pShaderName, staticIndex, temp );
+ }
+ }
+ }
+
+ pShaderCache->deleteThis();
+
+
+ //
+ // Next, we warm PROGRAMS (which are pairs of shaders) =================
+ //
+
+ KeyValues *pProgramCache = new KeyValues( "programcache" );
+ pProgramCache->LoadFromFile( g_pFullFileSystem, PROGRAM_CACHE_FILE, "MOD" );
+
+ if ( !pProgramCache )
+ {
+ Warning( "Could not find program cache file!\n" );
+ return;
+ }
+
+ // Run through each program in the cache
+ FOR_EACH_SUBKEY( pProgramCache, pProgramKey )
+ {
+ KeyValues *pValue = pProgramKey->GetFirstValue();
+ const char *pVertexShaderName = pValue->GetString();
+ pValue = pValue->GetNextValue();
+ const char *pPixelShaderName = pValue->GetString();
+ pValue = pValue->GetNextValue();
+ int nVertexShaderStaticIndex = pValue->GetInt();
+ pValue = pValue->GetNextValue();
+ int nPixelShaderStaticIndex = pValue->GetInt();
+ pValue = pValue->GetNextValue();
+ int nVertexShaderDynamicIndex = pValue->GetInt();
+ pValue = pValue->GetNextValue();
+ int nPixelShaderDynamicIndex = pValue->GetInt();
+
+ ShaderLookup_t vshLookup;
+ vshLookup.m_Name = m_ShaderSymbolTable.AddString( pVertexShaderName ); // TODO: use String() here and catch this odd case
+ vshLookup.m_nStaticIndex = nVertexShaderStaticIndex;
+ VertexShader_t vertexShader = m_VertexShaderDict.Find( vshLookup );
+
+ ShaderLookup_t pshLookup;
+ pshLookup.m_Name = m_ShaderSymbolTable.AddString( pPixelShaderName );
+ pshLookup.m_nStaticIndex = nPixelShaderStaticIndex;
+ PixelShader_t pixelShader = m_PixelShaderDict.Find( pshLookup );
+
+ // If we found both shaders, do the link!
+ if ( ( vertexShader != m_VertexShaderDict.InvalidIndex() ) && ( pixelShader != m_PixelShaderDict.InvalidIndex() ) )
+ {
+ #ifdef DX_TO_GL_ABSTRACTION
+ //HardwareShader_t hardwareVertexShader = vshLookup.m_ShaderStaticCombos.m_pHardwareShaders[nVertexShaderDynamicIndex];
+ //HardwareShader_t hardwarePixelShader = pshLookup.m_ShaderStaticCombos.m_pHardwareShaders[nPixelShaderDynamicIndex];
+
+ HardwareShader_t hardwareVertexShader = m_VertexShaderDict[vertexShader].m_ShaderStaticCombos.m_pHardwareShaders[nVertexShaderDynamicIndex];
+ HardwareShader_t hardwarePixelShader = m_PixelShaderDict[pixelShader].m_ShaderStaticCombos.m_pHardwareShaders[nPixelShaderDynamicIndex];
+
+ if ( ( hardwareVertexShader != INVALID_HARDWARE_SHADER ) && ( hardwarePixelShader != INVALID_HARDWARE_SHADER ) )
+ {
+ if ( S_OK != Dx9Device()->LinkShaderPair( (IDirect3DVertexShader9 *)hardwareVertexShader, (IDirect3DPixelShader9 *)hardwarePixelShader ) )
+ {
+ Warning( "Could not link OpenGL shaders: %s (%d, %d) : %s (%d, %d)\n", pVertexShaderName, nVertexShaderStaticIndex, nVertexShaderDynamicIndex, pPixelShaderName, nPixelShaderStaticIndex, nPixelShaderDynamicIndex );
+ }
+ }
+ #endif
+ }
+ else
+ {
+ Warning( "Invalid shader linkage: %s (%d, %d) : %s (%d, %d)\n", pVertexShaderName, nVertexShaderStaticIndex, nVertexShaderDynamicIndex, pPixelShaderName, nPixelShaderStaticIndex, nPixelShaderDynamicIndex );
+ }
+ }
+
+ pProgramCache->deleteThis();
+
+ float elapsed = ( float )( Sys_FloatTime() - st ) * 1000.0;
+ DevMsg( "WarmShaderCache took %.3f msec\n", elapsed );
+ }
+
+#endif
+//----------------------------------------------------------------------------------old code
+
+#ifdef DX_TO_GL_ABSTRACTION
+// if shaders are changed in a way that requires the client-side cache to be invalidated,
+// increment this string - such changes include combo changes (skips, adding combos)
+const char *k_pszShaderCacheRootKey = "glshadercachev002";
+#endif
+
+void CShaderManager::SaveShaderCache( char *cacheName )
+{
+#ifdef DX_TO_GL_ABSTRACTION // must ifdef, it uses calls which don't exist in the real DX9 interface
+
+ KeyValues *pProgramCache = new KeyValues( k_pszShaderCacheRootKey );
+
+ if ( !pProgramCache )
+ {
+ Warning( "Could not write to program cache file!\n" );
+ return;
+ }
+
+ int i=0;
+ GLMShaderPairInfo info;
+
+ do
+ {
+ Dx9Device()->QueryShaderPair( i, &info );
+
+ if (info.m_status==1)
+ {
+ // found one
+ // extract values of interest which represent a pair of shaders
+
+ if (info.m_vsName[0] && info.m_psName[0] && (info.m_vsDynamicIndex > -1) && (info.m_psDynamicIndex > -1) )
+ {
+ // make up a key - this thing is really a list of tuples, so need not be keyed by anything particular
+ KeyValues *pProgramKey = pProgramCache->CreateNewKey();
+ Assert( pProgramKey );
+
+ pProgramKey->SetString ( "vs", info.m_vsName );
+ pProgramKey->SetString ( "ps", info.m_psName );
+
+ pProgramKey->SetInt ( "vs_static", info.m_vsStaticIndex );
+ pProgramKey->SetInt ( "ps_static", info.m_psStaticIndex );
+
+ pProgramKey->SetInt ( "vs_dynamic", info.m_vsDynamicIndex );
+ pProgramKey->SetInt ( "ps_dynamic", info.m_psDynamicIndex );
+ }
+ }
+ i++;
+ } while( info.m_status >= 0 );
+
+ pProgramCache->SaveToFile( g_pFullFileSystem, cacheName, "MOD" );
+ pProgramCache->deleteThis();
+
+ // done! whew
+#endif
+}
+
+bool CShaderManager::LoadShaderCache( char *cacheName )
+{
+#ifdef DX_TO_GL_ABSTRACTION
+ KeyValues *pProgramCache = new KeyValues( "" );
+ bool found = pProgramCache->LoadFromFile( g_pFullFileSystem, cacheName, "MOD" );
+
+ if ( !found )
+ {
+ Warning( "Could not load program cache file %s\n", cacheName );
+ return false;
+ }
+
+ if ( Q_stricmp( pProgramCache->GetName(), k_pszShaderCacheRootKey ) )
+ {
+ Warning( "Ignoring out-of-date shader cache (%s) with root key %s\n", cacheName, pProgramCache->GetName() );
+ return false;
+ }
+
+ int nTotalLinkedShaders = 0;
+ int nTotalKeyValues = 0;
+
+ // walk the table..
+ FOR_EACH_SUBKEY( pProgramCache, pProgramKey )
+ {
+ nTotalKeyValues++;
+
+ // extract values decribing the specific active pair
+ // then see if either stage needs a compilation done
+ // then proceed to link
+
+ KeyValues *pValue = pProgramKey->GetFirstValue();
+ if (!pValue)
+ continue;
+ const char *pVertexShaderName = pValue->GetString();
+
+ pValue = pValue->GetNextValue();
+ if (!pValue)
+ continue;
+ const char *pPixelShaderName = pValue->GetString();
+
+ pValue = pValue->GetNextValue();
+ if (!pValue)
+ continue;
+ int nVertexShaderStaticIndex = pValue->GetInt();
+
+ pValue = pValue->GetNextValue();
+ if (!pValue)
+ continue;
+ int nPixelShaderStaticIndex = pValue->GetInt();
+
+ pValue = pValue->GetNextValue();
+ if (!pValue)
+ continue;
+ int nVertexShaderDynamicIndex = pValue->GetInt();
+
+ pValue = pValue->GetNextValue();
+ if (!pValue)
+ continue;
+ int nPixelShaderDynamicIndex = pValue->GetInt();
+
+ ShaderLookup_t vshLookup;
+ vshLookup.m_Name = m_ShaderSymbolTable.AddString( pVertexShaderName ); // TODO: use String() here and catch this odd case
+ vshLookup.m_nStaticIndex = nVertexShaderStaticIndex;
+ VertexShader_t vertexShader = m_VertexShaderDict.Find( vshLookup );
+
+ // if the VS was not found - now is the time to build it
+ if( vertexShader == m_VertexShaderDict.InvalidIndex())
+ {
+ char temp[1024];
+
+ V_snprintf( temp, sizeof(temp), "vs-file %s vs-index %d", pVertexShaderName, nVertexShaderStaticIndex );
+ CreateVertexShader( pVertexShaderName, nVertexShaderStaticIndex, temp );
+
+ // this one should not fail
+ vertexShader = m_VertexShaderDict.Find( vshLookup );
+ Assert( vertexShader != m_VertexShaderDict.InvalidIndex());
+ }
+
+ ShaderLookup_t pshLookup;
+ pshLookup.m_Name = m_ShaderSymbolTable.AddString( pPixelShaderName );
+ pshLookup.m_nStaticIndex = nPixelShaderStaticIndex;
+ PixelShader_t pixelShader = m_PixelShaderDict.Find( pshLookup );
+
+ if( pixelShader == m_PixelShaderDict.InvalidIndex())
+ {
+ char temp[1024];
+
+ V_snprintf( temp, sizeof(temp), "ps-file %s ps-index %d", pPixelShaderName, nPixelShaderStaticIndex );
+ CreatePixelShader( pPixelShaderName, nPixelShaderStaticIndex, temp );
+
+ // this one should not fail
+ pixelShader = m_PixelShaderDict.Find( pshLookup );
+ Assert( pixelShader != m_PixelShaderDict.InvalidIndex());
+ }
+
+ // If we found both shaders, do the link!
+ if ( ( vertexShader != m_VertexShaderDict.InvalidIndex() ) && ( pixelShader != m_PixelShaderDict.InvalidIndex() ) )
+ {
+ // double check that the hardware shader arrays are actually instantiated.. bail on the attempt if not (odd...)
+ if (m_VertexShaderDict[vertexShader].m_ShaderStaticCombos.m_pHardwareShaders && m_PixelShaderDict[pixelShader].m_ShaderStaticCombos.m_pHardwareShaders)
+ {
+ // and sanity check the indices..
+ if ( (nVertexShaderDynamicIndex>=0) && (nPixelShaderDynamicIndex>=0) )
+ {
+ HardwareShader_t hardwareVertexShader = m_VertexShaderDict[vertexShader].m_ShaderStaticCombos.m_pHardwareShaders[nVertexShaderDynamicIndex];
+ HardwareShader_t hardwarePixelShader = m_PixelShaderDict[pixelShader].m_ShaderStaticCombos.m_pHardwareShaders[nPixelShaderDynamicIndex];
+
+ if ( ( hardwareVertexShader != INVALID_HARDWARE_SHADER ) && ( hardwarePixelShader != INVALID_HARDWARE_SHADER ) )
+ {
+ if ( S_OK != Dx9Device()->LinkShaderPair( (IDirect3DVertexShader9 *)hardwareVertexShader, (IDirect3DPixelShader9 *)hardwarePixelShader ) )
+ {
+ Warning( "Could not link OpenGL shaders: %s (%d, %d) : %s (%d, %d)\n", pVertexShaderName, nVertexShaderStaticIndex, nVertexShaderDynamicIndex, pPixelShaderName, nPixelShaderStaticIndex, nPixelShaderDynamicIndex );
+ }
+ else
+ {
+ nTotalLinkedShaders++;
+ }
+ }
+ }
+ else
+ {
+ Warning( "nVertexShaderDynamicIndex or nPixelShaderDynamicIndex was negative\n" );
+ }
+ }
+ else
+ {
+ Warning( "m_pHardwareShaders was null\n" );
+ }
+ }
+ else
+ {
+ Warning( "Invalid shader linkage: %s (%d, %d) : %s (%d, %d)\n", pVertexShaderName, nVertexShaderStaticIndex, nVertexShaderDynamicIndex, pPixelShaderName, nPixelShaderStaticIndex, nPixelShaderDynamicIndex );
+ }
+ }
+
+ Msg( "Loaded program cache file \"%s\", total keyvalues: %i, total successfully linked: %i\n", cacheName, nTotalKeyValues, nTotalLinkedShaders );
+
+ return true;
+
+#else
+ return false; // have to return a value on Windows build to appease compiler
+#endif
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Creates and destroys vertex shaders
+//-----------------------------------------------------------------------------
+VertexShader_t CShaderManager::CreateVertexShader( const char *pFileName, int nStaticVshIndex, char *debugLabel )
+{
+ MEM_ALLOC_CREDIT();
+
+ if ( !pFileName )
+ {
+ return INVALID_SHADER;
+ }
+
+ #if 0 //old
+ if ( mat_cacheshaders.GetBool() )
+ {
+ WriteToShaderCache( pFileName, nStaticVshIndex );
+ }
+ #endif
+
+ VertexShader_t shader;
+ ShaderLookup_t lookup;
+ lookup.m_Name = m_ShaderSymbolTable.AddString( pFileName );
+ lookup.m_nStaticIndex = nStaticVshIndex;
+ shader = m_VertexShaderDict.Find( lookup );
+ if ( shader == m_VertexShaderDict.InvalidIndex() )
+ {
+ //printf("\nCShaderManager::CreateVertexShader( filename = %s, staticVshIndex = %d - not in cache", pFileName, nStaticVshIndex );
+
+ shader = m_VertexShaderDict.AddToTail( lookup );
+ if ( !LoadAndCreateShaders( m_VertexShaderDict[shader], true, debugLabel ) )
+ {
+ return INVALID_SHADER;
+ }
+ }
+ m_VertexShaderDict[shader].IncRefCount();
+ return shader;
+}
+
+//-----------------------------------------------------------------------------
+// Create pixel shader
+//-----------------------------------------------------------------------------
+PixelShader_t CShaderManager::CreatePixelShader( const char *pFileName, int nStaticPshIndex, char *debugLabel )
+{
+ MEM_ALLOC_CREDIT();
+
+ if ( !pFileName )
+ {
+ return INVALID_SHADER;
+ }
+
+ #if 0 //old
+ if ( mat_cacheshaders.GetBool() )
+ {
+ WriteToShaderCache( pFileName, nStaticPshIndex );
+ }
+ #endif
+
+ PixelShader_t shader;
+ ShaderLookup_t lookup;
+ lookup.m_Name = m_ShaderSymbolTable.AddString( pFileName );
+ lookup.m_nStaticIndex = nStaticPshIndex;
+ shader = m_PixelShaderDict.Find( lookup );
+ if ( shader == m_PixelShaderDict.InvalidIndex() )
+ {
+ shader = m_PixelShaderDict.AddToTail( lookup );
+ if ( !LoadAndCreateShaders( m_PixelShaderDict[shader], false, debugLabel ) )
+ {
+ return INVALID_SHADER;
+ }
+ }
+ m_PixelShaderDict[shader].IncRefCount();
+ return shader;
+}
+
+//-----------------------------------------------------------------------------
+// Clear the refCounts to zero
+//-----------------------------------------------------------------------------
+void CShaderManager::ClearVertexAndPixelShaderRefCounts()
+{
+ for ( VertexShader_t vshIndex = m_VertexShaderDict.Head();
+ vshIndex != m_VertexShaderDict.InvalidIndex();
+ vshIndex = m_VertexShaderDict.Next( vshIndex ) )
+ {
+ m_VertexShaderDict[vshIndex].m_nRefCount = 0;
+ }
+
+ for ( PixelShader_t pshIndex = m_PixelShaderDict.Head();
+ pshIndex != m_PixelShaderDict.InvalidIndex();
+ pshIndex = m_PixelShaderDict.Next( pshIndex ) )
+ {
+ m_PixelShaderDict[pshIndex].m_nRefCount = 0;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Destroy all shaders that have no reference
+//-----------------------------------------------------------------------------
+void CShaderManager::PurgeUnusedVertexAndPixelShaders()
+{
+ #ifdef DX_TO_GL_ABSTRACTION
+ if (mat_autosave_glshaders.GetInt())
+ {
+ SaveShaderCache("glshaders.cfg");
+ }
+ return; // don't purge shaders, it's too costly to put them back
+ #endif
+
+ // iterate vertex shaders
+ for ( VertexShader_t vshIndex = m_VertexShaderDict.Head(); vshIndex != m_VertexShaderDict.InvalidIndex(); )
+ {
+ Assert( m_VertexShaderDict[vshIndex].m_nRefCount >= 0 );
+
+ // Get the next one before we potentially delete the current one.
+ VertexShader_t next = m_VertexShaderDict.Next( vshIndex );
+ if ( m_VertexShaderDict[vshIndex].m_nRefCount <= 0 )
+ {
+ DestroyVertexShader( vshIndex );
+ }
+ vshIndex = next;
+ }
+
+ // iterate pixel shaders
+ for ( PixelShader_t pshIndex = m_PixelShaderDict.Head(); pshIndex != m_PixelShaderDict.InvalidIndex(); )
+ {
+ Assert( m_PixelShaderDict[pshIndex].m_nRefCount >= 0 );
+
+ // Get the next one before we potentially delete the current one.
+ PixelShader_t next = m_PixelShaderDict.Next( pshIndex );
+ if ( m_PixelShaderDict[pshIndex].m_nRefCount <= 0 )
+ {
+ DestroyPixelShader( pshIndex );
+ }
+ pshIndex = next;
+ }
+}
+
+
+
+void* CShaderManager::GetCurrentVertexShader()
+{
+ return (void*)m_HardwareVertexShader;
+}
+
+void* CShaderManager::GetCurrentPixelShader()
+{
+ return (void*)m_HardwarePixelShader;
+}
+
+
+//-----------------------------------------------------------------------------
+// The low-level dx call to set the vertex shader state
+//-----------------------------------------------------------------------------
+void CShaderManager::SetVertexShaderState( HardwareShader_t shader, DataCacheHandle_t hCachedShader )
+{
+ if ( m_HardwareVertexShader != shader )
+ {
+ RECORD_COMMAND( DX8_SET_VERTEX_SHADER, 1 );
+ RECORD_INT( ( int )shader ); // hack hack hack
+
+ Dx9Device()->SetVertexShader( (IDirect3DVertexShader9*)shader );
+ m_HardwareVertexShader = shader;
+ }
+}
+
+void CShaderManager::BindVertexShader( VertexShaderHandle_t hVertexShader )
+{
+ HardwareShader_t hHardwareShader = m_RawVertexShaderDict[ (VertexShaderIndex_t)hVertexShader] ;
+ SetVertexShaderState( hHardwareShader );
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets a particular vertex shader as the current shader
+//-----------------------------------------------------------------------------
+void CShaderManager::SetVertexShader( VertexShader_t shader )
+{
+ // Determine which vertex shader to use...
+ if ( shader == INVALID_SHADER )
+ {
+ SetVertexShaderState( 0 );
+ return;
+ }
+
+ int vshIndex = m_nVertexShaderIndex;
+ Assert( vshIndex >= 0 );
+ if( vshIndex < 0 )
+ {
+ vshIndex = 0;
+ }
+
+ ShaderLookup_t &vshLookup = m_VertexShaderDict[shader];
+// Warning( "vsh: %s static: %d dynamic: %d\n", m_ShaderSymbolTable.String( vshLookup.m_Name ),
+// vshLookup.m_nStaticIndex, m_nVertexShaderIndex );
+
+#ifdef DYNAMIC_SHADER_COMPILE
+ HardwareShader_t &dxshader = m_VertexShaderDict[shader].m_ShaderStaticCombos.m_pHardwareShaders[vshIndex];
+ if ( dxshader == INVALID_HARDWARE_SHADER )
+ {
+ // compile it since we haven't already!
+ dxshader = CompileShader( m_ShaderSymbolTable.String( vshLookup.m_Name ), vshLookup.m_nStaticIndex, vshIndex, true );
+ Assert( dxshader != INVALID_HARDWARE_SHADER );
+
+ if( IsX360() )
+ {
+ //360 does not respond well at all to bad shaders or Error() calls. So we're staying here until we get something that compiles
+ while( dxshader == INVALID_HARDWARE_SHADER )
+ {
+ Warning( "A dynamically compiled vertex shader has failed to build. Pausing for 5 seconds and attempting rebuild.\n" );
+#ifdef _WIN32
+ Sleep( 5000 );
+#elif POSIX
+ usleep( 5000 );
+#endif
+ dxshader = CompileShader( m_ShaderSymbolTable.String( vshLookup.m_Name ), vshLookup.m_nStaticIndex, vshIndex, true );
+ }
+ }
+ }
+#else
+ if ( vshLookup.m_Flags & SHADER_FAILED_LOAD )
+ {
+ Assert( 0 );
+ return;
+ }
+#ifdef _DEBUG
+ vshDebugIndex = (vshDebugIndex + 1) % MAX_SHADER_HISTORY;
+ Q_strncpy( vshDebugName[vshDebugIndex], m_ShaderSymbolTable.String( vshLookup.m_Name ), sizeof( vshDebugName[0] ) );
+#endif
+ Assert( vshIndex < vshLookup.m_ShaderStaticCombos.m_nCount );
+ HardwareShader_t dxshader = vshLookup.m_ShaderStaticCombos.m_pHardwareShaders[vshIndex];
+#endif
+
+ if ( IsPC() && ( dxshader == INVALID_HARDWARE_SHADER ) && m_bCreateShadersOnDemand )
+ {
+#ifdef DYNAMIC_SHADER_COMPILE
+ ShaderStaticCombos_t::ShaderCreationData_t *pCreationData = &m_VertexShaderDict[shader].m_ShaderStaticCombos.m_pCreationData[vshIndex];
+#else
+ ShaderStaticCombos_t::ShaderCreationData_t *pCreationData = &vshLookup.m_ShaderStaticCombos.m_pCreationData[vshIndex];
+#endif
+
+ dxshader = CreateD3DVertexShader( ( DWORD * )pCreationData->ByteCode.Base(), pCreationData->ByteCode.Count(), m_ShaderSymbolTable.String( vshLookup.m_Name ) );
+
+#ifdef DYNAMIC_SHADER_COMPILE
+ // copy the compiled shader handle back to wherever it's supposed to be stored
+ m_VertexShaderDict[shader].m_ShaderStaticCombos.m_pHardwareShaders[vshIndex] = dxshader;
+#else
+ vshLookup.m_ShaderStaticCombos.m_pHardwareShaders[vshIndex] = dxshader;
+#endif
+ }
+
+ Assert( dxshader );
+
+#ifndef DYNAMIC_SHADER_COMPILE
+ if( !dxshader )
+ {
+ Error( "!!!!!Using invalid shader combo!!!!! Consult a programmer and tell them to build debug materialsystem.dll and stdshader*.dll. Run with \"mat_bufferprimitives 0\" and look for CMaterial in the call stack and see what m_pDebugName is. You are likely using a shader combo that has been skipped.\n" );
+ }
+#endif
+
+ SetVertexShaderState( dxshader );
+}
+
+//-----------------------------------------------------------------------------
+// The low-level dx call to set the pixel shader state
+//-----------------------------------------------------------------------------
+void CShaderManager::SetPixelShaderState( HardwareShader_t shader, DataCacheHandle_t hCachedShader )
+{
+ if ( m_HardwarePixelShader != shader )
+ {
+ Dx9Device()->SetPixelShader( (IDirect3DPixelShader*)shader );
+ m_HardwarePixelShader = shader;
+ }
+}
+
+void CShaderManager::BindPixelShader( PixelShaderHandle_t hPixelShader )
+{
+ HardwareShader_t hHardwareShader = m_RawPixelShaderDict[ (PixelShaderIndex_t)hPixelShader ];
+ SetPixelShaderState( hHardwareShader );
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets a particular pixel shader as the current shader
+//-----------------------------------------------------------------------------
+void CShaderManager::SetPixelShader( PixelShader_t shader )
+{
+ if ( shader == INVALID_SHADER )
+ {
+ SetPixelShaderState( 0 );
+ return;
+ }
+
+ int pshIndex = m_nPixelShaderIndex;
+ Assert( pshIndex >= 0 );
+ ShaderLookup_t &pshLookup = m_PixelShaderDict[shader];
+// Warning( "psh: %s static: %d dynamic: %d\n", m_ShaderSymbolTable.String( pshLookup.m_Name ),
+// pshLookup.m_nStaticIndex, m_nPixelShaderIndex );
+
+#ifdef DYNAMIC_SHADER_COMPILE
+ HardwareShader_t &dxshader = m_PixelShaderDict[shader].m_ShaderStaticCombos.m_pHardwareShaders[pshIndex];
+ if ( dxshader == INVALID_HARDWARE_SHADER )
+ {
+ // compile it since we haven't already!
+ dxshader = CompileShader( m_ShaderSymbolTable.String( pshLookup.m_Name ), pshLookup.m_nStaticIndex, pshIndex, false );
+// Assert( dxshader != INVALID_HARDWARE_SHADER );
+
+ if( IsX360() )
+ {
+ //360 does not respond well at all to bad shaders or Error() calls. So we're staying here until we get something that compiles
+ while( dxshader == INVALID_HARDWARE_SHADER )
+ {
+ Warning( "A dynamically compiled pixel shader has failed to build. Pausing for 5 seconds and attempting rebuild.\n" );
+#ifdef _WIN32
+ Sleep( 5000 );
+#elif POSIX
+ usleep( 5000 );
+#endif
+ dxshader = CompileShader( m_ShaderSymbolTable.String( pshLookup.m_Name ), pshLookup.m_nStaticIndex, pshIndex, false );
+ }
+ }
+ }
+#else
+ if ( pshLookup.m_Flags & SHADER_FAILED_LOAD )
+ {
+ Assert( 0 );
+ return;
+ }
+#ifdef _DEBUG
+ pshDebugIndex = (pshDebugIndex + 1) % MAX_SHADER_HISTORY;
+ Q_strncpy( pshDebugName[pshDebugIndex], m_ShaderSymbolTable.String( pshLookup.m_Name ), sizeof( pshDebugName[0] ) );
+#endif
+ HardwareShader_t dxshader = pshLookup.m_ShaderStaticCombos.m_pHardwareShaders[pshIndex];
+#endif
+
+ if ( IsPC() && ( dxshader == INVALID_HARDWARE_SHADER ) && m_bCreateShadersOnDemand )
+ {
+#ifdef DYNAMIC_SHADER_COMPILE
+ ShaderStaticCombos_t::ShaderCreationData_t *pCreationData = &m_PixelShaderDict[shader].m_ShaderStaticCombos.m_pCreationData[pshIndex];
+#else
+ ShaderStaticCombos_t::ShaderCreationData_t *pCreationData = &pshLookup.m_ShaderStaticCombos.m_pCreationData[pshIndex];
+#endif
+
+ const char *pShaderName = m_ShaderSymbolTable.String( pshLookup.m_Name );
+ dxshader = CreateD3DPixelShader( ( DWORD * )pCreationData->ByteCode.Base(), pCreationData->iCentroidMask, pCreationData->ByteCode.Count(), pShaderName );
+
+#ifdef DYNAMIC_SHADER_COMPILE
+ // copy the compiled shader handle back to wherever it's supposed to be stored
+ m_PixelShaderDict[shader].m_ShaderStaticCombos.m_pHardwareShaders[pshIndex] = dxshader;
+#else
+ pshLookup.m_ShaderStaticCombos.m_pHardwareShaders[pshIndex] = dxshader;
+#endif
+ }
+
+ AssertMsg( dxshader != INVALID_HARDWARE_SHADER, "Failed to set pixel shader." );
+ SetPixelShaderState( dxshader );
+}
+
+//-----------------------------------------------------------------------------
+// Resets the shader state
+//-----------------------------------------------------------------------------
+void CShaderManager::ResetShaderState()
+{
+ // This will force the calls to SetVertexShader + SetPixelShader to actually set the state
+ m_HardwareVertexShader = (HardwareShader_t)-1;
+ m_HardwarePixelShader = (HardwareShader_t)-1;
+
+ SetVertexShader( INVALID_SHADER );
+ SetPixelShader( INVALID_SHADER );
+}
+
+//-----------------------------------------------------------------------------
+// Destroy a particular vertex shader
+//-----------------------------------------------------------------------------
+void CShaderManager::DestroyVertexShader( VertexShader_t shader )
+{
+ ShaderStaticCombos_t &combos = m_VertexShaderDict[shader].m_ShaderStaticCombos;
+ int i;
+ for ( i = 0; i < combos.m_nCount; i++ )
+ {
+ if ( combos.m_pHardwareShaders[i] != INVALID_HARDWARE_SHADER )
+ {
+ IDirect3DVertexShader9* pShader = ( IDirect3DVertexShader9 * )combos.m_pHardwareShaders[i];
+ UnregisterVS( pShader );
+#ifdef DBGFLAG_ASSERT
+ int nRetVal =
+#endif
+ pShader->Release();
+ Assert( nRetVal == 0 );
+ }
+ }
+ delete [] combos.m_pHardwareShaders;
+ combos.m_pHardwareShaders = NULL;
+
+ if ( combos.m_pCreationData != NULL )
+ {
+ delete [] combos.m_pCreationData;
+ combos.m_pCreationData = NULL;
+ }
+
+ m_VertexShaderDict.Remove( shader );
+}
+
+//-----------------------------------------------------------------------------
+// Destroy a particular pixel shader
+//-----------------------------------------------------------------------------
+void CShaderManager::DestroyPixelShader( PixelShader_t pixelShader )
+{
+ ShaderStaticCombos_t &combos = m_PixelShaderDict[pixelShader].m_ShaderStaticCombos;
+ int i;
+ for ( i = 0; i < combos.m_nCount; i++ )
+ {
+ if ( combos.m_pHardwareShaders[i] != INVALID_HARDWARE_SHADER )
+ {
+ IDirect3DPixelShader* pShader = ( IDirect3DPixelShader * )combos.m_pHardwareShaders[i];
+ UnregisterPS( pShader );
+#ifdef DBGFLAG_ASSERT
+ int nRetVal =
+#endif
+ pShader->Release();
+ Assert( nRetVal == 0 );
+ }
+ }
+ delete [] combos.m_pHardwareShaders;
+ combos.m_pHardwareShaders = NULL;
+
+ if ( combos.m_pCreationData != NULL )
+ {
+ delete [] combos.m_pCreationData;
+ combos.m_pCreationData = NULL;
+ }
+
+ m_PixelShaderDict.Remove( pixelShader );
+}
+
+
+//-----------------------------------------------------------------------------
+// Destroys all shaders
+//-----------------------------------------------------------------------------
+void CShaderManager::DestroyAllShaders( void )
+{
+ // Remarking this out because it's conflicting with dxabstract's shutdown resource leak detection code (we leak thousands of shaders at shutdown with this in place).
+ // I see no reason why we would want to do this in D3D9 but not GL?
+//#ifdef DX_TO_GL_ABSTRACTION
+// return;
+//#endif
+
+ for ( VertexShader_t vshIndex = m_VertexShaderDict.Head();
+ vshIndex != m_VertexShaderDict.InvalidIndex(); )
+ {
+ Assert( m_VertexShaderDict[vshIndex].m_nRefCount >= 0 );
+ VertexShader_t next = m_VertexShaderDict.Next( vshIndex );
+ DestroyVertexShader( vshIndex );
+ vshIndex = next;
+ }
+
+ for ( PixelShader_t pshIndex = m_PixelShaderDict.Head();
+ pshIndex != m_PixelShaderDict.InvalidIndex(); )
+ {
+ Assert( m_PixelShaderDict[pshIndex].m_nRefCount >= 0 );
+ PixelShader_t next = m_PixelShaderDict.Next( pshIndex );
+ DestroyPixelShader( pshIndex );
+ pshIndex = next;
+ }
+
+ // invalidate the file cache
+ m_ShaderFileCache.Purge();
+}
+
+//-----------------------------------------------------------------------------
+// print all vertex and pixel shaders along with refcounts to the console
+//-----------------------------------------------------------------------------
+void CShaderManager::SpewVertexAndPixelShaders( void )
+{
+ // only spew a populated shader file cache
+ Msg( "\nShader File Cache:\n" );
+ for ( int cacheIndex = m_ShaderFileCache.Head();
+ cacheIndex != m_ShaderFileCache.InvalidIndex();
+ cacheIndex = m_ShaderFileCache.Next( cacheIndex ) )
+ {
+ ShaderFileCache_t *pCache = &m_ShaderFileCache[cacheIndex];
+ Msg( "Total Combos:%9d Static:%9d Dynamic:%7d SeekTable:%7d Ver:%d '%s'\n",
+ pCache->m_Header.m_nTotalCombos,
+ pCache->m_Header.m_nTotalCombos/pCache->m_Header.m_nDynamicCombos,
+ pCache->m_Header.m_nDynamicCombos,
+ pCache->IsOldVersion() ? 0 : pCache->m_Header.m_nNumStaticCombos,
+ pCache->m_Header.m_nVersion,
+ m_ShaderSymbolTable.String( pCache->m_Filename ) );
+ }
+ Msg( "\n" );
+
+ // spew vertex shader dictionary
+ int totalVertexShaders = 0;
+ int totalVertexShaderSets = 0;
+ for ( VertexShader_t vshIndex = m_VertexShaderDict.Head();
+ vshIndex != m_VertexShaderDict.InvalidIndex();
+ vshIndex = m_VertexShaderDict.Next( vshIndex ) )
+ {
+ const ShaderLookup_t &lookup = m_VertexShaderDict[vshIndex];
+ const char *pName = m_ShaderSymbolTable.String( lookup.m_Name );
+ Msg( "vsh 0x%8.8x: static combo:%9d dynamic combos:%6d refcount:%4d \"%s\"\n", vshIndex,
+ ( int )lookup.m_nStaticIndex, ( int )lookup.m_ShaderStaticCombos.m_nCount,
+ lookup.m_nRefCount, pName );
+ totalVertexShaders += lookup.m_ShaderStaticCombos.m_nCount;
+ totalVertexShaderSets++;
+ }
+
+ // spew pixel shader dictionary
+ int totalPixelShaders = 0;
+ int totalPixelShaderSets = 0;
+ for ( PixelShader_t pshIndex = m_PixelShaderDict.Head();
+ pshIndex != m_PixelShaderDict.InvalidIndex();
+ pshIndex = m_PixelShaderDict.Next( pshIndex ) )
+ {
+ const ShaderLookup_t &lookup = m_PixelShaderDict[pshIndex];
+ const char *pName = m_ShaderSymbolTable.String( lookup.m_Name );
+ Msg( "psh 0x%8.8x: static combo:%9d dynamic combos:%6d refcount:%4d \"%s\"\n", pshIndex,
+ ( int )lookup.m_nStaticIndex, ( int )lookup.m_ShaderStaticCombos.m_nCount,
+ lookup.m_nRefCount, pName );
+ totalPixelShaders += lookup.m_ShaderStaticCombos.m_nCount;
+ totalPixelShaderSets++;
+ }
+
+ Msg( "Total unique vertex shaders: %d\n", totalVertexShaders );
+ Msg( "Total vertex shader sets: %d\n", totalVertexShaderSets );
+ Msg( "Total unique pixel shaders: %d\n", totalPixelShaders );
+ Msg( "Total pixel shader sets: %d\n", totalPixelShaderSets );
+}
+
+CON_COMMAND( mat_spewvertexandpixelshaders, "Print all vertex and pixel shaders currently loaded to the console" )
+{
+ ( ( CShaderManager * )ShaderManager() )->SpewVertexAndPixelShaders();
+}
+
+const char *CShaderManager::GetActiveVertexShaderName()
+{
+#if !defined( _DEBUG )
+ return "";
+#else
+ if ( !m_HardwareVertexShader )
+ {
+ return "NULL";
+ }
+ return vshDebugName[vshDebugIndex];
+#endif
+}
+
+const char *CShaderManager::GetActivePixelShaderName()
+{
+#if !defined( _DEBUG )
+ return "";
+#else
+ if ( !m_HardwarePixelShader )
+ {
+ return "NULL";
+ }
+ return pshDebugName[pshDebugIndex];
+#endif
+}
+
+#ifdef DYNAMIC_SHADER_COMPILE
+void CShaderManager::FlushShaders( void )
+{
+ for( VertexShader_t shader = m_VertexShaderDict.Head();
+ shader != m_VertexShaderDict.InvalidIndex();
+ shader = m_VertexShaderDict.Next( shader ) )
+ {
+ int i;
+ ShaderStaticCombos_t &combos = m_VertexShaderDict[shader].m_ShaderStaticCombos;
+ for( i = 0; i < combos.m_nCount; i++ )
+ {
+ if( combos.m_pHardwareShaders[i] != INVALID_HARDWARE_SHADER )
+ {
+#ifdef _DEBUG
+ int nRetVal=
+#endif
+ ( ( IDirect3DVertexShader9 * )combos.m_pHardwareShaders[i] )->Release();
+ Assert( nRetVal == 0 );
+ }
+ combos.m_pHardwareShaders[i] = INVALID_HARDWARE_SHADER;
+ }
+ }
+
+ for( PixelShader_t shader = m_PixelShaderDict.Head();
+ shader != m_PixelShaderDict.InvalidIndex();
+ shader = m_PixelShaderDict.Next( shader ) )
+ {
+ int i;
+ ShaderStaticCombos_t &combos = m_PixelShaderDict[shader].m_ShaderStaticCombos;
+ for( i = 0; i < combos.m_nCount; i++ )
+ {
+ if( combos.m_pHardwareShaders[i] != INVALID_HARDWARE_SHADER )
+ {
+#ifdef _DEBUG
+ int nRetVal =
+#endif
+ ( ( IDirect3DPixelShader * )combos.m_pHardwareShaders[i] )->Release();
+ Assert( nRetVal == 0 );
+ }
+ combos.m_pHardwareShaders[i] = INVALID_HARDWARE_SHADER;
+ }
+ }
+
+ // invalidate the file cache
+ m_ShaderFileCache.Purge();
+}
+#endif
+
+#ifdef DYNAMIC_SHADER_COMPILE
+static void MatFlushShaders( void )
+{
+#if defined( _X360 )
+ XBX_rSyncShaderCache();
+#endif
+ ( ( CShaderManager * )ShaderManager() )->FlushShaders();
+}
+#endif
+
+#ifdef DYNAMIC_SHADER_COMPILE
+CON_COMMAND( mat_flushshaders, "flush all hardware shaders when using DYNAMIC_SHADER_COMPILE" )
+{
+ MatFlushShaders();
+}
+#endif
+
+CON_COMMAND( mat_shadercount, "display count of all shaders and reset that count" )
+{
+ Warning( "Num Pixel Shaders = %d Vertex Shaders=%d\n", s_NumPixelShadersCreated, s_NumVertexShadersCreated );
+ s_NumVertexShadersCreated = 0;
+ s_NumPixelShadersCreated = 0;
+}
+
+#if defined( DX_TO_GL_ABSTRACTION )
+void CShaderManager::DoStartupShaderPreloading()
+{
+ if (mat_autoload_glshaders.GetInt())
+ {
+ double flStartTime = Plat_FloatTime();
+
+ s_NumVertexShadersCreated = s_NumPixelShadersCreated = 0;
+
+ // try base file
+#ifdef OSX
+ if ( !LoadShaderCache("glbaseshaders_osx.cfg") ) // factory cache
+#else
+ if ( !LoadShaderCache("glbaseshaders.cfg") ) // factory cache
+#endif
+ {
+ Warning( "Could not find base GL shader cache file\n" );
+ }
+
+ if ( !LoadShaderCache("glshaders.cfg") ) // user mutable cache
+ {
+ Warning( "Could not find user GL shader cache file\n" );
+ }
+
+ double flEndTime = Plat_FloatTime();
+ Msg( "Precache: Took %d ms, Vertex %d, Pixel %d\n", ( int )( ( flEndTime - flStartTime ) * 1000.0 ), s_NumVertexShadersCreated, s_NumPixelShadersCreated );
+ }
+}
+#endif
+
diff --git a/materialsystem/shaderapidx9/vertexshaderdx8.h b/materialsystem/shaderapidx9/vertexshaderdx8.h
new file mode 100644
index 0000000..5483eec
--- /dev/null
+++ b/materialsystem/shaderapidx9/vertexshaderdx8.h
@@ -0,0 +1,135 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#ifndef VERTEXSHADERDX8_H
+#define VERTEXSHADERDX8_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "shaderapi/ishaderapi.h"
+#include "locald3dtypes.h"
+
+
+// uncomment to get dynamic compilation for HLSL shaders
+// X360 NOTE: By default, the system looks for a shared folder named "stdshaders" on the host machine and is completely compatible with -dvd. Ensure that the share is writable if you plan on generating UPDB's.
+//#define DYNAMIC_SHADER_COMPILE
+
+// Uncomment to use remoteshadercompiler.exe as a shader compile server
+// Must also set mat_remoteshadercompile to remote shader compile machine name
+//#define REMOTE_DYNAMIC_SHADER_COMPILE
+
+// uncomment to get spew about what combos are being compiled.
+//#define DYNAMIC_SHADER_COMPILE_VERBOSE
+
+// Uncomment to use remoteshadercompiler.exe as a shader compile server
+// Must also set mat_remoteshadercompile to remote shader compile machine name
+//#define REMOTE_DYNAMIC_SHADER_COMPILE
+
+// uncomment and fill in with a path to use a specific set of shader source files. Meant for network use.
+// PC path format is of style "\\\\somemachine\\sourcetreeshare\\materialsystem\\stdshaders"
+// Xbox path format is of style "net:\\smb\\somemachine\\sourcetreeshare\\materialsystem\\stdshaders"
+// - Xbox dynamic compiles without a custom path default to look directly for "stdshaders" share on host pc
+
+//#define DYNAMIC_SHADER_COMPILE_CUSTOM_PATH ""
+
+// uncomment to get disassembled (asm) shader code in your game dir as *.asm
+//#define DYNAMIC_SHADER_COMPILE_WRITE_ASSEMBLY
+
+// uncomment to get disassembled (asm) shader code in your game dir as *.asm
+//#define WRITE_ASSEMBLY
+
+
+enum VertexShaderLightTypes_t
+{
+ LIGHT_NONE = -1,
+ LIGHT_SPOT = 0,
+ LIGHT_POINT = 1,
+ LIGHT_DIRECTIONAL = 2,
+ LIGHT_STATIC = 3,
+ LIGHT_AMBIENTCUBE = 4,
+};
+
+//-----------------------------------------------------------------------------
+// Vertex + pixel shader manager
+//-----------------------------------------------------------------------------
+abstract_class IShaderManager
+{
+protected:
+
+ // The current vertex and pixel shader index
+ int m_nVertexShaderIndex;
+ int m_nPixelShaderIndex;
+
+public:
+ // Initialize, shutdown
+ virtual void Init() = 0;
+ virtual void Shutdown() = 0;
+
+ // Compiles vertex shaders
+ virtual IShaderBuffer *CompileShader( const char *pProgram, size_t nBufLen, const char *pShaderVersion ) = 0;
+
+ // New version of these methods [dx10 port]
+ virtual VertexShaderHandle_t CreateVertexShader( IShaderBuffer* pShaderBuffer ) = 0;
+ virtual void DestroyVertexShader( VertexShaderHandle_t hShader ) = 0;
+ virtual PixelShaderHandle_t CreatePixelShader( IShaderBuffer* pShaderBuffer ) = 0;
+ virtual void DestroyPixelShader( PixelShaderHandle_t hShader ) = 0;
+
+ // Creates vertex, pixel shaders
+ virtual VertexShader_t CreateVertexShader( const char *pVertexShaderFile, int nStaticVshIndex = 0, char *debugLabel = NULL ) = 0;
+ virtual PixelShader_t CreatePixelShader( const char *pPixelShaderFile, int nStaticPshIndex = 0, char *debugLabel = NULL ) = 0;
+
+ // Sets which dynamic version of the vertex + pixel shader to use
+ FORCEINLINE void SetVertexShaderIndex( int vshIndex );
+ FORCEINLINE void SetPixelShaderIndex( int pshIndex );
+
+ // Sets the vertex + pixel shader render state
+ virtual void SetVertexShader( VertexShader_t shader ) = 0;
+ virtual void SetPixelShader( PixelShader_t shader ) = 0;
+
+ // Resets the vertex + pixel shader state
+ virtual void ResetShaderState() = 0;
+
+ // Returns the current vertex + pixel shaders
+ virtual void *GetCurrentVertexShader() = 0;
+ virtual void *GetCurrentPixelShader() = 0;
+
+ virtual void ClearVertexAndPixelShaderRefCounts() = 0;
+ virtual void PurgeUnusedVertexAndPixelShaders() = 0;
+
+ // The low-level dx call to set the vertex shader state
+ virtual void BindVertexShader( VertexShaderHandle_t shader ) = 0;
+ virtual void BindPixelShader( PixelShaderHandle_t shader ) = 0;
+
+#if defined( _X360 )
+ virtual const char *GetActiveVertexShaderName() = 0;
+ virtual const char *GetActivePixelShaderName() = 0;
+#endif
+
+#if defined( DX_TO_GL_ABSTRACTION )
+ virtual void DoStartupShaderPreloading() = 0;
+#endif
+};
+
+//-----------------------------------------------------------------------------
+//
+// Methods related to setting vertex + pixel shader state
+//
+//-----------------------------------------------------------------------------
+FORCEINLINE void IShaderManager::SetVertexShaderIndex( int vshIndex )
+{
+ m_nVertexShaderIndex = vshIndex;
+}
+
+FORCEINLINE void IShaderManager::SetPixelShaderIndex( int pshIndex )
+{
+ m_nPixelShaderIndex = pshIndex;
+}
+
+#endif // VERTEXSHADERDX8_H
diff --git a/materialsystem/shaderapidx9/winutils.cpp b/materialsystem/shaderapidx9/winutils.cpp
new file mode 100644
index 0000000..5da2493
--- /dev/null
+++ b/materialsystem/shaderapidx9/winutils.cpp
@@ -0,0 +1,93 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// winutils.cpp
+//
+//===========================================================================//
+
+#include "winutils.h"
+
+#ifndef _WIN32
+
+#include "appframework/ilaunchermgr.h"
+
+// LINUX path taken from //Steam/main/src/tier0/platform_posix.cpp - Returns installed RAM in MB.
+static unsigned long GetInstalledRAM()
+{
+ unsigned long ulTotalRamMB = 2047;
+
+#ifdef LINUX
+ char rgchLine[256];
+ FILE *fpMemInfo = fopen( "/proc/meminfo", "r" );
+ if ( !fpMemInfo )
+ return ulTotalRamMB;
+
+ const char *pszSearchString = "MemTotal:";
+ const uint cchSearchString = strlen( pszSearchString );
+ while ( fgets( rgchLine, sizeof(rgchLine), fpMemInfo ) )
+ {
+ if ( !strncasecmp( pszSearchString, rgchLine, cchSearchString ) )
+ {
+ char *pszVal = rgchLine+cchSearchString;
+ while( isspace(*pszVal) )
+ ++pszVal;
+ ulTotalRamMB = atol( pszVal ) / 1024; // go from kB to MB
+ break;
+ }
+ }
+ fclose( fpMemInfo );
+#endif
+
+ // 128 Gb limit for now (should future proof us for a while)
+ ulTotalRamMB = MIN( ulTotalRamMB, 1024 * 128 );
+ return ulTotalRamMB;
+}
+
+void GlobalMemoryStatus( MEMORYSTATUS *pOut )
+{
+ unsigned long nInstalledRamInMB = GetInstalledRAM();
+
+ // For safety assume at least 128MB
+ nInstalledRamInMB = MAX( nInstalledRamInMB, 128 );
+
+ uint64 ulTotalRam = static_cast<uint64>( nInstalledRamInMB ) * ( 1024 * 1024 );
+ ulTotalRam = MIN( ulTotalRam, 0xFFFFFFFF );
+
+ pOut->dwTotalPhys = static_cast<SIZE_T>( ulTotalRam );
+}
+
+void Sleep( unsigned int ms )
+{
+ DebuggerBreak();
+ ThreadSleep( ms );
+}
+
+bool IsIconic( VD3DHWND hWnd )
+{
+ // FIXME for now just act non-minimized all the time
+ //DebuggerBreak();
+ return false;
+}
+
+BOOL ClientToScreen( VD3DHWND hWnd, LPPOINT pPoint )
+{
+ DebuggerBreak();
+ return true;
+}
+
+void* GetCurrentThread()
+{
+ DebuggerBreak();
+ return 0;
+}
+
+void SetThreadAffinityMask( void *hThread, int nMask )
+{
+ DebuggerBreak();
+}
+
+bool GUID::operator==( const struct _GUID &other ) const
+{
+ DebuggerBreak();
+ return memcmp( this, &other, sizeof( GUID ) ) == 0;
+}
+#endif
diff --git a/materialsystem/shaderapidx9/winutils.h b/materialsystem/shaderapidx9/winutils.h
new file mode 100644
index 0000000..0874fba
--- /dev/null
+++ b/materialsystem/shaderapidx9/winutils.h
@@ -0,0 +1,21 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+//
+//
+//==================================================================================================
+#ifndef WINUTILS_H
+#define WINUTILS_H
+
+#include "togl/rendermechanism.h" // for win types
+
+#if !defined(_WIN32)
+
+ void Sleep( unsigned int ms );
+ bool IsIconic( VD3DHWND hWnd );
+ BOOL ClientToScreen( VD3DHWND hWnd, LPPOINT pPoint );
+ void* GetCurrentThread();
+ void SetThreadAffinityMask( void *hThread, int nMask );
+ void GlobalMemoryStatus( MEMORYSTATUS *pOut );
+#endif
+
+#endif // WINUTILS_H
diff --git a/materialsystem/shaderapidx9/wmi.cpp b/materialsystem/shaderapidx9/wmi.cpp
new file mode 100644
index 0000000..1b0644f
--- /dev/null
+++ b/materialsystem/shaderapidx9/wmi.cpp
@@ -0,0 +1,182 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "resource.h"
+
+// Avoid conflicts with MSVC headers and memdbgon.h
+#undef PROTECTED_THINGS_ENABLE
+#include "basetypes.h"
+
+#define _WIN32_DCOM
+#include <comdef.h>
+#pragma warning( disable : 4127 ) // VS 2010 warning?
+#pragma warning( disable : 4805 ) // VS 2013 warning: warning C4805: '==' : unsafe mix of type 'INT' and type 'bool' in operation
+#include <atlcomtime.h>
+#pragma warning( default : 4805 )
+#pragma warning( default : 4127 )
+#include <wbemidl.h>
+
+// NOTE: This has to be the last file included!
+#include "tier0/memdbgon.h"
+
+
+# pragma comment(lib, "wbemuuid.lib")
+
+uint64 GetVidMemBytes( void )
+{
+ static int bBeenHere = false;
+ static uint64 nBytes = 0;
+
+ if( bBeenHere )
+ {
+ return nBytes;
+ }
+
+ bBeenHere = true;
+
+ // Initialize COM
+ HRESULT hr = CoInitialize( NULL );
+ if ( FAILED( hr ) )
+ {
+ OutputDebugString ( "GetWMIDeviceStats - Unable to initialize COM library.\n");
+ return 0;
+ }
+
+ // Obtain the initial locator to WMI
+ IWbemLocator *pLoc = NULL;
+
+ hr = CoCreateInstance(
+ CLSID_WbemLocator,
+ 0,
+ CLSCTX_INPROC_SERVER,
+ IID_IWbemLocator, (LPVOID *) &pLoc);
+
+ if ( FAILED( hr ) )
+ {
+ OutputDebugString ( "GetWMIDeviceStats - Failed to create IWbemLocator object.\n");
+ CoUninitialize();
+ return 0;
+ }
+
+ // Connect to WMI through the IWbemLocator::ConnectServer method
+
+ IWbemServices *pSvc = NULL;
+
+ // Connect to the root\cimv2 namespace with
+ // the current user and obtain pointer pSvc
+ // to make IWbemServices calls.
+ hr = pLoc->ConnectServer(
+ _bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
+ NULL, // User name. NULL = current user
+ NULL, // User password. NULL = current
+ 0, // Locale. NULL indicates current
+ NULL, // Security flags.
+ 0, // Authority (e.g. Kerberos)
+ 0, // Context object
+ &pSvc // pointer to IWbemServices proxy
+ );
+
+ if ( FAILED( hr ) )
+ {
+ OutputDebugString ( "GetWMIDeviceStats - Could not connect.\n");
+ pLoc->Release();
+ CoUninitialize();
+ return 0;
+ }
+
+// OutputDebugString ( L"GetWMIDeviceStats - Connected to ROOT\\CIMV2 WMI namespace\n");
+
+
+ // Set security levels on the proxy
+
+ hr = CoSetProxyBlanket(
+ pSvc, // Indicates the proxy to set
+ RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx
+ RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx
+ NULL, // Server principal name
+ RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx
+ RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
+ NULL, // client identity
+ EOAC_NONE // proxy capabilities
+ );
+
+ if ( FAILED( hr ) )
+ {
+ OutputDebugString ( "GetWMIDeviceStats - Could not set proxy blanket.\n");
+ pSvc->Release();
+ pLoc->Release();
+ CoUninitialize();
+ return 0;
+ }
+
+
+ // Use the IWbemServices pointer to make requests of WMI
+
+ //
+ // --- Win32_VideoController --------------------------------------------------
+ //
+
+ IEnumWbemClassObject* pEnumerator = NULL;
+ hr = pSvc->ExecQuery( bstr_t("WQL"), bstr_t("SELECT * FROM Win32_VideoController"),
+ WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
+
+ if ( FAILED( hr ) )
+ {
+ OutputDebugString ( "GetWMIDeviceStats - Query for Win32_VideoController failed.\n");
+
+ pSvc->Release();
+ pLoc->Release();
+ CoUninitialize();
+ return 0;
+ }
+
+
+ // Get the data from the above query
+ IWbemClassObject *pclsObj = NULL;
+ ULONG uReturn = 0;
+
+ while ( pEnumerator )
+ {
+ HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
+
+ if(0 == uReturn)
+ {
+ break;
+ }
+
+ VARIANT vtProp;
+ VariantInit(&vtProp);
+
+ // Pluck a series of properties out of the query from Win32_VideoController
+
+// hr = pclsObj->Get(L"Description", 0, &vtProp, 0, 0); // Basically the same as "VideoProcessor"
+// if ( SUCCEEDED( hr ) )
+// {
+// wsprintf( pAdapter->m_szPrimaryAdapterDescription, vtProp.bstrVal );
+// }
+
+ hr = pclsObj->Get(L"AdapterRAM", 0, &vtProp, 0, 0);
+ if ( SUCCEEDED( hr ) )
+ {
+ nBytes = vtProp.ulVal; // Video RAM in bytes, AdatperRam is returned as the I4 type so we read it out as unsigned int,
+ // see http://msdn.microsoft.com/en-us/library/windows/desktop/aa394512(v=vs.85).aspx
+ }
+
+ VariantClear(&vtProp);
+ }
+
+ // Cleanup
+ pSvc->Release();
+ pLoc->Release();
+ pEnumerator->Release();
+ if ( pclsObj )
+ {
+ pclsObj->Release();
+ }
+ CoUninitialize();
+
+ return nBytes;
+}
diff --git a/materialsystem/shaderapidx9/wmi.h b/materialsystem/shaderapidx9/wmi.h
new file mode 100644
index 0000000..8f8fe13
--- /dev/null
+++ b/materialsystem/shaderapidx9/wmi.h
@@ -0,0 +1,17 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#ifndef WMI_H
+#define WMI_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+uint64 GetVidMemBytes( void );
+
+
+#endif // WMI_H
diff --git a/materialsystem/shaderapidx9/xbox/xbox.def b/materialsystem/shaderapidx9/xbox/xbox.def
new file mode 100644
index 0000000..231fd7c
--- /dev/null
+++ b/materialsystem/shaderapidx9/xbox/xbox.def
@@ -0,0 +1,3 @@
+LIBRARY shaderapidx9_360.dll
+EXPORTS
+ CreateInterface @1