Jump to content

  • Log In with Google      Sign In   
  • Create Account


DX9 fullscreen alt-tab issue [solved - ish]


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
10 replies to this topic

#1 Damocles   Members   -  Reputation: 133

Like
0Likes
Like

Posted 15 June 2010 - 02:17 AM

I'm having a hell of a problem here...

My game, when you alt-tab away (from fullscreen) then alt-tab back, goes screwy. The screen doesn't return to a fullscreen display. Instead, it shows the game window as a thin-bordered black-filled window only, fitting to the screen resolution. The game then receives no updates other than keyboard input (mouse input seems to be ignored) and I have no choice but to quit out.

This problem only happens on Vista/W7 - on XP it restores just fine. I tried disabling aero/visual themes, etc, but that's not the issue.

Under the DX9 debug spew, there's this:

Direct3D9: :Window 000609d6 is on top of us!!
Direct3D9: :Window 000609d6 is on top of us!!
Direct3D9: :Window 000609d6 is on top of us!!
Direct3D9: :Window 000609d6 is on top of us!!
Direct3D9: :WM_SYSKEYUP: wParam=00000009 lParam=a00f0001
Direct3D9: :Hot key pressed, switching away from app
Direct3D9: :Window 000609d6 is on top of us!!
Direct3D9: :WM_ACTIVATEAPP: BEGIN Deactivating app pid=0000093c, tid=000012ec
Direct3D9: :DoneExclusiveMode
Direct3D9: :INACTIVE: 0000093c: Restoring original mode (1440x900x22x75) at adapter index 0
Direct3D9: :Window 000609d6 is on top of us!!
Direct3D9: :WM_DISPLAYCHANGE: 1440x900x32
Direct3D9: :*** Active state changing
Direct3D9: :WM_ACTIVATEAPP: DONE Deactivating app pid=0000093c, tid=000012ec
Direct3D9: (ERROR) :Lost due to display uniqueness change

This comes about when I first alt-tab away from the app, and the debug runtimes will break here, on the call to TextCooperativeLevel. The app has handled the lost device, and entered a loop where it checks the coop level every 1/2 second waiting for the time to reset, except it fails. The coop level return value is then D3DERR_DEVICENOTRESET, but resetting the device after this results in the black window mentioned above.

Googling around I see a lot of people have hit the "Lost due to display uniqueness change" DX9 error, but I haven't seen any solutions. There's a lot of talk about an NVidia driver bug, but my test HW is ATI.

I've checked my lost device code carefully, all state blocks are freed and there's no problem with a reset when running in windowed mode or when making a fullscreen resolution change, only when tabbing away from a fullscreen app.

Anyone have any ideas what the cause might be?

[Edited by - Damocles on June 16, 2010 3:35:21 AM]

Sponsor:

#2 Evil Steve   Members   -  Reputation: 1955

Like
0Likes
Like

Posted 15 June 2010 - 02:26 AM

Are you changing your window style before / after resetting the device? (If not, you should be).

Can we see your lost device / device reset code?

#3 freeworld   Members   -  Reputation: 325

Like
0Likes
Like

Posted 15 June 2010 - 02:47 AM

Quote:
INACTIVE: 0000093c: Restoring original mode (1440x900x22x75) at adapter index 0


when you restore the app, are you trying to create a device with a 22 bpp format?

#4 Damocles   Members   -  Reputation: 133

Like
0Likes
Like

Posted 15 June 2010 - 02:51 AM

I make a change to the style only if the app has switched between windowed/fullscreen. However, as part of my attempts to fix this I have tried changing the styles before and after, and both when doing resets.

My lost/reset code and the code to handle app restoration is a bit spread out, so if something seems missing below, tell me as I probably just forgot to include a method...

// these are the two main methods for handling loss/reset (there's very few unmanaged resources in the game)

bool D3DGraphics::IsDeviceLost()
{
HRESULT hr = d3d->TestCooperativeLevel();
if (hr==D3DERR_DEVICELOST)
{
// device lost and not ready to be reset - sleep (to give other apps a chance) then return true
Sleep(100);
return true;
}
else if (hr == D3DERR_DRIVERINTERNALERROR)
{
// bums - driver issues
MessageBox(0, "Internal Graphics Card Driver Error - unable to continue", 0, 0);
PostQuitMessage(0);
return true;
}
else if (hr == D3DERR_DEVICENOTRESET)
{
app->OnLostDevice();
HR(d3d->Reset(&pres));
app->OnReset();
return false; // device has been reset, so not lost
}
else
{
// device not lost and is active
return false;
}
}

void D3DGraphics::OnLostDevice()
{
if (defRenderTex)
defRenderTex->OnLostDevice();
if (bloomTex)
bloomTex->OnLostDevice();
if (backBufferSurface)
backBufferSurface->Release();
}

void D3DGraphics::OnReset()
{
if (defRenderTex)
defRenderTex->OnReset();
if (bloomTex)
bloomTex->OnReset();
d3d->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backBufferSurface);
}



this is how I handle the system messages for losing/gaining focus:

case WM_ACTIVATE:
if (!app)
return DefWindowProc(hWnd, message, wParam, lParam);
if (LOWORD(wParam)==WA_INACTIVE)
{
// being deactivated
if (!bPaused)
{
app->Pause();
app->bMinimized=true;
UnhookWindowsHookEx(keyHook);
app->OnLostDevice();
}
}
else if (LOWORD(wParam)==WA_ACTIVE || LOWORD(wParam)==WA_CLICKACTIVE)
{
// being activated
if (app->bMinimized) // restoring a window
{
keyHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyHookProc, hInst, 0);
app->OnReset();
app->Unpause();
app->bMinimized=false;
}
}
break;



That code above works fine under XP, but not under Vista/W7. Thinking I need to reset the window/display for Vista, I tried adding a call to the method below (to no avail):

void D3DGraphics::UpdateWindowSizes(const int& width, const int& height)
{
RECT DeskRect, WinRect;
int DesktopW, DesktopH;
SystemParametersInfo(SPI_GETWORKAREA,0,&DeskRect,0);

DesktopW=DeskRect.right-DeskRect.left;
DesktopH=DeskRect.bottom-DeskRect.top;

DWORD Style=0, StyleEx=0;

if (config->bWindowed)
{
Style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
StyleEx = WS_BORDER | WS_SYSMENU;
}
else
{
Style = WS_POPUP;
StyleEx = WS_EX_APPWINDOW;
}

WinRect.top = WinRect.left = 0;
WinRect.right = width;
WinRect.bottom = height;

SetWindowLong(hWnd, GWL_STYLE, Style);
SetWindowLong(hWnd, GWL_EXSTYLE, StyleEx);

AdjustWindowRectEx(&WinRect,Style,FALSE,StyleEx);

int Xc, Yc;

Xc=DeskRect.left+(((DeskRect.right-DeskRect.left)/2)-(width/2));
Yc=DeskRect.top+(((DeskRect.bottom-DeskRect.top)/2)- (height/2));

SetWindowPos(hWnd,HWND_TOPMOST,Xc,Yc,
WinRect.right-WinRect.left,WinRect.bottom-WinRect.top,
SWP_NOZORDER|SWP_SHOWWINDOW|SWP_DEFERERASE|SWP_NOCOPYBITS|SWP_DRAWFRAME|SWP_FRAMECHANGED);

}



I may be wrong, but that code should resize the window to fullscreen, and force the redraw through SetWindowPos. Yet it results in a wrongly sized iwndow, and not fullscreen.

Something has changed though - I'm not sure what I've done but now when D3D breaks on the reset attempt, VS is showing me the file setlocal.h and the error is on line 264, which seems to be something to do with the locale settings of windows? Very odd.

#5 Damocles   Members   -  Reputation: 133

Like
0Likes
Like

Posted 15 June 2010 - 02:54 AM

Quote:

when you restore the app, are you trying to create a device with a 22 bpp format


No, and I have no idea where that 22 bit depth is coming from. You can see in the next line it's setting a 32 bit depth, and I don't make any calls to create a new device on loss/reset, I just use the existing one. So that 22 has to be something internal DX is doing.

#6 Evil Steve   Members   -  Reputation: 1955

Like
0Likes
Like

Posted 15 June 2010 - 03:08 AM

Quote:
Original post by Damocles
Quote:
when you restore the app, are you trying to create a device with a 22 bpp format


No, and I have no idea where that 22 bit depth is coming from. You can see in the next line it's setting a 32 bit depth, and I don't make any calls to create a new device on loss/reset, I just use the existing one. So that 22 has to be something internal DX is doing.
I seem to recall seeing that before, I think it's just a typo in the D3D debug spew.

For input: Are you running your app as Administrator? Using a low level keyboard hook sounds like something user apps may not be able to do.

#7 Damocles   Members   -  Reputation: 133

Like
0Likes
Like

Posted 15 June 2010 - 03:15 AM

Oh yeah, good point. I do run as admin, and hadn't thought about the keyboard hook stuff. I'll probably have to rework that - good catch.

#8 mhagain   Crossbones+   -  Reputation: 7467

Like
0Likes
Like

Posted 15 June 2010 - 03:54 AM

You need to go into a loop after resetting until another TestCooperativeLevel returns D3D_OK, then recover your resources.

#9 Evil Steve   Members   -  Reputation: 1955

Like
0Likes
Like

Posted 15 June 2010 - 04:02 AM

Quote:
Original post by mhagain
You need to go into a loop after resetting until another TestCooperativeLevel returns D3D_OK, then recover your resources.
No, you only need to do that if Reset() fails. But since you should be calling TestCooperativeLevel() before trying to Reset(), it's unlikely that Reset() would fail.

#10 Damocles   Members   -  Reputation: 133

Like
0Likes
Like

Posted 15 June 2010 - 04:30 AM

I think I'm making progress (or just making things worse :) )...

After shuffling around the execution order a little, I am now at a stage where the DX9 spew is this:

Direct3D9: :WM_SYSKEYUP: wParam=00000009 lParam=a00f0001
Direct3D9: :Hot key pressed, switching away from app
Direct3D9: :WM_ACTIVATEAPP: BEGIN Deactivating app pid=00001628, tid=000017c4
Direct3D9: :DoneExclusiveMode
Direct3D9: :INACTIVE: 00001628: Restoring original mode (1440x900x22x75) at adapter index 0
Direct3D9: :WM_DISPLAYCHANGE: 1440x900x32
Direct3D9: :*** Active state changing
Direct3D9: :WM_ACTIVATEAPP: DONE Deactivating app pid=00001628, tid=000017c4
Direct3D9: :WM_SYSKEYUP: wParam=00000012 lParam=80380001
Direct3D9: :WM_ACTIVATEAPP: BEGIN Deactivating app pid=00001628, tid=000017c4
Direct3D9: :*** Already deactivated
Direct3D9: :WM_ACTIVATEAPP: DONE Deactivating app pid=00001628, tid=000017c4
Direct3D9: :WM_ACTIVATEAPP: Ignoring while minimized
Direct3D9: (ERROR) :************************************************************
Direct3D9: (ERROR) :ASSERTION FAILED! File s:\gfx_aug09\windows\directx\dxg\inactive\d3d9\d3d\fw\d3dobj.cpp Line 63: m_cRef > 0
Direct3D9: (ERROR) :************************************************************
Direct3D9: (ERROR) :Lost due to display uniqueness change
Direct3D9: (WARN) :Window does not have focus. TestCooperativeLevel fails
Direct3D9: (WARN) :Window does not have focus. TestCooperativeLevel fails
Direct3D9: (WARN) :Window does not have focus. TestCooperativeLevel fails
Direct3D9: (WARN) :Window does not have focus. TestCooperativeLevel fails
etc etc

This window not having focus thing intrigues me. I'm not sure why the window would not have focus when I have just tabbed back to it (or clicked it's icon). The assertion line worries me, not sure what's triggering that.

Does any of this shed any light for you guys?

#11 Damocles   Members   -  Reputation: 133

Like
0Likes
Like

Posted 15 June 2010 - 09:34 PM

I found it, or at least I found a way around it...

I added a 0.75 second delay between the call to device->Reset and when it started drawing. It seems the problem lay in the app trying to draw a little bit too soon, and the device wasn't quite ready.

This is odd, because at the very start of my update loop is a cooplevel test to ensure I don't try and draw on a device that's not ok, but that test was returning ok. Very strange, but by giving it a small window to get it's shit together, it now resumes normally. Very strange, but I'm not about to go digging around any further now it's working, for fear of breaking it again :)




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS