DX9 fullscreen alt-tab issue [solved - ish]

Started by
9 comments, last by Damocles 13 years, 10 months ago
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]
------------------------------------------[New Delta Games] | [Sliders]
Advertisement
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?
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?
[ dev journal ]
[ current projects' videos ]
[ Zolo Project ]
I'm not mean, I just like to get to the point.
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.
------------------------------------------[New Delta Games] | [Sliders]
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.
------------------------------------------[New Delta Games] | [Sliders]
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.
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.
------------------------------------------[New Delta Games] | [Sliders]
You need to go into a loop after resetting until another TestCooperativeLevel returns D3D_OK, then recover your resources.

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

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.
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?
------------------------------------------[New Delta Games] | [Sliders]

This topic is closed to new replies.

Advertisement