Archived

This topic is now archived and is closed to further replies.

BrianMJC

Resetting the D3D Device Causing Crashes and Frustration!

Recommended Posts

Hi all, I''m stumped (again!). I am trying to use textures instead of surfaces in a custom font (not system font but a class with an array of images). But my game crashes when I reset the 3D device. I know enough to release the textures as soon as I detect the device is lost. When I comment out the font loader and string printing routines, it resets flawlessly. I traced the code in the debugger to make sure, and the textures are in fact released and set to NULL prior to encountering the Reset device method. Anybody have a clue? I don''t! And neither do the MS Docs!! I appreciate any help. Much thanks, Brian P.S. Here''s some source code. My routine calls OpenScene, does rendering, then calls RenderScene (Side Note: I use inline methods to mask D3D because I plan to convert to OpenGL/Linux in the future, so this''ll make it easier). TestFocus is called repeatedly in a pause state until the device is ready for reset. It then goes to GraphicsReset.
// O P E N   S C E N E //////////////////////////////////////////////////////

//

// Opens the viewport in order to begin rendering.

//

// return value - success or failure

//

inline estate OpenScene ()

    {

    // Clear the viewport.

    sr = ClearScreen ();
    if (!sr)
        {
        Log ("OpenScene -- Failed to clear the screen.");
        return g_ceSError;
        }
    
    // Begin the scene.

    g_pd3dDev->BeginScene ();

    return g_eState;

    }


// R E N D E R   S C E N E ///////////////////////////////////////////////////

//

// Renders the scene to the viewport.

//

// return value - continue or pause if focus lost.

//

inline estate RenderScene ()

    {

    // End the scene.

    g_pd3dDev->EndScene ();
    
    // Present the scene.

    hr = g_pd3dDev->Present (NULL, NULL, NULL, NULL);
    if (D3DERR_DEVICELOST == hr)

        if (g_bFocus)

            {

            // Release all lost resources...

            // Lose the fonts.

            delete g_pfonUncial;

            // Lose the cursors.

            delete g_pcurMain;

            // Recall state, log results and pause until focus is restored.

            g_ePrevState = g_eState;
            g_bFocus = false;
            Log ("RenderScene -- Lost device, switching to windowed mode.");
            return g_ceSPause;

            }

    return g_eState;
            
    }


// T E S T   F O C U S ///////////////////////////////////////////////////////

//

// Tests to see if we have regained focus so we know when to reset graphics.

//

// return value - ready or not

//

bool TestFocus ()

    {

    hr = g_pd3dDev->TestCooperativeLevel ();
    if (D3DERR_DEVICENOTRESET == hr)
        {
        Log ("TestFocus -- Device available for reset, switching back to fullscreen.");
        return true;
        }
    return false;

    }


// G R A P H I C S   R E S E T ///////////////////////////////////////////////

//

// Reset the graphics.

//

// return value - success or failure

//

estate GraphicsReset ()

    {
    
    // Grab display mode.

    g_pd3d->EnumAdapterModes (D3DADAPTER_DEFAULT, g_uMode, &g_d3dDisplayMode);

    // Fill in back buffer information relevant to fullscreen mode...

    // Screen width and height..

    g_d3dParams.BackBufferWidth = g_d3dDisplayMode.Width;
    g_d3dParams.BackBufferHeight = g_d3dDisplayMode.Height;
    
    // Not windowed mode, use desired refresh rate.

    g_d3dParams.Windowed = false;
    g_d3dParams.FullScreen_RefreshRateInHz = g_d3dDisplayMode.RefreshRate;

    // Reset render states...

    // Turn on ambient lighting.

    g_pd3dDev->SetRenderState (D3DRS_LIGHTING, true);
    g_pd3dDev->SetRenderState (D3DRS_AMBIENT, D3DCOLOR_XRGB (255, 255, 255));

    // Enable alpha testing.

    g_pd3dDev->SetRenderState (D3DRS_ALPHATESTENABLE, true);
    g_pd3dDev->SetRenderState (D3DRS_ALPHAREF, 1);
    g_pd3dDev->SetRenderState (D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);

    // Enable alpha blending.

    g_pd3dDev->SetRenderState (D3DRS_ALPHABLENDENABLE, true);
    g_pd3dDev->SetRenderState (D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
    g_pd3dDev->SetRenderState (D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
    g_pd3dDev->SetRenderState (D3DRS_BLENDOP, D3DBLENDOP_ADD);

    // And voila, reset it.

    hr = g_pd3dDev->Reset (&g_d3dParams);
    if (FAILED (hr))
        {
        sReport = "GraphicsReset -- Failed to reset graphics: ";
        sReport += D3DError (hr);
        Log (sReport);
        return g_ceSError;
        }

    // Recreate textures...

    // Create all cursors.

    g_pcurMain = new ccursor;
    sr = g_pcurMain->Load ("Art//CursorMain.png", ccursor::eSmall, 16, 0);

    if (!sr)
        {
        Log ("GraphicsReset -- Failed to create the main cursor.");
        return g_ceSError;
        }

    // Create uncial font.

    g_pfonUncial = new cfont;
    sr = g_pfonUncial->Load ("Art//FontUncial_New.png", "Art//FontUncial_New.bin");

    if (!sr)
        {
        Log ("GraphicsReset -- Failed to create the uncial font.");
        return g_ceSError;
        }

    g_bFocus = true;

    return g_ePrevState;

    }

Share this post


Link to post
Share on other sites
If I remember correctly, you don''t have to release textures on a device lost state if you''ve marked those textures as Managed.

Share this post


Link to post
Share on other sites
Are you 100% sure that all objects created in D3DPOOL_DEFAULT are released before you call g_pd3dDev->Reset()? There are probably many objects created in your custom font class, so it could be anything in there.

Also, all those renderstates that you painfully set in GraphicsReset() will be wiped out as soon as you reset the device. Just move them below the g_pd3dDev->Reset() call.


Dustin Franklin
Mircrosoft DirectX MVP

Share this post


Link to post
Share on other sites
GroZZleR -- If I try running without releasing the textures, the Reset device method fails (it returns D3DERR_DEVICELOST) and the game logs the error to file and exits... which is better than crashing I suppose.

You do have to release "any D3DPOOL_DEFAULT resources" prior to calling the Reset method, though (see quote from MS Docs below).

circlesoft -- Well, I never say 100%, but I''m 99% sure of it. The only content in my font class is an array of 96 character structs (each with a IDirect3DTexture8 pointer (set as D3DPOOL_DEFAULT) and an integer variable), an enumerated variable and two boolean variables, plus static consts and methods. And I verified that all textures are released and set to NULL prior to calling Reset. Further, if I comment out all font code, the game works perfectly fine, suggesting there''s a problem with the font.

It says in the MS docs:

quote:

Before calling the IDirect3DDevice9::Reset method for a device, an application should release any explicit render targets, depth stencil surfaces, additional swap chains, state blocks and D3DPOOL_DEFAULT resources associated with the device .



I am definitely not using depth stencil surfaces, and the only swap chain in use is my primary and back buffer chain. I don''t know what a state block is, nor am I certain what "render target" means - do they mean the back buffer? If so, I''ve got that covered.

Thanks for the tip about the render states. That was silly.

Share this post


Link to post
Share on other sites
All DEFAULT pool textures must be released. Note that SetTexture() will (conceptually) hold a reference count on the texture, so make sure to SetTexture(NULL) before Reset()-ing the device. It may very well be that you release all textures, but the effective texture on the device is still set to one of the textures you released. And it may be that the device does not actually hold a ref count when you SetTexture(). Thus, stale pointer problems ensue.

Share this post


Link to post
Share on other sites
hplus0603 -- You got it! That would have taken me 3 months to figure out, at least. Thanks!

Now I just have to figure out why it turns my object pointers into 0xdddddddd''s... I think I can take it from here.

DrunkenHyena -- I used to, but it caused problems with other applications.

Thanks everyone.

Share this post


Link to post
Share on other sites
quote:
Original post by BrianMJC
DrunkenHyena -- I used to, but it caused problems with other applications.



You should keep it installed. If any (poorly written) programs have a problem with it you can switch to Retail in the control panel when you run them. Debug runtime is a very valuable tool.


Stay Casual,

Ken
Drunken Hyena

Share this post


Link to post
Share on other sites
quote:
Original post by BrianMJC
Now I just have to figure out why it turns my object pointers into 0xdddddddd''s... I think I can take it from here.


FYI, memory that''s initialized like that is probably set like that in debug mode, which means you haven''t initialized it to zero yet.

Share this post


Link to post
Share on other sites
Say, I'm not out it yet!

My DrawPrimitiveUP calls fail, returning D3DERR_INVALIDCALL. Only happens after resetting.

The Reset method succeeds, I successfully delete and set to NULL all textures, and recreate them without errors after resetting, and set the render states correctly. The SetTexture, SetTransform and SetMaterial calls prior to DrawPrimitiveUP work fine (return D3D_OK). My custom vertex array (the memory address parameter 'aVertex' to DrawPrimitiveUP, below) is valid and setup correctly, I verified this.

Here's my method code to display quad textures (triangle strips of 2 triangles / 4 vertices), which are my font character textures:


// D I S P L A Y /////////////////////////////////////////////////////////////

//

// Display texture onscreen.

//

// return value - success or failure

// fptDst - destination origin (up-left) point to render to screen, in pixels

// td - texture descriptor

//

inline estate ctexture::Display (fpoint &fptDst, stexdesc &td)

{

// Set texture to render.

hr = g_pd3dDev->SetTexture (0, pd3dTexture);
if (FAILED (hr))
{
sReport = "ctexture::Display -- Failed to set texture: ";
sReport += D3DError (hr);
Log (sReport);
return g_ceSError;
}

// Set world transformation matrix.

D3DXMatrixIdentity (&g_d3dxMatrix);
g_d3dxMatrix._11 = 1.0 / g_cfVideoWidthD2;
g_d3dxMatrix._41 = fptDst.x * g_d3dxMatrix._11;
g_d3dxMatrix._22 = -1.0 / g_cfVideoHeightD2;
g_d3dxMatrix._42 = fptDst.y * g_d3dxMatrix._22;
hr = g_pd3dDev->SetTransform (D3DTS_WORLD, &g_d3dxMatrix);
if (FAILED (hr))
{
sReport = "ctexture::Display -- Failed to set world transform matrix: ";
sReport += D3DError (hr);
Log (sReport);
return g_ceSError;
}

// Setup material to reflect desired color.

ZeroMem (d3dMaterial);
d3dMaterial.Ambient.r = td.fc.r;
d3dMaterial.Ambient.g = td.fc.g;
d3dMaterial.Ambient.b = td.fc.b;
d3dMaterial.Ambient.a = td.fc.a;
hr = g_pd3dDev->SetMaterial (&d3dMaterial);
if (FAILED (hr))
{
sReport = "ctexture::Display -- Failed to setup material: ";
sReport += D3DError (hr);
Log (sReport);
return g_ceSError;
}

// Draw texture.

hr = g_pd3dDev->DrawPrimitiveUP (D3DPT_TRIANGLESTRIP, 2, aVertex, sizeof (cvertex));
if (FAILED (hr))
{
sReport = "ctexture::Display -- Failed to draw texture: ";
sReport += D3DError (hr);
Log (sReport);
return g_ceSError;
}

return g_eState;

}


Also...

DrunkenHyena -- I reinstalled the debug runtime version of DX, but how is it utilized? Automatically, or do I have to launch something or set some settings in MSVC? These MS help files are kinda skimpy to say the least!

Also, also...

P.S. Does anyone know how to use the debugger when your app goes to fullscreen mode? It would be helpful if I could trace my game as it runs in fullscreen without having to resort to writing variable values to a log file.

[edited by - BrianMJC on April 6, 2004 9:29:57 PM]

Share this post


Link to post
Share on other sites
I just recovered from a similar problem after losing the device. Bottom line, RELEASE everything after a device lost, and re-init everything to get it back.

Share this post


Link to post
Share on other sites
2dcoder -- Yep, I''m going to have to do exactly that. I''m already way behind schedule, not to mention well beyond my tolerance limits for staring uselessly at my monitor for days on end! Thanks.

Share this post


Link to post
Share on other sites