如何重置我的DirectX 9设备?

时间:2013-11-14 14:33:03

标签: c++ directx

最近,我在我的3D应用程序中发现了一个使用DirectX 9的错误。错误是每次我使用alt-tab或ctrl-alt-delete时,程序会冻结或似乎什么都不做。我环顾四周,发现我需要使用IDirect3DDevice9::TestCooperativeLevelIDirect3DDevice9::Reset来重置设备。但是我现在正在努力的是(据我所知)在我Reset设备之前,我需要在重置设备并重新分配资源之前在D3DPOOL_MANAGE中释放资源重置后回到它?我该怎么做呢?下面是我为重置设备而获得的代码(在IsDeviceLost()函数中)。

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;
    }
}

非常感谢任何帮助或建议。感谢

1 个答案:

答案 0 :(得分:3)

您无需在D3DPOOL_MANAGED中释放资源。您需要在D3DPOOL_DEFAULT中释放资源。

如果您正在使用D3DX对象(ID3DXFont,ID3DXMesh,ID3DXSprite),they typically have "OnLostDevice" and "OnResetDevice" methods。你应该在适当的情况下调用这些方法。

如果一个对象没有任何处理“DeviceLost”状态的方法,并且它们应该被释放,只需在重置设备之前销毁该对象,然后重新加载它。

请注意,D3DPOOL_MANAGED对象由驱动程序自动重新加载,不需要任何“帮助”来处理reset / devicelost。你确实需要关注所有其他物品。

除了我所说/写的内容之外,您显然应该阅读DirectX SDK文档。它们覆盖了documentation中丢失的设备,而DirectX示例通常可以在设备重置后继续使用。