DirectDraw7 Flip very slow

Started by
14 comments, last by Aardvajk 18 years, 1 month ago
Quote:Original post by EasilyConfused
What's the easiest way to time your framerate accurately? Happy to post some stats if someone can give me a couple of lines of code to do it. time.h?


Download a trial version of Fraps: http://www.fraps.com/ [smile]


Quote:However, have just tried passing DDFLIP_NOVSYNC to Flip and guess what - speeds up enormously but graphics go all shuddery again, so at least I now know exactly what the problem is.

Very confused now. How on earth do I get my nice solid-moving graphics back?

Must admit the code does use pixels-per-frame movement but surely if I move sprites based on time instead, the result will be really jerky on the hardware that is causing problems?


Synopsis and thoughts:

1) when Flip() waits for VSYNC, it caps the rate of your render loop at the frequency of your monitors vsync/refresh (or the next lowest multiple). So for example, with a 60Hz display mode, your loop will run at most 60 times a second (and if it can't run at that speed it'll run at 30 times a second, and so on).


2) when Flip() waits for VSYNC, if the stuff you're drawing isn't stressing the graphics card at all, your loop will always run at that rate for every frame. So if your animation code says something like "position.x += 2", then things will always move at the same rate and so look smooth, because you 'know' the x position will always move by 2 pixels every 1/60th of a second (using the example of 60Hz from above).


3) when Flip() *doesn't* wait for VSYNC, the rate your loop runs is usually determined by external factors such as the exact amount of time the graphics card took to render your scene; what other processes and threads running on the computer were up to at that time; where in your loop your thread was pre-empted by the thread scheduler; which window messages were recieved by your message pump; etc.

This combination of external things is as good as random over time; because of this, if you aren't locking your loop to VSYNC, the rate at which your loop makes an iteration and the time it takes Flip() to return will vary for each iteration of the loop. So your "position.x += 2" still moves by 2 pixels every loop iteration, but the time between loop iterations varies, thus you get jerky animation...


4) Another artifact you see when you don't wait for VYSNC is tearing - where the monitor/TV hasn't finished updating the display when you display the new frame - you get a tear at the location of the raster (aka scanline) where the bottom half of the display contains the previous frame and the top half contains the current frame. That's kinda what waiting for VSYNC is intended to prevent - if you make the new frame visible when the raster is off screen (the vertical blanking interval/gap), you don't see any tearing: http://en.wikipedia.org/wiki/VBI


5) Since you say the animation on the 98 machine is smooth, just faster, I'd be interested in knowing what frame rate you get on each of the machines (possibly using Fraps - or simply timing how long it takes between iterations of your loop).

It could be the case that *all* of the machines are synchronised to VSYNC, but all set to different refresh rates (e.g. 85Hz for the 98 machine and 60Hz for the 2000 and XP machines).


6) I'd definitely 100% advise using time based animation rather than assuming your loop will always iterate at the same rate, that way you should get smooth motion regardless of the frame rate - even if it isn't synchronised to VSYNC.


7) I though of something entirely unrelated for us to look at: Your window message handling loop (PeekMessage/GetMessage, etc), the window procedure where you react to those messages, and how they fit in with iterations of your loop.

There are subtle differences in the way the message queues work on 9x platforms (95/98/ME) compared to NT platforms (NT/2000/XP).

Try specifying DDFLIP_NOVSYNC on the 98 machine too - if that runs more smoothly than on the 2000/XP machines, then it could be an indication of your render loop not being called from the most appropriate place or using a blocking call to fetch messages.


Quote:I'm going back to writing text adventures at this rate (all together now - probably a good idea based on your understanding of graphics code...)


Nah, stick at it - nobody was born with knowledge of graphics programming - we all had to learn this stuff at some point or other in our programming histories.

Simon O'Connor | Technical Director (Newcastle) Lockwood Publishing | LinkedIn | Personal site

Advertisement
SC1A - thanks for your useful (and last very kind) comments. Will have a look at fraps when I get a chance.

WinMain message loop is as follows (Engine.OnCycle is where the rendering and flip is called)

WinMain().../* Initialisation */...    while(true)        {        if(PeekMessage(&Msg,NULL,0,0,PM_REMOVE))            {            if(Msg.message==WM_QUIT) break;            TranslateMessage(&Msg);            DispatchMessage(&Msg);            }        Engine.OnCycle();        }.../* Cleanup etc */...}


Messages are then handled as follows (using windowsx.h crackers)


void OnDestroy(HWND Hw)
{
PostQuitMessage(0);
}

void OnKey(HWND Hw,UINT Code,bool Down,int Repeat,UINT Flags)
{
Key=Down;
}

LRESULT CALLBACK WndProc(HWND Hw,UINT Msg,WPARAM wParam,LPARAM lParam)
{
switch(Msg)
{
HANDLE_MSG(Hw,WM_DESTROY,OnDestroy);

HANDLE_MSG(Hw,WM_KEYDOWN,OnKey);
HANDLE_MSG(Hw,WM_KEYUP,OnKey);

default: return DefWindowProc(Hw,Msg,wParam,lParam);
}

return 0;
}


As an aside, the 98 and XP machines run the game stupidly fast with DDFLIP_NOVSYNC but as you have all suggested I get the tearing effect when I do this. Also for some reason my gamma fade doesn't seem to work when I do this so I assume there must be a better solution. I tried upping the refresh rate on the XP machine yesterday (ducking under the desk as I did so in case it exploded) all the way to like 100 and something but didn't speed anything up.

Thanks for all your help so far though. At least I now know what is causing the problem.
Fraps reckons 60 fps when the monitor refresh is 60 (predictabley) and 75 fps when I put the monitor up to 120. Still running slower than on my 98 machine.

I fully understand what the problem is now but still don't get how commercial games get around this problem. Or is it just that this XP machine is rubbish for games?
Sorry - being a bit thick. Just tried upping the animation rate and moving the sprites faster and looks lovely with hardware on and locking to vsync.

Obviously need to have a total rewrite to time-based animation and movement like you all suggested.

Guess I need to look into millisecond timers. Anybody got a good place to start?

Here are some links which I found helpful when implementing time based movement:

High Resolution Timing In Games

Achieving Frame Rate Independent Game Movement

Timing and FPS

mcp
Cheers. They were really helpful.

Big thanks to everyone that has helped me through this issue. Gamedev rocks.

This topic is closed to new replies.

Advertisement