Allegro.cc - Online Community

Allegro.cc Forums » Allegro Development » GFX_SAFE jitters on Windows

This thread is locked; no one can reply to it. rss feed Print
GFX_SAFE jitters on Windows
Runesabre
Member #7,573
August 2006
avatar

When I run my game client using Allegro 4.2.1 and GFX_AUTODETECT_WINDOWED at 800x600 it works perfectly.

When I use GFX_SAFE, it "works" except the whole display inside the window box appears to be jittering up and down by one pixel line (the window itself is stationary, just the contents appear to be jittering up and down like a camera shake effect).

_______________
Runesabre
Connecting People through Inspiring Interactive Entertainment
Enspira Online

Matthew Leverton
Supreme Loser
January 1999
avatar

I was actually going to post this same thing. It happens with the GDI driver and is most pronounced when doing lots of blits.

Run the Allegro demo with dirty rectangles in GDI to see it happen.

Peter Wang
Member #23
April 2000

My guess is there's an off-by-one error in render_proc() in src/win/wgdi.c that deals with updating the dirty lines of the screen.

Matthew Leverton
Supreme Loser
January 1999
avatar

Another weird thing, at least on Vista, is that the GDI (I think) DX windowed display isn't always updated. For instance, when I run the demo and it tries to set a crazy 320x200 mode, after failing at several tries, it finally sets a windowed mode. However, nothing is displayed unless I move the Window around. The GUI for selecting the mode / update system isn't displayed as well.

Once the game starts, it works. And if I select GDI, I get the bouncing behavior. Attached a MingW32, static version of demo.exe in case anyone else wants to test that out.

Edit: It happens to the Direct X windows mode sometimes with GFX_AUTODETECT, 320, 200. After failing to set full screen, it then sets a windowed mode. Since the demo is in 8-bit, Vista shuts down its advanced graphics display. Then sometimes there is nothing displayed in the window. But sometimes it works. And if I use GFX_AUTODETECT_WINDOWED it doesn't ever seem to do it.

Edit 2:

Quote:

My guess is there's an off-by-one error in render_proc() in src/win/wgdi.c that deals with updating the dirty lines of the screen.

Setting top_line to 0 inside the if{} fixes it. I'll try to see why.

Edit 3: What's odd is that it doesn't happen until after the Allegro logo zooms up. I changed it to be like this:

top_line = toggle ? 16 : 0;
toggle = 1 - toggle;

And as soon as the logo is finished zooming, it starts jumping by 16 pixels.

Edit 4: The problem, I think, is here (stretch_blit_to_hdc @ gdi.c):

  StretchDIBits(dc, 
    dest_x, dest_y, 
    dest_w, dest_h, 
    src_x, bitmap->h - src_y - src_h, 
    src_w, src_h, 
    pixels, bi, DIB_RGB_COLORS, SRCCOPY);

Allegro's GDI bitmaps are top down DIB, created by using a negative height. From what I can gather StretchDIBits always works with bottom,left thus the weird src_y calculation. (That goes against what the MSDN documentation says.)

However, with top-down DIBs there is some sort of bug (?) with certain sx,sy (0,0 ?) coordinates that causes the behavior to be reversed. But I cannot figure out what it is.

When I switch Allegro to use bottom-up DIBs, then the jerkiness goes away, but everything is upside down (and some artifacts appear, but probably due to my hack). If I then swap the dest_h and dest_y to be negative, it flips it right side up (and the jerkiness is still gone).

Edit 5: Changing stretch_blit_to_hdc @ gdi.c to this, "fixes" the problem by not drawing the left most line:

1 // sy is the bottom-up coordinate (src_y is from the top)
2 int sy = bitmap->h - src_y - src_h;
3 
4 if (sy == 0 && src_x == 0 && src_h != bitmap->h)
5 {
6 // the buggy behavior is here, so don't draw the left most line to work around it
7 StretchDIBits(dc,
8 dest_x+1, dest_y,
9 dest_w-1, dest_h,
10 src_x+1, sy,
11 src_w-1, src_h,
12 pixels, bi, DIB_RGB_COLORS, SRCCOPY);
13 }
14 else
15 {
16 StretchDIBits(dc,
17 dest_x, dest_y,
18 dest_w, dest_h,
19 src_x, sy,
20 src_w, src_h,
21 pixels, bi, DIB_RGB_COLORS, SRCCOPY);
22 }

The problem is if you are blitting the source rectangle of (0,y1)-(x2,bmp->h) with y1 > 0, then everything is drawn from (0,0) [using coords from the top-left]. So, for example: if you are blitting from (0,16)-(0,479) to (0,16), then you really get (0,0)-(0,463) drawn at destination (0,16). But if x1 != 0 or y1 == 0, then it's fine.

So we need an expression that is able to represent that case without triggering the error. Perhaps something can be done with negative heights (those are treated as flipped), but nothing is working yet.

Edit 6: I think this solves the problem:

StretchDIBits(dc, 
  dest_x, dest_h+dest_y-1, dest_w, -dest_h,
  src_x, bitmap->h-src_y+1, src_w, -src_h, 
  pixels, bi, DIB_RGB_COLORS, SRCCOPY);

Just replace the current StretchDIBits line with that one.

Runesabre
Member #7,573
August 2006
avatar

That's looks like a lot of nice debugging, Matthew. Hopefully this solves the issue. Nice work!

_______________
Runesabre
Connecting People through Inspiring Interactive Entertainment
Enspira Online

Matthew Leverton
Supreme Loser
January 1999
avatar

Attached is an updated DLL. Please test it out to see if it fixes the problem for you.

I wrote a complete description of the problem on the wiki, and will send a patch to the mailing list.

Just for reference, this is a test program:

1#include "allegro.h"
2 
3int main(void)
4{
5 allegro_init();
6 
7 install_keyboard();
8 set_color_depth(32);
9 set_gfx_mode(GFX_GDI, 640,480, 0,0);
10 
11 // full screen
12 clear_to_color(screen, makecol(255,0,255));
13 rect(screen, 0,0, SCREEN_W-1,SCREEN_H-1, makecol(0,255,0));
14 readkey();
15 
16 // bottom half
17 clear_bitmap(screen);
18 readkey();
19 
20 rect(screen, 0,SCREEN_H/2, SCREEN_W-1,SCREEN_H-1, makecol(0,255,0));
21 readkey();
22 
23 // top half
24 clear_bitmap(screen);
25 readkey();
26 
27 rect(screen, 0,0, SCREEN_W-1,SCREEN_H/2-1, makecol(0,255,0));
28 readkey();
29 
30
31 
32 return 0;
33 
34}
35END_OF_MAIN();

With Allegro 4.2.1 the bottom rectangle is never seen on the screen because Windows actually blits the top half of the buffer since the rectangle touches the bottom left corner! The full screen rectangles and top rectangles are fine. [The readkey()'s after the clear()'s are necessary to prevent the full screen from being refreshed by the clear().]

With my patch, all three cases work. Hopefully it doesn't introduce any other weird problems.

Runesabre
Member #7,573
August 2006
avatar

The updated DLL fixes the issue. Nice work :)

I did notice the framerate dropped significantly on my machine from 250 to 180 though. I'm guessing this is a debug DLL (since it's twice as large as the original 4.2.1 DLL)?

_______________
Runesabre
Connecting People through Inspiring Interactive Entertainment
Enspira Online

Matthew Leverton
Supreme Loser
January 1999
avatar

It's compiled by MinGW, which produces larger DLLs than MSVC.

Try this DLL as well. It only runs the new code for the problem case. (As I wrote on the Wiki, it's possible that this reverse blitting is slower.)

Runesabre
Member #7,573
August 2006
avatar

This DLL also solves the problem (with no discernible side effects), with only a minor performance hit (~260fps --> ~240 fps).

_______________
Runesabre
Connecting People through Inspiring Interactive Entertainment
Enspira Online

Matt Smith
Member #783
November 2000

Is this only in Vista? I have never experienced this problem in 98SE or XP. I'm not very happy about taking a 10% performance hit for the sake of a Vista bug, which may be temporary. If the lib is patched, can you make sure you comment it so it can be reversed later?

Matthew Leverton
Supreme Loser
January 1999
avatar

The bug is present on XP and Vista, but not Windows 98 (as far as I can tell). It's been reported many times over the last several years (pre-Vista), and only now has it been fixed. I would imagine that it effects anything other than Windows 9x/ME.

The reversed blitting fix is only applied for the one case that is a problem: a rectangle touching the bottom, left corner of the source that is less than the height of the bitmap. So I really doubt there is a 10% hit. The difference in the above frame count could easily be due to different compilers and optimization levels.

A detailed explanation is linked on my previous post.

Go to: