Danny
Danny

Reputation: 9634

How to reset my DirectX 9 device?

Recently, I've found a bug in my 3D application that uses DirectX 9. The bug is that everytime I alt-tab or ctrl-alt-delete, the program freezes or seems to do nothing. I've looked around and found out that I need to reset my device by using IDirect3DDevice9::TestCooperativeLevel and IDirect3DDevice9::Reset. But what I'm struggling on at the moment is that (as far as I know) before I Reset the device, I need to release the resouce in D3DPOOL_MANAGE before I reset the device and reallocate the resource back to it after the Reset? How do I do this? Below is the code I've got for the reset of my device (in the IsDeviceLost() function).

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

Any help or advice will be greatly appreciated. Thanks

Upvotes: 2

Views: 7996

Answers (1)

SigTerm
SigTerm

Reputation: 26439

You don't need to release resources in D3DPOOL_MANAGED. You need to release resources in D3DPOOL_DEFAULT.

If you're using D3DX objects (ID3DXFont, ID3DXMesh, ID3DXSprite), they typically have "OnLostDevice" and "OnResetDevice" methods. You should call those methods in appropriate situations.

If an object does not have any methods for dealing with "DeviceLost" state, and they should be released, simply destroy the object before resetting the device, and reload it afterwards.

Please note that D3DPOOL_MANAGED objects are reloaded automatically by the driver and don't need any "help" from you to deal with reset/devicelost. YOu do need to take care about all other objects.

In addition to what I said/wrote, you should obviously read DirectX SDK documentation. They cover lost devices in their documentation, and DirectX examples normally survive device reset just fine.

Upvotes: 3

Related Questions