PDA

View Full Version : How do you recover from Alt+Tab?


VengefulPastry
12-26-2004, 01:16 PM
Using Visual Basic/DirectX 8 in full-screen mode.

So, somebody is playing your game, and hits Alt+Tab (or Windows pops up with a message, taking control of the graphics/desktop). Your game is minimized and paused, with a little tab at the bottom of the screen to reinstate it as the focus.

When I click on the tab on the bottom bar to reinstate the game, the game does indeed start running again (numbers are being crunched, AI is running, sounds are playing), although without the graphics.... so my question is, how do I retake control of the graphics from Windows that just stole it for its Alt+Tab/Warning message antics?

Ideas?

C_Coder
12-26-2004, 01:53 PM
Using Direct X you will have to reload all the graphics when this happens.
On every frame, you have to call TestCooperativeLevel() and check that if the return value is D3DERR_DEVICELOST. If it is, then you will have to restore your device by recreating the device and reloading all your textures.

Sad but true...had to go all through it...Took me 3 months to code a decent 2D library using Direct X... :D

VengefulPastry
12-26-2004, 04:15 PM
... for this wonderful "feature"?

I figured I would have to reinitialize the graphics settings, but reload all of the textures too? Sigh, just when I thought I enjoyed programming...

Hmmm.... I wonder if there is an "easier" solution, like telling the user that "Alt+Tab" performs the same task as the "Esc" key: it exits the program (that's what I have happen at the moment, I was just hoping for an easy fix).

C_Coder
12-26-2004, 04:45 PM
I've read in MSDN that there is a way to set the Cooperative Level in a way that the Alt+Tab and/or the Win key are disabled while in your game.

You have to look for that though as I do not have it handy at the moment. :rolleyes:

BedroomCoder
12-26-2004, 05:02 PM
Surely theres some way to disable alt + tab? like, if you press tab + alt, it says "saving... quitting..." or something?

Dan MacDonald
12-26-2004, 05:08 PM
You can store your textures different ways, depending on the flag you use when loading them. I think there's a SHARED_POOL or something like that (over 3 years since i've done any DX programming) that allows them to persist through an alt-tab.

C_Coder
12-26-2004, 05:12 PM
You can store your textures different ways, depending on the flag you use when loading them. I think there's a SHARED_POOL or something like that (over 3 years since i've done any DX programming) that allows them to persist through an alt-tab.

Yes I recall it should be the MANAGED flag. I think there were some drawbacks...hmmm...why didn't I use them then... :rolleyes:

Sante
12-26-2004, 05:43 PM
You can use the MANAGED flag to avoid having to destroy textures and buffers, but keep in mind that what it does is saving a copy of them in the system memory, and automatically restoring from that copy. So, your program would be using much more memory than really needed. You can do that if you don't use too many textures, but I think it's better to reload them.

In any case, you'd have to restore the device itself, and backbuffer, z-buffer, etc...

ogracian
12-26-2004, 06:08 PM
You could aslo check the "Game Coding Complete" book by Mike McShaffry,
It contains a LOT of valuable info on this and other interesting topics, it really help me to solve a lot of things that I ever thinked about it.

In special check the chapter 11 - Special Considerations for Developing Windows Games, it shows how to handle LOST SURFACES (DirectDraw7) on full screen windowed modes swithching.

Regards,
Oscar

Rainer Deyke
12-26-2004, 06:27 PM
I would just like to point out that when I find out that a game doesn't support alt+tab (which is usually within five minutes of starting the game), I immediately uninstall it.

Duke
12-26-2004, 07:24 PM
I would just like to point out that when I find out that a game doesn't support alt+tab (which is usually within five minutes of starting the game), I immediately uninstall it.
MS seems to be on your side. :)
From DirectX FAQ (not the exact quote):
Q: How do I disable Alt-TAB in my game?
A: You don't.

Plain and simple, huh?
Since I'm inexperienced in Direct3D programming, I used Direct3D Application Framework as a base from which I built my game. Later I removed all the excess code I found. Admitedly, it is unoptimized, but it did the job for me. Didn't have to think about the Alt-TAB issue at all, just followed the guidlines.
@VengefulPastry - I used C++/DX9, so I'm not sure if this framework exists in VB/DX8 combination. Anyway, C_Coder pointed in the right direction.

BedroomCoder
12-26-2004, 08:29 PM
I would just like to point out that when I find out that a game doesn't support alt+tab (which is usually within five minutes of starting the game), I immediately uninstall it.


>_>


<_<


>_>


Whhhhhhhhhy?

Yossarian
12-26-2004, 08:45 PM
@Bedroom

Because losing control of you puter sucks.

Seriously, keep in mind all of us with day jobs and wives that think we're doing our taxes... we *need* the ability to quickly minimize an app and switch over to our fake spreadsheet or text editor :)

wazoo
12-27-2004, 12:16 AM
Hehehe...boy does that bring back memories of the old Leisure Suit Larry games (back when they were fun). Someone's coming up the stairs....op! Boss Key!

Anyways, disabling Alt+Tab is a no-no, because not only is it unconventional, but it's damn annoying when you need to switch to something else (say a bittorrent session or something..;) )

Seriously, C_Coder's on the right path. You need to check the TestCooperativeLevel result every frame, then reset the device accordingly.

Actually it's not all that painfull, as pretty much the only thing you gotta worry about is the textures....the vertex buffers should be handled automatically (provided you create them with the DEFAULT_POOL setting)..

When you reset the device, it's also a great place to throw in basic d3d device settings for your game (ie. certain lighting levels, texture pipeline defaults, culling mode, etc).

C_Coder
12-27-2004, 02:29 AM
I had to do the device creation process + render state settings and texture loading into separate functions so that I call them when the device is lost. Also I store all the filenames of the textures I loaded (+ handles) in a list so that when the device is lost, the texture loading function will automatically reload the textures by their filename and in the same handle variable of before. This is not very trivial to do. Just design it good in the first place.

Or just use a premade library if you do not feel like going through all this. :D

And by the way, I had the same dilemma before implementing this...should I or should I not disable Alt+Tab? Well the result was the same...where's that boss key? :p

Kai Backman
12-27-2004, 03:58 AM
I implemented this by creating wrapper classes around all D3D objects that needed to be Released and Restored after a loss of device. This affects only memory allocated using D3DPOOL_DEFAULT ie. things stored in video memory. If you use D3DPOOL_MANAGED D3D will essentially do the same thing for you. Each object contains two instances of the data: system_memory (D3DPOOL_SYSTEMMEM) and video_memory (D3DPOOL_DEFAULT).

Here are the three states.

Initial:
system_memory - INVALID
video_memory - INVALID

Released:
system_memory - VALID
video_memory - INVALID

Active:
system_memory - VALID
video_memory - VALID

Unloaded->Released
- Load the system memory copy from disk or create it programmatically if needed.

Released->Active
- Allocate a new buffer from D3D_POOL to hold the data (vertex buffer, index buffer etc).
- Copy the data from system_memory to video_memory

Active->Released
- Call ->Release() on video_memory instance and invalidate the interface pointer

There is a central repository that has links to all entities that need state management. At startup it loops through the entities and changes their state to Released. When the video devide is aquired it again changes the state to Active. When lost backs down to Released and when required again up to active.

Using a central manager class with state stored in each entity makes for a more robust system. You can loose the device at any point, most importantly during a systemwide Released->Active state change, so you need to know which entities to back down to Released state from Active. You need to properly step back everything (using ->Release()) before you reaquire the device, otherwise you will get an error.

I hope this helps! :)

BedroomCoder
12-27-2004, 05:03 AM
@Bedroom

Because losing control of you puter sucks.

Seriously, keep in mind all of us with day jobs and wives that think we're doing our taxes... we *need* the ability to quickly minimize an app and switch over to our fake spreadsheet or text editor :)

You play games at WORK?!?!?!? :eek:

Night Elf
12-27-2004, 06:27 AM
Handling lost surfaces can become a pain in the back if you don't consider it from the start, but with some careful coding it's not really so bad.

Use the D3DPOOL_MANAGED flag when creating all your resources. That way, DirectX will keep a copy of them in system memory and automatically restore it when the app is reactivated. This doesn't waste memory, because it's the only way to do resource restoring fast. You can't reload your textures from the hard drive, it'd be too slow.

There are certain resources which memory pool you can't choose. These are automatically stored in the D3DPOOL_DEFAULT memory pool. With these kind of resources (which include, for example, ID3DXSprite and ID3DXFont), you need to release and reload them by hand. Luckily, D3DX provides very simple functions to do this. For example you have ID3DXSprite::OnLostDevice() and ID3DXSprite::OnResetDevice().

So, to handle this last kind of resources you must do this in each iteration of the main loop:


HRESULT HR;
HR = m_pD3DDev->TestCooperativeLevel();
if (HR == D3DERR_DEVICELOST)
{
// Continue to next frame, your application has lost focus
// and there's nothing you can do right now
}
else if (HR == D3DERR_DEVICENOTRESET)
{
// Destroy all D3DPOOL_DEFAULT resources, for example:
m_pD3DSprite->OnLostDevice();

// Reset the D3D device
HR = m_pD3DDev->Reset(&m_PresentParams);

// If the device could be reset
if (SUCCEEDED(HR))
{
// Recreate all D3DPOOL_DEFAULT resources, for example:
m_pD3DSprite->OnResetDevice();

// Reapply all your render states and texture states
}
else
{
// Device is still lost, wait till next frame
}
}


My code is in C++, but it should be almost exactly the same in VB.

The best you could do to handle the destruction/recreation of D3DPOOL_DEFAULT resources is to have some kind of list grouping all these resources; each time you create one of these, you add it to the list. So then it's just a matter of looping through the list and calling each resource's OnLost() or OnReset() methods.

C_Coder
12-27-2004, 06:46 AM
You play games at WORK?!?!?!? :eek:
We have to keep the gaming spirit alive even at work no? :p

Also it is good to distract yourself for 5 minutes... :D

VengefulPastry
12-27-2004, 07:16 AM
It wasn't so bad to handle after all. I think most of the pain of handling the reload of the textures was imagined, not real.

My game now works with Alt+Tab (and returning from it), and I assume from any other loss of focus...

Thanks C_Coder! And everybody else!

C_Coder
12-27-2004, 08:58 AM
My pleasure! :D

VengefulPastry
12-28-2004, 03:52 PM
OK, I was too quick to proclaim victory on this one.

The game works great. You hit Alt+Tab, do your Windows stuff, and then click on the minimized game button on the bottom taskbar, and the game comes back, reinitializing the graphics, and plays great again for hours and hours until you decide to quit. No problems....

....unless, while you are playing, you try to Alt+Tab again. Now Windows will only take the keyboard and mouse, but leaves the video alone. So you have my game displayed, but keys/mouse control is doing Windows stuff in the background (I assume). My game logic is still running, so I know Windows refused to suspend for Alt+Tab this second time.

I use the same exact process to initially load DirectX graphics/mouse/keyboard at the beginning of the game as I do recovering from Alt+Tab (there is no difference in fact, I just call the same exact procedure).

Any idea what Windows may be doing different, that it won't actually take control the second time Alt+Tab (or CTRL-ALT-Del for that matter) is used?

Thanks ahead of time!

C_Coder
12-28-2004, 04:08 PM
This happens to me as well. If you use exactly the same resolution of your current desktop, that's when it happens. I never found a resolution for it though.

You have to lock the desktop or press Ctrl+Alt+Del to get your windows back again.

Cannot help there. :(

Badman
12-28-2004, 04:19 PM
You could aslo check the "Game Coding Complete" book by Mike McShaffry,
It contains a LOT of valuable info on this and other interesting topics, it really help me to solve a lot of things that I ever thinked about it.

In special check the chapter 11 - Special Considerations for Developing Windows Games, it shows how to handle LOST SURFACES (DirectDraw7) on full screen windowed modes swithching.

Regards,
Oscar

Let me second Game Coding Complete - it will tell you a whole bunch of little game development tricks that will save you a whole bunch of time and that you would otherwise have to discover through a lot of your own effort. Plus, it's actually fun to read - Mike has a whole bunch of great stories from his years of game development. My copy is well-read and signed by the author :)

DangerCode
12-28-2004, 10:12 PM
Any idea what Windows may be doing different, that it won't actually take control the second time Alt+Tab (or CTRL-ALT-Del for that matter) is used?

Are you re-aquiring the Direct Input devices?

C_Coder
12-29-2004, 02:21 AM
I was mentioning a different problem than mentioned here. My problem is that when I error out and show a message box, Windows will not go to window mode but will keep the game showing even though the keyboard responds to window events.

So my post was reather pointless. :p

Yes you have to reaquire the input devices when input is lost. I had to do that as well.

VengefulPastry
12-29-2004, 06:58 AM
Are you re-aquiring the Direct Input devices?

Yes. I have a procedure called "InitDirectX" which initializes everything to do with DirectX, including graphics, input, and well, everything. I call it when first starting the program, and then when recovering from Alt+Tab.

Like I said it works great. After recovering from Alt+Tab (or CTRL-Alt-Del or any other loss of focus) the game runs great, reinitializing DirectX with graphics, input, etc. Just as if I had never left to begin with.

However, trying to exit again just plain does not work. My graphics remain, but input control is given to windows (I can occasionally see the Windows taskbar at the bottom trying to peek through my graphics). My graphics are constantly updating as normal, but Windows never takes over to minimize the current operation (my game); it just steals back the mouse and keyboard.

Ideas?

Night Elf
12-29-2004, 12:56 PM
What does your game do when it's inactive? I don't know if this is your problem, but maybe you're forgetting to halt your program when you detect it's lost focus.

VengefulPastry
12-29-2004, 01:06 PM
What does your game do when it's inactive?

I've tried both pausing everything until I regain focus and pausing nothing. Both methods work fine through the first Alt+Tab. Neither method will allow Alt+Tab again.

It is as if Windows uses one method to grab the focus the first time, and a different method the second time.