丟失的設備
一個Microsoft? Direct3D?可以處于操作狀態或丟失狀態。操作狀態是設備的正常狀態,設備按預期運行并present所有渲染結果。當事件發生時,如全屏應用程序失去鍵盤輸入焦點,設備就轉變到丟失狀態,這會導致渲染無法進行。丟失狀態表現為所有渲染操作的悄然失敗,這意味著即使渲染操作失敗所有的渲染方法仍可以返回成功碼。在這種情況下,IDirect3DDevice9: resent返回錯誤碼D3DERR_DEVICELOST。
Direct3D有意沒有對可能導致設備丟失的所有情況進行詳細說明。一些典型的例子包括窗口失去焦點,例如用戶按下了ALT+TAB或彈出了一個系統對話框。設備也會因為電源管理事件而丟失,或者另一個應用程序進行全屏操作。另外,任何對IDirect3DDevice9::Reset調用的失敗會把設備置為丟失狀態。
注意 可以保證所有繼承自IUnknown的方法在設備丟失后仍能正常工作。設備丟失后,每個函數一般有三種可能:
調用失敗,返回值為D3DERR_DEVICELOST – 這意味著應用程序必須發現設備已經丟失,從而知道一些事情沒有按照預期進行。 悄然失敗,返回值為S_OK或其它值 – 若函數調用悄然失敗,則應用程序一般無法區分出“調用成功”或“悄然失敗”。 函數返回一個返回值。 對丟失的設備作出響應
設備在被重置后,應該重新創建資源(包括顯存資源)。如果設備丟失了,那么應用程序應該查詢設備狀態,看是否可以將之恢復回操作狀態。如果不行,那么就等到設備可以被恢復為止。
如果設備可以被恢復,那么應用程序應該銷毀所有顯存資源和交換鏈,并準備恢復。然后,應用程序調用IDirect3DDevice9::Reset方法。Reset方法是當設備丟失時唯一有效的方法,并且是應用程序可用來把設備從丟失狀態恢復到操作狀態的唯一方法。除非應用程序釋放所有在D3DPOOL_DEFAULT中分配的資源,包括用IDirect3DDevice9::CreateRenderTarget和IDirect3DDevice9::CreateDepthSstencilSurface方法創建的資源,否則Reset將會失敗。
Direct3D中大部分被頻繁調用的方法不返回任何關于設備是否已丟失的信息。應用程序可以繼續調用渲染方法,如IDirect3DDevice9: rawPrimitive,而不會收到設備丟失的通知。在Direct3D內部,這些操作被拋棄,直到設備被重置為操作狀態為止。
通過查詢IDirect3DDevice9::TestCooperativeLevel方法的返回值,應用程序可以決定在遇到設備丟失時如何處理。
管理資源
資源管理是將資源從系統內存提升到設備可訪問存儲器及從設備可訪問存儲器中拋棄的過程。Microsoft? Direct3D?運行庫有自己的基于最近最少使用(least-recently-used)優先級技術的管理算法。當Direct3D檢測到在一幀中——在IDirect3DDevice9::BeginScene和IDirect3DDevice9::EndScene調用之間——設備可訪問內存無法同時存儲所有資源時,它就切換到最近最多使用(most-recently-used)優先級技術。
在創建時使用D3DPOOL_MANAGED標志指定一個由系統管理的資源。由系統管理的資源在設備的丟失狀態和操作狀態間的轉換中持續存在。通過調用IDirect3DDevice9::Reset設備可以被重置,并且這類資源可以繼續正常運作而無需重新載入圖片。但是,如果設備必須被銷毀和重建,那么所有用D3DPOOL_MANAGED創建的資源也必須被重建。
在創建時使用D3DPOOL_DEFAULT標志指定把資源放在默認的池中。在默認的池中的資源在設備從丟失狀態到操作狀態的轉換過程中不持續存在,這些資源必須在調用Reset之前釋放,然后重建。
更多有關設備的丟失狀態的信息,請參閱丟失的設備。
注意不是所有的類型和用途都支持資源管理。例如,用D3DUSAGE_RENDERTARGET標志創建的對象不支持資源管理。另外,不建議對需要頻繁改變其內容的對象使用資源管理。例如,在某些硬件上對一個每幀都需改變的頂點緩存進行自動管理會嚴重降低性能。但是,對紋理資源來說這不是一個問題。
例子(摘自codesampler):
以下內容為程序代碼:
//----------------------------------------------------------------------------- // Name: invalidateDeviceObjects() // Desc: If the lost device can be restored, the application prepares the // device by destroying all video-memory resources and any // swap chains. This is typically accomplished by using the SAFE_RELEASE // macro. //----------------------------------------------------------------------------- HRESULT invalidateDeviceObjects( void ) { // // To see how mismanagement of an object''s reference counter can cause us // problems when calling Reset on the device, uncomment the line below. // The line below will call AddRef() on the vertex buffer object, which w // ill add one to the vertex buffer''s reference count. This will cause it // to hang around after we call Release() on it, which is not what we // wanted to happen here. // //g_pVertexBuffer->AddRef();
// // NOTE: You could use the SAFE_RELEASE macro to invalidate your device // objects like so: // SAFE_RELEASE( g_pTexture ) SAFE_RELEASE( g_pVertexBuffer ) SAFE_RELEASE( g_pTeapotMesh ) return S_OK; }
//----------------------------------------------------------------------------- // Name: restoreDeviceObjects() // Desc: You are encouraged to develop applications with a single code path to // respond to device loss. This code path is likely to be similar, if not // identical, to the code path taken to initialize the device at startup. //----------------------------------------------------------------------------- HRESULT restoreDeviceObjects( void ) { // // Set some important state settings... //
D3DXMATRIX matProj; D3DXMatrixPerspectiveFovLH( &matProj, D3DXToRadian( 45.0f ), 640.0f / 480.0f, //(float)(g_d3dpp.BackBufferWidth / g_d3dpp.BackBufferHeight), 0.1f, 100.0f ); g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE ); g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE ); g_pd3dDevice->SetRenderState( D3DRS_SPECULARENABLE, TRUE );
g_pd3dDevice->SetLight( 0, &g_pLight0 ); g_pd3dDevice->LightEnable( 0, TRUE );
g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, D3DCOLOR_COLORVALUE( 0.2f, 0.2f, 0.2f, 1.0f ) );
// // Create a texture object... //
D3DXCreateTextureFromFile( g_pd3dDevice, "test.bmp", &g_pTexture );
g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR ); g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
// // Create a vertex buffer... // // NOTE: When a device is lost, vertex buffers created using // D3DPOOL_DEFAULT must be released properly before calling // IDirect3DDevice9::Reset. //
g_pd3dDevice->CreateVertexBuffer( 4*sizeof(QuadVertex), D3DUSAGE_WRITEONLY, QuadVertex::FVF_Flags, //D3DPOOL_MANAGED, // Does not have to be properly Released before calling IDirect3DDevice9::Reset D3DPOOL_DEFAULT, // Must be Released properly before calling IDirect3DDevice9::Reset &g_pVertexBuffer, NULL ); void *pVertices = NULL;
g_pVertexBuffer->Lock( 0, sizeof(g_quadVertices), (void**)&pVertices, 0 ); memcpy( pVertices, g_quadVertices, sizeof(g_quadVertices) ); g_pVertexBuffer->Unlock();
// // Create a mesh object... // // NOTE: When a device is lost, meshes created using D3DXMESH_DYNAMIC // must be released properly before calling IDirect3DDevice9::Reset. //
D3DXLoadMeshFromX( "teapot.x", //D3DXMESH_SYSTEMMEM, // Does not have to be properly Released before calling IDirect3DDevice9::Reset //D3DXMESH_MANAGED, // Does not have to be properly Released before calling IDirect3DDevice9::Reset //D3DXMESH_WRITEONLY, // Does not have to be properly Released before calling IDirect3DDevice9::Reset D3DXMESH_DYNAMIC, // Must be Released properly before calling IDirect3DDevice9::Reset g_pd3dDevice, NULL, NULL, NULL, NULL, &g_pTeapotMesh ); return S_OK; }
//----------------------------------------------------------------------------- // Name: render() // Desc: //----------------------------------------------------------------------------- void render( void ) { // // Before we render, we need to make sure we haven''t lost our device. // If we have, we''ll need to restore it before we can continue. //
HRESULT hr;
if( g_bDeviceLost == true ) { // Yield some CPU time to other processes Sleep( 100 ); // 100 milliseconds
// // Test the cooperative level to see if it''s okay to render. // The application can determine what to do on encountering a lost // device by querying the return value of the TestCooperativeLevel // method. //
if( FAILED( hr = g_pd3dDevice->TestCooperativeLevel() ) ) { // The device has been lost but cannot be reset at this time. // Therefore, rendering is not possible and we''ll have to return // and try again at a later time. if( hr == D3DERR_DEVICELOST ) return;
// The device has been lost but it can be reset at this time. if( hr == D3DERR_DEVICENOTRESET ) { // // If the device can be restored, the application prepares the // device by destroying all video-memory resources and any // swap chains. //
invalidateDeviceObjects();
// // Then, the application calls the Reset method. // // Reset is the only method that has an effect when a device // is lost, and is the only method by which an application can // change the device from a lost to an operational state. // Reset will fail unless the application releases all // resources that are allocated in D3DPOOL_DEFAULT, including // those created by the IDirect3DDevice9::CreateRenderTarget // and IDirect3DDevice9::CreateDepthStencilSurface methods. //
hr = g_pd3dDevice->Reset( &g_d3dpp );
if( FAILED(hr ) ) return;
// // Finally, a lost device must re-create resources (including // video memory resources) after it has been reset. //
restoreDeviceObjects(); }
return; }
g_bDeviceLost = false; }
// // Render a teapot and textured quad... //
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_COLORVALUE(0.35f,0.53f,0.7f,1.0f), 1.0f, 0 );
g_pd3dDevice->BeginScene(); { D3DXMATRIX matView; D3DXMATRIX matWorld; D3DXMATRIX matRotation; D3DXMATRIX matTranslation;
D3DXMatrixIdentity( &matView ); g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );
// Place and render first teapot... D3DXMatrixRotationYawPitchRoll( &matRotation, D3DXToRadian(g_fSpinX), D3DXToRadian(g_fSpinY), 0.0f ); D3DXMatrixTranslation( &matTranslation, 1.5f, 0.0f, 6.0f ); matWorld = matRotation * matTranslation; g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
g_pd3dDevice->SetMaterial( &g_teapotMtrl ); g_pTeapotMesh->DrawSubset(0);
// Place and render textured quad... D3DXMatrixTranslation( &matTranslation, -1.5f, 0.0f, 6.0f ); matWorld = matRotation * matTranslation; g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
g_pd3dDevice->SetMaterial( &g_quadMtrl ); g_pd3dDevice->SetTexture( 0, g_pTexture ); g_pd3dDevice->SetStreamSource( 0, g_pVertexBuffer, 0, sizeof(QuadVertex) ); g_pd3dDevice->SetFVF( QuadVertex::FVF_Flags ); g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 ); } g_pd3dDevice->EndScene();
// // If Present fails with D3DERR_DEVICELOST the application needs to be // notified so it cleanup resources and reset the device. //
hr = g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
if( g_bHandleLostDevice == true ) { if( hr == D3DERR_DEVICELOST ) g_bDeviceLost = true; } } |
|
|