📄 transitiontable.cpp
字号:
//-----------------------------------------------------------------------------
// Apply shader state (stuff that doesn't lie in the transition table)
//-----------------------------------------------------------------------------
void CTransitionTable::ApplyShaderState( const ShadowState_t &shadowState, const ShadowShaderState_t &shaderState )
{
// 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, shaderState.m_nStaticVshIndex );
ShaderManager()->SetPixelShader( shaderState.m_PixelShader, shaderState.m_nStaticPshIndex );
#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_VERTEX_SHADER );
ShaderManager()->SetPixelShader( INVALID_PIXEL_SHADER );
#ifdef DEBUG_BOARD_STATE
BoardShaderState().m_VertexShader = INVALID_VERTEX_SHADER;
BoardShaderState().m_PixelShader = INVALID_PIXEL_SHADER;
BoardShaderState().m_nStaticVshIndex = 0;
BoardShaderState().m_nStaticPshIndex = 0;
#endif
}
}
//-----------------------------------------------------------------------------
// Makes the board state match the snapshot
//-----------------------------------------------------------------------------
void CTransitionTable::UseSnapshot( StateSnapshot_t snapshotId )
{
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( )
{
// 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;
SetRenderState( D3DRS_ALPHABLENDENABLE, m_CurrentState.m_AlphaBlendEnable );
SetRenderState( D3DRS_SRCBLEND, m_CurrentState.m_SrcBlend );
SetRenderState( D3DRS_DESTBLEND, m_CurrentState.m_DestBlend );
// GR
m_CurrentState.m_SeparateAlphaBlendEnable = false;
m_CurrentState.m_SrcBlendAlpha = D3DBLEND_ONE;
m_CurrentState.m_DestBlendAlpha = D3DBLEND_ZERO;
SetRenderState( D3DRS_SEPARATEALPHABLENDENABLE, m_CurrentState.m_SeparateAlphaBlendEnable );
SetRenderState( D3DRS_SRCBLENDALPHA, m_CurrentState.m_SrcBlendAlpha );
SetRenderState( D3DRS_DESTBLENDALPHA, m_CurrentState.m_DestBlendAlpha );
int nTextureUnits = ShaderAPI()->GetActualNumTextureUnits();
for ( int i = 0; i < nTextureUnits; ++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 );
}
// Disable z overrides...
m_CurrentState.m_bOverrideDepthEnable = false;
m_CurrentState.m_ForceDepthFuncEquals = false;
ApplyTransition( m_DefaultTransition, m_DefaultStateSnapshot );
ShaderManager()->SetVertexShader( INVALID_VERTEX_SHADER );
ShaderManager()->SetPixelShader( INVALID_PIXEL_SHADER );
}
//-----------------------------------------------------------------------------
// 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 )
{
SetRenderState( D3DRS_ZFUNC, D3DCMP_EQUAL );
}
else
{
SetRenderState( D3DRS_ZFUNC, 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 )
{
SetRenderState( D3DRS_ZENABLE, D3DZB_TRUE );
SetRenderState( D3DRS_ZWRITEENABLE, m_CurrentState.m_OverrideZWriteEnable );
}
else
{
SetRenderState( D3DRS_ZENABLE, CurrentShadowState().m_ZEnable );
SetRenderState( D3DRS_ZWRITEENABLE, CurrentShadowState().m_ZFunc );
}
}
}
//-----------------------------------------------------------------------------
// Perform state block overrides
//-----------------------------------------------------------------------------
void CTransitionTable::PerformShadowStateOverrides( )
{
// Deal with funky overrides here, because the state blocks can't...
if ( m_CurrentState.m_ForceDepthFuncEquals )
{
SetRenderState( D3DRS_ZFUNC, D3DCMP_EQUAL );
}
if ( m_CurrentState.m_bOverrideDepthEnable )
{
SetRenderState( D3DRS_ZENABLE, D3DZB_TRUE );
SetRenderState( D3DRS_ZWRITEENABLE, m_CurrentState.m_OverrideZWriteEnable );
}
}
//-----------------------------------------------------------------------------
// Finds identical transition lists and shares them
//-----------------------------------------------------------------------------
#define TEST_RENDER_STATEBLOCK_VALUE( _state ) \
if( pOp->m_Op == ::Apply ## _state ) \
{ \
if ( state1.m_ ## _state == state2.m_ ## _state ) \
continue; \
return false; \
}
#define TEST_TEXTURE_STATEBLOCK_VALUE( _state, _stage ) \
if( pOp->m_Op == ::Apply ## _state ) \
{ \
if ( state1.m_TextureStage[_stage].m_ ## _state == state2.m_TextureStage[_stage].m_ ## _state ) \
continue; \
return false; \
}
bool CTransitionTable::DoStateBlocksMatch( const TransitionList_t *pTransition, int nToSnapshot1, int nToSnapshot2 ) const
{
// We know they are the same if the dest snapshot is identical
if ( nToSnapshot1 == nToSnapshot2 )
return true;
// FIXME: This is gross!!
// Otherwise we gotta check the values associated with each state-setting method
const TransitionOp_t *pOp = &m_TransitionOps[pTransition->m_FirstOperation];
const ShadowState_t &state1 = m_ShadowStateList[nToSnapshot1];
const ShadowState_t &state2 = m_ShadowStateList[nToSnapshot2];
for ( int k = 0; k < pTransition->m_nOpCountInStateBlock; ++k, ++pOp )
{
TEST_RENDER_STATEBLOCK_VALUE( ZFunc );
TEST_RENDER_STATEBLOCK_VALUE( ZEnable );
TEST_RENDER_STATEBLOCK_VALUE( ZWriteEnable );
TEST_RENDER_STATEBLOCK_VALUE( ColorWriteEnable );
TEST_RENDER_STATEBLOCK_VALUE( AlphaTestEnable );
TEST_RENDER_STATEBLOCK_VALUE( AlphaFunc );
TEST_RENDER_STATEBLOCK_VALUE( AlphaRef );
TEST_RENDER_STATEBLOCK_VALUE( FillMode );
TEST_RENDER_STATEBLOCK_VALUE( Lighting );
TEST_RENDER_STATEBLOCK_VALUE( SpecularEnable );
TEST_RENDER_STATEBLOCK_VALUE( SRGBWriteEnable );
TEST_RENDER_STATEBLOCK_VALUE( AlphaBlendEnable );
TEST_RENDER_STATEBLOCK_VALUE( SrcBlend );
TEST_RENDER_STATEBLOCK_VALUE( DestBlend );
TEST_TEXTURE_STATEBLOCK_VALUE( TexCoordIndex, pOp->m_Argument );
TEST_TEXTURE_STATEBLOCK_VALUE( ColorOp, pOp->m_Argument );
TEST_TEXTURE_STATEBLOCK_VALUE( ColorArg1, pOp->m_Argument );
TEST_TEXTURE_STATEBLOCK_VALUE( ColorArg2, pOp->m_Argument );
TEST_TEXTURE_STATEBLOCK_VALUE( AlphaOp, pOp->m_Argument );
TEST_TEXTURE_STATEBLOCK_VALUE( AlphaArg1, pOp->m_Argument );
TEST_TEXTURE_STATEBLOCK_VALUE( AlphaArg2, pOp->m_Argument );
// Should never get here!
Assert( 0 );
}
return true;
}
//-----------------------------------------------------------------------------
// Finds identical transition lists and shares them
//-----------------------------------------------------------------------------
IDirect3DStateBlock9 *CTransitionTable::FindIdenticalStateBlock( TransitionList_t *pTransition, int toSnapshot ) const
{
Assert( pTransition );
// FIXME: Could we bake this into the identical transition list test?
for ( int to = m_TransitionTable.Count(); --to >= 0; )
{
for ( int from = m_TransitionTable[to].Count(); --from >= 0; )
{
const TransitionList_t *pTest = &m_TransitionTable[to][from];
// Ignore the transition we're currently working on
if ( pTransition == pTest )
continue;
// Not only do the ops need to match, but so do the values the ops use in the snapshots
if ( pTest->m_nOpCountInStateBlock != pTransition->m_nOpCountInStateBlock )
continue;
bool bFoundOpMatch = true;
if ( pTest->m_FirstOperation != pTransition->m_FirstOperation )
{
const TransitionOp_t *pOp1 = &m_TransitionOps[pTest->m_FirstOperation];
const TransitionOp_t *pOp2 = &m_TransitionOps[pTransition->m_FirstOperation];
for ( int k = 0; k < pTransition->m_nOpCountInStateBlock; ++k )
{
if ( (pOp1->m_Op != pOp2->m_Op) || (pOp1->m_Argument != pOp2->m_Argument) )
{
bFoundOpMatch = false;
break;
}
++pOp1, ++pOp2;
}
}
if ( !bFoundOpMatch )
continue;
// Now we gotta check that the set values are the same.
if ( !DoStateBlocksMatch( pTest, to, toSnapshot ) )
continue;
return pTest->m_pStateBlock;
}
}
return NULL;
}
IDirect3DStateBlock9 *CTransitionTable::CreateStateBlock( TransitionList_t& list, int snapshot )
{
Assert( list.m_NumOperations > 0 );
HRESULT hr = D3DDevice()->BeginStateBlock( );
Assert( !FAILED(hr) );
// Necessary to set the bools so that the state blocks always have the info in them
ApplyTransitionList( snapshot, list.m_FirstOperation, list.m_nOpCountInStateBlock );
IDirect3DStateBlock9 *pStateBlock;
hr = D3DDevice()->EndStateBlock( &pStateBlock );
Assert( !FAILED(hr) );
return pStateBlock;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -