Sign in to follow this  
Soul Reaver

[DirectX 9] Mesh gone after device reset

Recommended Posts

Soul Reaver    108
Hi, I've a probably easy-to-solve problem but it seems really strange to me. After a device reset my mesh is not being rendered anymore. Here is my code:
Mesh::Mesh(D3DDevice* device, std::string folder , std::string file, bool optimize)
{
	_device = device;

	ID3DXBuffer *mtrlBuffer, *adjBuffer;
	D3DXLoadMeshFromX((folder + file).c_str(), D3DXMESH_MANAGED,
					  _device, &adjBuffer, &mtrlBuffer, 0,
					  &_numFaces, &_mesh);

	D3DXMATERIAL* mtrl = (D3DXMATERIAL*)mtrlBuffer->GetBufferPointer();

	for(uint i = 0; i < _numFaces; i++)
	{
		_material.push_back(mtrl[i].MatD3D);

		if(mtrl[i].pTextureFilename != 0)
		{
			D3DTexture* tex;
			std::string f = folder + mtrl[i].pTextureFilename;
			D3DXCreateTextureFromFileEx(_device, f.c_str(), 0,      
                                                    0, 0, 0,
						    D3DFMT_UNKNOWN,  
                                                    D3DPOOL_MANAGED, 
                                                    D3DX_DEFAULT,
						    D3DX_DEFAULT, 0, NULL, 
                                                    NULL, &tex);
			_texture.push_back(tex);
		}
		else
			_texture.push_back(0);
	}

	mtrlBuffer->Release();

	if(optimize)
	{
		_mesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT |
                                       D3DXMESHOPT_COMPACT |
  				       D3DXMESHOPT_VERTEXCACHE,
				       (DWORD*)adjBuffer->GetBufferPointer(),
				       0, 0, 0);
	}

	adjBuffer->Release();
}

void Mesh::render()
{
	for(uint i = 0; i < _numFaces; i++)
	{
		_device->SetMaterial(&_material[i]);
		_device->SetTexture(0, _texture[i]);
		HRESULT hr = _mesh->DrawSubset(i);
		if(FAILED(hr))
			MessageBox(NULL, DXGetErrorString(hr), "", MB_OK);
	}
}


The things that are strange to me are that -the mesh is in the managed pool -the texture pointers are not 0 -the DrawSubset() function doesn't fail -the output of direct3d9 looks fine Any ideas what I'm doing wrong? Thanks in advance

Share this post


Link to post
Share on other sites
Soul Reaver    108
Quote:
Original post by MJP
Have you tried enabling the debug runtimes to see if they give you any warnings? Also, have you tried looking at a frame in PIX to see what's going on?


The D3D9 debug runtime is enabled but I see no unusual output as I said before.

I found out that the mesh isn't gone completely. It just renders only 1 triangle which is black. I couldn't see it at first because backface culling is enabled.

I don't really know what to do with the results of PIX since I have never used it before.

Share this post


Link to post
Share on other sites
Buckeye    10747
Do you use the same ResetDevice() function when you reset as you do when you initially create the device? If the mesh renders correctly just after you create the device and mesh, it sounds like you set different parameters from your initial device creation when you reset the device. Check all your present params, lighting params, render states, etc., to ensure they're the same when you both create and reset the device.

Share this post


Link to post
Share on other sites
Evil Steve    2017
Quote:
Original post by Soul Reaver
Thanks for you help,

it was in fact because I didn't reset the renderstates and lights.
I thought these options wouldn't be affected when the device is lost.
When the device is reset, it's reset to the same state it was in when the device was created - so ALL device state is reset.

Share this post


Link to post
Share on other sites
Buckeye    10747
Glad you found the problem. I use the same ResetDevice() routine following both creation and reset to ensure things stay the same. You might try that.

Share this post


Link to post
Share on other sites
Tispe    1468
Sorry for the bump but what code do you use for restoring the meshes/lights after the App regains focus?

Do you cycle through each Mesh object or something?

Edit: I though I had to readress textures and materials.

Fix: I made a new function to set all render states which is called at startup and after device gets focus

Share this post


Link to post
Share on other sites
Buckeye    10747
[quote name='Tispe' timestamp='1298991930' post='4780561']
Sorry for the bump but what code do you use for restoring the meshes/lights after the App regains focus?

Do you cycle through each Mesh object or something?
[/quote]
Not sure what you mean by "restore." In any case, what you do in response to WM_SETFOCUS depends on what you do in response to WM_KILLFOCUS.

If you're having a problem, you should describe it.

Share this post


Link to post
Share on other sites
mhagain    13430
As an aside, you shouldn't be performing lost device handling in response to WM_ messages. It will only end in tears.

To quote from the SDK:
[quote]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.[/quote]
In other words, you aren't capturing all events that can cause a device to become lost, and the time will come when it bites you. Check the HRESULT of your IDirect3DDevice9::Present (or IDirect3DSwapChain9::Present) call for D3DERR_DEVICELOST instead.

Share this post


Link to post
Share on other sites
Tispe    1468
[quote name='mhagain' timestamp='1298999230' post='4780590']
As an aside, you shouldn't be performing lost device handling in response to WM_ messages. It will only end in tears.

To quote from the SDK:
[quote]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.[/quote]
In other words, you aren't capturing all events that can cause a device to become lost, and the time will come when it bites you. Check the HRESULT of your IDirect3DDevice9::Present (or IDirect3DSwapChain9::Present) call for D3DERR_DEVICELOST instead.
[/quote]

hmm, I tried this:

[code]
if(d3ddev->Present(NULL, NULL, NULL, NULL) != D3D_OK)
ResetDevice();
[/code]

ResetDevice() is the same function called when WM_ACTIVATEAPP is recieved. But the screen is blank after I ALT-TAB out and back in.I have to remove the whole WM_ messages routine to make it work.

Do I need to stop rendering when the app no longer has focus? Seems to me Present() will be ran in the background and I "reset" the device 60 times/sec while the app is minimized

Share this post


Link to post
Share on other sites
Buckeye    10747
In general, you would be better off [i]not[/i] performing any device/rendering functions in response to window messages.

I would suggest you call ResetDevice() at only [b]one[/b] location in your code (other than in your CreateDevice() routine), probably in your run loop after you call dev->TestCooperativeLevel, and the result of TestCooperativeLevel indicates that's the appropriate action to take.

With regard to what you tried: if dev->Present fails, ResetDevice() may not be the proper thing to do. The failure may not be a result of the device needing to be reset.

With regard to gaining/losing focus, it's possible to have your application run in background if there's an overriding reason. However, it would be probably be better to pause your app when it loses focus. That's an indication that the user (for the moment) isn't interested in your window.

Share this post


Link to post
Share on other sites
mhagain    13430
[quote name='Tispe' timestamp='1299000226' post='4780597']
hmm, I tried this:

[code]
if(d3ddev->Present(NULL, NULL, NULL, NULL) != D3D_OK)
ResetDevice();
[/code]

ResetDevice() is the same function called when WM_ACTIVATEAPP is recieved. But the screen is blank after I ALT-TAB out and back in.I have to remove the whole WM_ messages routine to make it work.

Do I need to stop rendering when the app no longer has focus? Seems to me Present() will be ran in the background and I "reset" the device 60 times/sec while the app is minimized
[/quote]

Try something like this instead:
[code]hr = d3ddev->Present (NULL, NULL, NULL, NULL);
if (hr == D3DERR_DEVICELOST)
{
while (1)
{
hr = d3ddev->TestCooperativeLevel ();
switch (hr)
{
case D3D_OK:
// device is no longer lost and reset has completed successfully; recover resources here
return; // note: this assumes that this test is the last thing in the function it's being called from
case D3DERR_DEVICELOST:
// 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!)
break;
default:
// something bad happened! quit the program.
break;
}
Sleep (5); // yield some CPU
}
}[/code]

Share this post


Link to post
Share on other sites
Tispe    1468
[quote name='Buckeye' timestamp='1299002222' post='4780606']
With regard to what you tried: if dev->Present fails, ResetDevice() may not be the proper thing to do. The failure may not be a result of the device needing to be reset.
[/quote]

Now I only reset if its lost

[code]
if(d3ddev->Present(NULL, NULL, NULL, NULL) == D3DERR_DEVICELOST)
ResetDevice();
[/code]

where ResetDevice():

[code]
void ResetDevice()
{
if(d3ddev)
{
MSG msg;
while(d3ddev->TestCooperativeLevel() != D3DERR_DEVICENOTRESET)
{
//WaitMessage();
PeekMessage( &msg, NULL, 0, 0, PM_REMOVE );
TranslateMessage(&msg);
DispatchMessage(&msg);
Sleep(5);
}

if(FAILED(d3dspt->OnLostDevice()))
ErrorMessage(L"The d3dspt->OnLostDevice function failed");
if(FAILED(dxfont->OnLostDevice()))
ErrorMessage(L"The dxfont->OnLostDevice function failed");

if(FAILED(d3ddev->Reset(&d3dpp)))
ErrorMessage(L"The d3ddev->Reset function failed");

if(FAILED(d3dspt->OnResetDevice()))
ErrorMessage(L"The d3dspt->OnResetDevice function failed");
if(FAILED(dxfont->OnResetDevice()))
ErrorMessage(L"The dxfont->OnResetDevice function failed");
DeviceSettings();
}
}
[/code]

Proper enough?

Share this post


Link to post
Share on other sites
Buckeye    10747
[quote]Proper enough?[/quote]
Wow. Actually, no. It appears you're just trying to patch things together.

First - the general principle of checking whether the device is valid [i]after[/i] you've gone through updating and rendering, as a personal opinion, is backwards. Testing for a properly setup device should be done [i]before[/i] it's needed for updating/creating objects/rendering/etc.

Second - I would suggest you separate windows messaging and DirecxtX processing to the greatest degree possible.

Take a look at the general arrangement of message processing, device status testing, updating, etc., in some of the SDK examples. Examing the flow Microsoft takes sounds like your best bet.

Share this post


Link to post
Share on other sites
Tispe    1468
So don't use Present() to check if the device is lost? Should I TestCooperativeLevel() each time I enter my rendering function and "abort" if there is an error?

In response to windows messaging, I do have the outer layer of the main loop seperate from DX stuff. This function however is just a secondary message handler for when the device is lost, I read that you should take care of messages while you try to reset the device.

Share this post


Link to post
Share on other sites
Buckeye    10747
[quote name='Tispe' timestamp='1299011225' post='4780660']
So don't use Present() to check if the device is lost?[/quote]
I wouldn't check for a specific error, no. I would use the FAILED macro to check it, if I needed to use the device before I call TestCooperativeLevel the next time, or, if for some other reason, I needed to know that the buffer had been successfully presented before continuing.

[quote]Should I TestCooperativeLevel() each time I enter my rendering function and "abort" if there is an error?[/quote]
First, TestCooperativeLevel doesn't return an "error" code, per se. It provides information about the status of the device. Some of the conditions indicated are actually to be expected.

Second, why even enter the rendering function if there's a problem?

[quote]In response to windows messaging, I do have the outer layer of the main loop seperate from DX stuff. This function however is just a secondary message handler for when the device is lost,[/quote]

Have you reviewed the general flow in some of the SDK examples as suggested? Look at EmptyProject, for instance. It sounds like you need a structured approach to your loop and you could probably do worse than follow the same flow shown in an SDK example.

[quote]I read that you should take care of messages while you try to reset the device.[/quote]
Sounds like a good idea - but not mixed in with DirectX functions.

Share this post


Link to post
Share on other sites
Tispe    1468
To be honest I have not used DXUT before. The concept of CALLBACKS are still strange to me. I read up on it and understand that you provide a pointer to a function as argument to another function. I get the basics but when looking at the EmptyProject.cpp code it is stange why you need to "Set the callback functions" when you can just have prototypes and call the functions as I need them.

You talk about the "flow" of a typical SDK example, but reading the forums it is said that using DXUT for a release is not used much, if at all. So I need my own structute and I have one. DXUT and CALLBACKS as I understand it is just a generalisation that can be replaced by simple functions and their prototypes.

I want to alt-tab, toggle fullscreen or change resolution mid-game so I want to call a function to do that, it should be simple. How my loop is built should be irrelevant. We can discuss later how we can optimize it.

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