Vertical tearing in Windowed Mode

BlitzMax Forums/BlitzMax Module Tweaks/Vertical tearing in Windowed Mode

Grey Alien(Posted 2006) [#1]
I was experiencing vertical tearing in (DirectX) Windowed Mode and Skidracer suggested setting the HZ of the windowed mode to be the same as the dekstop. Sounds logical, and it IS an improvement using Flip -1 (still bad on Flip 0 or Flip 1) BUT there is still at least one big tear that stays at the same place on the screen each time. [edit] Well, it stays in the same place for that run, but then moves for the next run. I guess this is because Graphics() is being called at a random point in the frame, it's not being synchronised with VWait or anything.

Other people have ran the test and confirmed that it happens on their machine.

It's fine in full-screen mode btw and also fine in BlitzPlus!

DesktopRefreshRate = GetDeviceCaps(GetDC(0),VREFRESH)

Graphics 1024,768,0,DesktopRefreshRate 
'Graphics 1024,768,32

While Not KeyHit(KEY_ESCAPE)
  Cls
   
  mx = MouseX()
  my = MouseY() 
  
  DrawRect mx,my,100,768
    
  Flip -1 'try changing this. 0 and 1 are no good on my PC, -1 is best
Wend
End



skidracer(Posted 2006) [#2]
Oops, just found a DDBLTFX_NOTEARING flag which I haven't seen before, seems to be being ignored but may fix it for others, will do some more testing and hopefully have a fix for this soon.


Grey Alien(Posted 2006) [#3]
This sound AMAZING, thanks skidracer! :-) fingers crossed...


Grey Alien(Posted 2006) [#4]
It occurs to me that the reason the tear remains constant whilst the game is running but is actually at a different height each time you run the game is because Graphics can be called at any point duing a single frame and so even though the refresh rate is the same as the desktop refresh rate, they are not started together (synchronised). If there were, i.e. graphics waited for a vwait before setting itself up, this might solve the problem.


Yan(Posted 2006) [#5]
@Skidracer - It appears that DDBLTFX_NOTEARING is ignored on W2k and XP. :o/
I found this article on the subject which may help some.


Grey Alien(Posted 2006) [#6]
bummer about that flag. What I don't get it BlitzPlus (DirectX1) has no tearing in windowed mode. Probably I guess the 3D cards have to draw differently using DirectX7, but of course I'm no expert on this for sure.


Grey Alien(Posted 2006) [#7]
Any progress on this or is the concensus to use a MaxGUI window instead?


Damien Sturdy(Posted 2006) [#8]
Is there no way at all in Max to calculate the current scanline?

[edit]

A BlitzMax version of this;

http://www.blitzbasic.com/b3ddocs/command.php?name=ScanLine&ref=2d_a-z


Grey Alien(Posted 2006) [#9]
No not afaik unless it's hidden in the modules.


Damien Sturdy(Posted 2006) [#10]
Heh, I just emailed you, but you saw this :-)

It's dissapointing if it doesn't exist.


skidracer(Posted 2006) [#11]
I don't see the problem with adding a blitzplus style vwait command to the dxgraphics driver (blitzplus vwait busy waits on directdraw's GetVerticalBlankStatus and then calls WaitForVerticalBlank).


Yan(Posted 2006) [#12]
Could Flip 1 (in windowed mode) do that?

It'll be more consistent with the way non-windowed graphic modes work, IMHO.

At the moment Flip 1 appears to just be the same as Flip 0 when windowed.


Grey Alien(Posted 2006) [#13]
Skidracer: Yeah a VWait command would be brilliant, so we'd do VWait then Flip 0 or what in windowed mode? It could also be useful in full-screen mode for some graphics cards that still seem to show tearing even if Flip 1 is used.

Also I guess I agree with Ian, as what is Flip 1 supposed to do in windowed mode anyway?


skidracer(Posted 2006) [#14]
I can't get blitzplus to pass the tearing test so not sure if it is that great an idea: (tears around scanline 30 on my display):

tried with vwait / flip 0 combinations also...
; blitzplus tearing test
Graphics 1024,768,0,2
While Not KeyHit(1)
	Cls
	Rect MouseX(),MouseY(),50,800
	Flip
Wend



Grey Alien(Posted 2006) [#15]
Skidracer: Your BlitzPlus code totally works on mine, whereas Max code doesn't that's why I raised the issue. Even if a fix only works on *more* machines (instead of *all*), it's better right?

Also a point about your code, is it ALWAYS at scanline 30? As normally tearing moves around on Max. At least it's constant, meaning something is working with the synchronising.

re: my max code, I've added this edit to the top post:
Well, it stays in the same place for that run, but then moves for the next run. I guess this is because Graphics() is being called at a random point in the frame, it's not being synchronised with VWait or anything
as in the Flips are running at the same speed as the refresh rate but not doing any Vwait at all, so they can occur anywhere within the frame (sorry if you already get this, just wanted to make it clear)

Note that without setting the Hz to match the desktop, the tearing is all over the place, which is to be expected if the Hz is 60 or whatever.


skidracer(Posted 2006) [#16]
if you want to do some testing try inserting:
			ddraw.WaitForVerticalBlank DDWAITVB_BLOCKBEGIN,0

before the call to PrimarySurface.Blt (somewhere around line 378 of dxgraphics.mod/d3d7graphics.bmx)


Yan(Posted 2006) [#17]
Running GA's example with VWait, gives pretty good results on my system (Flip 0/1). I can't see any tearing at all.


Robert Cummings(Posted 2006) [#18]
Flip 0 should tear, shouldn't it?


Yan(Posted 2006) [#19]
Yeah normally, but with the above mod, VWait is always enabled in windowed mode.

It's just for testing. :o)


Grey Alien(Posted 2006) [#20]
WOW, omg, it's lush and perfect and I love you (well let's forget that last bit). The example code at the top of the post has NO tearing with all states of Flip (-1, 0, 1) also my Game Framework demo "Attack of the Mutant Greys" is totally perfect in windowed mode now. Very good. I guess you just need to fiddle with the implementation before the next release so that flip 0 still tears due to no Vsync and Flip 1 uses this new code, and as for flip -1 ... ??? Or add a Vwait command to the keywords?

Great work, this is really looking good now! :-) But am I to understand that you (Skidracer) are still seeing tearing on your PC?


Grey Alien(Posted 2006) [#21]
I've also tried pasting

PrimaryDevice.ddraw.WaitForVerticalBlank DDWAITVB_BLOCKBEGIN,0


into my DirectX apps directly before the flip command in windowed mode and it works too. Is there any reason this wouldn't be safe Skidracer e.g. it comes before Device.EndScene() instead of after it? If no problem then I can wrap this and call it ccVWait() and stick it in my framework until a new version of BlitzMax comes out (assuming you'll incoporate this somehow instead of leaving it as an optional module tweak, yes?)


ImaginaryHuman(Posted 2006) [#22]
Is OpenGL affected in Window mode with any tearing?

It is my understanding that if you do Flip 0, you should expect to see tearing because it does not do any kind of software timing to synchronize with the vertical refresh, nor any kind of synchronization with the hardware refresh rate.

Then in Flip 1, you should not see any tearing whatsoever and it should be synchronized to the rate you specified. If the rate you specified is the same as the desktop rate, you definitely should see no tearing and each flip should automatically sense (or be already synchronized with) the vwait at all time and every time. However, if the rate you specify is different from the desktop hertz, and you Flip 1, should the Flip try to lock the flip event to be synchronized to the nearest verticle blank, or should it just go ahead and flip at the exact computed time that it thinks it needs to to be `evenly spaced time per frame`? If it waits, the framerate won't be maximimal, and might not even reach the requested rate, because it would be vwaiting too much? It would have to be either:

a) Open a window at the same hertz rate as the desktop and do a Flip 1 with no tearing and with vwait.

or

b) Open a window at some different hertz rate and do a Flip 0 and get tearing all over the place.

?????


Chris C(Posted 2006) [#23]
well I've tried a number of systems/cards with opengl and flip 1 and they seem to work fine...

maybe this is a directx problem be I dont see it in a number of systems, then again we may be lucky...


Grey Alien(Posted 2006) [#24]
Is OpenGL affected in Window mode with any tearing?
Yes, the code at the top of the post is, with Flip-1 on PCs but seems ok with Flip 1! However, if I set call Graphics with 0 as the Hz param (instead of DesktopRefreshRate) OpenGL is fine with Flip 1 AND -1 ! Obviously Flip 0 always gives tearing, which is to be expected.


Chris C(Posted 2006) [#25]
specifically what combination of hardware/ OS do you see this on? I curious


skidracer(Posted 2006) [#26]
This is a DX7/DirectDraw problem, run the code at the top on an XP PC and move the mouse left and right near the top of the window.

I would imaging GL on XP routes its windows refresh through the dx8/9 HAL driver which supports a much more sane present system for DC flipping.


Grey Alien(Posted 2006) [#27]
Skidracer: instead of making the module modification I made your code into a function (just so other people can use it easily) that I called before Flip in windowed mode. This fixed the vertical tearing on mine, but on some other PCs I've tested the vertical tearing reamins, but in the same place (quite high up) each time. Is this because there is a delay caused between my function call and the PrimarySurface.Blt line in dxgraphics.mod/d3d7graphics.bmx? i.e. it calls EndScene and does some stuff with an array. Is this enough to slow it so the tear is still visible at the same height each frame? Your thoughts on this are welcome. Plus are you going to implement this fully in the next version?


Grey Alien(Posted 2006) [#28]
An Update: When I made a function called VWait that did this:

PrimaryDevice.ddraw.WaitForVerticalBlank DDWAITVB_BLOCKBEGIN,0

and called it manually before each Flip, it did help, but often a single non-moving tear was visible on my PC and other PCs near the top of the screen.

However, if I add in
ddraw.WaitForVerticalBlank DDWAITVB_BLOCKBEGIN,0

before the call to PrimarySurface.Blt (somewhere around line 378 of dxgraphics.mod/d3d7graphics.bmx) as per Skidracer's suggestion, I see no tear anywhere at all on my PC. Haven't tried it on other PCs yet.

Conclusion: calling vwait before flip is not good enough because the other code in Flip() i.e.
Device.EndScene()
Local src[]=[0,0,width,height]
Local dest[]=[0,0,width,height]
ClientToScreen hwnd,dest
dest[2]:+dest[0]
dest[3]:+dest[1]

obviously takes too long and thus by the time the Blit occurs, the scanline has already moved onto the visible area of the screen.

Therefore I recommend that this be an official module modification made by BRL, at least for when Flip -1 or 1 is used in windowed mode (not for Flip 0).

If anyone else can test the module modification and report back how it looks on their PC, that would be great. Indiepath says it's fine on his.


TartanTangerine (was Indiepath)(Posted 2006) [#29]
My Flip Method looks like this :

	Method Flip(sync)
		Device.EndScene()
		If sync
'			Local res,dc 'quick lock to empty queue
'			res=BackBuffer.Lock(Null,ddsd,DDLOCK_READONLY|DDLOCK_WAIT,Null )
'			res=BackBuffer.Unlock(Null)
		EndIf
		If state&DX7FULLSCREEN
			PrimarySurface.Flip Null,flipflags
		Else
			Local src[]=[0,0,width,height]
			Local dest[]=[0,0,width,height]
			ClientToScreen hwnd,dest
			dest[2]:+dest[0]
			dest[3]:+dest[1]
			
			Local _ddbltfx:DDBLTFX = New DDBLTFX
			_ddbltfx.dwSize = SizeOf(DDBLTFX)
			_ddbltfx.dwDDFX = DDBLTFX_NOTEARING ' This is actually ignored on XP
			
			ddraw.WaitForVerticalBlank DDWAITVB_BLOCKBEGIN,0
			PrimarySurface.Blt dest,BackBuffer,src,DDBLT_WAIT|DDBLT_DDFX,_ddbltfx
		EndIf
		Device.BeginScene()
	End Method


BUT WaitForVerticalBlank ties the system up so I'd like to find another method


Yan(Posted 2006) [#30]
So you hate Flip 0 then... ;o)

Could that potentially wait for two vblanks before blitting on Win9x machines?


Grey Alien(Posted 2006) [#31]
maybe so, perhaps the flag should be removed if it does nothing.

Yeah Flip 0 stinks for 2d games, not so bad for 3D but I'm still not a fan.