Jump to content
  • Advertisement
Sign in to follow this  
JeZ-l-Lee

DirectX 9.0c: Handling "Lost Device"?

This topic is 2109 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi,

 

What is the best method to handle a "lost device" in DirectX 9.0c?

Please look at the source code below and tell me if I am doing it correctly or not.

I "Reset" the DirectX device and reload the DirectX Sprites...

 

Thanks!

 

JeZ+Lee

 

 

Sprite Loading Function:

bool Visuals::LoadSpritesIntoMemoryAndInitialize(bool DeviceReset)
{
HRESULT result;
char filePath[256];

    strcpy_s(filePath, "~\0");

    for (int index = 0; index < NumberOfSprites; index++)
    {
        switch(index)
        {
            case 0:
                strcpy_s(filePath, "Data/Visuals/Screen-Fade-Black-Box.png");
                break;

            case 5:
                strcpy_s(filePath, "Data/Visuals/16BitSoft-Logo.png");
                break;

            case 6:
                strcpy_s(filePath, "Data/Visuals/Title-BG.png");
                break;

            case 7:
                strcpy_s(filePath, "Data/Visuals/TC5-Logo.png");
                break;

            default:
                strcpy_s(filePath, "~");
                break;
        }

        strcat_s(filePath, "\0");

        if (filePath[0] != '~')
        {
            D3DXIMAGE_INFO imageInfo;
            result = D3DXGetImageInfoFromFileA(filePath, &imageInfo);
//            if FAILED (hResult){
//            return false;
//            }

            D3DXCreateTextureFromFileExA(DXDevice, filePath,  imageInfo.Width, imageInfo.Height, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN,
                                         D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &Sprites[index].Texture);

            result = D3DXCreateSprite(DXDevice, &Sprites[index].DXSprite);

            if (DeviceReset == false)
            {
                Sprites[index].ScreenX = 400.0f;
                Sprites[index].ScreenY = 240.0f;
                Sprites[index].ScaleX = 1.0f;
                Sprites[index].ScaleY = 1.0f;
                Sprites[index].RotationDegree = 0.0f;
                Sprites[index].RedHue = 255;
                Sprites[index].GreenHue = 255;
                Sprites[index].BlueHue = 255;
                Sprites[index].Transparency = 255;
                Sprites[index].Smooth = true;
                Sprites[index].FlipX = false;
                Sprites[index].FlipY = false;
                Sprites[index].OriginalWidth = imageInfo.Width;
                Sprites[index].OriginalHeight = imageInfo.Height;

                D3DSURFACE_DESC textureInfo;
                Sprites[index].Texture->GetLevelDesc(0, &textureInfo);
                Sprites[index].TextureWidth = textureInfo.Width;
                Sprites[index].TextureHeight = textureInfo.Height;

                Sprites[index].AnimationTimer = -1.0f;
            }
        }
    }

    return(true);
}

Screen Render Function:

void Visuals::DisplayScreenBufferOntoDisplay(void)
{
HRESULT result;

    result = DXDevice->Present( NULL, NULL, NULL, NULL );

    if (result != D3D_OK)
    {
        D3DDISPLAYMODE d3ddm;
        DXD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm );
        D3DPRESENT_PARAMETERS d3dpp;
        ZeroMemory( &d3dpp, sizeof(d3dpp) );
        d3dpp.Windowed               = TRUE;
        d3dpp.SwapEffect             = D3DSWAPEFFECT_DISCARD;
        d3dpp.BackBufferFormat       = d3ddm.Format;
        d3dpp.EnableAutoDepthStencil = TRUE;
        d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
        d3dpp.PresentationInterval   = D3DPRESENT_INTERVAL_IMMEDIATE;
        DXDevice->Reset(&d3dpp);

        for (int index = 0; index < NumberOfSprites; index++)
        {
            if (Sprites[index].DXSprite != NULL)  Sprites[index].DXSprite->Release();
            if (Sprites[index].Texture != NULL)  Sprites[index].Texture->Release();
        }

        LoadSpritesIntoMemoryAndInitialize(true);
    }
}

Share this post


Link to post
Share on other sites
Advertisement

mhagain has explained everything perfectly (at least to my knowledge).

 

Just 2 remarks:

It is almost always wrong to compare an HRESULT to a specific success code like D3D_OK. Please use the SUCCEEDED and FAILED macros instead.

 

The best way to wait for the next attempt to reset is IMHO MsgWaitForMultipleObjects, like this:

DWORD result = MsgWaitForMultipleObjects(0, NULL, FALSE, 10, QS_ALLINPUT);

Share this post


Link to post
Share on other sites

It is almost always wrong to compare an HRESULT to a specific success code like D3D_OK. Please use the SUCCEEDED and FAILED macros instead.

 

This is actually one of those cases where you do want to check for specific HRESULTS; consider it an exception to the general rule.  You definitely want to act on D3DERR_DEVICELOST (and only D3DERR_DEVICELOST) from your Present call, and you can't implement the TestCooperativeLevel recovery without checking for specific values.

Share this post


Link to post
Share on other sites

This is what I use: 

hr = device->Present(NULL, NULL, NULL, NULL);

	if (hr == D3DERR_DEVICELOST){
		LostDevice = true;
	}
if(LostDevice){
		RecoverDevice();
	} else {
		Render();
	}
RecoverDevice()
{
	HRESULT hr = NULL;

	hr = device->TestCooperativeLevel();
	switch (hr)
	{
	case D3D_OK:
		// device is no longer lost and reset has completed successfully; recover resources here
		LostDevice = false;
		return;  // note: this assumes that this test is the last thing in the function it's being called from
	case D3DERR_DEVICELOST:
		Sleep(5);
		// device is still lost; can't do anything so do nothing
		break;
	case D3DERR_DEVICENOTRESET:
		// device is ready to be reset; Release resources here and then Reset it
		// (be sure to test the hr from your Reset call too!)
		//ReleaseResources();
		ResetDevice();
		break;
	default:
		MessageBox(NULL, L"TestCooperativeLevel() failed", L"Error", MB_OK);
		PostQuitMessage(0);
		return;
	}
}
Edited by Tispe

Share this post


Link to post
Share on other sites


You definitely want to act on D3DERR_DEVICELOST

Yes, of course. This is why I wrote "don't compare with specific success codes" (... to check for success). You definetely need to handle specific failure codes sometimes.

But I don't want to be dogmatic; this starts getting of topic.

Share this post


Link to post
Share on other sites
My experience/ what I do is take care of this in my main message handler, for example to handle wm_size messages, wm_... etc, which likely cause lost devices.

A few things nice to know:
- directinput devices can also get lost
- not applicable when in windowed mode
- use "OnLostDevice" and after resetting "OnResetDevice" for your resources, I believe freeing recources goes for everything in the d3d default pool, resources in the managed pool should be find
- always check if the reset was succesfull, I only quit my "switch" statement when it's succeeded

If you want I can post my handling code from my "winproc" message handler function.

Share this post


Link to post
Share on other sites

My experience/ what I do is take care of this in my main message handler, for example to handle wm_size messages, wm_... etc, which likely cause lost devices.

 

This is definitely the wrong way to do it; see http://msdn.microsoft.com/en-us/library/windows/desktop/bb174714%28v=vs.85%29.aspx

 

 

By design, the full set of scenarios that can cause a device to become lost is not specified. Some typical examples include loss of focus, such as when the user presses ALT+TAB or when a system dialog is initialized. Devices can also be lost due to a power management event, or when another application assumes full-screen operation. In addition, any failure from IDirect3DDevice9::Reset puts the device into a lost state.

 

(My emphasis).

 

If you're not checking for D3DERR_DEVICELOST from your Present call, you're going to miss some of those scenarios.

Share this post


Link to post
Share on other sites

Hi,

 

Thanks for all the replies and information...

 

I don't think I will be implementing a full screen option.

(just current maximize window button option)

 

So the DirectX device can never get lost in windowed mode?

Let me know, thanks!

 

JeZ+Lee

Share this post


Link to post
Share on other sites

Normally no, but it's not that hard to implement it. I posted basically all the code you need.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!