Fullscreen Problem

Started by
9 comments, last by mdl731 12 years, 10 months ago
Hello people!

I've been working on a 2D platform game with my DirectX and C++ engine, and It's coming along nice (considering that I just learned DirectX 5 weeks ago). Anyway, now I'm trying to implement the toggle fullscreen at runtime functionality on the engine but I'm having some problems...

This is the code I'm using:



void Engine::ToggleFullScreen(bool value)
{
DWORD dwStyle, dwExStyle;

D3DDISPLAYMODE dm;
this->mD3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &dm);

D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = !value;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;

d3dpp.EnableAutoDepthStencil = true;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
d3dpp.hDeviceWindow = mWindowHandle;
d3dpp.BackBufferCount = 1;
d3dpp.BackBufferFormat = dm.Format;

if(value)
{
d3dpp.BackBufferWidth = dm.Width;
d3dpp.BackBufferHeight = dm.Height;

dwStyle = WS_POPUP;
dwExStyle = WS_EX_APPWINDOW;

ShowCursor(false);
}
else
{
d3dpp.BackBufferWidth = gEngine->GetScreenWidth();
d3dpp.BackBufferHeight = gEngine->GetScreenHeight();

dwStyle = WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX;
dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;

ShowCursor(true);
}

mSpriteHandler->OnLostDevice();

HRESULT hRes = mDevice->Reset(&d3dpp);

mSpriteHandler->OnResetDevice();

SetWindowLong(mWindowHandle, GWL_STYLE, dwStyle);
SetWindowLong(mWindowHandle, GWL_EXSTYLE, dwExStyle);
ShowWindow(mWindowHandle, SW_SHOW);

}



When i press alt+enter the window style is the only thing that changes, the game keeps running and accepting input but the game screen is frozen.

Anyone knows what am I doing wrong????:(
Advertisement
your have to re-load textures ,mesh, to a gpu , when they gone from its video memory cause of alt-tab,alt-enter which over write its video memory.
You should be allocating most resources in D3DPOOL_MANAGED so releasing and recreating them shouldn't be needed. I'm willing to bet that your SetWindowLong and ShowWindow calls are causing the device to become lost, so maybe move them to before your reset call. Also, if you're not checking the return HRESULT from your Present call for D3DERR_DEVICELOST, you should do so. There are plenty of threads on here about the best way to handle that situation (and if you're going fullscreen you'll definitely need to at some time). I'll see if I can dig one up later on if you want.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.


your have to re-load textures ,mesh, to a gpu , when they gone from its video memory cause of alt-tab,alt-enter which over write its video memory.


All the textures for the sprites I'm using are D3DPOOL_MANAGED, am I supposed to release and recreate them like the D3DPOOL_DEFAULT textures?

You should be allocating most resources in D3DPOOL_MANAGED so releasing and recreating them shouldn't be needed. I'm willing to bet that your SetWindowLong and ShowWindow calls are causing the device to become lost, so maybe move them to before your reset call. Also, if you're not checking the return HRESULT from your Present call for D3DERR_DEVICELOST, you should do so. There are plenty of threads on here about the best way to handle that situation (and if you're going fullscreen you'll definitely need to at some time). I'll see if I can dig one up later on if you want.


I'm checking now the HRESULT codes of my RenderStop function:



int Engine::RenderStop()
{
if(this->mDevice == 0)
return 0;
if(this->mDevice->EndScene() != D3D_OK)
{
Message("Device EndScene Failed");
return 0;
}

HRESULT hRes = this->mDevice->Present(0,0,0,0);
if(hRes == D3DERR_DEVICELOST)
{
Message("Device Lost");
return 0;
}

return 1;
}



And the problem seems to be in the EndScene() call, i have no idea why though.....

Edit: I just checked again <_< and the problem is at the Reset() call. What can cause Reset() to fail??

Edit: I just checked again <_< and the problem is at the Reset() call. What can cause Reset() to fail??


You'll most probably get a direct answer to that question by using the Debug D3D runtimes. (DirectX Control Panel -> Use debug version of Direct3D).

[quote name='mdl731' timestamp='1307481162' post='4820693']
Edit: I just checked again <_< and the problem is at the Reset() call. What can cause Reset() to fail??


You'll most probably get a direct answer to that question by using the Debug D3D runtimes. (DirectX Control Panel -> Use debug version of Direct3D).
[/quote]

Thanks for the reply, that was helpful. I just checked the debug and i get this error when i try to switch to full screen:

Direct3D9: (ERROR) :All user created D3DPOOL_DEFAULT surfaces must be freed before ResetEx can succeed. ResetEx Fails.
Direct3D9: (ERROR) :ResetEx failed and ResetEx/TestCooperativeLevel/Release are the only legal APIs to be called subsequently.

But now I'm confused, because I'm not using any texture or surface on the D3DPOOL_DEFAULT.....

This is how I load and image to a texture for my sprites:


bool Texture::Load(std::string filename, D3DCOLOR transcolor)
{
HRESULT hResult;
D3DXIMAGE_INFO info;

hResult = D3DXGetImageInfoFromFile(filename.c_str(), &info);
if(hResult != D3D_OK)
{
mTexture = 0;
return false;
}

hResult = D3DXCreateTextureFromFileEx(gEngine->GetDevice(),
filename.c_str(), info.Width, info.Height,
1, 0, D3DFMT_UNKNOWN,
D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT,
transcolor, &info, 0, &mTexture);

if(hResult != D3D_OK)
{
mTexture = 0;
return false;
}

mTexture->GetLevelDesc(0, &mDesc);

return true;
}
There are some other calls that could result in D3D holding on to a default pool surface. One in particular to watch out for is IDirect3DDevice9::GetBackBuffer - the surface it returns will need to be Released. Basically double-check any Get call you might have that gives you a D3D interface as it's commonly your responsibility to Release it when done.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.


There are some other calls that could result in D3D holding on to a default pool surface. One in particular to watch out for is IDirect3DDevice9::GetBackBuffer - the surface it returns will need to be Released. Basically double-check any Get call you might have that gives you a D3D interface as it's commonly your responsibility to Release it when done.


Thanks man!, that seemed to be the problem. I was using the IDirect3DDevice9::GetBackBuffer for my TileScroller class and I didn't Release() the surface it returned. Now fullscreen toggle works like a charm. The only problem I have now when I try to atl+tab the program the device gets lost. Any ideas how can I solve that?
Believe it or not, you've already got over 90% of the code you need for this. You check for a D3DERR_DEVICELOST from your Present call, and if you get one, you handle it something like this (this is just one way I've found that works well for me, there will be others):
  1. Start an infinite loop.
  2. Sleep for a few milliseconds because you don't want to be hogging the CPU while you're not the active app. You might also want to run a Peek/Translate/Dispatch message loop here.
  3. Call IDirect3DDevice9::TestCooperativeLevel; what you do next depends on the HRESULT you get from this call.
  4. If you get D3DERR_DEVICELOST the device is still lost, so let your infinite loop go to it's next iteration.
  5. If you get D3DERR_DEVICENOTRESET the device is ready to be reset. Release your resources and call Reset. Don't recreate anything just yet, we'll be doing that shortly. Just let the loop spin again.
  6. If you get D3D_OK the device reset has completed so recreate your resources and exit the infinite loop.
  7. If you get D3DERR_DRIVERINTERNALERROR or anything else, something bad happened and the only really safe/reliable course of action is to exit the program (with an appropriate error message if you wish).
A common mistake you see is that people try to handle this from WM_ACTIVATE in their window procedure. This is not a good idea as - while it will handle the Alt-Tab case - it won't handle other events that may cause a device to become lost. Microsoft delibrately don't document the full range of events because they quite honestly can't. Anything from power saving, screen savers, another app stealing the focus, the user crashing out of the app or yanking out their gfx card, and a myriad other circumstances could be the cause. The only really safe way is to check the HRESULT of your Present call.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

This topic is closed to new replies.

Advertisement