Jump to content
  • Advertisement
Sign in to follow this  
AndreTheGiant

FPS frustrations

This topic is 1025 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

I'm not new to game dev, but I've got annoying issue thats been bothering me for months. I'm really hoping someone has seen this before!
 
I've got a pretty simple 2d game written in C# / directX. I'm having a problem with my FPS tanking periodically, and I cannot figure out why. 
 
I have a simple architecture - each game loop I update once and render once. I have very fine-grained profiling code everywhere, so I know exactly how long everything takes.
 
Initially I had a very tight game loop. Update, Render, repeat. FPS averaged between 800 - 1000, and never dipped below 700. My profiling showed that the time was approximately equally split between updating and rendering. To simplify the discussion, lets round up and call it 1 millisecond for updating, and 1 millisecond for rendering, even though they're both actually faster.
 
Now, I realized this is killing the processor unnecessarily, so I decided to add a sleep() for a few milliseconds at the end of my Render() function. Although this gave the processor a much needed break, we all know this is not a great solution because sleep() is not guaranteed to wake up, and therefore can give inconsistant results.
 
Then I found out that enabling VSYNC was exactly what I was looking for. I removed my sleep() call, and turned on VSYNC. The VSYNC will basically give me a hardware "sleep" thats supposedly guaranteed to "wake up" just in time to render the scene, and therefore give me a very consistant 60 FPS. Because its based on the monitor refresh rate, it allows my Update() method to have some fluctuations. For example, if my update() takes 1 millisecond, then the VSYNC will "sleep" for 15 milliseconds (1 + 15 = 16 which is 60 FPS). But if for some reason my update() takes 7 milliseconds, then VSYNC should only sleep for 9 milliseconds, still giving me 60 FPS. In other words, as long as my update doesn't exceed 16 milliseconds ( minus whatever time it takes to actually render), then I should never really see anything less than 60 FPS. Make sense so far? Is this even correct?
 
Well what actually happens is my FPS stays at 60 FPS most of the time, but frequently (I'd say randomly every 5 to 30 seconds), the FPS slows down to 40ish for a few seconds, then goes back up to 60. During this time, the gameplay is choppy and its very unpleasent, especially for me the developer!
 
I dont understand how this can be happening. As I explained above, my update code and render code take about 1 millisecond each. Even during these slowdowns, the update code is STILL taking about 1 millisecond, so I know its not some kind of spike in game logic. I assume it must be the render code that is somehow spiking from 1 millisecond to over 16 milliseconds(so basically causing the VSYNC to sleep for 15 + 16 instead of just 15).  But I dont know what would cause this. Unfortunately there is no way that I know of to debug the render step, because there is basically one function you call (device.present() ) - which is essentially a black box that sends the commands to the graphics card. This is the function call that blocks and takes 15 (or 15+16) milliseconds to return. I dont know how to figure out why it takes 15+16 sometimes.
 
I dont know whats causing this. I know it does not have to do with the complexity of the scene, because I've done specific tests where I have 1000's of moving enemies on the screen, VS tests where there is basically nothing going on at all. The FPS slowdowns still happen every approximately 5-30 seconds regardless of what is happening in the game.
 
This game is way to simple, and my computer way too fast to ever see a single FPS drop below 60. Suggestions please!

 

Share this post


Link to post
Share on other sites
Advertisement

Assuming D3D9 (please confirm), are you doing vsync with D3DPRESENT_INTERVAL_DEFAULT or with D3DPRESENT_INTERVAL_ONE?  If the former, it will use a low-resolution timer for syncing, which may explain what you're seeing - if so, try switching to the latter and see what happens.

Share this post


Link to post
Share on other sites
Have you checked in your profiler to see if garbage collection is causing this?

In my past I've dabbled with xna which is c# and d3d9 based and this is an issue. You have to carefully plan your variables and scope to ensure that gc doesn't kick in when you don't want it to at unexpected times in the game loop...

Share this post


Link to post
Share on other sites

I'm very familiar with garbage collection in C# and I don't believe thats my issue. I've designed scopes specifically to minimize garbage collection, and besides, my profiler would show any GC time that occurs. 

It was a good suggestion though, one of the first things I thought of too.

 

Edit: 
I guess there is one place that I dont have visibility - the call to device.present(). This is the black box that takes all the time to wait for VSYNC + render. If garbage collection is happening within this timeframe, I'm not sure what that would look like. I suppose its possible that garbage collection is happening, and only happening during that function call, and also taking more than 16 milliseconds, and occurring for dozens / hundreds of frames in a row, but only while that function is being invoked and not ouside of the function... but really none of that makes any sense to me. And besides, I just dont have that much garbage to clean up. 

Edited by AndreTheGiant

Share this post


Link to post
Share on other sites

Doesn't "DEFAULT" mean vsync enabled and "ONE" is vsync disabled?

 

For D3D9:

 

D3DPRESENT_INTERVAL_DEFAULT means vsync is enabled but uses the default low-res system timer.

D3DPRESENT_INTERVAL_ONE means vsync is enabled but uses timeBeginPeriod for a higher res timer.

D3DPRESENT_INTERVAL_IMMEDIATE means vsync is disabled.

 

Source: https://msdn.microsoft.com/en-us/library/windows/desktop/bb172585%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396

 

For D3D10+ vsync interval is a parameter to the Present call.  I assume that the OP isn't using D3D10+ because he mentions "device.Present"; on 10+ Present is a method of the swap chain.

 

For D3D8- things get weird, but let's hope that the OP isn't on one of those versions.

Edited by mhagain

Share this post


Link to post
Share on other sites

Ok So I checked and I was in fact using PresentInterval.Default. I changed it to PresentInterval.One and tested it out for a while. Unfortunately the issue still happens, I don't see any difference. I guess that rules one thing out.

Share this post


Link to post
Share on other sites

I use a Sleep(0) in my projects, to give the scheduler time for other tasks if needed, I've never seen it affect the framerate negatively, but it makes my Windows more responsive so to speak: by doing it you allow Windows to allot time for other things.. If you don't do it, and your project runs a very fast loop you will hog CPU time..

Also, my engine is using a high res timer when not running in vsync, which skips the update() and render() parts if 1/60 seconds has not passed since last update, and Sleep(0) ensures that the "idle period" in my engine doesn't hog too much juice (since when not updating and rendering it will run in a very short loop (and very fast), checking for next time slot plus windows messages). This works very well for me!

 

Maybe you could try some of these things, and see if it helps or makes it worse?

 

https://msdn.microsoft.com/en-us/library/windows/desktop/ms686298%28v=vs.85%29.aspx

Edited by vinterberg

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.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!