Seriously, why all the jitters and flashes?

Blitz3D Forums/Blitz3D Programming/Seriously, why all the jitters and flashes?

Orgull(Posted 2005) [#1]
Hi there.

I've already made two topics that discuss jitters but now I've clearly identified the problem. Please note that this problem does NOT occur with my DBPro programs, so it's not a display setup issue. It is also NOT a timing issue, I've used fixed framerates from 15-120 in DBPro and DBC and I've never ever had this problem.


If I use frame limiting (various techniques) on my 2D or 3D programs in BB3D, and if I use any fps setting other than 60fps, my screen "jitters" and occasionally "flashes" black. Why?


My display is set to "application preference" for vsync. I get flashes whether I use flip true or flip false or any of the other combinations. This is not a "tearing" issue, I know what tearing looks like and this is not it.

Here, please try this simple code...
Graphics 1024,768,32,0

SetBuffer BackBuffer()

SeedRnd MilliSecs()

While Not KeyHit(1)

count# = MilliSecs()
.pattern1
Color Rnd(0,255),Rnd(0,255),Rnd(0,255)
Plot Rnd(0,1023),Rnd(0,767)
If MilliSecs()-count# < 1000/60 Then Goto pattern1

Flip True 

Wend

This code runs nice and smooth with no jitters as long as debug mode is turned off.

If you change the 60 value in "If MilliSecs()-count# < 1000/60" to anything significantly less than 60... try 50, 40 or 30, please tell me if you get the same jitters and flashes that I do?

And I will say in advance that this is NOT a timing issue... similar code run in DBPro is rock steady regardless of what fps it's set at.

In fact here's my DBpro code:
Set Display mode 1024,768,32
sync on

do

count# = timer()
pattern1:
color=rgb(Rnd(255),Rnd(255),Rnd(255))
ink color,0
Dot Rnd(1023),Rnd(767)
If timer()-count# < 1000/60 Then Goto pattern1

sync

loop

Help? Thanks.

P.S. Just made another confirmation... the above code (BB3D) is rock steady at any fps value if I run in windowed mode but not if I run in fullscreen mode. What the heck? And it's MANY times faster in windowed mode too compared to fullscreen... seriously what the heck?


GfK(Posted 2005) [#2]
This is almost certainly a double-buffering issue (altho I don't get it on my system).

If you run in debug mode (or any windowed mode), Blitz uses pseudo double-buffering (faked). There are some systems which this doesn't work very well on.

Turn debug mode on and force fullscreen mode with your graphics command (Graphics 1024,768,32,1).


Orgull(Posted 2005) [#3]
Gfk said: "Turn debug mode on and force fullscreen mode with your graphics command (Graphics 1024,768,32,1). "

Tried it.

Jitters even worse than before now, again with any frame setting lower than 60.

And I agree that this is a double buffering issue... just wish I knew what to do about it.


Oddball(Posted 2005) [#4]
The flickering is due to the back buffer and front buffers having different images upon them. Basically you are drawing some pixels to one buffer, flipping the buffers, then drawing pixels to a different buffer. This creates two images that are not identical and hence appears to 'jitter'. The following code should do what you are trying to achieve without the jitters.



Ideally this code should just draw straight to the front buffer, but I was just illustrating a point.


Orgull(Posted 2005) [#5]
HOLY MACKINAW! Oddball that code works... but there's no flip?

Wait... I think I'm getting something here... the front buffer is what's showing on the screen right? Even if I never use flip, the video card, when it comes time to refresh, grabs whatever's in the front buffer and slaps it on the screen, am I right?

This might explain the problems I'm having in 3D with fullscreen as well...


VIP3R(Posted 2005) [#6]
There's not much point in doing that Oddball, you may as well just draw straight to the frontbuffer.

[edit] Oh, you just pointed that out - sorry I missed it ;)

Graphics 1024,768,32,0

SetBuffer FrontBuffer()

SeedRnd MilliSecs()

While Not KeyHit(1)

Color Rnd(0,255),Rnd(0,255),Rnd(0,255)
Plot Rnd(0,1023),Rnd(0,767)

Wend

It will run much faster too ;)


Orgull(Posted 2005) [#7]
Yikes VIP3R, your code works too... even when I insert my timing code and slow it down to 30 or even 5 it's stable with no jitters!

Ok so double buffering IS the issue. Now to figure out a way to fix the problem in 3D as well.

Thanks all!


Oddball(Posted 2005) [#8]
Sorry Vip3r caught you out with my little edit.

Just to clarify a little more Orgull. When you use the flip command what ever was on the frontbuffer is now on the back buffer and whatever was on the backbuffer is now on the frontbuffer. It merely flips the contents of the two buffers.


Orgull(Posted 2005) [#9]
oooh... see that's where I was going wrong...

I saw flip as putting the backbuffer into the frontbuffer and then the backbuffer staying put, sort of... so really if I'm not using cls between flips what I really need is a way to keep the backbuffer from getting overwritten by the front buffer....

hmm...

thanks again!

P.S. How did you get your code to ber green and in a cool box when mine was just blue and boring?


VIP3R(Posted 2005) [#10]
Btw Orgull, if you calculate the refresh rate of the monitor (you can do this) then your original code will work correctly.

All you would need to change is 1000/RefreshRate instead of 1000/60. I've got some refresh rate calculation code here if you need it.


Orgull(Posted 2005) [#11]
Yes please VIP3R, how can you determine your monitors refresh rate from within BB3D?


Ross C(Posted 2005) [#12]
I don't believe you can do that. One way i suppose though, is to measure the FPS with "flip true".

I've noticed something else also.

Your doing

1000/60

this will return an integer number, since both numbers in the calculation are integers.

1000/60.0


Will solve that problem :o)


wizzlefish(Posted 2005) [#13]
Strange...I don't notice any problem.


VIP3R(Posted 2005) [#14]
@RossC: Oh yes you can :)

This code works fine for me anyway...
Print GetRefreshRate()

WaitKey()

Function GetRefreshRate()

Accuracy=300

For count=1 To Accuracy

	Timer=MilliSecs()

	VWait

	Timer=MilliSecs()-Timer

	Rate#=Rate+1000/Float(Timer)

Next

Return Rate/Accuracy

End Function



Sledge(Posted 2005) [#15]

what I really need is a way to keep the backbuffer from getting overwritten by the front buffer



Make a new buffer and use that instead. eg...
WIDTH=800
HEIGHT=600

Graphics WIDTH,HEIGHT,0,1
screenBuffer=CreateImage(WIDTH,HEIGHT)

While Not KeyHit(1)
SetBuffer ImageBuffer(screenBuffer)
Color Rand(50,255),Rand(50,255),Rand(50,255)
Plot Rand(0,WIDTH-1),Rand(0,HEIGHT-1)

SetBuffer BackBuffer()
DrawBlock screenBuffer,0,0
Flip

Wend



sswift(Posted 2005) [#16]
I dunno what you're doing. :-)

When I draw my graphics, I clear the backbuffer then redraw the whole thing, then I flip.

When I flip, the backbuffer becomes the frontbuffer. The backbuffer() pointer now points to the buffer that used to be the front buffer. It is now the buffer I should write to.

I also do triple buffering as suggested above, but only because drawing to an offscreen image is much faster than drawing to the screen. If I am doing alpha blending and other blending operations in 2D I need this speed. I lose some speed overall because of the copy I have to do at the end, but because I can draw pixels many times more it makes up for it when I am doing lots of blending.

As for 3D, I can't see what you could be doing wrong there, unless you are doing 3D over a blank background, and do not have cameraclsmode set to clear the color and zbuffer. But if that were the case you'd have 50 copies of the cube onscreen and not just two flipping back and forth.

Unless you were flipping and not calling renderworld every time you flip. Then you would be flipping an older image back to the visible screen.

I didn't see anyhting in your 3D demo which looked like you were doing any of that though. It looked normal to me, other than the afterimages normally caused by low framerates and high contrast.


jfk EO-11110(Posted 2005) [#17]
Here's my 2c:

Not all machines work correctly with Flip or Vwait. While Flip may use a 50HZ interval, the true VSync Intervall of the monitor may be something diffrent, eg. 60Hz. So there will be an interferency, resulting in jittering motion and "cut off frames".

There is only one fool proof method, you need to measue Vwait, to see if it's working correctly. Something like:

vwait
t1=millisecs()
vwait
t2=millisecs()


vs=(t2-t1)

use_vsync=0
if vs>2
 ; vwait seems to work
 use_vsync=1
endif

...

; and inside the game loop:
if use_vsync=1
 vwait
 flip false ; use hardware-synchronized doublebuffering
else
 flip true ; use bruteforce 50 Hz doublebuffering
endif



Mark Tiffany(Posted 2005) [#18]
It's probably worth pointing out that you can't rely on the behaviour of backbuffers & frontbuffers on flip for different setups. That is, some graphics cards will swap buffers on a flip, others will copy from the back to front buffer (as you had expected).

You should *always* start from scratch every frame (i.e. Cls the backbuffer), or use triple-buffering and draw to your very own buffer as sswift suggested. That way you know exactly what's on screen on everyone's system.


Orgull(Posted 2005) [#19]
Agreed Mark, I think sswifts suggestion of writing to an image buffer might be best for my needs. That way I can be absolutely sure of what will be rendered during each frame.

Thanks again to everyone for all the great help!