2013-11-14 151 views
1

最近,我發現在我的3D應用程序使用DirectX 9的錯誤是,每次我使用Alt-Tab或CTRL-ALT-刪除程序凍結或似乎做什麼的錯誤。我環顧四周,發現我需要通過使用IDirect3DDevice9::TestCooperativeLevelIDirect3DDevice9::Reset來重置我的設備。但是,我掙扎的時刻是,(據我所知)之前,我Reset設備,我需要釋放的種源在D3DPOOL_MANAGE之前,我重置設備和復位後重新分配資源回嗎?我該怎麼做呢?以下是我用於重置設備的代碼(位於IsDeviceLost()函數中)。如何重置我的DirectX 9設備?

DirectX.h

#pragma once 
#pragma comment(lib, "d3d9.lib") 

#include<d3d9.h> 
#include<d3dx9math.h> 

#include"Window.h" 
#include"Vertex.h" 
#include"Shader.h" 

#define VERTEXFORMAT (D3DFVF_XYZ | D3DFVF_TEX1) //Flags for the Flexible Vertex Format (FVF) 

class Shader; 

class DirectX 
{ 
public: 
    DirectX(std::string windowTitle, int x, int y, unsigned int windowWidth, unsigned int windowHeight, bool fullscreen); 
    virtual ~DirectX(); 

    static LPDIRECT3D9 direct3D; 
    static LPDIRECT3DDEVICE9 device; 
    static IDirect3DVertexDeclaration9* vertexDec; 
    static ID3DXEffect* currentShaderEffect; 

    void CheckShaderVersion(); 
    bool IsDeviceLost(); 

protected: 
    D3DPRESENT_PARAMETERS direct3DPresPara; 

    Window *window; 
    unsigned int width; 
    unsigned int height; 
    D3DXMATRIX projMatrix; 

private: 
    void Initialize(bool fullscreenMode); 
}; 

Direct.cpp

#include"DirectX.h" 

LPDIRECT3D9 DirectX::direct3D = NULL; 
LPDIRECT3DDEVICE9 DirectX::device = NULL; 
IDirect3DVertexDeclaration9* DirectX::vertexDec = NULL; 
ID3DXEffect* DirectX::currentShaderEffect = NULL; 

DirectX::DirectX(std::string windowTitle, int x, int y, unsigned int windowWidth, unsigned int windowHeight, bool fullscreen) 
{ 
    width = windowWidth; 
    height = windowHeight; 

    window = new Window(windowTitle.c_str(), windowWidth, windowHeight, x, y, fullscreen); 

    Initialize(fullscreen); 

    D3DXMatrixPerspectiveFovLH(&projMatrix, 
           D3DXToRadian(45), 
           (float)width/(float)height, 
           1.0f, 
           15000.0f); 

    //device->SetTransform(D3DTS_PROJECTION, &projMatrix); 
} 

DirectX::~DirectX() 
{ 
    direct3D->Release(); 
    device->Release(); 
    vertexDec->Release(); 

    delete vertexDec; 
    delete currentShaderEffect; 
    delete window; 
} 

void DirectX::Initialize(bool fullscreenMode) 
{ 
    direct3D = Direct3DCreate9(D3D_SDK_VERSION); 

    ZeroMemory(&direct3DPresPara, sizeof(direct3DPresPara)); 

    switch(fullscreenMode) 
    { 
     case true: 
      direct3DPresPara.Windowed = false; 
     break; 
     case false: 
      direct3DPresPara.Windowed = true; 
    } 

    direct3DPresPara.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; //turns off VSync, comment this line of code to turn VSync back on 
    direct3DPresPara.SwapEffect = D3DSWAPEFFECT_DISCARD; 
    direct3DPresPara.hDeviceWindow = window->GetHandle(); 
    direct3DPresPara.BackBufferFormat = D3DFMT_X8R8G8B8; 
    direct3DPresPara.BackBufferWidth = width; 
    direct3DPresPara.BackBufferHeight = height; 
    direct3DPresPara.EnableAutoDepthStencil = TRUE; 
    direct3DPresPara.AutoDepthStencilFormat = D3DFMT_D16; 

    direct3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window->GetHandle(), D3DCREATE_SOFTWARE_VERTEXPROCESSING, &direct3DPresPara, &device); 

    D3DVERTEXELEMENT9 vertexElement[] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, 
              {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, 
              D3DDECL_END()}; 

    device->CreateVertexDeclaration(vertexElement, &vertexDec); 

    //currentShaderEffect = 0; 
} 

void DirectX::CheckShaderVersion() 
{ 
    D3DCAPS9 caps; 

    device->GetDeviceCaps(&caps); 

    bool stop = false; 
    int i = 6; 
    while(!stop) 
    { 
     if(caps.VertexShaderVersion < D3DVS_VERSION(i, 0)) 
     { 
      i--; 
     } 
     else 
     { 
      std::cout << "you are using shader model " << i << std::endl; 
      stop = true; 
     } 
    } 

    //std::cout << caps.VertexShaderVersion << std::endl; 
    //std::cout << D3DVS_VERSION(3, 0) << std::endl; 
} 

bool DirectX::IsDeviceLost() 
{ 
    HRESULT result = device->TestCooperativeLevel(); 

    if(result == D3DERR_DEVICELOST) 
    { 
     Sleep(20); //Sleep for a little bit then try again. 
     return true; 
    } 
    else if(result == D3DERR_DRIVERINTERNALERROR) 
    { 
     MessageBox(0, "Internal Driver Error. The program will now exit.", 0, 0); 
     PostQuitMessage(0); 
     return true; 
    } 
    else if(result == D3DERR_DEVICENOTRESET) 
    { 
     device->Reset(&direct3DPresPara); 
     return false; 
    } 
    else 
    { 
     return false; 
    } 
} 

任何幫助或建議將不勝感激。由於

+0

'D3DPOOL_MANAGED'實際上並不需要這麼多的解決這個問題。最簡單的方法就是創建一些即將失效的事物,以便在發生這種情況時它們已經被銷燬並重新創建。 – chris

回答

3

你並不需要釋放資源D3DPOOL_MANAGED。您需要釋放D3DPOOL_DEFAULT中的資源。

如果您使用的是D3DX對象(ID3DXFont,ID3DXMesh,ID3DXSprite),they typically have "OnLostDevice" and "OnResetDevice" methods。你應該在適當的情況下調用這些方法。

如果對象不具備對付「DeviceLost」狀態的任何方法,他們應該被釋放,簡單復位設備之前銷燬對象,之後重新裝入。

請注意,D3DPOOL_MANAGED對象由驅動程序自動加載,並且不需要任何「幫助」從你處理復位/ devicelost。你需要關心所有其他物體。

除了我說/寫的,很顯然你應該閱讀的DirectX SDK文檔。它們涵蓋了documentation中丟失的設備,並且DirectX示例通常在設備重置後仍然可以正常運行。

+0

感謝您的信息。我不使用任何D3DX對象。實際上,此刻,我寫了自己的OBJMesh和Heightmap類。這是否意味着我必須從程序中刪除任何OBJMesh或模型,並重新初始化它的數據,如頂點緩衝區,紋理等? – Danny

+0

@Danny:如果我沒有記錯,那麼網格和紋理都可以放入D3DPOOL_MANAGED中,除非它們有D3DUSAGE_DYNAMIC標誌(在這種情況下它們只能放入POOL_DEFAULT中)。因此,如果將網格/紋理放入托管池中,則不需要執行任何操作。如果我沒有記錯,Shaders不能放入托管池中,應該釋放並重新創建。此外,如果您不確定是什麼阻止您重置設備,則可以安裝調試DirectX並查看MSVC中的調試輸出> – SigTerm

+0

着色器以及頂點聲明不需要在丟失的設備上釋放。 – cdoubleplusgood