Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Page flipping and window focus - strange behavior

This thread is locked; no one can reply to it. rss feed Print
Page flipping and window focus - strange behavior
Locutus266
Member #7,638
August 2006

Hello,

I have developed an Allegro game and I am testing it under Windows. Recently my game developed the behavior that it doesn't recognize any more keyboard commands or other "window messages", when I switch into the background and then back to the game again. It's not a fullscreen window, by the way.

If it loses window focus once, not even the close-buttons works anymore, although the game keeps running and the screen is still being updated. After clicking on the close button, Windows keeps asking to quit the task (although the game still runs).

Unfortunately I didn't now when this problem developed and I have made numerous changes to the code since.

When I use double buffering, the problem doesn't exist.

I have tried inserting some rest() commands because I was afraid that all the CPU load is keeping the KEYDOWN messages to reach Allegro's window loop, but that obviously isn't the problem either.

Maybe someone here has some good advice for me. What can cause such strange behavior?

Best Regards,
Christoph B.

Arthur Kalliokoski
Second in Command
February 2005
avatar

I only use Allegro to make a few image utilities, under Windows the last few versions gray out the close button (the "x" at top right on titlebar). What version do you have? I also have trouble with focus when using console at the same time, maybe you're not makeing it as a native Windows program? I forget what the preferred option to "-mwindows" is for mingw.

They all watch too much MSNBC... they get ideas.

orz
Member #565
August 2000

Arthur_Kalliokoski: try calling the allegro function set_close_button_callback to get the exit button to not be greyed out.

Locutus266:
I do not know what would block both the exit button and keyboard input. The exit button is handled by src/win/wwnd.c: directx_wnd_proc. Keyboard input is handled by src/win/winput.c: input_thread_proc. What version of Allegro are you using?
edit: PS you could try posting code here, though it sounds like the sort of problem that might only occur on some computers.

Kris Asick
Member #1,424
July 2001

I have had this problem before too, and at first I seemed to be the only person to experience it. It has to do with an incompatibility in all versions of Allegro starting with v4.1.0, manual bitmap locking or page flipping, and from what I understood, Windows 98. If you're not using Windows 98, it might be important to know which OS you're using specifically and what kind of video card you have. (My video card is an ASUS branded GeForce FX 5200.) The problem is related to the input sub-system. Since and including Allegro 4.1.0, all I/O threads under Windows were merged into one, but something that was changed as a result is causing this problem, and only on very few systems. (I assumed it was a Windows 98 thing.)

On my system, the problem only happens full-screen. Even CTRL-ALT-DEL stops working when it happens and I have to reboot with the reset button on my tower.

To get around the problem, I had to do two things:

1: Not manually lock bitmaps or use the show_video_bitmap() command. (Limiting me to double buffering, though I can still call vsync() to at least get close to page flipping quality.)

2: Add rest(1) or Sleep(1) to my game loops to give time back to the OS to prevent the I/O from stuttering. (A potentially related problem that started at the same time as the page flipping / bitmap locking problem.)

Besides that workaround I do not have the faintest idea how to solve the problem, and since the computers it happens on are very specific, I doubt anyone does. (I've brought it up three times in the past and never resolved it any of those times. All I managed to find out was when the problem began.)

One other workaround would be to go back to using Allegro 4.0.3, but you'll be giving up other fixes and the "_ex" functions if you do.

--- Kris Asick (Gemini)
--- http://www.pixelships.com

--- Kris Asick (Gemini)
--- http://www.pixelships.com

Locutus266
Member #7,638
August 2006

Hello and thanks for your replies.

I am using Allegro version 4.2.0 under Windows XP. The graphics card is some Intel onboard crap. Haven't tried it on a different PC, yet. But I will test it on a Windows ME machine soon and let you know what comes out of it.

Going back to Allegro 4.0.3 unfortunately is not an option for me, but thanks for pointing out that this might be a version-specific issue.

This is a simplified version of my main game loop:

1while (!done)
2{
3 if (blit_buffer)
4 {
5 show_video_bitmap(screen_buffer);
6 
7 if (screen_buffer == page1)
8 screen_buffer = page2;
9 else
10 screen_buffer = page1;
11 
12 fps_temp++; //Increase frame counter
13 clear_to_color(screen_buffer, black); //Reset memory bitmap to blackness.
14 blit_buffer = 0;
15 }
16 
17 ComputeEvents(); //User input
18 
19 //Logic
20 
21 while (pending_cycles > 0)
22 {
23 object_updates_and_stuff();
24 
25 pending_cycles--;
26 }
27
28 //Rendering
29 if (pending_frames > 0)
30 {
31 draw_objects();
32 
33 pending_frames--; blit_buffer = 1;
34 }
35
36 rest(1);
37 
38 //Set quit condition, if user pressed close button.
39 if (x_button_pressed) done = 1;
40}

If you have questions, simply ask.

orz: The exit button works fine, if the application didn't lose focus before. After having lost focus once and then switching back to it, the window simply doesn't process any Window messages anymore and then Windows thinks it's stuck, so it asks me to kill it if I hit the close button.

EDIT: I have been able to look further into it by commenting out some code. If I don't load any sprites into VRAM (or don't use VRAM->screen blit operations) the problem doesn't exist.

This is my function to load memory bitmpas into VRAM:

1BITMAP* pnd_LoadIntoVRAM(BITMAP* sprite)
2{
3 //This function creates a video bitmap and copies a given source bitmap to it.
4
5 BITMAP* video_bitmap = create_video_bitmap(sprite->w, sprite->h);
6 
7 if (video_bitmap != NULL)
8 {
9 clear_to_color(video_bitmap, bitmap_mask_color(video_bitmap));
10 draw_sprite(video_bitmap, sprite, 0, 0);
11 return video_bitmap;
12 }
13 
14 return NULL;
15}

Any suggestions on it?

Best regards,
Christoph B.

orz
Member #565
August 2000

I don't know much WIN32, but I will take a stab at it.

My current guess is that that the event loop gets stopped during handling one of the WM messages that occurs on switch out or switch in. On my setup (winXP, MSVC 7.1, slightly modified Allegro 4.2.1), the only WM message that allegro processes on switch out is WM_ACTIVATE, and the ones it processes on switch in are WM_ACTIVATE followed by WM_PAINT. Several other WM_*s are sent, but Allegro doesn't seem to do anything with them so I don't think they can cause problems. I don't see any obvious causes of failure for WM_ACTIVATE. WM_PAINT could conceivably block waiting on _enter_gfx_critical() if the main thread screwed up unlocking it. One way to test for this would be to have your main thread check the value of gfx_crit_sect_nesting (declared in allegro/platform/aintwin.h). I think it should be zero most of the time that you don't have any bitmaps locked.

What OS are you using? I have access only to win2k and winXP.
Can you attach a debugger and see what wnd_thread_proc thread is doing when messages stop getting through?
What display switching mode are you in? Does this happen in both SWITCH_BACKAMNESIA and SWITCH_AMNESIA?
Do you have any switch out/in callbacks installed?
Can you somehow tell if this happens on switch out or on switch back in?
Can you figure out what the last WM_* that was recieved by directx_wnd_proc is?

tobing
Member #5,213
November 2004
avatar

I have something similar, which occurs mostly when the game is starting, but the window is not immediately active (because I opened or activated another window in the meantime, e.g. my browser). Switching back and forth usually helps, so I didn't go into any detail with this. Just wanted to report that I also have this problem. WinXP, allegro 4.2.1.

Locutus266
Member #7,638
August 2006

@orz:

I am using Windows XP SP2.

Unfortunately I cannot use a debugger, since I am using MinGW and Dev-Cpp and somehow it's not working correctly. (Step-by-Step cursor jumps back and forth wildly in code)

If I use SWITCH_BACKGROUND, the game is halted when I switch back to the window (reactivating it) the second time (the first switch works fine).

If I use SWITCH_AMNESIA or SWITCH_BACKANMESIA, the game is halted instantly when the game window loses focus the first time.

No switching callbacks are installed.

As I said, this problem only occurs if I use VRAM bitmaps. I don't do any locking on them yet. I suspect that it has something to do with Allegro's automatic bitmap locking mechanism. However, I tried putting in some calls to acquire_screen() and acquire_bitmap() (and releasing them of course), but nothing helped.

To find out, what window message the last one is that is being received, I'd have to modify Allegro code I guess. That could take me some time. But I'll try and report back if I find something out.

Thanks for your comments so far.

Christoph B.

orz
Member #565
August 2000

tobing:
I've seen that bug as well, but never managed to produce it on 4.2.x. I've seen progams with identical source code where one binary would produce that and one would not... possibly due to different dll versions.

Locutus266:
I've linked to this in the Allegro Development forum on the assumption that it's an Allegro bug. Thread here:
http://www.allegro.cc/forums/thread/590303
There does appear to be several things wrong with Allegro's graphics synchronization stuff, but I haven't yet found likely to produce your symptoms in particular.

edit:
The bug I found was actually 1 bug, not multiple bugs. It wouldn't have any effect like you're seeing though, at least not in SWITCH_BACKAMNESIA mode. Just in case, you could try changing aintwin.h and then rebuilding Allegro. Change is:
old (incorrect) code:

#define _exit_gfx_critical()   LeaveCriticalSection(&gfx_crit_sect); \
                               gfx_crit_sect_nesting-- 

corrected code:

#define _exit_gfx_critical()   gfx_crit_sect_nesting--;\
                               LeaveCriticalSection(&gfx_crit_sect) 

Locutus266
Member #7,638
August 2006

Hello orz,

yesterday I tried my game on a different PC with a decent graphics card -> Same problem.

I have installed MSYS and rebuilt Allegro 4.2.0 (which is actually the version I am using) and inserted your corrected code. Unfortunately, the bug still persists, (using SWITCH_BACKGROUND or SWITCH_AMNESIA). No change there.

I have decided to strip down my game of any unnecessary code, only to reproduce the bug. I will put it somewhere on the net, when I have done this.

Best regards,
Christoph B.

Kris Asick
Member #1,424
July 2001

You know, this is the kind of thing where it's important to check the example programs that come with Allegro and see if the problem exists there.

On my system, the problem I described above happens in ALL of the example programs. (And in the triple buffering example my I/O access is lost immediately and permanently.) (Correction: All of the example programs which use page flipping.)

--- Kris Asick (Gemini)
--- http://www.pixelships.com

--- Kris Asick (Gemini)
--- http://www.pixelships.com

Locutus266
Member #7,638
August 2006

@Kris:

I tried it with exflip.c. I even put in a VRAM->VRAM blit and forced it to windowed mode, because I am doing this in my game and that's what forces it to crash in the first place. However, the example seems to work fine. I wasn't able to reproduce the behavior.

That's why I am planning to strip my game from code until it works. :-)

For anyone who's interested in my code, I have put the latest version of my game at

http://locutus266.homelinux.net/pnd-2.0-beta.zip

No special configuration is needed to compile. Dev-Cpp might be good, though.

Regards,
locutus

orz
Member #565
August 2000

Hm... it has the same broken-alt-tabbing on my computer. I'll set up a project to see what's going on.

edit1:
unrelated to your problem (probably), but necessary for me to compile:
vol_start_ticks is exported and imported as different types.
pnd_GetSysCaps() is used with different prototype.

The crash happens on IDirectDrawSurface2_Restore most of the time.
But, I believe the cause is your bug not Allegro's bug:
specifically, changing this code:

    if ((!page1) || (!page2))
    {
      page_flip = 0;
      pnd_Notice("   ...error creating video memory pages.");
    }

    clear_to_color(page1, black);
    clear_to_color(page2, black);
    screen_buffer = page2;

to this:

    if ((!page1) || (!page2))
    {
      page_flip = 0;
      pnd_Notice("   ...error creating video memory pages.");
      if (page1) destroy_bitmap(page1);
      if (page2) destroy_bitmap(page2);
    }
    else {
      clear_to_color(page1, black);
      clear_to_color(page2, black);
      screen_buffer = page2;
      return 1;
    }

appears to fix the issue. With your existing code, the next few lines immediately after this execute, changing screen_buffer to point at a memory bitmap. Why exactly that's crashing I do not know, but it's clearly not what you intended to do, and making it do what you intended to do eliminates the crashes.

Locutus266
Member #7,638
August 2006

@orz:

Well, I guess you found the problem! Thanks a lot for looking in to it.

It works on my computer, too after changing that error. Setting up a screen buffer in RAM obviously makes no sense if two video pages already were allocated for page-flipping. It should only happen, if setting up page-flipping threw an error.

Of course that code was wrong and I didn't see it.
Sorry for the false alert. :)

Quote:

vol_start_ticks is exported and imported as different types.
pnd_GetSysCaps() is used with different prototype.

How come your compiler complains about that? I also want to know, if I did something like this wrong. ;) Is there a command-line switch?

While we're at it: How did you like my code and do you have any suggestions on improving it? (I still have the problem that animation is mostly very jaggy and not smooth. I suppose it's a timer granularity issue.

Best Regards,
locutus

Tobias Dammers
Member #2,604
August 2002
avatar

Quote:

Unfortunately I cannot use a debugger, since I am using MinGW and Dev-Cpp and somehow it's not working correctly. (Step-by-Step cursor jumps back and forth wildly in code)

You haven't compiled with any optimizations enabled, have you? Because if you have, the compiler may have rearranged a lot of your code to make it more efficient. As a result, some of your statements may be executed somewhere you don't expect them, and other statements may not be executed at all - the program still produces the same output, but it cannot easily be linked to the original source code any more.
Compile without optimizations (see if there are any -O switches enabled in your compiler setting) and try again.

Quote:

It works on my computer, too after changing that error. Setting up a screen buffer in RAM obviously makes no sense if two video pages already were allocated for page-flipping. It should only happen, if setting up page-flipping threw an error.

If something has failed, and you try to recover gracefully, make sure you clean up the the resulting mess before doing anything else.
Just because the second page cannot be allocated, doesn't mean the first one cannot.

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Locutus266
Member #7,638
August 2006

@Tobias:

Thanks! I believe optimization was the problem. Debugging works fine now.

Go to: