How to smooth out dropped frames?

BlitzMax Forums/BlitzMax Programming/How to smooth out dropped frames?

Grey Alien(Posted 2007) [#1]
Hiya, check out this code sample

Strict

SetGraphicsDriver D3D7Max2DDriver()
'SetGraphicsDriver GLMax2DDriver() 

Graphics 800,600,0

Local x# = 0
Local TimingMethod = 1
Local width = 200
Local height = 200
Local FPS# = 85 'target FPS
Local MSPerFrame# = 1000.0/FPS
Local Delta# = 0

'grab an image of a rectangle with a one pixel border for anti-aliasing
Cls
DrawRect 1,1,width-2,height-2
Local Image:TImage = CreateImage(width,height,1)
GrabImage image,0,0

Local LastTime = MilliSecs()

While Not KeyHit(Key_ESCAPE)
	Local now = MilliSecs()	
	Local Elapsed# = now-LastTime
	LastTime = now

	'logic
	Select TimingMethod 
		Case 0
			x:+1 'fixed amount each frame
		Case 1
			Delta# = Elapsed/MSPerFrame
			x:+Delta			
	End Select	
	If x>= 800 Then x:-(800+width)

	'draw
	Cls
	DrawText Delta,0,0
	Print Elapsed
	SetBlend AlphaBlend
	'Note: Rectangles are drawn at integer coords so look jerky with Timing Method 1
	DrawRect x,50,width,height
	'Note: Image is drawn at a floating point coord and anti-aliased with Timing Method 1
	DrawImage image,x,350
	Flip 1
Wend


Basically TimingMethod=0 will move one pixel per frame, so it's pretty smooth but will be a different speed on different PCs (depending on Desktop Hz). TimingMethod=1 will move by a delta amount each frame based on elapsed time, so will be the same speed on all PCs.

Note that the top rectangle is only drawn at integer coords with DrawRect by the graphics card so will look a bit jerky with TimingMethod=1, whereas the bottom rectangle (uses DrawImage) will look smoother due to Anti-Aliasing on the edges of the rectangle. Anyway, that's not the point of this post, I just thought I'd mention it so as not to send you on a red herring (lol, I mean wild goose chase).

Here's the thing: both skip/jerk a little bit occasionally, but it looks worse on the delta time version.

When I look at the output window in the IDE I can see where the jerks occur because the normal values (millsecs between each frame) are around 11,12,13 and when a skip occurs it goes up to 21 or 22 for one frame then 0 or 1 for the next frame.

This means that a frame doesn't get drawn when you expect to see it, so the old frame remains on-screen for longer. Then the new frame is flipped onto the screen.

With TimingMethod=0 this simply results in a time loss as the delay is never "caught up". However, with TimingMethod=1 the delta time makes the shape jump ahead a bit to catch up for the loss, and then worse, because it thinks the next frame took no time at all, it doesn't move it on much - a double whammy of crap compensation.

So, if I can't get to the bottom of why these delays occur (must be windows/other apps doing a load of background stuff) my challenge is to smoothly compensate/interpolate when these glitches (and possibly bigger glitches occur). Perhaps I could say, OK don't catch up that loss in one frame, do it over several frames. Also if a frame takes lower than expected, it could subtract that from the "pool" of time to catch up. Sound sensible?

Any ideas? Thanks, this is driving me nuts!


Grey Alien(Posted 2007) [#2]
Also this behaviour is often worse just after the app runs until it "settles down". Why would frames drop so much at the start? I could understand the first frame being delayed in some cases as images are moved into VRAM but not after that, but maybe BMax or Windows are still doing a bit of disk thrashing or clean up I guess.

See look at these numbers:


See how it's chronic then smooths out?


ImaginaryHuman(Posted 2007) [#3]
Note that the graphics card does not necessarily `do` all of the drawing commands you've given it, right away. They are cached. You could try a glFinish() before you flip to see if that helps.

Maybe the driver also has something to do with why there is a delay in flipping the display. There might be some o/s task that takes up some time causing the delay too, who knows.

I would also think you would want to correct any jumping anomaly as soon as possible, not causing a slowdown delay over several frames.


Grey Alien(Posted 2007) [#4]
glFinish()[quote]Thanks, wonder what the DX version is...

[quote]I would also think you would want to correct any jumping anomaly as soon as possible, not causing a slowdown delay over several frames.
The jumping anomaly looks unnatural, so I think it would be better to smooth it out over a few frames.


TartanTangerine (was Indiepath)(Posted 2007) [#5]
Your MSPerFrame is inaccurate, this will cause under and over compensation from time to time. Also printing to the IDE will cause unpredictible slowdowns.

Change the code to
Local FPS# = 85.0 'target FPS - Note how we are using a floating point number and not an Int
Local MSPerFrame# = 1000.0/FPS ' - Again a float, not an Int



Grey Alien(Posted 2007) [#6]
Indiepath, well spotted, thanks. Yes removing the print seems to smooth it out on mine. I added the print as it looked a bit rough originally, but that was due to the dodgy MSPerFRame probably. Bit like quantum physics this, when I examine it (with Print) I change it (i.e. it becomes worse)! Anyway, I'm still considering adding in some compensation code and testing it (with print) and then taking print out and giving it to some users who experience jerky movement/scrolling to test.