/*! \brief Bitset based Render State Manager \author Sung-jin Park [Orcinus] \remark 예 - KStateManager::GetInstance<4>(); // 4는 Texture Stage 갯수 순서 - SetPass( # ); => m_pEffect->BeginPass( # ); => PushCurrentStateToDevice(); */ #pragma once #include #include //#include #include #include #include //#define STATEMANAGER_TEST // Test Mode Enable //#ifdef STATEMANAGER_TEST #include //#endif namespace StateManager { enum STATE_DEF { RS_MAX = 210 //< Render State Key 값의 Max 수치 ,RS_CNT = 96 //< Render State Count. Tessellation 관련 State는 포함하지 않음. 포함한다면 103개 ,SS_MAX = 14 //< Sampler State Key 값의 Max 수치 ,SS_CNT = 13 //< Sampler State Count. ,TS_MAX = 33 //< Texture Stage State Key 값의 Max 수치 ,TS_CNT = 18 //< Texture Stage State Count. ,MAX_TEXTURESTAGE = D3DDP_MAXTEXCOORD //< Max Texture Stage 개수 }; #ifdef STATEMANAGER_TEST static bool g_OuputPushString = true; #endif struct ST_RenderState{}; struct ST_SamplerState{}; struct ST_TextureState{}; //-------------------------------------------------------------------------------------- // Render State Holder : RenderState, SamplerState, TextureStageState 별로 고유 데이터 //-------------------------------------------------------------------------------------- template< typename RsType > struct _RsHolder; template<> struct _RsHolder< ST_RenderState > { static void init(); // 필수 호출 필요 static DWORD DefaultState[1][RS_MAX]; static DWORD StateIndexTable[RS_MAX]; static DWORD IndexStateTable[RS_CNT]; //! 변화된 RenderState를 Setting 하는 함수 객체 struct SetStateFN { SetStateFN() { m_pDevice = NULL; m_pData = NULL; m_page = 0; } SetStateFN( IDirect3DDevice9* pDevice, DWORD* pData, bool page, DWORD stage ) { m_pDevice = pDevice; m_pData = pData; m_page = page; } void operator() ( int index ) { // 이전 State 와 현재 State가 다를때만 세팅함 if( *(m_pData+(m_page*RS_MAX)+IndexStateTable[index]) != *(m_pData+((!m_page)*RS_MAX)+IndexStateTable[index]) ) { #ifdef STATEMANAGER_TEST if( g_OuputPushString ) { _oprint( "SetRenderState - state_type:%u, value:%u, curpage:%u \n" , IndexStateTable[index], *(m_pData+(m_page*RS_MAX)+IndexStateTable[index]), (DWORD)m_page ); } #else m_pDevice->SetRenderState( (D3DRENDERSTATETYPE)IndexStateTable[index], *(m_pData+(m_page*RS_MAX)+IndexStateTable[index]) ); #endif } } IDirect3DDevice9* m_pDevice; DWORD* m_pData; bool m_page; }; //! 두번째 이후 Pass에 대한 함수 객체. 이전 State Data에 변화된 값을 저장한다. struct SetStateMultiPassFN { SetStateMultiPassFN() { m_pDevice = NULL; m_pData = NULL; m_page = 0; } SetStateMultiPassFN( IDirect3DDevice9* pDevice, DWORD* pData, bool page, DWORD stage ) { m_pDevice = pDevice; m_pData = pData; m_page = page; } void operator() ( int index ) { // 이전 State 와 현재 State가 다를때만 세팅함 if( *(m_pData+(m_page*RS_MAX)+IndexStateTable[index]) != *(m_pData+((!m_page)*RS_MAX)+IndexStateTable[index]) ) { #ifdef STATEMANAGER_TEST if( g_OuputPushString ) { _oprint( "SetRenderState - state_type:%u, value:%u, curpage:%u \n" , IndexStateTable[index], *(m_pData+(m_page*RS_MAX)+IndexStateTable[index]), (DWORD)m_page ); } #else m_pDevice->SetRenderState( (D3DRENDERSTATETYPE)IndexStateTable[index], *(m_pData+(m_page*RS_MAX)+IndexStateTable[index]) ); #endif // Prev State Data에 바뀐 State를 세팅한다. *(m_pData+((!m_page)*RS_MAX)+IndexStateTable[index]) = (*(m_pData+(m_page*RS_MAX)+IndexStateTable[index])); } } IDirect3DDevice9* m_pDevice; DWORD* m_pData; bool m_page; }; }; template<> struct _RsHolder< ST_SamplerState > { static void init(); static DWORD DefaultState[MAX_TEXTURESTAGE][SS_MAX]; // Sampler State 는 Stage와 상관없어 항상 Default가 같지만, 통일성을위해 static DWORD StateIndexTable[SS_MAX]; static DWORD IndexStateTable[SS_CNT]; //! 변화된 RenderState를 Setting 하는 함수 객체 struct SetStateFN { SetStateFN() { m_pDevice = NULL; m_pData = NULL; m_page = 0; } SetStateFN( IDirect3DDevice9* pDevice, DWORD* pData, bool page, DWORD stage ) { m_pDevice = pDevice; m_pData = pData; m_page = page; m_stage = stage;} void operator() ( int index ) { // 이전 State 와 현재 State가 다를때만 세팅함 if( *(m_pData+(m_page*SS_MAX)+IndexStateTable[index]) != *(m_pData+((!m_page)*SS_MAX)+IndexStateTable[index]) ) { #ifdef STATEMANAGER_TEST if( g_OuputPushString ) { _oprint( "SetSamplerState - stage:%u, state_type:%u, value:%u, curpage:%u \n" , m_stage, IndexStateTable[index], *(m_pData+(m_page*SS_MAX)+IndexStateTable[index]), (DWORD)m_page ); } #else m_pDevice->SetSamplerState( m_stage, (D3DSAMPLERSTATETYPE)IndexStateTable[index], *(m_pData+(m_page*SS_MAX)+IndexStateTable[index]) ); #endif } } IDirect3DDevice9* m_pDevice; DWORD* m_pData; bool m_page; DWORD m_stage; }; struct SetStateMultiPassFN { SetStateMultiPassFN() { m_pDevice = NULL; m_pData = NULL; m_page = 0; } SetStateMultiPassFN( IDirect3DDevice9* pDevice, DWORD* pData, bool page, DWORD stage ) { m_pDevice = pDevice; m_pData = pData; m_page = page; m_stage = stage;} void operator() ( int index ) { // 이전 State 와 현재 State가 다를때만 세팅함 if( *(m_pData+(m_page*SS_MAX)+IndexStateTable[index]) != *(m_pData+((!m_page)*SS_MAX)+IndexStateTable[index]) ) { #ifdef STATEMANAGER_TEST if( g_OuputPushString ) { _oprint( "SetSamplerState - stage:%u, state_type:%u, value:%u, curpage:%u \n" , m_stage, IndexStateTable[index], *(m_pData+(m_page*SS_MAX)+IndexStateTable[index]), (DWORD)m_page ); } #else m_pDevice->SetSamplerState( m_stage, (D3DSAMPLERSTATETYPE)IndexStateTable[index], *(m_pData+(m_page*SS_MAX)+IndexStateTable[index]) ); #endif // Prev State Data에 바뀐 State를 세팅한다. *(m_pData+((!m_page)*SS_MAX)+IndexStateTable[index]) = (*(m_pData+(m_page*SS_MAX)+IndexStateTable[index])); } } IDirect3DDevice9* m_pDevice; DWORD* m_pData; bool m_page; DWORD m_stage; }; }; template<> struct _RsHolder< ST_TextureState > { static void init(); static DWORD DefaultState[MAX_TEXTURESTAGE][TS_MAX]; // Texture State는 Stage에 따라 다른 State가 있기 때문에 이중 배열 static DWORD StateIndexTable[TS_MAX]; static DWORD IndexStateTable[TS_CNT]; //! 변화된 RenderState를 Setting 하는 함수 객체 struct SetStateFN { SetStateFN() { m_pDevice = NULL; m_pData = NULL; m_page = 0; } SetStateFN( IDirect3DDevice9* pDevice, DWORD* pData, bool page, DWORD stage ) { m_pDevice = pDevice; m_pData = pData; m_page = page; m_stage = stage;} void operator() ( int index ) { // 이전 State 와 현재 State가 다를때만 세팅함 if( *(m_pData+(m_page*TS_MAX)+IndexStateTable[index]) != *(m_pData+((!m_page)*TS_MAX)+IndexStateTable[index]) ) { #ifdef STATEMANAGER_TEST if( g_OuputPushString ) { _oprint( "SetTextureStageState - stage:%u, state_type:%u, value:%u, curpage:%u \n" , m_stage, IndexStateTable[index], *(m_pData+(m_page*TS_MAX)+IndexStateTable[index]), (DWORD)m_page ); } #else m_pDevice->SetTextureStageState( m_stage, (D3DTEXTURESTAGESTATETYPE)IndexStateTable[index], *(m_pData+(m_page*TS_MAX)+IndexStateTable[index]) ); #endif } } IDirect3DDevice9* m_pDevice; DWORD* m_pData; bool m_page; DWORD m_stage; }; struct SetStateMultiPassFN { SetStateMultiPassFN() { m_pDevice = NULL; m_pData = NULL; m_page = 0; } SetStateMultiPassFN( IDirect3DDevice9* pDevice, DWORD* pData, bool page, DWORD stage ) { m_pDevice = pDevice; m_pData = pData; m_page = page; m_stage = stage;} void operator() ( int index ) { // 이전 State 와 현재 State가 다를때만 세팅함 if( *(m_pData+(m_page*TS_MAX)+IndexStateTable[index]) != *(m_pData+((!m_page)*TS_MAX)+IndexStateTable[index]) ) { #ifdef STATEMANAGER_TEST if( g_OuputPushString ) { _oprint( "SetTextureStageState - stage:%u, state_type:%u, value:%u, curpage:%u \n" , m_stage, IndexStateTable[index], *(m_pData+(m_page*TS_MAX)+IndexStateTable[index]), (DWORD)m_page ); } #else m_pDevice->SetTextureStageState( m_stage, (D3DTEXTURESTAGESTATETYPE)IndexStateTable[index], *(m_pData+(m_page*TS_MAX)+IndexStateTable[index]) ); #endif // Prev State Data에 바뀐 State를 세팅한다. *(m_pData+((!m_page)*TS_MAX)+IndexStateTable[index]) = (*(m_pData+(m_page*TS_MAX)+IndexStateTable[index])); } } IDirect3DDevice9* m_pDevice; DWORD* m_pData; bool m_page; DWORD m_stage; }; }; //-------------------------------------------------------------------------------------- // cache D3DRENDERSTATE //-------------------------------------------------------------------------------------- template < typename _Kty, typename _RsHolder, int _State_Max = RS_MAX, int _State_Cnt = RS_CNT > class KRenderStateCache { public: typedef _RsHolder StateTable; typedef typename StateTable::SetStateFN SetStateFN; typedef typename StateTable::SetStateMultiPassFN SetStateMultiPassFN; public: // 2개의 Page를 Swap 하며, State 기록을 한다. c_bits<_State_Cnt> changeidx[2]; DWORD data[2][_State_Max]; bool current_page; DWORD current_stage; public: inline void init( DWORD stage = 0 ) { current_page = 0; current_stage = stage; memcpy( data[0], StateTable::DefaultState[stage], sizeof(data[0]) ); memcpy( data[1], StateTable::DefaultState[stage], sizeof(data[1]) ); changeidx[0].reset(); changeidx[1].reset(); } // compare_prev -> 이전 설정값과 비교한다. inline void set_val( _Kty key, DWORD value, bool compare_prev = false ) { if( compare_prev && data[!current_page][key] != value ) // 이전 설정값과 비교 changeidx[current_page].set( StateTable::StateIndexTable[key] ); else if( StateTable::DefaultState[current_stage][key] != value ) // Default 와 비교 changeidx[current_page].set( StateTable::StateIndexTable[key] ); else changeidx[current_page].reset( StateTable::StateIndexTable[key] ); data[current_page][key] = value; } inline DWORD get_val( _Kty key ) { // 값이 변화된경우 Data에서, 아닐경우 Default에서 if( changeidx[current_page].test( StateTable::StateIndexTable[key] ) ) return data[current_page][key]; else return StateTable::DefaultState[current_stage][key]; } inline void commit( IDirect3DDevice9* pDevice, DWORD pass = 0 ) { if( pass == 0 ) { c_bits<_State_Cnt> ch_set( changeidx[0], changeidx[1] ); // OR is Default Constructor // Set RenderStates if( ch_set.any() ) ch_set.for_each_on( SetStateFN( pDevice, *data, current_page, current_stage ) ); } else { // for multi pass if( changeidx[current_page].any() ) { changeidx[current_page].for_each_on( SetStateMultiPassFN( pDevice, *data, current_page, current_stage ) ); } // SetStateMultiPassFN에 의해 이전 Data에 현제 세팅이 저장되어 이것을 Current에 복구시킨다. memcpy( data[current_page], data[!current_page], sizeof(data[current_page]) ); // 이전 State Change Set을 포함하여 현제 세팅에 저장한다. changeidx[current_page] |= changeidx[!current_page]; } // Swap current_page = (!current_page); // clear index set changeidx[current_page].reset(); // clear data memcpy( data[current_page], StateTable::DefaultState[current_stage], sizeof(data[current_page]) ); } }; //------------------------------------------------------------------------------------------------------------- // State Block //------------------------------------------------------------------------------------------------------------- struct KRenderStateElement { KRenderStateElement( DWORD _type, DWORD _value ) : statetype( _type ), value( _value ) {} DWORD statetype; DWORD value; }; struct KStageStateElement { KStageStateElement( DWORD _stage, DWORD _type, DWORD _value ) : stage( _stage ),statetype( _type ), value( _value ) {} DWORD stage; DWORD statetype; DWORD value; }; struct KStateBlock { std::vector vRenderStateBlock; std::vector vSamplerStateBlock; std::vector vTextureStateBlock; }; struct _RenderStateCompareFN { _RenderStateCompareFN( DWORD _state ) { state = _state; } bool operator() ( const KRenderStateElement& p1 ) { if( p1.statetype == state ) return true; else return false; } DWORD state; }; struct _StageStateCompareFN { _StageStateCompareFN( DWORD _stage, DWORD _state ) { stage = _stage; state = _state; } bool operator() ( const KStageStateElement& p1 ) { if( (p1.stage == stage) && (p1.statetype == state) ) return true; else return false; } DWORD stage; DWORD state; }; //------------------------------------------------------------------------------------------------------------- // StateManager Interface //------------------------------------------------------------------------------------------------------------- template< int > class KStateManagerImpl; class KStateManager : public ID3DXEffectStateManager { public: KStateManager( LPDIRECT3DDEVICE9 pDevice ) : m_lRef(1L), m_pDevice(pDevice) { // Increment the reference count on the device, because a pointer to it has been copied for later use #ifndef STATEMANAGER_TEST m_pDevice->AddRef(); #endif } virtual ~KStateManager() { #ifndef STATEMANAGER_TEST m_pDevice->Release(); #endif } template< int NSTAGE > static KStateManager* Create( LPDIRECT3DDEVICE9 pDevice ) { KStateManager* pStateManager = NULL; pStateManager = new KStateManagerImpl( pDevice ); if( NULL == pStateManager ) { assert( pStateManager ); return NULL; } return pStateManager; } virtual void ManagedSetRenderState( D3DRENDERSTATETYPE state, DWORD value ) = 0; virtual void ManagedSetTextureStageState( DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value ) = 0; virtual void ManagedSetSamplerState( DWORD stage, D3DSAMPLERSTATETYPE, DWORD value ) = 0; virtual void ManagedSetStateBlock( DWORD key ) = 0; virtual void PushCurrentStateToDevice() = 0; virtual void RestoreDefault() = 0; //! StateBlock Create. State Value가 Default 와 다를 경우만 세팅 합니다. virtual void BeginStateBlock() = 0; virtual void EndStateBlock( DWORD key ) = 0; virtual bool BeginPass( LPD3DXEFFECT effect, DWORD pass ) = 0; virtual bool EndPass( LPD3DXEFFECT effect ) = 0; virtual void PresentCurrentRenderState( bool bShow ) = 0; virtual void PresentCurrentSamplerState( bool bShow ) = 0; virtual void PresentCurrentTextureState( bool bShow ) = 0; #ifdef STATEMANAGER_TEST virtual void TestRenderState() = 0; virtual void TestSamplerState() = 0; virtual void TestTextureState() = 0; virtual void TestStateBlock() = 0; virtual void TestMultiPass() = 0; virtual void TestRestoreDefault() = 0; virtual void TestPresent() = 0; virtual void TestPerformance( DWORD count ) = 0; virtual void TestForClearStateBlock() = 0; #endif protected: LONG m_lRef; LPDIRECT3DDEVICE9 m_pDevice; public: // methods inherited from ID3DXEffectStateManager STDMETHOD(QueryInterface)(THIS_ REFIID iid, LPVOID *ppv) { if (iid == IID_IUnknown || iid == IID_ID3DXEffectStateManager) { *ppv = static_cast(this); } else { *ppv = NULL; return E_NOINTERFACE; } reinterpret_cast(this)->AddRef(); return S_OK; } STDMETHOD_(ULONG, AddRef)(THIS) { return (ULONG)InterlockedIncrement( &m_lRef ); } STDMETHOD_(ULONG, Release)(THIS) { if( 0L == InterlockedDecrement( &m_lRef ) ) { delete this; return 0L; } return m_lRef; } STDMETHOD(SetTexture)(THIS_ DWORD dwStage, LPDIRECT3DBASETEXTURE9 pTexture ) { return m_pDevice->SetTexture( dwStage, pTexture ); } STDMETHOD(SetVertexShader)(THIS_ LPDIRECT3DVERTEXSHADER9 pShader ) { return m_pDevice->SetVertexShader( pShader ); } STDMETHOD(SetPixelShader)(THIS_ LPDIRECT3DPIXELSHADER9 pShader ) { return m_pDevice->SetPixelShader( pShader ); } STDMETHOD(SetFVF)(THIS_ DWORD dwFVF ) { return m_pDevice->SetFVF( dwFVF ); } STDMETHOD(SetTransform)(THIS_ D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX *pMatrix ) { return m_pDevice->SetTransform( State, pMatrix ); } STDMETHOD(SetMaterial)(THIS_ CONST D3DMATERIAL9 *pMaterial ) { return m_pDevice->SetMaterial( pMaterial ); } STDMETHOD(SetLight)(THIS_ DWORD Index, CONST D3DLIGHT9 *pLight ) { return m_pDevice->SetLight( Index, pLight ); } STDMETHOD(LightEnable)(THIS_ DWORD Index, BOOL Enable ) { return m_pDevice->LightEnable( Index, Enable ); } STDMETHOD(SetNPatchMode)(THIS_ FLOAT NumSegments ) { return m_pDevice->SetNPatchMode( NumSegments ); } STDMETHOD(SetVertexShaderConstantF)(THIS_ UINT RegisterIndex, CONST FLOAT *pConstantData, UINT RegisterCount ) { return m_pDevice->SetVertexShaderConstantF( RegisterIndex, pConstantData, RegisterCount ); } STDMETHOD(SetVertexShaderConstantI)(THIS_ UINT RegisterIndex, CONST INT *pConstantData, UINT RegisterCount ) { return m_pDevice->SetVertexShaderConstantI( RegisterIndex, pConstantData, RegisterCount ); } STDMETHOD(SetVertexShaderConstantB)(THIS_ UINT RegisterIndex, CONST BOOL *pConstantData, UINT RegisterCount ) { return m_pDevice->SetVertexShaderConstantB( RegisterIndex, pConstantData, RegisterCount ); } STDMETHOD(SetPixelShaderConstantF)(THIS_ UINT RegisterIndex, CONST FLOAT *pConstantData, UINT RegisterCount ) { return m_pDevice->SetPixelShaderConstantF( RegisterIndex, pConstantData, RegisterCount ); } STDMETHOD(SetPixelShaderConstantI)(THIS_ UINT RegisterIndex, CONST INT *pConstantData, UINT RegisterCount ) { return m_pDevice->SetPixelShaderConstantI( RegisterIndex, pConstantData, RegisterCount ); } STDMETHOD(SetPixelShaderConstantB)(THIS_ UINT RegisterIndex, CONST BOOL *pConstantData, UINT RegisterCount ) { return m_pDevice->SetPixelShaderConstantB( RegisterIndex, pConstantData, RegisterCount ); } }; //------------------------------------------------------------------------------------------------------------- // StateManager Implement //------------------------------------------------------------------------------------------------------------- template< int NSTAGE > class KStateManagerImpl : public KStateManager { public: KStateManagerImpl( LPDIRECT3DDEVICE9 pDevice ); virtual ~KStateManagerImpl(); protected: void ClearStateBlock(); public: virtual void ManagedSetRenderState( D3DRENDERSTATETYPE state, DWORD value ); virtual void ManagedSetTextureStageState( DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value ); virtual void ManagedSetSamplerState( DWORD stage, D3DSAMPLERSTATETYPE, DWORD value ); virtual void ManagedSetStateBlock( DWORD key ); virtual void PushCurrentStateToDevice(); virtual void RestoreDefault(); virtual void BeginStateBlock(); virtual void EndStateBlock( DWORD key ); virtual bool BeginPass( LPD3DXEFFECT effect, DWORD pass ); virtual bool EndPass( LPD3DXEFFECT effect ); virtual void PresentCurrentRenderState( bool bShow ); virtual void PresentCurrentSamplerState( bool bShow ); virtual void PresentCurrentTextureState( bool bShow ); #ifdef STATEMANAGER_TEST virtual void TestRenderState(); virtual void TestSamplerState(); virtual void TestTextureState(); virtual void TestStateBlock(); virtual void TestMultiPass(); virtual void TestRestoreDefault(); virtual void TestPresent(); virtual void TestPerformance( DWORD count ); virtual void TestForClearStateBlock() { ClearStateBlock(); } virtual void TestForSetPass( DWORD pass ) { m_dwCurrentPass = pass; } #endif public: // methods inherited from ID3DXEffectStateManager STDMETHOD(SetRenderState)(THIS_ D3DRENDERSTATETYPE d3dRenderState, DWORD dwValue ) { ManagedSetRenderState( d3dRenderState, dwValue ); return D3D_OK; } STDMETHOD(SetSamplerState)(THIS_ DWORD dwStage, D3DSAMPLERSTATETYPE d3dSamplerState, DWORD dwValue ) { ManagedSetSamplerState( dwStage, d3dSamplerState, dwValue ); return D3D_OK; } STDMETHOD(SetTextureStageState)(THIS_ DWORD dwStage, D3DTEXTURESTAGESTATETYPE d3dTextureStageState, DWORD dwValue ) { ManagedSetTextureStageState( dwStage, d3dTextureStageState, dwValue ); return D3D_OK; } protected: KRenderStateCache, RS_MAX, RS_CNT> m_RenderStateCache; KRenderStateCache, SS_MAX, SS_CNT> m_SamplerStateCacheArry[NSTAGE]; KRenderStateCache, TS_MAX, TS_CNT> m_TextureStageStateCacheArray[NSTAGE]; std::map< DWORD, KStateBlock* > m_StateBlocks; KStateBlock* m_pBlockBuffer; DWORD m_dwCurrentPass; }; template KStateManagerImpl::KStateManagerImpl( LPDIRECT3DDEVICE9 pDevice ) : KStateManager(pDevice), m_pBlockBuffer(0) { // 순서에 주의. RsHolder 먼저 초기화. _RsHolder::init(); _RsHolder::init(); _RsHolder::init(); m_RenderStateCache.init(); for( int i = 0; i < NSTAGE; i++ ) { m_TextureStageStateCacheArray[i].init( i ); m_SamplerStateCacheArry[i].init( i ); } m_dwCurrentPass = 0; } template KStateManagerImpl::~KStateManagerImpl() { ClearStateBlock(); } template void KStateManagerImpl::ClearStateBlock() { assert( !m_pBlockBuffer ); if( m_pBlockBuffer ) { delete m_pBlockBuffer; m_pBlockBuffer = NULL; } for( std::map::iterator it = m_StateBlocks.begin(); it != m_StateBlocks.end(); it++ ) { KStateBlock* pBlock = (*it).second; delete pBlock; } m_StateBlocks.clear(); m_dwCurrentPass = 0; } template void KStateManagerImpl::ManagedSetRenderState( D3DRENDERSTATETYPE state, DWORD value ) { if( NULL != m_pBlockBuffer ) { // Stroy : Default State가 들어오면, 스테이트 블럭에 포함시키지 않는다. // 동일한 스테이트는 하나만 존재해야 하며, 중복해서 세팅된다면 마지막에 세팅된 값이 삽입된다. 디폴트면 제거 된다. std::vector::iterator it = std::find_if( m_pBlockBuffer->vRenderStateBlock.begin(), m_pBlockBuffer->vRenderStateBlock.end(), _RenderStateCompareFN(state) ); if( it != m_pBlockBuffer->vRenderStateBlock.end() ) { if( _RsHolder::DefaultState[0][state] != value ) (*it ) = KRenderStateElement( state, value ); else m_pBlockBuffer->vRenderStateBlock.erase( it ); } else { if( _RsHolder::DefaultState[0][state] != value ) m_pBlockBuffer->vRenderStateBlock.push_back( KRenderStateElement( state, value ) ); } } else { // 첫번째 패스가 아닐때, Prev State와 비교하여 세팅을 해준다. m_RenderStateCache.set_val( state, value, m_dwCurrentPass > 0 ); } } template void KStateManagerImpl::ManagedSetSamplerState( DWORD stage, D3DSAMPLERSTATETYPE state, DWORD value ) { assert( NSTAGE > stage ); if( NULL != m_pBlockBuffer ) { // Stroy : Default State가 들어오면, 스테이트 블럭에 포함시키지 않는다. // 동일한 스테이트는 하나만 존재해야 하며, 중복해서 세팅된다면 마지막에 세팅된 값이 삽입된다. 디폴트면 제거 된다. std::vector::iterator it = std::find_if( m_pBlockBuffer->vSamplerStateBlock.begin(), m_pBlockBuffer->vSamplerStateBlock.end(), _StageStateCompareFN(stage, state) ); if( it != m_pBlockBuffer->vSamplerStateBlock.end() ) { if( _RsHolder::DefaultState[stage][state] != value ) (*it ) = KStageStateElement( stage, state, value ); else m_pBlockBuffer->vSamplerStateBlock.erase( it ); } else { if( _RsHolder::DefaultState[stage][state] != value ) m_pBlockBuffer->vSamplerStateBlock.push_back( KStageStateElement( stage, state, value ) ); } } else m_SamplerStateCacheArry[stage].set_val( state, value, m_dwCurrentPass > 0 ); } template void KStateManagerImpl::ManagedSetTextureStageState( DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value ) { assert( NSTAGE > stage ); if( NULL != m_pBlockBuffer ) { // Stroy : Default State가 들어오면, 스테이트 블럭에 포함시키지 않는다. // 동일한 스테이트는 하나만 존재해야 하며, 중복해서 세팅된다면 마지막에 세팅된 값이 삽입된다. 디폴트면 제거 된다. std::vector::iterator it = std::find_if( m_pBlockBuffer->vTextureStateBlock.begin(), m_pBlockBuffer->vTextureStateBlock.end(), _StageStateCompareFN(stage, state) ); if( it != m_pBlockBuffer->vTextureStateBlock.end() ) { if( _RsHolder::DefaultState[stage][state] != value ) (*it ) = KStageStateElement( stage, state, value ); else m_pBlockBuffer->vTextureStateBlock.erase( it ); } else { if( _RsHolder::DefaultState[stage][state] != value ) m_pBlockBuffer->vTextureStateBlock.push_back( KStageStateElement( stage, state, value ) ); } } else m_TextureStageStateCacheArray[stage].set_val( state, value, m_dwCurrentPass > 0 ); } template void KStateManagerImpl::ManagedSetStateBlock( DWORD key ) { assert( !m_pBlockBuffer ); std::map::iterator it = m_StateBlocks.find( key ); if( it != m_StateBlocks.end() ) { KStateBlock* pBlock = (*it).second; std::vector::iterator it_re = pBlock->vRenderStateBlock.begin(); for( ; it_re != pBlock->vRenderStateBlock.end(); it_re++ ) { ManagedSetRenderState( (D3DRENDERSTATETYPE)(*it_re).statetype, (*it_re).value ); } std::vector::iterator it_se = pBlock->vSamplerStateBlock.begin(); for( ; it_se != pBlock->vSamplerStateBlock.end(); it_se++ ) { ManagedSetSamplerState( (*it_se).stage, (D3DSAMPLERSTATETYPE)(*it_se).statetype, (*it_se).value ); } it_se = pBlock->vTextureStateBlock.begin(); for( ; it_se != pBlock->vTextureStateBlock.end(); it_se++ ) { ManagedSetTextureStageState( (*it_se).stage, (D3DTEXTURESTAGESTATETYPE)(*it_se).statetype, (*it_se).value ); } } } template void KStateManagerImpl::RestoreDefault() { // Set All State to Default PushCurrentStateToDevice(); PushCurrentStateToDevice(); } template void KStateManagerImpl::PushCurrentStateToDevice() { m_RenderStateCache.commit( m_pDevice, m_dwCurrentPass ); for( int i = 0; i < NSTAGE; i++ ) { m_TextureStageStateCacheArray[i].commit( m_pDevice, m_dwCurrentPass ); m_SamplerStateCacheArry[i].commit( m_pDevice, m_dwCurrentPass ); } // Current Pass Reset - BeginPass 에서 다시 세팅해줌 m_dwCurrentPass = 0; } template void KStateManagerImpl::BeginStateBlock() { assert( !m_pBlockBuffer ); if( NULL != m_pBlockBuffer ) delete m_pBlockBuffer; m_pBlockBuffer = new KStateBlock; } template void KStateManagerImpl::EndStateBlock( DWORD key ) { assert( m_pBlockBuffer ); if( NULL == m_pBlockBuffer ) return; std::map< DWORD, KStateBlock* >::iterator it = m_StateBlocks.find( key ); if( it != m_StateBlocks.end() ) { delete (*it).second; (*it).second = NULL; } m_StateBlocks.insert( std::map< DWORD, KStateBlock* >::value_type(key, m_pBlockBuffer) ); m_pBlockBuffer = NULL; } template bool KStateManagerImpl::BeginPass( LPD3DXEFFECT effect, DWORD pass ) { m_dwCurrentPass = pass; #ifdef STATEMANAGER_TEST HRESULT hr = D3D_OK; #else STATEMANAGER_TEST HRESULT hr = effect->BeginPass( pass ); #endif PushCurrentStateToDevice(); assert( hr == D3D_OK ); return hr == D3D_OK; } template bool KStateManagerImpl::EndPass( LPD3DXEFFECT effect ) { m_dwCurrentPass = 0; #ifdef STATEMANAGER_TEST HRESULT hr = D3D_OK; #else HRESULT hr = effect->EndPass(); #endif assert( hr == D3D_OK ); return hr == D3D_OK; } template void KStateManagerImpl::PresentCurrentRenderState( bool bShow ) { if( !bShow ) return; _oprint( "=============== Start Present Changed Current [RenderState] =================\n" ); for( int i = 0; i < RS_CNT; i++ ) { if( m_RenderStateCache.data[m_RenderStateCache.current_page][ _RsHolder::IndexStateTable[i] ] != _RsHolder::DefaultState[0][ _RsHolder::IndexStateTable[i] ] ) { _oprint( "RenderStateType : %u, Value : %u\n", _RsHolder::IndexStateTable[i] , m_RenderStateCache.data[m_RenderStateCache.current_page][ _RsHolder::IndexStateTable[i] ] ); } } _oprint( "=============== End Present Changed Current [RenderState] =================\n" ); } template void KStateManagerImpl::PresentCurrentSamplerState( bool bShow ) { if( !bShow ) return; _oprint( "=============== Start Present Changed Current [SamplerState] =================\n" ); for( int stage = 0; stage < NSTAGE; stage++ ) { for( int i = 0; i < SS_CNT; i++ ) { if( m_SamplerStateCacheArry[stage].data[m_SamplerStateCacheArry[stage].current_page][ _RsHolder::IndexStateTable[i] ] != _RsHolder::DefaultState[stage][ _RsHolder::IndexStateTable[i] ] ) { _oprint( "Stage : %d, SamplerStateType : %u, Value : %u\n", stage, _RsHolder::IndexStateTable[i] , m_SamplerStateCacheArry[stage].data[m_SamplerStateCacheArry[stage].current_page][ _RsHolder::IndexStateTable[i] ] ); } } } _oprint( "=============== End Present Changed Current [SamplerState] =================\n" ); } template void KStateManagerImpl::PresentCurrentTextureState( bool bShow ) { if( !bShow ) return; _oprint( "=============== Start Present Changed Current [TextureState] =================\n" ); for( int stage = 0; stage < NSTAGE; stage++ ) { for( int i = 0; i < TS_CNT; i++ ) { if( m_TextureStageStateCacheArray[stage].data[m_TextureStageStateCacheArray[stage].current_page][ _RsHolder::IndexStateTable[i] ] != _RsHolder::DefaultState[stage][ _RsHolder::IndexStateTable[i] ] ) { _oprint( "Stage : %d, TextureStateType : %u, Value : %u\n", stage, _RsHolder::IndexStateTable[i] , m_TextureStageStateCacheArray[stage].data[m_TextureStageStateCacheArray[stage].current_page][ _RsHolder::IndexStateTable[i] ] ); } } } _oprint( "=============== End Present Changed Current [TextureState] =================\n" ); } static void PresentDeviceRenderState( LPDIRECT3DDEVICE9 pDevice, bool bShow ) { if( !bShow ) return; _oprint( "=============== Start Present Changed Device [RenderState] =================\n" ); if( pDevice ) { DWORD dwValue; for( int i = 0; i < RS_CNT; i++ ) { pDevice->GetRenderState( (D3DRENDERSTATETYPE)_RsHolder::IndexStateTable[i], &dwValue ); if( dwValue != _RsHolder::DefaultState[0][ _RsHolder::IndexStateTable[i] ] ) { _oprint( "RenderStateType : %u, Value : %u\n", _RsHolder::IndexStateTable[i], dwValue ); } } } _oprint( "=============== End Present Changed Device [RenderState] =================\n" ); } static void PresentDeviceSamplerState( LPDIRECT3DDEVICE9 pDevice, DWORD max_stage, bool bShow ) { if( !bShow ) return; _oprint( "=============== Start Present Changed Device [SamplerState] =================\n" ); if( pDevice ) { DWORD dwValue; for( DWORD stage = 0; stage < max_stage; stage++ ) { for( int i = 0; i < SS_CNT; i++ ) { pDevice->GetSamplerState( stage, (D3DSAMPLERSTATETYPE)_RsHolder::IndexStateTable[i], &dwValue ); if( dwValue != _RsHolder::DefaultState[stage][ _RsHolder::IndexStateTable[i] ] ) { _oprint( "Stage : %u, SamplerStateType : %u, Value : %u\n", stage, _RsHolder::IndexStateTable[i], dwValue ); } } } } _oprint( "=============== End Present Changed Device [SamplerState] =================\n" ); } static void PresentDeviceTextureState( LPDIRECT3DDEVICE9 pDevice, DWORD max_stage, bool bShow ) { if( !bShow ) return; _oprint( "=============== Start Present Changed Device [TextureState] =================\n" ); if( pDevice ) { DWORD dwValue; for( DWORD stage = 0; stage < max_stage; stage++ ) { for( int i = 0; i < TS_CNT; i++ ) { pDevice->GetTextureStageState( stage, (D3DTEXTURESTAGESTATETYPE)_RsHolder::IndexStateTable[i], &dwValue ); if( dwValue != _RsHolder::DefaultState[stage][ _RsHolder::IndexStateTable[i] ] ) { _oprint( "Stage : %u, TextureStateType : %u, Value : %u\n", stage, _RsHolder::IndexStateTable[i], dwValue ); } } } } _oprint( "=============== End Present Changed Device [TextureState] =================\n" ); } //-------------------------------------------------------------------------------------- // Test Code //-------------------------------------------------------------------------------------- #ifdef STATEMANAGER_TEST template void KStateManagerImpl::TestRenderState() { _oprint( "--------------------TestRenderState [Start]----------------------\n" ); // 초기화 테스트 if( memcmp( m_RenderStateCache.data[ m_RenderStateCache.current_page ], _RsHolder::DefaultState[m_RenderStateCache.current_stage], sizeof(DWORD)*RS_MAX ) != 0 ) { _oprint( "StateManager Default State Initialize Failed - memcmp is nonzero \n" ); } if( m_RenderStateCache.data[ m_RenderStateCache.current_page ][ D3DRS_ZENABLE ] != TRUE ) { _oprint( "StateManager Initialize Failed - D3DRS_ZENABLE = %u \n", m_RenderStateCache.data[ m_RenderStateCache.current_page ][ D3DRS_ZENABLE ] ); } if( m_RenderStateCache.data[ m_RenderStateCache.current_page ][ D3DRS_ALPHABLENDENABLE ] != FALSE ) { _oprint( "StateManager Initialize Failed - D3DRS_ALPHABLENDENABLE = %u \n", m_RenderStateCache.data[ m_RenderStateCache.current_page ][ D3DRS_ALPHABLENDENABLE ] ); } // ManagedSetRenderState Function Test ManagedSetRenderState( D3DRS_ZENABLE, FALSE ); ManagedSetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); if( m_RenderStateCache.data[ m_RenderStateCache.current_page ][ D3DRS_ZENABLE ] != FALSE ) { _oprint( "1. ManagedSetRenderState( D3DRS_ZENABLE, FALSE ) - Failed\n" ); } if( m_RenderStateCache.data[ m_RenderStateCache.current_page ][ D3DRS_ALPHABLENDENABLE ] != TRUE ) { _oprint( "1. ManagedSetRenderState( D3DRS_ZENABLE, FALSE ) - Failed\n" ); } // Commit Test _oprint( "1. Commit Test : D3DRS_ZENABLE - %d(FALSE), D3DRS_ALPHABLENDENABLE - %d(TRUE) \n", D3DRS_ZENABLE, D3DRS_ALPHABLENDENABLE ); bool prev_page = m_RenderStateCache.current_page; PushCurrentStateToDevice(); if( prev_page == m_RenderStateCache.current_page ) { _oprint( "Commit : Swap Failed - current_page is not changed \n" ); } if( memcmp( m_RenderStateCache.data[ m_RenderStateCache.current_page ], _RsHolder::DefaultState[m_RenderStateCache.current_stage], sizeof(DWORD)*RS_MAX ) != 0 ) { _oprint( "Commit : Data Clear & Reset Failed - memcmp is nonzero \n" ); } // 같은 스테이트 한번 더 세팅 ManagedSetRenderState( D3DRS_ZENABLE, FALSE ); ManagedSetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); if( m_RenderStateCache.data[ m_RenderStateCache.current_page ][ D3DRS_ZENABLE ] != FALSE ) { _oprint( "2. ManagedSetRenderState( D3DRS_ZENABLE, FALSE ) - Failed\n" ); } if( m_RenderStateCache.data[ m_RenderStateCache.current_page ][ D3DRS_ALPHABLENDENABLE ] != TRUE ) { _oprint( "2. ManagedSetRenderState( D3DRS_ZENABLE, FALSE ) - Failed\n" ); } // Commit Test _oprint( "2. Commit Test : D3DRS_ZENABLE - %d(FALSE), D3DRS_ALPHABLENDENABLE - %d(TRUE) \n", D3DRS_ZENABLE, D3DRS_ALPHABLENDENABLE ); prev_page = m_RenderStateCache.current_page; PushCurrentStateToDevice(); // 아무것도 세팅하지 않고 Commit 해본다. // Commit Test _oprint( "3. Commit Test(To Default) : D3DRS_ZENABLE - %d(TRUE), D3DRS_ALPHABLENDENABLE - %d(FALSE) \n", D3DRS_ZENABLE, D3DRS_ALPHABLENDENABLE ); prev_page = m_RenderStateCache.current_page; PushCurrentStateToDevice(); _oprint( "--------------------TestRenderState [End]----------------------\n" ); } template void KStateManagerImpl::TestSamplerState() { _oprint( "--------------------TestSamplerState [Start]----------------------\n" ); // 초기화 테스트 for( int i = 0; i < NSTAGE; i++ ) { if( memcmp( m_SamplerStateCacheArry[i].data[ m_SamplerStateCacheArry[i].current_page ], _RsHolder::DefaultState[i], sizeof(DWORD)*SS_MAX ) != 0 ) { _oprint( "SamplerState Default State Initialize Failed - memcmp is nonzero \n" ); } if( m_SamplerStateCacheArry[i].data[ m_SamplerStateCacheArry[i].current_page ][ D3DSAMP_ADDRESSU ] != D3DTADDRESS_WRAP ) { _oprint( "SamplerState Initialize Failed - D3DSAMP_ADDRESSU[%d] is Not D3DTADDRESS_WRAP(%u). is %u\n" , i, D3DTADDRESS_WRAP, m_SamplerStateCacheArry[i].data[ m_SamplerStateCacheArry[i].current_page ][ D3DSAMP_ADDRESSU ] ); } if( m_SamplerStateCacheArry[i].data[ m_SamplerStateCacheArry[i].current_page ][ D3DSAMP_MINFILTER ] != D3DTEXF_POINT ) { _oprint( "SamplerState Initialize Failed - D3DSAMP_MINFILTER[%d] is Not D3DTEXF_POINT(%u). is %u\n" , i, D3DTEXF_POINT, m_SamplerStateCacheArry[i].data[ m_SamplerStateCacheArry[i].current_page ][ D3DSAMP_MINFILTER ] ); } } // ManagedSetRenderState Function Test ManagedSetSamplerState( 1, D3DSAMP_ADDRESSU, D3DTADDRESS_MIRROR ); ManagedSetSamplerState( 3, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC ); if( m_SamplerStateCacheArry[1].data[ m_SamplerStateCacheArry[1].current_page ][ D3DSAMP_ADDRESSU ] != D3DTADDRESS_MIRROR ) { _oprint( "1. ManagedSetSamplerState( 1, D3DSAMP_ADDRESSU, D3DTADDRESS_MIRROR ) - Failed\n" ); } if( m_SamplerStateCacheArry[3].data[ m_SamplerStateCacheArry[3].current_page ][ D3DSAMP_MINFILTER ] != D3DTEXF_ANISOTROPIC ) { _oprint( "1. ManagedSetSamplerState( 3, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC ) - Failed\n" ); } // Commit Test _oprint( "1. Commit Test : D3DSAMP_ADDRESSU(1) - %u = %u, D3DSAMP_MINFILTER(3) - %u = %u \n" , D3DSAMP_ADDRESSU, D3DTADDRESS_MIRROR, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC ); bool prev_page = m_SamplerStateCacheArry[1].current_page; PushCurrentStateToDevice(); if( prev_page == m_SamplerStateCacheArry[1].current_page ) { _oprint( "Commit : Swap Failed - current_page is not changed \n" ); } if( memcmp( m_SamplerStateCacheArry[2].data[ m_SamplerStateCacheArry[2].current_page ], _RsHolder::DefaultState[2], sizeof(DWORD)*SS_MAX ) != 0 ) { _oprint( "Commit : Data Clear & Reset Failed - memcmp is nonzero \n" ); } // 같은 스테이트 한번 더 세팅 ManagedSetSamplerState( 1, D3DSAMP_ADDRESSU, D3DTADDRESS_MIRROR ); ManagedSetSamplerState( 3, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC ); if( m_SamplerStateCacheArry[1].data[ m_SamplerStateCacheArry[1].current_page ][ D3DSAMP_ADDRESSU ] != D3DTADDRESS_MIRROR ) { _oprint( "2. ManagedSetRenderState( D3DSAMP_ADDRESSU, D3DTADDRESS_MIRROR ) - Failed\n" ); } if( m_SamplerStateCacheArry[3].data[ m_SamplerStateCacheArry[3].current_page ][ D3DSAMP_MINFILTER ] != D3DTEXF_ANISOTROPIC ) { _oprint( "2. ManagedSetRenderState( D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC ) - Failed\n" ); } // Commit Test _oprint( "2. Commit Test : D3DSAMP_ADDRESSU(1) - %u = %u, D3DSAMP_MINFILTER(3) - %u = %u \n" , D3DSAMP_ADDRESSU, D3DTADDRESS_MIRROR, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC ); PushCurrentStateToDevice(); // 아무것도 세팅하지 않고 Commit 해본다. // Commit Test _oprint( "3. Commit Test(To Default) : D3DSAMP_ADDRESSU(1) - %u = %u, D3DSAMP_MINFILTER(3) - %u = %u \n" , D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP, D3DSAMP_MINFILTER, D3DTEXF_POINT ); PushCurrentStateToDevice(); _oprint( "--------------------TestSamplerState [End]----------------------\n" ); } template void KStateManagerImpl::TestTextureState() { _oprint( "--------------------TestTextureState [Start]----------------------\n" ); // 초기화 테스트 for( int i = 0; i < NSTAGE; i++ ) { if( memcmp( m_TextureStageStateCacheArray[i].data[ m_TextureStageStateCacheArray[i].current_page ], _RsHolder::DefaultState[i], sizeof(DWORD)*TS_MAX ) != 0 ) { _oprint( "TextureState Default State Initialize Failed - memcmp is nonzero \n" ); } if( m_TextureStageStateCacheArray[i].data[ m_TextureStageStateCacheArray[i].current_page ][ D3DTSS_COLOROP ] != D3DTOP_DISABLE ) { _oprint( "TextureState Initialize Failed - D3DTSS_COLOROP[%d] is Not D3DTOP_DISABLE(%u). is %u\n" , i, D3DTOP_DISABLE, m_TextureStageStateCacheArray[i].data[ m_TextureStageStateCacheArray[i].current_page ][ D3DTSS_COLOROP ] ); } if( m_TextureStageStateCacheArray[i].data[ m_TextureStageStateCacheArray[i].current_page ][ D3DTSS_TEXCOORDINDEX ] != i ) { _oprint( "TextureState Initialize Failed - D3DTSS_TEXCOORDINDEX[%d] is Not %d. is %u\n" , i, i, m_TextureStageStateCacheArray[i].data[ m_TextureStageStateCacheArray[i].current_page ][ D3DTSS_TEXCOORDINDEX ] ); } } // ManagedSetRenderState Function Test ManagedSetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_SUBTRACT ); ManagedSetTextureStageState( 3, D3DTSS_TEXCOORDINDEX, 1 ); if( m_TextureStageStateCacheArray[1].data[ m_TextureStageStateCacheArray[1].current_page ][ D3DTSS_COLOROP ] != D3DTOP_SUBTRACT ) { _oprint( "1. ManagedSetTextureState( 1, D3DTSS_COLOROP, D3DTOP_SUBTRACT ) - Failed\n" ); } if( m_TextureStageStateCacheArray[3].data[ m_TextureStageStateCacheArray[3].current_page ][ D3DTSS_TEXCOORDINDEX ] != 1 ) { _oprint( "1. ManagedSetTextureState( 3, D3DTSS_TEXCOORDINDEX, 1 ) - Failed\n" ); } // Commit Test _oprint( "1. Commit Test : D3DTSS_COLOROP(1) - %u = %u, D3DTSS_TEXCOORDINDEX(3) - %u = %u \n" , D3DTSS_COLOROP, D3DTOP_SUBTRACT, D3DTSS_TEXCOORDINDEX, 1 ); bool prev_page = m_TextureStageStateCacheArray[1].current_page; PushCurrentStateToDevice(); if( prev_page == m_TextureStageStateCacheArray[1].current_page ) { _oprint( "Commit : Swap Failed - current_page is not changed \n" ); } if( memcmp( m_TextureStageStateCacheArray[2].data[ m_TextureStageStateCacheArray[2].current_page ], _RsHolder::DefaultState[2], sizeof(DWORD)*TS_MAX ) != 0 ) { _oprint( "Commit : Data Clear & Reset Failed - memcmp is nonzero \n" ); } // 같은 스테이트 한번 더 세팅 ManagedSetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_SUBTRACT ); ManagedSetTextureStageState( 3, D3DTSS_TEXCOORDINDEX, 1 ); if( m_TextureStageStateCacheArray[1].data[ m_TextureStageStateCacheArray[1].current_page ][ D3DTSS_COLOROP ] != D3DTOP_SUBTRACT ) { _oprint( "2. ManagedSetRenderState( D3DTSS_COLOROP, D3DTOP_SUBTRACT ) - Failed\n" ); } if( m_TextureStageStateCacheArray[3].data[ m_TextureStageStateCacheArray[3].current_page ][ D3DTSS_TEXCOORDINDEX ] != 1 ) { _oprint( "2. ManagedSetRenderState( D3DTSS_TEXCOORDINDEX, 1 ) - Failed\n" ); } // Commit Test _oprint( "2. Commit Test : D3DTSS_COLOROP(1) - %u = %u, D3DTSS_TEXCOORDINDEX(3) - %u = %u \n" , D3DTSS_COLOROP, D3DTOP_SUBTRACT, D3DTSS_TEXCOORDINDEX, 1 ); PushCurrentStateToDevice(); // 아무것도 세팅하지 않고 Commit 해본다. // Commit Test _oprint( "3. Commit Test(To Default) : D3DTSS_COLOROP(1) - %u = %u, D3DTSS_TEXCOORDINDEX(3) - %u = %u \n" , D3DTSS_COLOROP, D3DTOP_DISABLE, D3DTSS_TEXCOORDINDEX, 3 ); PushCurrentStateToDevice(); _oprint( "--------------------TestTextureState [End]----------------------\n" ); } template void KStateManagerImpl::TestStateBlock() { _oprint( "--------------------TestStateBlock [Start]----------------------\n" ); // Block Create Test. BeginStateBlock(); if( m_pBlockBuffer == NULL ) _oprint( "BeginStateBlock Failed - m_pBlockBuffer is NULL\n" ); ManagedSetRenderState( D3DRS_ZENABLE, FALSE ); ManagedSetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID ); // is default if( m_pBlockBuffer->vRenderStateBlock.back().statetype == D3DRS_FILLMODE ) _oprint( "ManagedSetRenderState Failed - Setted Default State\n" ); ManagedSetSamplerState( 2, D3DSAMP_MINFILTER, D3DTEXF_LINEAR ); ManagedSetSamplerState( 2, D3DSAMP_MINFILTER, D3DTEXF_POINT ); ManagedSetSamplerState( 2, D3DSAMP_MINFILTER, D3DTEXF_LINEAR ); ManagedSetTextureStageState( 3, D3DTSS_TEXCOORDINDEX, 1 ); EndStateBlock( 1 ); if( m_pBlockBuffer != NULL ) _oprint( "EndStateBlock Failed - m_pBlockBuffer is not NULL\n" ); if( m_StateBlocks.empty() ) _oprint( "EndStateBlock Failed - m_StateBlocks is Empty\n" ); // SetStateBlock Test. ManagedSetStateBlock( 1 ); _oprint( "ManagedSetStateBlock Performed. D3DRS_ZENABLE(%u) - FALSE, D3DSAMP_MINFILTER[2](%u) - %u, D3DTSS_TEXCOORDINDEX[3](%u) - 1\n" , D3DRS_ZENABLE, D3DSAMP_MINFILTER, D3DTEXF_LINEAR, D3DTSS_TEXCOORDINDEX ); PushCurrentStateToDevice(); // Clear & Delete Test TestForClearStateBlock(); if( m_pBlockBuffer != NULL ) _oprint( "ClearStateBlock Failed - m_pBlockBuffer is not NULL\n" ); if( !m_StateBlocks.empty() ) _oprint( "ClearStateBlock Failed - m_StateBlocks is not Empty\n" ); _oprint( "--------------------TestStateBlock [End]----------------------\n" ); } template void KStateManagerImpl::TestMultiPass() { _oprint( "--------------------TestMultiPass [Start]----------------------\n" ); // 일단 클리어 PushCurrentStateToDevice(); // 0 번째 패스 _oprint( "0. 0번째 패스 PushCurrentStateToDevice()\n" ); TestForSetPass( 0 ); // Set Render State From EffectInterface. ManagedSetRenderState( D3DRS_ZENABLE, FALSE ); ManagedSetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); ManagedSetSamplerState( 1, D3DSAMP_ADDRESSU, D3DTADDRESS_MIRROR ); ManagedSetSamplerState( 3, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC ); ManagedSetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_SUBTRACT ); ManagedSetTextureStageState( 3, D3DTSS_TEXCOORDINDEX, 1 ); BeginPass( NULL, 0 ); EndPass( NULL ); // 검증 if( m_RenderStateCache.data[!m_RenderStateCache.current_page][D3DRS_ZENABLE] != FALSE || m_RenderStateCache.data[!m_RenderStateCache.current_page][D3DRS_ALPHABLENDENABLE] != TRUE || m_SamplerStateCacheArry[1].data[!m_SamplerStateCacheArry[1].current_page][D3DSAMP_ADDRESSU] != D3DTADDRESS_MIRROR || m_SamplerStateCacheArry[3].data[!m_SamplerStateCacheArry[3].current_page][D3DSAMP_MINFILTER] != D3DTEXF_ANISOTROPIC || m_TextureStageStateCacheArray[1].data[!m_TextureStageStateCacheArray[1].current_page][D3DTSS_COLOROP] != D3DTOP_SUBTRACT || m_TextureStageStateCacheArray[3].data[!m_TextureStageStateCacheArray[3].current_page][D3DTSS_TEXCOORDINDEX] != 1 ) { _oprint( "FAILED - 0 번째 패스 세팅 잘못됨\n" ); } // 1 번째 패스 _oprint( "1. 1번째 패스 PushCurrentStateToDevice()\n" ); TestForSetPass( 1 ); // 1번째 패스에서 변경된 스테이트 세팅 (이펙트 내부에서 세팅된것) ManagedSetRenderState( D3DRS_ALPHABLENDENABLE, FALSE ); // To Default ManagedSetRenderState( D3DRS_FOGENABLE, TRUE ); // Default -> 변경 ManagedSetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE ); // To Default BeginPass( NULL, 1 ); EndPass( NULL ); // 검증 if( m_RenderStateCache.changeidx[m_RenderStateCache.current_page].any() ) { _oprint( "FAILED - 1번째 패서 Push 이후에 changeidx bitset 이 Clear가 안됨\n" ); } // 검증 if( m_RenderStateCache.data[!m_RenderStateCache.current_page][D3DRS_ZENABLE] != FALSE || m_RenderStateCache.data[!m_RenderStateCache.current_page][D3DRS_ALPHABLENDENABLE] != FALSE || m_RenderStateCache.data[!m_RenderStateCache.current_page][D3DRS_FOGENABLE] != TRUE || m_SamplerStateCacheArry[1].data[!m_SamplerStateCacheArry[1].current_page][D3DSAMP_ADDRESSU] != D3DTADDRESS_MIRROR || m_SamplerStateCacheArry[3].data[!m_SamplerStateCacheArry[3].current_page][D3DSAMP_MINFILTER] != D3DTEXF_ANISOTROPIC || m_TextureStageStateCacheArray[1].data[!m_TextureStageStateCacheArray[1].current_page][D3DTSS_COLOROP] != D3DTOP_DISABLE || m_TextureStageStateCacheArray[3].data[!m_TextureStageStateCacheArray[3].current_page][D3DTSS_TEXCOORDINDEX] != 1 ) { _oprint( "FAILED - 1 번째 패스 세팅 잘못됨\n" ); } // 2 번째 패스 _oprint( "2. 2번째 패스 PushCurrentStateToDevice()\n" ); TestForSetPass( 2 ); // 2번째 패스에서 변경된 스테이트 세팅 ManagedSetRenderState( D3DRS_FOGENABLE, FALSE ); // To Default BeginPass( NULL, 2 ); EndPass( NULL ); // 검증 if( m_RenderStateCache.changeidx[m_RenderStateCache.current_page].any() ) { _oprint( "FAILED - 2번째 패서 Push 이후에 changeidx bitset 이 Clear가 안됨\n" ); } // 검증 if( m_RenderStateCache.data[!m_RenderStateCache.current_page][D3DRS_ZENABLE] != FALSE || m_RenderStateCache.data[!m_RenderStateCache.current_page][D3DRS_ALPHABLENDENABLE] != FALSE || m_RenderStateCache.data[!m_RenderStateCache.current_page][D3DRS_FOGENABLE] != FALSE || m_SamplerStateCacheArry[1].data[!m_SamplerStateCacheArry[1].current_page][D3DSAMP_ADDRESSU] != D3DTADDRESS_MIRROR || m_SamplerStateCacheArry[3].data[!m_SamplerStateCacheArry[3].current_page][D3DSAMP_MINFILTER] != D3DTEXF_ANISOTROPIC || m_TextureStageStateCacheArray[1].data[!m_TextureStageStateCacheArray[1].current_page][D3DTSS_COLOROP] != D3DTOP_DISABLE || m_TextureStageStateCacheArray[3].data[!m_TextureStageStateCacheArray[3].current_page][D3DTSS_TEXCOORDINDEX] != 1 ) { _oprint( "FAILED - 2 번째 패스 세팅 잘못됨\n" ); } // 1 번째 패스 _oprint( "3. 3번째 패스 PushCurrentStateToDevice()\n" ); TestForSetPass( 3 ); // 3번째 패스에서 변경된 스테이트 세팅 ManagedSetTextureStageState( 3, D3DTSS_TEXCOORDINDEX, 0 ); // 변경 BeginPass( NULL, 3 ); EndPass( NULL ); // 검증 if( m_RenderStateCache.changeidx[m_RenderStateCache.current_page].any() ) { _oprint( "FAILED - 3번째 패서 Push 이후에 changeidx bitset 이 Clear가 안됨\n" ); } // 검증 if( m_RenderStateCache.data[!m_RenderStateCache.current_page][D3DRS_ZENABLE] != FALSE || m_RenderStateCache.data[!m_RenderStateCache.current_page][D3DRS_ALPHABLENDENABLE] != FALSE || m_RenderStateCache.data[!m_RenderStateCache.current_page][D3DRS_FOGENABLE] != FALSE || m_SamplerStateCacheArry[1].data[!m_SamplerStateCacheArry[1].current_page][D3DSAMP_ADDRESSU] != D3DTADDRESS_MIRROR || m_SamplerStateCacheArry[3].data[!m_SamplerStateCacheArry[3].current_page][D3DSAMP_MINFILTER] != D3DTEXF_ANISOTROPIC || m_TextureStageStateCacheArray[1].data[!m_TextureStageStateCacheArray[1].current_page][D3DTSS_COLOROP] != D3DTOP_DISABLE || m_TextureStageStateCacheArray[3].data[!m_TextureStageStateCacheArray[3].current_page][D3DTSS_TEXCOORDINDEX] != 0 ) { _oprint( "FAILED - 3 번째 패스 세팅 잘못됨\n" ); } _oprint( "--------------------TestMultiPass [End]----------------------\n" ); } template void KStateManagerImpl::TestRestoreDefault() { _oprint( "--------------------TestRestoreDefault [Start]----------------------\n" ); // State 변경 ManagedSetRenderState( D3DRS_ZENABLE, FALSE ); ManagedSetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); ManagedSetSamplerState( 1, D3DSAMP_ADDRESSU, D3DTADDRESS_MIRROR ); ManagedSetSamplerState( 3, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC ); ManagedSetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_SUBTRACT ); ManagedSetTextureStageState( 3, D3DTSS_TEXCOORDINDEX, 1 ); // Restore RestoreDefault(); // 검증 if( memcmp( m_RenderStateCache.data[0], _RsHolder::DefaultState[0], sizeof(DWORD)*RS_MAX ) != 0 || memcmp( m_RenderStateCache.data[1], _RsHolder::DefaultState[0], sizeof(DWORD)*RS_MAX ) != 0 ) { _oprint( "FAILED - Render State is Not Default \n" ); } if( memcmp( m_SamplerStateCacheArry[0].data[0], _RsHolder::DefaultState[0], sizeof(DWORD)*SS_MAX ) != 0 || memcmp( m_SamplerStateCacheArry[0].data[1], _RsHolder::DefaultState[0], sizeof(DWORD)*SS_MAX ) != 0 ) { _oprint( "FAILED - Sampler State is Not Default \n" ); } if( memcmp( m_TextureStageStateCacheArray[2].data[0], _RsHolder::DefaultState[2], sizeof(DWORD)*SS_MAX ) != 0 || memcmp( m_TextureStageStateCacheArray[2].data[1], _RsHolder::DefaultState[2], sizeof(DWORD)*SS_MAX ) != 0 ) { _oprint( "FAILED - Texture State is Not Default \n" ); } _oprint( "--------------------TestRestoreDefault [End]----------------------\n" ); } template void KStateManagerImpl::TestPresent() { _oprint( "--------------------TestPresent [Start]----------------------\n" ); RestoreDefault(); ManagedSetRenderState( D3DRS_ZENABLE, FALSE ); ManagedSetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); ManagedSetSamplerState( 1, D3DSAMP_ADDRESSU, D3DTADDRESS_MIRROR ); ManagedSetSamplerState( 3, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC ); ManagedSetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_SUBTRACT ); ManagedSetTextureStageState( 3, D3DTSS_TEXCOORDINDEX, 1 ); _oprint( "SetRenderState - RenderStateType : %u, value : %u\n", D3DRS_ZENABLE, FALSE ); _oprint( "SetRenderState - RenderStateType : %u, value : %u\n", D3DRS_ALPHABLENDENABLE, TRUE ); _oprint( "SetSamplerState - Stage : %u, SamplerStateType : %u, value : %u\n", 1, D3DSAMP_ADDRESSU, D3DTADDRESS_MIRROR ); _oprint( "SetSamplerState - Stage : %u, SamplerStateType : %u, value : %u\n", 3, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC ); _oprint( "SetTextureState - Stage : %u, TextureStateType : %u, value : %u\n", 1, D3DTSS_COLOROP, D3DTOP_SUBTRACT ); _oprint( "SetTextureState - Stage : %u, TextureStateType : %u, value : %u\n", 3, D3DTSS_TEXCOORDINDEX, 1 ); PresentCurrentRenderState( true ); PresentCurrentSamplerState( true ); PresentCurrentTextureState( true ); _oprint( "--------------------TestPresent [End]----------------------\n" ); } template void KStateManagerImpl::TestPerformance( DWORD count ) { RestoreDefault(); _oprint( "--------------------TestPerformance [Start]----------------------\n" ); // 라펠즈에서 많이 쓰이는 스테이트 블록 세팅 { BeginStateBlock(); ManagedSetRenderState( D3DRS_LIGHTING, FALSE ); // alpha blend ManagedSetRenderState( D3DRS_ALPHABLENDENABLE, FALSE ); ManagedSetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA ); ManagedSetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); ManagedSetRenderState( D3DRS_ZENABLE, TRUE ); ManagedSetRenderState( D3DRS_STENCILENABLE, FALSE ); // alpha test ManagedSetRenderState( D3DRS_ALPHATESTENABLE, TRUE ); ManagedSetRenderState( D3DRS_ALPHAREF, 0 ); ManagedSetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATER ); // vertex material source ManagedSetRenderState( D3DRS_COLORVERTEX, FALSE ); ManagedSetRenderState( D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1 ); ManagedSetRenderState( D3DRS_SPECULARMATERIALSOURCE, D3DMCS_COLOR2 ); ManagedSetRenderState( D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL ); ManagedSetRenderState( D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_MATERIAL ); // set to default for(int i = 0; i < NSTAGE ; ++i) { ManagedSetTextureStageState( i, D3DTSS_COLOROP, D3DTOP_DISABLE ); ManagedSetTextureStageState( i, D3DTSS_RESULTARG, D3DTA_CURRENT ); ManagedSetTextureStageState( i, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); ManagedSetSamplerState( i, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP ); ManagedSetSamplerState( i, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP ); ManagedSetSamplerState( i, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR ); ManagedSetSamplerState( i, D3DSAMP_MINFILTER, D3DTEXF_LINEAR ); ManagedSetSamplerState( i, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR ); } // texture state ManagedSetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); ManagedSetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); ManagedSetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_CURRENT ); ManagedSetTextureStageState( 0, D3DTSS_RESULTARG, D3DTA_CURRENT ); ManagedSetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); ManagedSetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); ManagedSetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_CURRENT ); ManagedSetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR ); ManagedSetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR ); ManagedSetSamplerState( 1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR ); ManagedSetSamplerState( 1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR ); ManagedSetSamplerState( 2, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR ); ManagedSetSamplerState( 2, D3DSAMP_MINFILTER, D3DTEXF_LINEAR ); ManagedSetSamplerState( 1, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR ); ManagedSetSamplerState( 2, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR ); ManagedSetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 ); ManagedSetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); ManagedSetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_LERP ); ManagedSetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE ); ManagedSetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_CURRENT ); ManagedSetTextureStageState( 1, D3DTSS_COLORARG0, D3DTA_DIFFUSE ); ManagedSetTextureStageState( 2, D3DTSS_COLOROP, D3DTOP_BLENDDIFFUSEALPHA ); ManagedSetTextureStageState( 2, D3DTSS_COLORARG1, D3DTA_TEXTURE ); ManagedSetTextureStageState( 2, D3DTSS_COLORARG2, D3DTA_CURRENT ); ManagedSetTextureStageState( 3, D3DTSS_COLOROP, D3DTOP_MODULATE2X ); ManagedSetTextureStageState( 3, D3DTSS_COLORARG1, D3DTA_SPECULAR ); ManagedSetTextureStageState( 3, D3DTSS_COLORARG2, D3DTA_CURRENT ); ManagedSetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 ); ManagedSetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); EndStateBlock( 11 ); } DWORD dwSetTime = 0; DWORD dwPushTime = 0; DWORD dwTime = ::GetSafeTickCount(); DWORD dwTemp = 0; g_OuputPushString = false; for( DWORD i = 0; i < count; i++ ) { dwTemp = GetSafeTickCount(); // ManagedSetStateBlock( 11 ); if( (i % 2) == 0 ) { ManagedSetRenderState( D3DRS_ZENABLE, FALSE ); ManagedSetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); ManagedSetSamplerState( 1, D3DSAMP_ADDRESSU, D3DTADDRESS_MIRROR ); ManagedSetSamplerState( 3, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC ); ManagedSetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_SUBTRACT ); ManagedSetTextureStageState( 3, D3DTSS_TEXCOORDINDEX, 1 ); } else { ManagedSetRenderState( D3DRS_ZENABLE, TRUE ); ManagedSetRenderState( D3DRS_ALPHABLENDENABLE, FALSE ); ManagedSetSamplerState( 1, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP ); ManagedSetSamplerState( 3, D3DSAMP_MINFILTER, D3DTEXF_NONE ); ManagedSetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_ADD ); ManagedSetTextureStageState( 3, D3DTSS_TEXCOORDINDEX, 2 ); } dwSetTime += GetSafeTickCount() - dwTemp; dwTemp = GetSafeTickCount(); PushCurrentStateToDevice(); dwPushTime += GetSafeTickCount() - dwTemp; } DWORD dwAfterTime = GetSafeTickCount(); g_OuputPushString = true; _oprint( " Test Count : [%u], TotalTime : [%u], SetTime : [%u], PushTime : [%u] \n", count, dwAfterTime - dwTime, dwSetTime, dwPushTime ); // Memcpy Time Test // DWORD test_rs[RS_MAX]; // DWORD test_ss[NSTAGE][SS_MAX]; // DWORD test_ts[NSTAGE][TS_MAX]; dwTime = GetSafeTickCount(); for( DWORD i = 0; i < count; i++ ) { memcpy( m_RenderStateCache.data[i%2], _RsHolder::DefaultState[0], sizeof(DWORD) * RS_MAX ); for( DWORD ss = 0; ss < NSTAGE; ss++ ) { memcpy( m_SamplerStateCacheArry[ss].data[i%2], _RsHolder::DefaultState[ss], sizeof(DWORD) * SS_MAX ); memcpy( m_TextureStageStateCacheArray[ss].data[i%2], _RsHolder::DefaultState[ss], sizeof(DWORD) * TS_MAX ); } } dwAfterTime = GetSafeTickCount(); _oprint( " [memcpy] Test Count : [%u], Time : [%u] \n", count, dwAfterTime - dwTime ); _oprint( "--------------------TestPerformance [End]----------------------\n" ); } #endif } // end namespace StateManager