//------------------------------------------------------------------------------ // Check for texture mis-match between GFX internal state and what is on the card // This function is expensive because of the readbacks from DX, and additionally // won't work unless it's a non-pure device. // // This function can crash or give false positives when the game // is shutting down or returning to the main menu as some of the textures // present in the mCurrentTexture array will have been freed. // // This function is best used as a quick check for mismatched state when it is // suspected. //------------------------------------------------------------------------------ void GFXD3D9Device::doParanoidStateCheck() { #ifdef TORQUE_DEBUG // Read back all states and make sure they match what we think they should be. // For now just do texture binds. for(U32 i = 0; i < getNumSamplers(); i++) { IDirect3DBaseTexture9 *b=NULL; getDevice()->GetTexture(i, &b); if ((mCurrentTexture[i].isNull()) && (mCurrentCubemap[i].isNull())) { AssertFatal(b == NULL, "GFXD3D9Device::doParanoidStateCheck - got non-null texture in expected NULL slot!"); getDevice()->SetTexture(i, NULL); } else { AssertFatal(mCurrentTexture[i] || mCurrentCubemap[i], "GFXD3D9Device::doParanoidStateCheck - got null texture in expected non-null slot!"); if (mCurrentCubemap[i]) { IDirect3DCubeTexture9 *cur= static_cast<GFXD3D9Cubemap*>(mCurrentCubemap[i].getPointer())->mCubeTex; AssertFatal(cur == b, "GFXD3D9Device::doParanoidStateCheck - mismatched cubemap!"); } else { IDirect3DBaseTexture9 *cur= static_cast<GFXD3D9TextureObject*>(mCurrentTexture[i].getPointer())->getTex(); AssertFatal(cur == b, "GFXD3D9Device::doParanoidStateCheck - mismatched 2d texture!"); } } SAFE_RELEASE(b); } #endif }
//----------------------------------------------------------------------------- // Reset D3D device //----------------------------------------------------------------------------- void GFXPCD3D9Device::reset( D3DPRESENT_PARAMETERS &d3dpp ) { if(!mD3DDevice) return; mInitialized = false; mMultisampleType = d3dpp.MultiSampleType; mMultisampleLevel = d3dpp.MultiSampleQuality; _validateMultisampleParams(d3dpp.BackBufferFormat, mMultisampleType, mMultisampleLevel); // Clean up some commonly dangling state. This helps prevents issues with // items that are destroyed by the texture manager callbacks and recreated // later, but still left bound. setVertexBuffer(NULL); setPrimitiveBuffer(NULL); for(S32 i=0; i<getNumSamplers(); i++) setTexture(i, NULL); // Deal with the depth/stencil buffer. if(mDeviceDepthStencil) { Con::printf("GFXPCD3D9Device::reset - depthstencil %x has %d ref's", mDeviceDepthStencil, mDeviceDepthStencil->AddRef()-1); mDeviceDepthStencil->Release(); } // First release all the stuff we allocated from D3DPOOL_DEFAULT releaseDefaultPoolResources(); // reset device Con::printf( "--- Resetting D3D Device ---" ); HRESULT hres = S_OK; hres = mD3DDevice->Reset( &d3dpp ); if( FAILED( hres ) ) { while( mD3DDevice->TestCooperativeLevel() == D3DERR_DEVICELOST ) { Sleep( 100 ); } hres = mD3DDevice->Reset( &d3dpp ); } D3D9Assert( hres, "GFXD3D9Device::reset - Failed to create D3D Device!" ); mInitialized = true; // Setup default states initStates(); // Now re aquire all the resources we trashed earlier reacquireDefaultPoolResources(); // Mark everything dirty and flush to card, for sanity. updateStates(true); }
void GFXDevice::updateStates(bool forceSetAll /*=false*/) { PROFILE_SCOPE(GFXDevice_updateStates); if(forceSetAll) { bool rememberToEndScene = false; if(!canCurrentlyRender()) { if (!beginScene()) { AssertFatal(false, "GFXDevice::updateStates: Unable to beginScene!"); } rememberToEndScene = true; } setMatrix( GFXMatrixProjection, mProjectionMatrix ); setMatrix( GFXMatrixWorld, mWorldMatrix[mWorldStackSize] ); setMatrix( GFXMatrixView, mViewMatrix ); setVertexDecl( mCurrVertexDecl ); for ( U32 i=0; i < VERTEX_STREAM_COUNT; i++ ) { setVertexStream( i, mCurrentVertexBuffer[i] ); setVertexStreamFrequency( i, mVertexBufferFrequency[i] ); } if( mCurrentPrimitiveBuffer.isValid() ) // This could be NULL when the device is initalizing mCurrentPrimitiveBuffer->prepare(); /// Stateblocks if ( mNewStateBlock ) setStateBlockInternal(mNewStateBlock, true); mCurrentStateBlock = mNewStateBlock; for(U32 i = 0; i < getNumSamplers(); i++) { switch (mTexType[i]) { case GFXTDT_Normal : { mCurrentTexture[i] = mNewTexture[i]; setTextureInternal(i, mCurrentTexture[i]); } break; case GFXTDT_Cube : { mCurrentCubemap[i] = mNewCubemap[i]; if (mCurrentCubemap[i]) mCurrentCubemap[i]->setToTexUnit(i); else setTextureInternal(i, NULL); } break; default: AssertFatal(false, "Unknown texture type!"); break; } } // Set our material setLightMaterialInternal(mCurrentLightMaterial); // Set our lights for(U32 i = 0; i < LIGHT_STAGE_COUNT; i++) { setLightInternal(i, mCurrentLight[i], mCurrentLightEnable[i]); } _updateRenderTargets(); if(rememberToEndScene) endScene(); return; } if (!mStateDirty) return; // Normal update logic begins here. mStateDirty = false; // Update Projection Matrix if( mProjectionMatrixDirty ) { setMatrix( GFXMatrixProjection, mProjectionMatrix ); mProjectionMatrixDirty = false; } // Update World Matrix if( mWorldMatrixDirty ) { setMatrix( GFXMatrixWorld, mWorldMatrix[mWorldStackSize] ); mWorldMatrixDirty = false; } // Update View Matrix if( mViewMatrixDirty ) { setMatrix( GFXMatrixView, mViewMatrix ); mViewMatrixDirty = false; } if( mTextureMatrixCheckDirty ) { for( S32 i = 0; i < getNumSamplers(); i++ ) { if( mTextureMatrixDirty[i] ) { mTextureMatrixDirty[i] = false; setMatrix( (GFXMatrixType)(GFXMatrixTexture + i), mTextureMatrix[i] ); } } mTextureMatrixCheckDirty = false; } // Update the vertex declaration. if ( mVertexDeclDirty ) { setVertexDecl( mCurrVertexDecl ); mVertexDeclDirty = false; } // Update the vertex buffers. for ( U32 i=0; i < VERTEX_STREAM_COUNT; i++ ) { if ( mVertexBufferDirty[i] ) { setVertexStream( i, mCurrentVertexBuffer[i] ); mVertexBufferDirty[i] = false; } if ( mVertexBufferFrequencyDirty[i] ) { setVertexStreamFrequency( i, mVertexBufferFrequency[i] ); mVertexBufferFrequencyDirty[i] = false; } } // Update primitive buffer // // NOTE: It is very important to set the primitive buffer AFTER the vertex buffer // because in order to draw indexed primitives in DX8, the call to SetIndicies // needs to include the base vertex offset, and the DX8 GFXDevice relies on // having mCurrentVB properly assigned before the call to setIndices -patw if( mPrimitiveBufferDirty ) { if( mCurrentPrimitiveBuffer.isValid() ) // This could be NULL when the device is initalizing mCurrentPrimitiveBuffer->prepare(); mPrimitiveBufferDirty = false; } // NOTE: With state blocks, it's now important to update state before setting textures // some devices (e.g. OpenGL) set states on the texture and we need that information before // the texture is activated. if (mStateBlockDirty) { setStateBlockInternal(mNewStateBlock, false); mCurrentStateBlock = mNewStateBlock; mStateBlockDirty = false; } if( mTexturesDirty ) { mTexturesDirty = false; for(U32 i = 0; i < getNumSamplers(); i++) { if(!mTextureDirty[i]) continue; mTextureDirty[i] = false; switch (mTexType[i]) { case GFXTDT_Normal : { mCurrentTexture[i] = mNewTexture[i]; setTextureInternal(i, mCurrentTexture[i]); } break; case GFXTDT_Cube : { mCurrentCubemap[i] = mNewCubemap[i]; if (mCurrentCubemap[i]) mCurrentCubemap[i]->setToTexUnit(i); else setTextureInternal(i, NULL); } break; default: AssertFatal(false, "Unknown texture type!"); break; } } } // Set light material if(mLightMaterialDirty) { setLightMaterialInternal(mCurrentLightMaterial); mLightMaterialDirty = false; } // Set our lights if(mLightsDirty) { mLightsDirty = false; for(U32 i = 0; i < LIGHT_STAGE_COUNT; i++) { if(!mLightDirty[i]) continue; mLightDirty[i] = false; setLightInternal(i, mCurrentLight[i], mCurrentLightEnable[i]); } } _updateRenderTargets(); #ifdef TORQUE_DEBUG_RENDER doParanoidStateCheck(); #endif }