Program crashes when D3D device is reset (DX9)

Started by
8 comments, last by CDProp 15 years, 3 months ago
I wrote a small windowed program (just one source file). I designed it to reset the D3D device every time the window is resized, so that I can change the back buffer size to match. It works just fine on my machine (Windows XP), however at my machine at work (also Windows XP), it crashes whenever I try to move or resize the window. I call the reset code whenever the WM_EXITSIZEMOVE message is processed, so I'm thinking that the reset is the culprit. Here's the problem: It'd debug the program at work, but I don't work there anymore. I'm tempted to shrug it off, but if there's something that I should know about resetting D3D devices that I'm missing, I'd really like to know it so that I don't put up future programs on my (future) website only to have potential (future) employers get crash bugs on all of them. So I was wondering if someone here might be able to help. I know this is not a lot of information to go on. I don't have any web space yet so I can't upload the project files and stuff. I can, however, post the relevant code here:

// Note: I'm only posting the functions involved in this
// process, as well as any global variables/objects referenced
// by those functions. The program has no classes, so all objects
// and variables should be either local or global. Since the
// program runs fun until the WM_EXITSIZEMOVE message is sent,
// it seems safe to assume that all of these objects are
// initialized properly in the beginning and that the rest of the
// program runs fine.

LPDIRECT3DDEVICE9 pDevice = NULL;
D3DPRESENT_PARAMETERS params;
LPD3DXMESH pEarth = NULL;
LPD3DXEFFECT pEarthEffect = NULL;
IDirect3DTexture9 *pEarthDay = NULL, *pEarthNight = NULL;

void OnLostDevice();
void OnResetDevice();

LRESULT CALLBACK mainWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch(msg)
	{
	case WM_CLOSE :
		DestroyWindow(hWnd);
		break;
	case WM_DESTROY :
		PostQuitMessage(0);
		break;
	case WM_EXITSIZEMOVE :
		RECT clientRect;
		GetClientRect(hWnd, &clientRect);
		params.BackBufferWidth = clientRect.right;
		params.BackBufferHeight = clientRect.bottom;
		OnLostDevice();
		HR(pDevice->Reset(&params));
		OnResetDevice();
		break;
	default :
		return DefWindowProc(hWnd, msg, wParam, lParam);
	}

	return 0;	
}

void OnLostDevice()
{
	// Earth Effect
	if(pEarthEffect)
	{
		pEarthEffect->Release();
		pEarthEffect = NULL;
	}

	// Earth Mesh
	if(pEarth)
	{
		pEarth->Release();
		pEarth = NULL;
	}

	// Earth Textures
	if(pEarthDay)
	{
		pEarthDay->Release();
		pEarthDay = NULL;
	}

	if(pEarthNight)
	{
		pEarthNight->Release();
		pEarthNight = NULL;
	}
}

void OnResetDevice()
{
	if(!pEarth)
		HR(D3DXCreateSphere(pDevice, 12.0f, NUM_SLICES, NUM_STACKS, &pEarth, NULL));

	if(!pEarthEffect)
		D3DXCreateEffectFromFile(pDevice, "C:\\_Programming Projects\\EarthNightDay\\EarthNightDay\\earth.fx", NULL, NULL, 0, NULL, &pEarthEffect, NULL);

	if(!pEarthDay)
		HR(D3DXCreateTextureFromFile(pDevice, "C:\\_Programming Projects\\EarthNightDay\\EarthNightDay\\earthmap1k.jpg", &pEarthDay));

	if(!pEarthNight)
		HR(D3DXCreateTextureFromFile(pDevice, "C:\\_Programming Projects\\EarthNightDay\\EarthNightDay\\earthlights1k.jpg", &pEarthNight));
}

Come to think of it, I don't see where I'm specifying a memory pool for these resources. Maybe that has something to do with it?
Advertisement
Could you at least tell us which line the program's crashing on, or what exception is being thrown?

Also FYI...D3DXCreateTextureFromFile will place textures in the MANAGED pool, so it's not necessary to Release them and re-load them. Same with ID3DXMesh and vertex/index buffers. You also don't need to Release and re-load Effects, you can just call ID3DXEffect::OnLostDevice and ID3DXEffect::OnResetDevice.
Thank you for the info. I will make the necessary changes. I wish I could tell you what line it is crashing on. Unfortunately, I no longer have access to the computer that it crashes with (it works fine on my computer here at home).

The only reason I was able to narrow it down to this section of code is because the crash only occurs when I attempt to move or resize the window, and so I figured out that it had something to do with how I was handling the WM_EXITSIZEMOVE message.

I suppose it could be a fluke...maybe there is something wrong with that particular computer, and not my program. I've only tested it on two computers -- the one here at home (where it works fine) and the one at my former work (where it crashes). So, what looks like a 50% crash rate could just be a case of a single anomaly being overrepresented in a small sample, if you will.

But at my level of expertise, I've found that if I have a problem, it's almost always my fault.

If anyone here is willing, I'd be happy to send the source as a 428k RAR file by email or something. If anyone can get it to crash in Visual Studio and tell me where and why, that would help me out a ton. I know that's a huge request, though, so if no one emails me, I won't be offended or even surprised. Just throwing that option out there in case. You can contact me at cdesign.proponentist at gmail dot com (that way you don't have to post your email address) and I would be most grateful.

On the computer where it crashes, do the SDK samples crash?

If not, then compare what they are doing to what you are doing in the window message processing.

My free book on Direct3D: "The Direct3D Graphics Pipeline"
My blog on programming, vintage computing, music, politics, etc.: Legalize Adulthood!

This sounds suspiciously like a device needing to get reset. Check the HRESULT from the Present() call, and see if that is the issue.
Unfortunately I don't have access to that computer anymore to test and see if the programming samples crash. It seems unlikely that the device needs to be reset since that is what I'm doing when that message is sent. Also, I am checking for the lost decide before rendering, so even if the Render function were called after the resize but before the message was processed, it still shouldn't even call Present.

It looks like this one might be too much of a pain to solve at the moment. I was hoping an expert on here would be able to look at my code and see something silly right off, but oh well.
Quote:Original post by CDProp
It looks like this one might be too much of a pain to solve at the moment. I was hoping an expert on here would be able to look at my code and see something silly right off, but oh well.
There's nothing wrong with any of the code you've posted there. What does the HR() function / macro do? Does it halt execution in any way?
In release mode, it does nothing:

#define HR(x) x

In debug, it passes the HRESULT to DXTrace:
#define HR(x){	HRESULT hr = x;	if(FAILED(hr))	{		DXTrace(__FILE__, __LINE__, hr, #x, TRUE);	}}


Edit: The above multi-line macro has the appropriate slashes, but I think they were messing up the board formatting or something, so I took them out.
I prefer using an inline function instead of a macro hack. Macros are generally a C style approach, but you're using C++, so use an inline function.

My free book on Direct3D: "The Direct3D Graphics Pipeline"
My blog on programming, vintage computing, music, politics, etc.: Legalize Adulthood!

You're right. That's just a vestige from a tutorial I got from a book quite a while ago.

This topic is closed to new replies.

Advertisement