Windowed VSync

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

natt
Posts: 76
Joined: Fri Oct 26, 2012 5:27 pm

Re: Windowed VSync

Post by natt »

koitsu wrote:...but QueryPerformanceCounter() will give you microsecond precision, despite slight bits of overhead (depends on what you're doing. So I'm still not convinced this is a problem. Here's some other information I found, which also contains code:
Good reads all around. Bizhawk actually has a timer throttle that uses a similar basic implementation; QueryPerformanceCounter() with Sleep() for long waits and Yield() for short waits. (I never looked at it until I read these articles, heh.) The CPU usage is quite high compared to D3D9 VSync throttle, and the particular implementation makes no attempt to synchronize anything to VBlank, but otherwise does well enough.

But perhaps I'm letting the original problem get away from me here... When does D3DPRESENT_INTERVAL_ONE not work right? And if the answer is "when crappy drivers!", then is there anything that can be guaranteed to work in such a situation? If all you have is GDI+, you can't guarantee any sort of timing because your paint commits have another dozen layers of sludge to go through before they get to hardware.
User avatar
James
Posts: 431
Joined: Sat Jan 22, 2005 8:51 am
Location: Chicago, IL
Contact:

Re: Windowed VSync

Post by James »

blargg wrote:Doesn't the OS allow you to have it blit the entire window on the next frame without any tearing?
Yes*. With DWM enabled (assuming Vista/7/8), that's the only behavior you'll get in windowed mode. In other words, you can generate 1000 frames per vsync interval, but DWM is only going to output the last completed frame.

* Mostly yes, at least. You're not guaranteed that the update will happen following the next vsync, as DWM can miss/skip frames (if, for example, dwm.exe scheduling is delayed).
get nemulator
http://nemulator.com
Zelex
Posts: 268
Joined: Fri Apr 29, 2011 9:44 pm

Re: Windowed VSync

Post by Zelex »

I've had no success with this in the past. I always get tearing. I've tried the GetRasterStatus and even many system specific hacks. Nothing was reliable, let alone reliable on other people's systems.
User avatar
mikejmoffitt
Posts: 1353
Joined: Sun May 27, 2012 8:43 pm

Re: Windowed VSync

Post by mikejmoffitt »

I have not pried into how it works, but in both Windowed and Fullscreen mode the Allegro library gives me no trouble with Vsync; my game runs at 60fps and I do not get tearing when scrolling. Allegro's Vsync does exactly what I would expect, and doesn't seem to eat a lot of CPU waiting for it either; the whole game as it stands now eats 30% of 1 of 8 cores.

I used this super-advanced function after flipping my buffer to the display:
Image
WedNESday
Posts: 1284
Joined: Thu Sep 15, 2005 9:23 am
Location: Berlin, Germany
Contact:

Re: Windowed VSync

Post by WedNESday »

mikejmoffitt if what you say is true/accurate, then windowed vsync is possible. However,

Code: Select all

Status = false;
timeBeginPeriod(1);

while (1)
{
	if (lpDD7->GetVerticalBlankStatus(&Status) != DD_OK)
		MessageBox(NULL, "GVBS FAIL", "", 0);
	if (Status == true)
		break;
	Sleep(1);
}

timeEndPeriod(1);

StretchBlt()......
Slows the application down to about 20 FPS when windowed which makes it difficult to see if VSYNC is actually working. But even if it did 20FPS is still unacceptable.
User avatar
James
Posts: 431
Joined: Sat Jan 22, 2005 8:51 am
Location: Chicago, IL
Contact:

Re: Windowed VSync

Post by James »

Remove the sleep statement. At 60Hz, the vertical blanking interval is only going to be about 1.4ms long. Your app is not guaranteed to be rescheduled in exactly 1ms, so it's possible that you're sleeping right past the vertical blanking period.
get nemulator
http://nemulator.com
WedNESday
Posts: 1284
Joined: Thu Sep 15, 2005 9:23 am
Location: Berlin, Germany
Contact:

Re: Windowed VSync

Post by WedNESday »

Did that and the speed fluctuates quite a lot. Plus it was hard to see if there was vsync but I think it did have it. But of course we had 100% CPU usage on 1 core.

Edit: Speed fluctuates so much it negates whether we even have vsync or not. Anyone know how allegro manages it?

Edit: Just had another thought. Basically Sleep() isn't accurate enough, only the CPU is, so what if we did the following;

1. Use any function DDraw/Allegro/Whatever to wait for a vblank.
2. Start a timer that runs alongside the CPU. Let's say that the CPU has 1000000 cycles per frame.
3. When the timer hits 1000000 cycles Blt and reset the timer.

Code: Select all

while (1)
{
	Timer = 0;
	Blt();
	ProcessFrame();
	Sleep(1) <-- Sleep where possible until another Sleep(1) would make Timer go above 1000000
	// lets say that for example 99000/1000000 cycles have now passed
	temp = 0;
	while (temp < 1000)
		temp++; // lets just say we know that this will kill the other 1000 off
}
This of course assumes that the CPU and the GPU run at precisely the same frame.
natt
Posts: 76
Joined: Fri Oct 26, 2012 5:27 pm

Re: Windowed VSync

Post by natt »

As far as I know, Allegro 5.0 only has D3D and OGL backends for windows; no GDI or DDraw stuff. It's probably just using the builtin D3D Present() mechanism for vsync. For OGL? Possibly one of the swapinterval extensions, or just hoping that the drivers enable OGL vsync by default.
User avatar
rainwarrior
Posts: 8731
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Windowed VSync

Post by rainwarrior »

WedNESday wrote:mikejmoffitt if what you say is true/accurate, then windowed vsync is possible. However,

Code: Select all

Status = false;
timeBeginPeriod(1);

while (1)
{
	if (lpDD7->GetVerticalBlankStatus(&Status) != DD_OK)
		MessageBox(NULL, "GVBS FAIL", "", 0);
	if (Status == true)
		break;
	Sleep(1);
}

timeEndPeriod(1);

StretchBlt()......
Slows the application down to about 20 FPS when windowed which makes it difficult to see if VSYNC is actually working. But even if it did 20FPS is still unacceptable.
A busy wait loop like that is not the way to do things in windows. Other programs will need to run, so even without the sleep() your application will lose time slices randomly. It will also drive up CPU/power usage entirely unnecessarily. There is a function called WaitForVerticalBlank which is designed for exactly this that should be used instead, if you really do want to wait for the hardware vblank. However, Present() is designed to wait for vsync and put the image on the screen with a timing the OS thinks is appropriate, which is more robust than trying to wait on vblank yourself. At your program's level there is no reliable way to vsync a windowed app; if it can be done, it is the OS's job.
Last edited by rainwarrior on Mon Dec 17, 2012 9:36 am, edited 1 time in total.
User avatar
rainwarrior
Posts: 8731
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Windowed VSync

Post by rainwarrior »

mikejmoffitt wrote:I have not pried into how it works, but in both Windowed and Fullscreen mode the Allegro library gives me no trouble with Vsync; my game runs at 60fps and I do not get tearing when scrolling. Allegro's Vsync does exactly what I would expect, and doesn't seem to eat a lot of CPU waiting for it either; the whole game as it stands now eats 30% of 1 of 8 cores.
I suspect that getting no tearing in windowed mode is really just a matter of luck with how it happens to be timed on your specific hardware setup. I don't believe there's a secret way to trick Windows into vsynching while windowed. Use the standard API for flipping your double buffer, and let the OS do vsync it if it can. Allegro just uses the standard D3D Present() method for vsynching, and this is what you should normally do.
User avatar
mikejmoffitt
Posts: 1353
Joined: Sun May 27, 2012 8:43 pm

Re: Windowed VSync

Post by mikejmoffitt »

rainwarrior wrote:
mikejmoffitt wrote:I have not pried into how it works, but in both Windowed and Fullscreen mode the Allegro library gives me no trouble with Vsync; my game runs at 60fps and I do not get tearing when scrolling. Allegro's Vsync does exactly what I would expect, and doesn't seem to eat a lot of CPU waiting for it either; the whole game as it stands now eats 30% of 1 of 8 cores.
I suspect that getting no tearing in windowed mode is really just a matter of luck with how it happens to be timed on your specific hardware setup. I don't believe there's a secret way to trick Windows into vsynching while windowed. Use the standard API for flipping your double buffer, and let the OS do vsync it if it can. Allegro just uses the standard D3D Present() method for vsynching, and this is what you should normally do.
Of note is that I do not think my hardware (and a lot of modern hardware) does a very good job of reporting Vsync... If I maximize the window to 1920x1200, I get tearing about 32px off the bottom of the screen, but it's consistently in the same spot, not the usual psuedo-random tearing position you would expect. In full-screen mode, there is no tearing.

Fun Fact II Turbo: A few quickie things I've made in Multimedia Fusion 2 with hardware acceleration enabled, whilst maximized but NOT in fullscreen mode do not tear whatsoever. How this was achieved I do not know, but it is interesting to observe.
User avatar
rainwarrior
Posts: 8731
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Windowed VSync

Post by rainwarrior »

blargg wrote:Doesn't the OS allow you to have it blit the entire window on the next frame without any tearing? It seems like very commonly-needed functionality, for anything showing any kind of video. At least on OS X (even back at 10.3, maybe earlier), this was automatic; once you were done with all the window drawing, I believe you just called a function to tell the OS to update it, and it would all occur on the next frame without any visual glitching or half-drawn things appearing.
I don't believe that the core Windows API ever had a way to do this directly (the core API was built around a single-buffered model). However, nowadays (as stated several times before) Direct3D has the Present() API which definitely knows about double buffering, and could potentially do this for the user. It probably can do this for the user in the right situations, but it doesn't in all situations.

The bottom line, I think, is that outside of Fullscreen mode, the ability to vsync is not directly under the program's control. The user's display drivers and the specifics of how they're configured are what really determines whether or not a double buffered Present() will act in a way that prevents tearing. You can try to hack a "windowed vsync" solution in software that seems to work on your system, but ultimately it's not going to work everywhere.

Also, newer APIs from Microsoft, like WPF, tend to just use D3D/Present() under the hood. It really is the way they expect you to do double buffering.

(Edit: sorry if I'm a broken record here.)
Drag
Posts: 1615
Joined: Mon Sep 27, 2004 2:57 pm
Contact:

Re: Windowed VSync

Post by Drag »

blargg wrote:Doesn't the OS allow you to have it blit the entire window on the next frame without any tearing? It seems like very commonly-needed functionality, for anything showing any kind of video. At least on OS X (even back at 10.3, maybe earlier), this was automatic; once you were done with all the window drawing, I believe you just called a function to tell the OS to update it, and it would all occur on the next frame without any visual glitching or half-drawn things appearing.
I believe Windows does this, starting with Vista. When I upgraded to 7, I left Aero turned on, and all of the emulators I use just automatically stopped tearing without me needing to do anything. So, the problem of vsyncing is probably going to disappear with time.
User avatar
Kasumi
Posts: 1293
Joined: Wed Apr 02, 2008 2:09 pm

Re: Windowed VSync

Post by Kasumi »

Indeed, I noticed tearing disappearing when switching to Aero on Vista. Which is a shame, because I like the classic theme :(.
natt
Posts: 76
Joined: Fri Oct 26, 2012 5:27 pm

Re: Windowed VSync

Post by natt »

Get better video drivers I guess? Windows 7 here, classic theme, nvidia card, and zero glitching or tearing on D3D with present interval one, even with a maximized window.
Post Reply