Jump to content
  • Advertisement
Sign in to follow this  
James C Smith

Not your typical Alt-Tab problem(screen frozen with game image when window minimized)

This topic is 3669 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Usually when programmers post a question about handling Alt-Tab in a full screen game they have a problem with restoring their textures when you return to the game after it has been minimized. It is usually easy to get a game to minimize and hard to get it to properly restore. In my case, I never have trouble restoring but I can’t get the full screen window to minimize in some cases. Every time I search for similar problem and answers I just find advice about how to restore lost textures. I have an annoying problem with my new game that uses a new D3D 8.1 renderer. If the game is running full screen it sometimes has trouble task switching. It doesn’t matter if you use Alt-Tab or Windows key or Ctrl-Esc or get task switched by a DRM when the 60 minute timer is up. No matter what causes the task switch, the game sometimes refuses to give up control of the display. The strange thing is this only happens when the desktop happens to be set to the same resolution as the game. It is a 1024 X 768 game running in full screen exclusive mode. Task switching back to a 1280 X 1024 desktop work every time. But task switching to a desktop that is also 1024 X 768 (same as the game) will fail about 1 in 3 times. When it fails some users think their computer is hung and end up rebooting. What is actually happening is Windows thinks the game minimized successfully. Other programs continue to run and the game actually continues to process its message queue. No processing is hung. Everything is running perfectly except the display is frozen with the game image on it. You can’t see anything including the Ctrl-Alt-Delete screen or the task manager. If you manage to Alt-Tab back to the game everything resumes perfectly. If you run a multi-monitor system it is much easier to get back to the game since only the one monitor is frozen and the other still runs your Windows task manager and other apps perfectly. FYI: On my multi monitor system, when the problem happens I see Windows draw the animation of the game’s window minimizaing back to the taskbar on the other monitor. It acts as if the window did minimize but the display is frozen. I have scrutinized all the code related to WM_ACTIVATE messages. We do almost nothing. Full screen DirectX apps are not actually reasonable for doing anything when they lose focus. Windows/DirectX automatically minimizes the full screen game. (or it is supposed to) My code works perfectly when the desktop is 1280 X 1024. The game minimizes every time. It just has trouble if the desktop is the same rez as the game. In that case it has trouble on every computer I have tried it on. I am using managed textures (D3DPOOL_MANAGED) so DirectX should automaicly be handling release and reloading the texure when the device is lost due to a task switch. I have added calls to TestCooperativeLevel() before every single D3D call to make sure I don’t try to do anything if the device is lost. This is based on the same framework we have used for years. Most of the windows message handling code is identical to previus game which don’t have this problems. For this game we just replaced the DirectDraw 5 code with Direct3D 8.1 code. We are using hardare acceleration for the first time and hating it. But all the other Windows message code and Direct Sound code is all the same as the code in the games that work fine. (FYI: This is a 2D "casual" game hence the use of DirectDraw 5 of D3D 8) I am out of ideas. Has anyone ever had trouble when their desktop is the same resolution as their full screen game? Has anyone ever had Alt-Tab minimize the Window but leave the display frozen? Any ideas what code I should change or where I could go to get more help.

Share this post


Link to post
Share on other sites
Advertisement
I turned up maximum debugging output and didn't learn anything usefull. This is what it said in a case where it failed


WM_ACTIVATE - not-active - not-minimized
Direct3D8: :WM_ACTIVATEAPP: BEGIN Deactivating app pid=00000b40, tid=00000f4c
Direct3D8: :DoneExclusiveMode
Direct3D8: :INACTIVE: 00000b40: Restoring original mode (1920x1200x22x60)
Direct3D8: :Enabling error mode, hotkeys
Direct3D8: :*** Active state changing
Direct3D8: :WM_ACTIVATEAPP: DONE Deactivating app pid=00000b40, tid=00000f4c
WM_ACTIVATE - not-active - minimized


The WM_ACTIVATE text is output by my code when it receives a WM_ACTIVE message.

In other words, DirectX ended exclusive mode, and Windows thinks my app is minimized, but the screen still show my app on it rather than the desktop.

When I captured the output from a successful case it was identical.

Share this post


Link to post
Share on other sites
I can't answer directly cause I never had this problem and I don't really code often but I've seem this in commercial games a couple of time. First thing I would look is your windows/direct3d initialization and message loop to see if there's something making the application "always on top" or using a higher thread priority or something like this.

Share this post


Link to post
Share on other sites
When a window is minimized the device isn't lost until you maximize the window again. So when the window is minimized you need to stop your rendering but continue your message loop. The only thing I can think of why there is a freeze is if your still rendering while the window is minimized. When you minimize your game the CPU usage for your game should drop to zero because it's not rendering.

Share this post


Link to post
Share on other sites
The game does realize it has been minimized and stops calling any drawing related functions but does continue to run the message loop and processes all messages. Stepping though it in the debugger verifies this as does the log file. When the app is later restored it resets the D3D device and everything work perfectly. The only problem is that during the time it was minimized the desktop never appeared.

Also, this works correctly half the time. When you hit the Windows key the game often minimizes successfully and I see the desktop. The window is not always on top. But the other half the time the window claims it is minimized (according to GetWindowPlacement) but the screen is stuck showing the game still.

Share this post


Link to post
Share on other sites
I think I am getting closer to solving this problem but it isn’t really making much sense.

Normally my game loop doesn’t call Update() and Draw() if the app is minimized. I change it to call Draw() anyway even when minimized and this makes the stuck screen problem go away. In this case I still don’t call Present() if the app is minimized but I do make several calls to IDirect3DDevice8 ::DrawPrimitive (). It doesn’t seem good to leave it this way so I need to figure out what side effect my Draw() has that is allow the Alt-Tab to work properly.

I verified that when I allow Draw to be disabled when minimized, and I get the frozen screen problem, I am defiantly calling PeekMessage 10 times per second and then processing ALL message if there are any before sleeping for 100 MS.

Share this post


Link to post
Share on other sites
I fixed it by adding a call to TestCooperativeLevel in my main game loop. I don't check the results from the function to change any behavior. Just calling this function and discarding the return value allows my game to minimize properly every time. I have no idea why.

In the past this function was never called when the game got minimized because as soon as I got the message that my app was being minimized I stopped making any calls to the graphics systems. All my drawing related functions started with a call to TestCooperativeLevel but I never called any of them because I knew the app was minimized. Now I call TestCooperativeLevel each loop just for the hell of it and everything is fine.

Share this post


Link to post
Share on other sites
Where do you detect the device status? That is, do you use the result of Present only or do you call dev->TestCooperativeLevel() in your run/message loop?

You need TestCooperativeLevel() while minimized (or at least after a WM_SIZE with SW_RESTORE after a SW_MINIMIZED) to reset the device when your window is restored but before you render.

EDIT - Well, there you go. Simultaneous posts. Glad you found the solution.

EDIT 2 - Actually, it's not for the hell of it. It's to detect a lost device or a need to reset before every render. It needs to occur just after PeekMessage but before you render. PeekMessage may result in the need to reset. Rendering with a lost or unreset device is the problem.

Share this post


Link to post
Share on other sites
What you describe doesn’t explain what I am seeing.
I always had a call to TestCooperativeLevel() before each render. I had no trouble restoring a lost device. The problem was, while minimized I never rendered and therefore never called TestCooperativeLevel(). I was just waiting for the window to get activated again before starting to call TestCooperativeLevel() and render again.

None of the documentation or examples suggested that TestCooperativeLevel() would have this kind of side effect. The fix was not to use the result of TestCooperativeLevel() to decide when to do a reset or anything like that. I am ignoring the result from TestCooperativeLevel(). Just calling TestCooperativeLevel() itself has some kind of side effect that allow the window to minimize. That doen't seem right.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!