Jump to content
  • Advertisement
Sign in to follow this  
Source

Arg! Vsync is killing me!

This topic is 4398 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi all. My engine currently runs at a smooth 350 FPS. In fullscreen, I get perfectly smooth scrolling with vsync enabled. However, as soon as I switch to windowed mode, for some reason every second or so the Present() function takes up to 20 ms to complete, resulting in a really annoying jolt. Any ideas as how to combat this? The refresh rates are the same in windowed + fullscreen and the time is being taken up by the present function, not by my game code. Please help me!

Share this post


Link to post
Share on other sites
Advertisement
Direct3D and the drivers are only allowed to (and within reason, capable of) getting so far ahead of the application. I think its defined to be 1.5 - 3 frames, but the evidence I've seen seems to be a bit more arbitrary.

Once the hardware gets too far ahead the Present() call will busy-wait/block until the application/hardware are back in sync. Thus your 20ms wait.

Or, as far as I can tell that is the likely reason.

As soon as you drop VSYNC then you can quite easily end up with erratic behaviour - tearing being the other classic problem. If you must, allow an option to disable it, but by default production/retail code should leave it switched on.

hth
Jack

Share this post


Link to post
Share on other sites
Thanks for your reply.

When you say "getting ahead of the application", what exactly do you mean?

At the moment, I:

* Perform mechanics (and dynamics synched to time since last update).

* Present() previous frame

* render new frame

Is there something I can do to fix this problem, or does it require a totally different engine layout?

Also, any idea why it works so well in fullscreen with the same refresh rate?

Thanks for your time =)

Share this post


Link to post
Share on other sites
Quote:
Original post by Source
When you say "getting ahead of the application", what exactly do you mean?
Direct3D has a command queue - when you issue various Set**() and Draw**() commands they aren't necessarily completed immediately, just added to the queue. Thus with profiling it might seem like things are drawn extremely quickly!

The driver/GPU then works its way through the queue. Simply put, if the queue fills up the the CPU has to wait until the GPU finishes some work in order to free up some space to insert the next command.

For similar reasons a Lock() operation can block and not return immediately - the contents of the buffer you're locking might depend on resources that are modified further along in the queue; thus it has to stall the CPU until that resource modification is finished.

Quote:
Original post by Source
Also, any idea why it works so well in fullscreen with the same refresh rate?
Its difficult to say for definite, but chances are that the larger screen-area translates to more pixel work which slows things down a bit and means that the GPU doesn't manage to "run away" so quickly and the queue doesn't fill up...

hth
Jack

Share this post


Link to post
Share on other sites
Well the core issue seems to stem from the fact that if I run the loop without any actual graphics or mechanics processing, I still get the occasional very long present() time when vsyncing.

Is there a method for smoothing these out - i.e. should I be pausing the simulation for a certain time interval based on the frame time?

Thanks for your time.

Share this post


Link to post
Share on other sites
Hmm, well thats a bit odd. Maybe its something similar, but not exactly, what I suggested...

Quote:
Original post by Source
Is there a method for smoothing these out - i.e. should I be pausing the simulation for a certain time interval based on the frame time?
You could try forcing a pipeline flush at the start or end of every frame...

IDirect3DQuery9* pEventQuery = NULL;
m_pD3DDevice->CreateQuery(D3DQUERYTYPE_EVENT, &pEventQuery);

// Add an end marker to the command buffer queue.
pEventQuery->Issue(D3DISSUE_END);

// Empty the command buffer and wait until the GPU is idle.
while(S_FALSE == pEventQuery->GetData( NULL, 0, D3DGETDATA_FLUSH ))
;

... // API calls

// Add an end marker to the command buffer queue.
pEventQuery->Issue(D3DISSUE_END);

// Force the driver to execute the commands from the command buffer.
// Empty the command buffer and wait until the GPU is idle.
while(S_FALSE == pEventQuery->GetData( NULL, 0, D3DGETDATA_FLUSH ))
;


The key is D3DGETDATA_FLUSH - see queries for more info.

hth
Jack

Share this post


Link to post
Share on other sites
Thanks for going to all that effort JJ - but I'm afraid it worked as well as I suspected :( No change.

One possible clue: When I set the present interval to DEFAULT (it was previously ONE) then I only get half the 75hz frame-rate, even though my code is far faster than the refresh interval.

Is this a core DirectX problem - should I recode in OGL?

Could anyone try running a DX in 75hz/vsync/windowed with a timer on the present function to see if it stays constant?

Really at my wits end with this one...

Share this post


Link to post
Share on other sites
Quote:
Original post by Source
Well the core issue seems to stem from the fact that if I run the loop without any actual graphics or mechanics processing, I still get the occasional very long present() time when vsyncing.


Even if you don't do any rendering work, presenting the new frame will at least take the refresh time, that's how VSYNC work.

So the real question is : what is your framerate with VSYNC on. If the refresh rate = frame rate, then you're good you won't be able to be faster than that.

LeGreg

Share this post


Link to post
Share on other sites
It isn't the vsync time which is the problem, L Greg - it is fact that every once in a while, the vsync part takes almost double the time it should, even though the program should be hitting every one perfectly.

Share this post


Link to post
Share on other sites
I've had this problem before. In my case, every 1 second the application would exhibit a weird unexpected jolt. After stripping down the app to a bare minimum, I realized that the only thing that happens in my app every second was the timer I had set up for frame rate calculation. I killed that timer and the problem was gone!

Strangely, though, I'd sometimes enable the timer and nothing bad would happen. Even more strangely, when I enable the timer and I get that annoying jolt, the jolt would disappear once I run Windows Media Player!!!!!!!!!!!!

Was this helpful?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!