Sign in to follow this  
all_names_taken

Crash when releasing device when app is closed

Recommended Posts

I get a crash when executing this:
if(g_pd3dDevice!=NULL) {
	g_pd3dDevice->Release();
}
Shouldn't this piece of code be absolutely guaranteed to be crash free? I'm sure it's this part where the crash comes, but not sure if this is the code causing it. I've put in test write out to an error log file before and after this piece of code and cornered the crash to happening exactly when Release() is called. Please tell me which further info is needed to diagnose this problem because I have no idea!

Share this post


Link to post
Share on other sites
ViLiO    1326
If you are using visual studio why not make use of its rather excellent built in debugger. You can change the directx runtime to debug and put the debug output level to maximum (this is in your control panel). Then if something nasty happens, visual studio's output window gets filled up with helpful information [smile]

Regards,
ViLiO

Share this post


Link to post
Share on other sites
JoeyBlow2    100
I added a line below to your code.



if(g_pd3dDevice!=NULL) {
g_pd3dDevice->Release();
g_pd3dDevice=NULL;
}



The idea is that g_pd3dDevice will always be null if its not initialized.

Therefore, when you start your program (or class in the constuctor), you need to set the g_pd3dDevice = NULL before its ever used or looked at. Also, when you release it, you need to set the variable back to NULL. Just because its ->Release()'d, doesn't mean the g_pd3dDevice = NULL. So you need to set it back.

Share this post


Link to post
Share on other sites
Dave Hunt    4872
Quote:
Original post by all_names_taken
Shouldn't this piece of code be absolutely guaranteed to be crash free?


No. If you have another call to g_pd3dDevice->Release() somewhere else in your code (or the one that's crashing is called more than once), then you are virtually guaranteed a crash. Once Release() is called, the pointer becomes invalid. When you release a COM object, you should always do:

if (g_pd3dDevice != NULL)
{
g_pd3dDevice->Release();
g_pd3dDevice = NULL;
}


Also, if you don't initialize your global pointer to NULL explicitly, then there is no guarantee that the pointer will be NULL when you check it. So, if your device creation fails, your pointer may still have garbage in it that would lead to a crash when you try to release it.

edit - yeah. what JoeyBlow2 said.

Share this post


Link to post
Share on other sites
Oh sorry for being so clumsy, I did have a g_pd3dDevice = NULL; line right where you put it and I inited the pointer to NULL. The error is something else :(.

Some further testing suggests that it doesn't occur when I'm rendering just a few faces at the time, like a square, but when I fill a vertex and index buffer with more, say 16 vertices and 18 indices, and call DrawIndexedPrimitive, I get this error when I quit the app (and the vertices don't appear). Maybe this could be the cause of it? But isn't it pretty usual for a game to render something as little as 16 vertices?

Share this post


Link to post
Share on other sites
Dave Hunt    4872
Are you sure your index and vertex buffers are large enough to hold the vertices? Are you passing the correct number of primitives (not vertices) to DrawIndexedPrimitive?

Share this post


Link to post
Share on other sites
Yes, I'm pretty sure of that. Should I post the code?

Anyway, from what I understand there are things that can screw up the device, so that later when you try to release it it crashes the app... Maybe I should try sending a smaller number of vertices and indices to the renderer, unless someone who has made an app that sends 18 or more can confirm that it should be possible with most hardware... Anyway I'll doublecheck the code and post it if it's helpful in any way.

Share this post


Link to post
Share on other sites
JoeyBlow2    100
I've sent 4 million indices to the device before... While the driver chokes on it (by severe stuttering), it doesn't blow up in the release.

I'm thinking (as Dave is) that you might be clobbering some memory with your pointers with the Vertex/Index buffers, so please post it.

Share this post


Link to post
Share on other sites
EnochDagor    180
I also get this when I declare textures or sprites or some other objects that use the Device object... I pass my Device around so that I am sure to only create one device... but when the device is lost, if an object is not destroyed before the device is lost, I get an OnDeviceLost event... and that's when it crashes.

This is easily remedied by insuring that you dispose of any resources obtained in your program when you are done with them... before releasing your device.

You can check to see if you're getting this sort of problem by checking the Output window of your application after the crash... first, you can stop the debugger before you call those methods... usually it won't crash when you go through them line by line until afterwards when you continue out of the function and the program begins to clean up resources. Anyway, that is a possibility.

-E

Share this post


Link to post
Share on other sites
Quote:
Original post by JoeyBlow2
I'm thinking (as Dave is) that you might be clobbering some memory with your pointers with the Vertex/Index buffers, so please post it.


Ok, the problem is my code is a mess at the moment... I'll try rewriting it and if the problem remains I'll repost it. Your suggestion seems likely, because I'm algorithmically creating the vertices and faces from a few variables...

Share this post


Link to post
Share on other sites
Supernat02    604
Maybe you aren't releasing it enough. Other COM objects may be referencing the device and if you don't release them, it doesn't get released. The value returned by the Device->Release() call is the number of references still remaining. It should be zero. If you set g_pd3dDevice to NULL immediately after the release call and the error goes away, then I would suspect these issues. Another thing is if you are trying to process a Draw call while releasing it. Is your program multi-threaded? Do you call Release upon program close, or when the user hits ALT F4 or uses the mouse to close it. If there is a difference in the error behavior based on using ALT F4 and using the mouse to click the X close button, then you need to place a check in your code prior to calling the pDevice->Present call.

Share this post


Link to post
Share on other sites
Here's the code where I fill the vertex and index buffers:

bool Heightmap::create(LPDIRECT3DDEVICE9 dxDevice) {
//ASSUME *height has reserved mapX*mapY array slots,
//and they are already filled in with height data, floats ranging from
//-10.0 to 1.0
const int BLOCK_X_SIZE = 10; //size between each point in heightmap
const int BLOCK_Y_SIZE = 10;

//Create Vertex buffer
if(FAILED(dxDevice->CreateVertexBuffer(mapX*mapY*sizeof(WORLDVERTEX), 0, D3DFVF_WORLDVERTEX, D3DPOOL_DEFAULT, &vertexBuffer, NULL))) {
return false;
}
//Lock buffer and load data to it
WORLDVERTEX *custVert;
if(FAILED(vertexBuffer->Lock(0, 0, (void**)&custVert, 0))) {
return false;
}
for(int i=0; i<mapX*mapY; i++) {
int xTemp =i%mapX;
int yTemp =i/mapX;
int x = (float)xTemp * BLOCK_X_SIZE;
int y = height[i];
int z = (float)yTemp * BLOCK_Y_SIZE;
custVert[i].position = D3DXVECTOR3(x, y, z);
custVert[i].normal = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
custVert[i].tu = 0.0f;
custVert[i].tu = 0.0f;
}
vertexBuffer->Unlock();

//Create index buffer
int numIndices = (mapX-1)*(mapY-1)*2;
if(FAILED(dxDevice->CreateIndexBuffer(numIndices*sizeof(WORD), 0, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &indexBuffer, NULL))) {
return false;
}
//Load data to index buffer
//Create two triangles per "square" of vertices
INDEX *pIndices;
if(FAILED(indexBuffer->Lock(0, 0, (void**)&pIndices, 0))) {
return false;
}
for(int j=0; j<mapY-1; j++) {
for(i=0; i<mapX-1; i++) {
pIndices[i+(mapX-1)*j].x = i+mapX*j;
pIndices[i+(mapX-1)*j].y = (i+1)+mapX*j;
pIndices[i+(mapX-1)*j].z = i+mapX*(j+1);

pIndices[numIndices/2+i+(mapX-1)*j].x = i+mapX*(j+1);
pIndices[numIndices/2+i+(mapX-1)*j].y = (i+1)+mapX*j;
pIndices[numIndices/2+i+(mapX-1)*j].z = (i+1)+mapX*(j+1);
}
}
indexBuffer->Unlock();
}





It's interesting that when I comment out this part I don't get any crash... Another interesting thing is that often when it crashes, I'm able to render it for 2 or 3 frames, before I get the crash... Have I got some kind of memory leak?

My program is single-threaded. It's full screen so the quit, I do with returning false from my main game loop function bool RunApp(). The main loop is something like this:

//ASSUME INIT STUFF HERE

MSG msg;
ZeroMemory(&msg, sizeof(msg));
while(msg.message!=WM_QUIT) {
if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
} else {
if(!RunApp()) {
break;
}
}
}

//CLEANUP STUFF HERE





Quit code in RunApp:

if(((GetAsyncKeyState(VK_ESCAPE) & 0x8000) ? 1 : 0)) {
return false;
}


[Edited by - all_names_taken on March 18, 2006 9:45:06 AM]

Share this post


Link to post
Share on other sites
Dave Hunt    4872
You are trying to use a structure with your index buffer. First, you told DX that your index buffer was numIndices * size of a WORD. Then, after you lock the index buffer, you are treating the buffer as an array of INDEX structures containing (apparently) 3 WORD values. So, you are writing way more data to the index buffer than it can hold (3 * the size, based on your code).

Share this post


Link to post
Share on other sites
Quote:
Original post by Supernat02
Are you creating the vertex and index buffer every frame? Are you sure you're releasing them?


Yes, creating it each frame for testing purposes before I can proceed to make a better organization of the code...

Quote:
Original post by Dave Hunt
You are trying to use a structure with your index buffer. First, you told DX that your index buffer was numIndices * size of a WORD. Then, after you lock the index buffer, you are treating the buffer as an array of INDEX structures containing (apparently) 3 WORD values. So, you are writing way more data to the index buffer than it can hold (3 * the size, based on your code).


Yes, that was the problem. Everyting works now! Thanks a lot!

Share this post


Link to post
Share on other sites
Dave Hunt    4872
Quote:
Original post by all_names_taken
Yes, that was the problem. Everyting works now! Thanks a lot!


You're quite welcome. Good luck with the rest of your project.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this