VWait not working?

Blitz3D Forums/Blitz3D Programming/VWait not working?

big10p(Posted 2005) [#1]
I'm trying to use "VWait : Flip False" to sync my app with the monitor refresh but I'm still getting tearing!? This is probably a problem at my end because I'm sure it used to work, but can you please run this small bit of code and let me know if you see tearing too:

	Graphics 800,600
	SetBuffer BackBuffer()

	While Not KeyHit(1)
		Cls
		
		Rect x,0,100,600,True
		x = x + 10
		If x > 800 Then x = 0
		
		VWait : Flip False
	Wend

	End


Any suggestions as to why it's not working for me would be appreciated. As I understand it, it can't be a GFX card issue as using VWait makes the CPU wait for the VBlank signal, unlike Flip True.


Naughty Alien(Posted 2005) [#2]
..smoth like silk here...


big10p(Posted 2005) [#3]
Oh, right - thanks. So, anybody know what might cause this to not work on my PC?


(tu) ENAY(Posted 2005) [#4]
> So, anybody know what might cause this to not work on my PC?

No. :)

INSERT COIN!


RFBcsa(Posted 2005) [#5]
Using False the top of the bar scrolls a little behind the rest of the bar. If I use True the bar moves 100% correctly.

I assume this has something to do with the vsync so it wouldn't worry me much. My settings have vsync turned off.


big10p(Posted 2005) [#6]
Using False the top of the bar scrolls a little behind the rest of the bar.
That's the 'tearing' I'm getting. It shouldn't be happening. What are your system specs, RFBcsa?

If I use True the bar moves 100% correctly.
So do I but I'm trying to find out why 'vwait:flip false' doesn't work anymore. :/


markcw(Posted 2005) [#7]
i get the same "tearing" its an optical illusion coz i tried print screening a few times and always the screen was fine.

but "flip" instead of "vwait:flip false" removed this "tearing".


KuRiX(Posted 2005) [#8]
The Vertical Sync Configuration can be overriden by the graphic driver.

Look in your driver settings that you have the vertical sync in the option: "controlled by application" or something like that...


markcw(Posted 2005) [#9]
have i missed something here?

i tried switching v-sync on my card on/off for ogl + d3d but it always has the "tearing"

if it helps, heres a screen of the panels that have a v-sync option:
edit: "picture woz 'ere"


big10p(Posted 2005) [#10]
i get the same "tearing" its an optical illusion coz i tried print screening a few times and always the screen was fine.
You can't take a screenshot of this effect because it's a mixture of two frames. :)

Fiddling with the vsync setting in my driver I can get rid of the tearing but the bars movement becomes really jerky. :/

Besides, I thought using 'vwait:flip false' isn't supposed to be affected by any driver settings - that's what the manual says and that's the reason I want to use it. I have no idea what's going on. :|


KuRiX(Posted 2005) [#11]
Have you tried full screen modes? perhaps you cannot override driver setting in window mode...


big10p(Posted 2005) [#12]
Yep, that demo code is in fullscreen (as long as debug is turned off). :)

I really can't understand what has happened as using this technique used to work great. I haven't upgraded my GFX driver or anything, either.


Hujiklo(Posted 2005) [#13]
What is your frame rate? Is it slow?..there can be a big leap in frame rate with synch off which can lead to a jerky frame rate with it switched on.


Shifty Geezer(Posted 2005) [#14]
Tearing on my machine too. GF4 Ti4200. Does this happen on other more complex programs? I haven't had a problem to date using Vwait : Flip False even though this example shows the problem. Maybethe fact it's running so fast makes for trouble????


big10p(Posted 2005) [#15]
Hujiklo: My monitor's frame rate is 60. This shouldn't be an issue though as VWait is simply meant to pause until a vertical blanking signal is received, regardless of monitor refresh rate.

Shifty: So you get the tearing but didn't used to, as well? I tried reverting back to an older version of blitz but the problem still exists. I just can't think why this isn't working anymore. I do still get this effect on larger programs but speed of loop execution shouldn't make any difference anyway. You can put a delay in the loop above and it still happens.


Shifty Geezer(Posted 2005) [#16]
I don't get tearing (that I've noticed) in my ODE program using VWait. If I put in a delay 10 command in your example tearing is much reduced, but there are jitters where Blitz isn't sync'd with the refresh. Prior to this I never used Blitz so couldn't say!


John Blackledge(Posted 2005) [#17]
Too weird! I'm also using a GF4 Ti4200, but NOT getting tearing.


big10p(Posted 2005) [#18]
Weird is right. :) I'm all out of ideas on this one.


jfk EO-11110(Posted 2005) [#19]
This whole sync thing is no longer an exact science. Some people told me Vsync didn't work on their machine. On my machine Flip doesn't wait anymore (flip true acts like flip false) but only after installing a new OS.

After all I came to the conclusion that it's best to measure the time that elapses, this should tell you if it works at all. When it's 50 Hz to say 120 Hz then there seens to be a working vsync. If the delay is almost zero, then you should try Flip true. If that is almost zero too then you're in troubles, but you still can use Millisecs to sync things "manually".


big10p(Posted 2005) [#20]
Well, as I said, my monitor is using a 60Hz refresh rate but it's not working - it used to, though. I can use Flip True to sync to the monitor refresh but this can be disabled in the driver so isn't a guaranteed method.

I can use a timer to guarantee 60FPS but this doesn't get around the problem of tearing. For scrolling etc., it looks horrible. :/

[edit] Thinking about it, vwait MUST BE working in a way - if it wasn't then the bar (in my demo) would move across the screen as quickly as possible. However, by the time the flip command is executed, the monitor has already started re-scanning the display. There seems to be some delay between the v-blank signal being received and the execution of Flip. Maybe the problem's with the Flip command, then?


big10p(Posted 2005) [#21]
OK, I just managed to get rid of the tearing...

I shut down all non-essential background tasks - virus scanner, firewall etc. - and the smooth scrolling returned!

So, it would seem the problem is other background tasks are grabbing the CPU right between the 'VWait' and the 'Flip False' commands. By the time the blitz app regains control, the v-blank signal has long past and the monitor has already started re-scanning.

I can't really think of a way to prevent this from happening, though. It would be nice to have a 'VFlip' command that combines the two and doesn't relinquish the CPU to other processes until it's fully executed.


jfk EO-11110(Posted 2005) [#22]
ha! Vertical Blank Interrupts! This sounds so very 68000ish. Remember the times when we altered the 10 Bit Palette in VBlank Interrupts only to get a few more than 16 Colors onscreen! Coding bloody asm interrupts for a hand full of colors.
Hmm - this kind of surprises me, wasn't it the way there ain't no proper VBlank Interrupts on x86 machines, because they need to be polled? Well maybe I'm wrong. But I remember the developer of the MenuetOS asked me(!) how to implement a VBlank Hardware Interrupt on the x86. Seems like it's not as easy as on a Atari ST...

oops, back on topic.

EDIT - uh, wait a minute, that palette interrupt used the horizontal blank interrupt. Color cycling used the vertical.


Trixx(Posted 2005) [#23]
You can simulate vwait using scanline().
Just a quick dirty example,put this instead of vwait:flip false :

Delay 5
Repeat: Until ScanLine()>=0 And ScanLine()<20 Or ScanLine()>600
Flip False

This removes tearing on my machine. If yours is much faster, try increasing delay value, or decreasing that "<20" . However, for perfect results on every machine, you should take into account time elapsed for the delay value, and also screen resolution.
Tell me if this removes tearing ...


big10p(Posted 2005) [#24]
Trixx: That does reduce the tearing considerably but not completely. Also, the bar still scrolls with frequent jerks. The problem is that other processes can take control of the CPU between the 'repeat:until' and 'flip false', thus we have the same problem as with 'vwait:flip false'.

TBH, I'm a bit confused as to why other processes can grab the CPU so much - I thought Blitz3D apps hogged 100% of CPU time, pretty much!?

BTW, you can actually dispense with the delay command by using the following method instead:
Repeat: Until ScanLine() > 600
Flip False
Repeat: Until ScanLine() < 600



Trixx(Posted 2005) [#25]
It is normal that other processes can "take control" anytime, because you can't reserve CPU just for yourself. And because of that, you should free some CPU time and power with Delay command, so other processes can finish their job. This way, it is less likely that they will interrupt you on "flip false".
As I said, for this to work perfect, you should calculate time for the next frame and use " delay timeRemaining" before "flip false".
Compare 'CPU usage' between my example and yours. If you use " Repeat: Until ScanLine() > 600 " , you are using 100% of the CPU, and then other processes will still fight for some CPU time immediately after that, i.e. just when you need to 'flip' . So, give them enough time to finish their job and everything should be fine.
Using "delay timeRemaining" B3D will use, let's say 20-40% of the CPU ( depends on system and your game of course ), and this practice is much better than standard 100% which we can see in majority of B3D games!


Sledge(Posted 2005) [#26]

So, it would seem the problem is other background tasks are grabbing the CPU right between the 'VWait' and the 'Flip False' commands...I can't really think of a way to prevent this from happening, though.



You could up the priority of the app'. Perturbatio wrote an app' launcher for me a few years ago to do this, perhaps he still has it (or the C source) knocking around. I'll have a look and see if I can find it.

EDIT: However, having just done some quick experimentation (because I get the same problem on my Ti4200), Trixx's Delay advice looks good.


Shifty Geezer(Posted 2005) [#27]
Which'll be why my addition of a Delay was helping earlier on. Nice info. Thanks.


big10p(Posted 2005) [#28]
OK, I see what you're getting at now, Trixx - I really shouldn't read posts when I've had a few beers. :)

Anyway, things are much improved if I use the following code, but still not perfect (occasional slight tearing and jerking):
	Graphics 800,600
	SetBuffer BackBuffer()

	While Not KeyHit(1)
		frame_start = MilliSecs()

		Cls
		Rect x,0,100,600,True
		x = x + 10
		If x > 800 Then x = 0
		
		frame_time = MilliSecs() - frame_start	

		If frame_time < 10 Then Delay (10 - frame_time)
		Repeat: Until (ScanLine()>=0 And ScanLine()<20) Or ScanLine()>600
		Flip False
	Wend

	End

However, I still don't understand the need for the scanline polling - that's essentially what VWait does anyway. If you change the repeat:until line in the above code with VWait, it works just as well.

Also, the way I'm calculating the delay is pretty rough-and-ready. Is there a better way?


Trixx(Posted 2005) [#29]
big10p, there are more than 600 scanlines in 800x600. I'm not sure about the exact number, but I think there are 624 of them and they are not all visible, i.e. let's say first 12 and last 12 are not really visible on your monitor.(I'm really not sure about these numbers) . VWait will wait until last scanline is 'drawn' on screen, but in this example you are 'flipping' a little bit earlier ( anywhere after 600'th line ) and this gives you better chance to flip on time than vwait.
Here is corrected version of your last example:
Graphics 800,600
	SetBuffer BackBuffer()
	
	Const TargetFPS=85 
	timePerFrame = 1000/TargetFPS
	
	While Not KeyHit(1)
		frame_start = MilliSecs()

		Cls
		Rect x,0,100,600,True
		x = x + 10
		If x > 800 Then x = 0
		
		usedTime  = MilliSecs() - frame_start
		remaining = timePerFrame - usedTime
		If remaining > 0 Then 
			Delay(remaining)
		End If
		Repeat: Until ScanLine()>=0 And ScanLine()<30 Or ScanLine()>600
		Flip False
	Wend
End

Also, I forgot to tell you why you need that " If Scanline()>=0 And ScanLine()<30) ... Take this example : On some slower machine, when logic+rendertime finish just 1ms later than it's needed to be on time , Scanline will already pass 624, and will be probably between 0-30. But, this is still not too late to flip, especially if top of the screen is static picture, like in my current project. If you use vwait, you would lose that frame, because vwait will wait for scanline to became 624 again, and you will end up with less FPS. On very slow machine, however, this won't help, but you can always experiment with these values, depending of your game. Obviously, this should go in combination with tweening. ( Delta time should be fine also ).


big10p(Posted 2005) [#30]
Trixx: I see what you're trying to do with the scanline polling but I don't think it makes much difference from using VWait, TBH - I still get a bit of tearing and jerking. Also, changing the FPS in the code you posted to 60 (which is what I want - my monitor refresh is 60Hz, too), the tearing and jerking is really bad.

I think I'm just going to have to come to some compromise and admit I'm not going to get rid of the tearing and jerking completely. Thanks for your input though - it's been interesting. :)


Grey Alien(Posted 2005) [#31]
Your original code is very smooth on mind BUT the occasional flicker occurs at the top of the bar.


Boulderdash(Posted 2005) [#32]
Thanks I tried using delay 1 until the right amount of time elapsed (16 millisecs) and things ran smoother, CPU usage showed 2 or 3% drop while still connected to internet.


Boulderdash(Posted 2005) [#33]
I tried this to keep my emulator at 60fps and it worked great! a small drop in CPU usage is a plus.Thanks for the tip!

timer#=MilliSecs()
f=timer#-oldtimer#
f=16-f
If f>0 Then Delay f
oldtimer#=timer#


jfk EO-11110(Posted 2005) [#34]
I didn't read the whole thread, so maybe it was already said: Whatever you do, you can never be sure wether Flip 1 or Vwait:Flip 0 will work on all machines. If you want your game as compatible as possibe, you need to determine how a machine handles them and then use a custom sync method (this is really a FAQ now).

First check how much time elapses between two vwaits. If it's near zero then it's likely vwait is not working as desired. So you should try to use Flip 1 instead. Test the time that elapses between 2 Flip 1 Calls. If this is near zero too, you need to use a special timing method, using millisecs, or scanline as it was mentioned before.

Basicly you need to replace all your FLIP Calls with something like MyFlip()

and a function MyFlip would look like this:

global FlipCounter ; is used to determine the current
;Frontbuffer (see tutorial section, hidden alerts)

global FlipMode ; this is set by the determination 
;described before, eg. 0 for vwait, 1 for flip true, 2 
;for millisecs solution.

global FlipTimer ; used for the millisecs solution
global FlipRate=17 ; used for millisecs solution
;...

function MyFlip(waitsync=1)
FlipCounter=FlipCounter xor 1
 if flipmode=0
  if waitsync<>0 then vwait
  flip 0
 endif
 if flipmode=1
  flip waitsync
 endif
 if flipmode=2
  if waitsync<>0
  while millisecs()< FlipTimer
   delay 1
  wend
  flip 0
  FlipTimer=millisecs()+FlipRate
  endif
 endif
end function

This may be not fully perfect of course. I only want to show you, you need to catch sync troubles and handle them individually.


big10p(Posted 2005) [#35]
jfk:

I've not heard of a machine where VWait doesn't work (i.e. pause until a vblank signal is received). Does this happen with TFT screens, or something?

Also, in your code above, why have you got the VWait after the Flip, and not before it?


VP(Posted 2005) [#36]
Certain gfx drivers will disable vsnc'ing as part of their neverending 'we get faster FPS than the competition' battle. /Rather, I should say they provide an option to disable vsync.

What is wrong with just plain old Flip? Does that really not work on all machines? I've never put the vwait in, unless I'm not using double buffering (rare).


big10p(Posted 2005) [#37]
Sure, you can turn off vsyncing on the GFX card, but VWait let's the CPU handle the signal, which I don't see how you could turn off or wouldn't work on ALL machines.

From the docs:
Note that this command is different to the vertical blank waiting mechanism in Flip because Flip will cause the graphics card (as opposed to the CPU) to wait for the next vertical blank. The vertical blank can be disabled on some graphics cards, hence it is quite common to use "VWait : Flip False" to ensure consistent updates on all setups.




VP(Posted 2005) [#38]
The CPU can only check what the gfx card, therefore the gfx driver, tells it.


big10p(Posted 2005) [#39]
I'm pretty sure the vertical blank is a non-maskable hardware signal that has nothing to do with the driver. Again, the docs seems to suggest this, too:
The vertical blank can be disabled on some graphics cards, hence it is quite common to use "VWait : Flip False" to ensure consistent updates on all setups.



jfk EO-11110(Posted 2005) [#40]
sorry, I ment vwait:flip 0, of course.

AFAIK unlike eg. the Atari ST that had a VBlank Hardware Interupt, in the X86 Architecture the CPU has to poll a Vsync Signal and then trigger an interrupt, Of course this can be turned off easily. Sometimes it's even hard not to miss the signal. Maybe this is diffrent on modern machines, but I think it really used to be this way.

The reason why someone would like to use Wvait:Flip 0 instead of Flip 1 is:
-Flip 1 is not synchronized with the Monitor Refresh rate, so Vwait will give a smoother gameplay.
-On some machines Flip 1 doesn't wait at all, but continues immediately, like Flip 0.

BTW I have never seen a machine that didn't support vwait, but some Blitz users told me about that.