Game runs choppy even with high frame rate

Started by
8 comments, last by DividedByZero 11 years, 9 months ago
[SOLVED~ I posted my insight on this below, plus some possible causes for stuttering in case someone has as similar problem]

Hi,[background=transparent] [/background]
[background=transparent]

[background=transparent]
[background=transparent]I'm coding a rhythm game and the game runs smoothly with uncapped fps. But when I try to cap it around 60 the game updates in little chunks, like hiccups, as if it was skipping frames or at a very low frame rate. The reason I need to cap frame rate is because in some computers I tested the fps varies a lot (from ~80 - ~250 fps) and those drops are noticeable and degrade response time. Since this is a rhythm game this is very important.[/background]
[background=transparent]This issue is driving me crazy. I've spent a a whole week already and still can't figure out the problem. I hope someone more experienced than me could shed some light on it. I'll try to put here all the hints I've tried along with the code for my game loop, so I apologize with this post gets too lengthy.[/background] [/background][/background]

[background=transparent]

[background=transparent][background=transparent]1st GameLoop:[/background]
[/background][/background]
[background=transparent][background=transparent]
const uint UPDATE_SKIP = 1000 / 60;
uint nextGameTick = SDL_GetTicks();[/background][/background]
while(isNotDone)
{
// only false when a QUIT event is generated!
if (processEvents())
{
if (SDL_GetTicks() > nextGameTick)
{
update(UPDATE_SKIP);
render();
nextGameTick += UPDATE_SKIP;
}
}
}
[/background][/background]
[background=transparent]

[background=transparent]
[background=transparent]2nd Game Loop:[/background]
[color=black][background=transparent] [/background][/background][/background][background=transparent][background=transparent][color=black][background=transparent]
const uint UPDATE_SKIP = 1000 / 60;
while (isNotDone)
{
LARGE_INTEGER startTime;
QueryPerformanceCounter(&startTime);[/background][/background][/background]
// process events will return false in case of a QUIT event processed
if (processEvents())
{
update(frameTime);
render();
}
LARGE_INTEGER endTime;
do {
QueryPerformanceCounter(&endTime);
frameTime = static_cast<uint>((endTime.QuadPart - startTime.QuadPart) * 1000.0 / frequency.QuadPart);
} while (frameTime < UPDATE_SKIP);
}
[/background][/background][/background]
[background=transparent]

[background=transparent]
[background=transparent][1] At first I thought is was a problem with timer resolution. I was using SDL_GetTicks, but even when I switched to QueryPerformanceCounter I saw no difference.[/background] [/background][/background]

[background=transparent]

[background=transparent][background=transparent][2] Then I thought it could be an rounding error in my position computation and since game updates are smaller in high FPS that would be less noticeable. Indeed there is an small error, but from my tests I realized that is not enough to produce the position jumps I'm getting. Also, another intriguing factor is that if I enable vsync I'll get smooth updates @60fps regardless frame cap code. So why not rely on vsync? Because some computers can force a disable on gfx card config.[/background] [/background][/background]

[background=transparent]

[background=transparent][background=transparent][3] I started printing the maximum and minimum frame time measured in 1sec span, in the hope that every a few frames one would take a long time and still not enough to drop my fps computation. With frame cap I get always min = 16ms and max = 18, and still, the game "does not moves like jagger".[/background] [/background][/background]

[background=transparent]

[background=transparent][background=transparent][4] My process priority is set to HIGH (Windows doesn't allow me to set REALTIME for some reason). As far as I know there is only one thread running along with the game (sound callback, which I really don't have access to it). I'm using Audiere. I then disabled Audiere by removing it from the project and still got the issue. Maybe there are some others threads running and one of them is taking too long to come back right in between when I measured frame times, I don't know. Is there a way to know which threads are attached to my process?[/background] [/background][/background]

[background=transparent]

[background=transparent][background=transparent][5] There are some dynamic data being created during game run. But It is a little bit hard to remove it to test. Maybe I'll have to harder this one.[/background]
[background=transparent]Well, as I told you I really don't know what to try next. What bugs me more is why at 60fps & vsync enabled I get smooth results and with 60fps no vsync I don't. Is there a way to implement software vsync???[/background] [/background][/background]

[background=transparent]

[background=transparent][background=transparent]Thanks in advance. I appreciate the ones that got this far and yet again I apologize for the long post.[/background] [/background] [/background]

Advertisement
Yup, V-sync solves that.
I believe the choppiness is due to the interference between your forced ("hard coded") 60 fps and the display's refresh rate, which is only 60 fps nominally, but actually it's not precisely 60 fps. So the solution is to enable V-sync instead of the "hard-coded" refresh rate.

I tried to solve that with different refresh rates (up to 300 fps), but there are always hiccups with the display without V-sync.

I don't know about software "V-sync". I was trying to implement one for days, but I couldn't make it work. There isn't any functions that do "wait until refresh is ready" or that queries when the refresh is ready.

What's wrong with V-sync? The input lag it introduces? It's a bit different topic, try to look into that, but as I recall, you don't have much control over that. The video card drivers queue more frames for some reason, so the actually displayed stuff is always 2-3 frames behind.

EDIT: I didn't notice this one:


[background=transparent]

[background=transparent][background=transparent]So why not rely on vsync? [/background][/background][/background]Because some computers can force a disable on gfx card config

That's the user's problem IMHO, not yours. It's her responsibility to change the setting of her driver, not yours. You can make a comment about this in the README/Help/Requirements file, I think that would be enough.

So just use v-sync (you can force enable/disable it in your software, if that's your problem. Maybe the ability to force it in the program depends on the driver or the video card, but I think it's doable)
I've seen the same (choppy with capped framerate/no vsync, smooth with vsync) and have basically come to the same conclusions - you're better off with vsync.

IMO forcing settings like this in driver control panels is quite evil. I can understand options such as adjusting texture quality for performance, but if an API exposes a setting then the driver should not override it. Ideal world, etc.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.


I believe the choppiness is due to the interference between your forced ("hard coded") 60 fps and the display's refresh rate


Thanks for replying to that. I agree with you about being user's responsibility to force that off. I'm also concerned that some Intel HD chipsets have a bug that fails to turn vsync on. My brother-in -law has one of those. I think I should put some more effort into this.

I get the hiccups by capping frame rate on software it doesn't matter if vsync is on or off. It can indeed be interference between vsync and my code, but it seems to be other problem too. I did a few more tests in the weekend and realized those hiccups are evenly spaced in time. With 30fps cap I get hiccups every ~2s, while at 60 I get every ~0.5s which is really annoying.

It just occurred to me. Can this be a thread yielding problem. I mean, maybe between my measured time and the update another thread would run making my time measure not right for that update. Next frame when it tries to compensate it would give a jump. If that is the case, how should I proceed, execute time query and update in a critical section, block interruptions if that is even allowed?

I'll try this a little harder, if I get some progress I'll let you know. Again, thanks for the insight, I really appreciate that.
Best Regards,

Hi,[background=transparent] [/background]
[background=transparent][background=transparent]
[background=transparent]I'm coding a rhythm game and the game runs smoothly with uncapped fps. But when I try to cap it around 60 the game updates in little chunks, like hiccups, as if it was skipping frames or at a very low frame rate. The reason I need to cap frame rate is because in some computers I tested the fps varies a lot (from ~80 - ~250 fps) and those drops are noticeable and degrade response time. Since this is a rhythm game this is very important.[/background]
[background=transparent]This issue is driving me crazy. I've spent a a whole week already and still can't figure out the problem. I hope someone more experienced than me could shed some light on it. I'll try to put here all the hints I've tried along with the code for my game loop, so I apologize with this post gets too lengthy.[/background] [/background][/background]

[background=transparent][background=transparent][background=transparent]1st GameLoop:[/background]
[/background][/background]
[background=transparent][background=transparent]
const uint UPDATE_SKIP = 1000 / 60;
uint nextGameTick = SDL_GetTicks();[/background][/background]
while(isNotDone)
{
// only false when a QUIT event is generated!
if (processEvents())
{
if (SDL_GetTicks() > nextGameTick)
{
update(UPDATE_SKIP);
render();
nextGameTick += UPDATE_SKIP;
}
}
}
[/background][/background]
[background=transparent][background=transparent]
[background=transparent]2nd Game Loop:[/background]
[color=black][background=transparent] [/background][/background][/background][background=transparent][background=transparent][color=black][background=transparent]
const uint UPDATE_SKIP = 1000 / 60;
while (isNotDone)
{
LARGE_INTEGER startTime;
QueryPerformanceCounter(&startTime);[/background][/background][/background]
// process events will return false in case of a QUIT event processed
if (processEvents())
{
update(frameTime);
render();
}
LARGE_INTEGER endTime;
do {
QueryPerformanceCounter(&endTime);
frameTime = static_cast<uint>((endTime.QuadPart - startTime.QuadPart) * 1000.0 / frequency.QuadPart);
} while (frameTime < UPDATE_SKIP);
}
[/background][/background][/background]
[background=transparent][background=transparent]
[background=transparent][1] At first I thought is was a problem with timer resolution. I was using SDL_GetTicks, but even when I switched to QueryPerformanceCounter I saw no difference.[/background] [/background][/background]

[background=transparent][background=transparent][background=transparent][2] Then I thought it could be an rounding error in my position computation and since game updates are smaller in high FPS that would be less noticeable. Indeed there is an small error, but from my tests I realized that is not enough to produce the position jumps I'm getting. Also, another intriguing factor is that if I enable vsync I'll get smooth updates @60fps regardless frame cap code. So why not rely on vsync? Because some computers can force a disable on gfx card config.[/background] [/background][/background]

[background=transparent][background=transparent][background=transparent][3] I started printing the maximum and minimum frame time measured in 1sec span, in the hope that every a few frames one would take a long time and still not enough to drop my fps computation. With frame cap I get always min = 16ms and max = 18, and still, the game "does not moves like jagger".[/background] [/background][/background]

[background=transparent][background=transparent][background=transparent][4] My process priority is set to HIGH (Windows doesn't allow me to set REALTIME for some reason). As far as I know there is only one thread running along with the game (sound callback, which I really don't have access to it). I'm using Audiere. I then disabled Audiere by removing it from the project and still got the issue. Maybe there are some others threads running and one of them is taking too long to come back right in between when I measured frame times, I don't know. Is there a way to know which threads are attached to my process?[/background] [/background][/background]

[background=transparent][background=transparent][background=transparent][5] There are some dynamic data being created during game run. But It is a little bit hard to remove it to test. Maybe I'll have to harder this one.[/background]
[background=transparent]Well, as I told you I really don't know what to try next. What bugs me more is why at 60fps & vsync enabled I get smooth results and with 60fps no vsync I don't. Is there a way to implement software vsync???[/background] [/background][/background]

[background=transparent][background=transparent][background=transparent]Thanks in advance. I appreciate the ones that got this far and yet again I apologize for the long post.[/background] [/background] [/background]


Try something like this instead



while(running) {
processMessages();
currentTime = getTimeFromOSSomehow();
while (currentTime > nextGameTick) {
update(timestep);
nextGameTick+=timestep;
}
render();
}

This should let the game render as fast as possible while doing updates at a fixed rate and most importantly, it will keep the game running at the correct speed even if the render framerate drops below X fps (and you can set the gamestate updates to run at 300 fps if you wish), you could quite easily take it a step further and pass nextGameTick - currentTime to the render function and have it extrapolate the rendered scene to get smooth animations (i think extrapolating works better for games like guitar hero as things are moving at a fixed predictable pace and interpolating adds some latency(+ requires you to store an old state))
[size="1"]I don't suffer from insanity, I'm enjoying every minute of it.
The voices in my head may not be real, but they have some good ideas!
I personally let the renderer run flat out and calculate the 'time since last frame' and then multiply this with your movement speed.

On a low spec system your scene might render at 100 FPS (for example) and another system might render at 200 FPS. But, the movent speed will be the same on any system. Think of old style games on the old 486 (if you were around then :) ). If you run these some of these on modern systems, they are un playable as they run uncontrollably fast (poor programming).

You will then only get legitimate choppiness if the video card is under extreme graphical load.

P.S. I have had exactly the same issue with frame locking. This is why I use the above method.
[color=#333333]
Well, after a lot of more tests I realized that the problem was either in the way I was measuring time, which I find really unlikely due to the fact that I've tested many timers, or something in the graphics card that was preventing it from rendering to screen, like it was skipping frames.[color=#333333]
I found the exact term for that and it made a lot easier to search for the solution after. It's called (macro/micro) stuttering. It can be caused by a whole variety of this, not related to your game (yay! the art of PC game programming).[color=#333333]
It could be due to an anti-virus running, instant message programs interference, multi-GPU sincronization (micro stuttering), laptop clock variety due to power consumption settings, intel processors can give errors due to "intel speed stepping" that changes cpu clock based on cpu usage (that would probably mess up with my QFC timer) http://www.intel.com/cd/channel/reseller/ASMO-NA/ENG/203838.htm, it could be a driver problem (nvidia as of today 07/12/12 has a driver bug that causes micro-stuttering in single GPU for GTX 6 card family): http://videocardz.com/33159/nvidia-v-sync-stuttering-caused-by-drivers-bug-fix-coming[color=#333333]
Well in my case I realized another particularity, as stated before that enabling vsync fixes the issue. What is probably happening is a tearing effect that gives the illusion of a frame skip, since the camera is fixed I don't see the "tear line", only notes scrolling weirdly. I can't really tell if a tearing is happening because it scrolls so fast, but I'm accepting it for now as vsync fixes the issue.[color=#333333]
I hope it helps someone out there struggling with this problem.
Yay, you found it! :)

But, this sounds like a placebo effect to me.

Does this stuttering happen on any 'off the shelf' game or just your app?

Bummer, back to the drawing board for you. :(

If you want I can share the timer I wrote with you (just to rule things out). As, I had exactly the same problem (but don't now after refactoring my timers).
I'm about to get my hands on a guitar hero and check that. I'd appreciate if you could share your time. Thanks.
Absolutely smile.png

#pragma once
class Timer
{
public:
Timer()
{
liCurrent.QuadPart=0;
liPrevious.QuadPart=0;
}
~Timer()
{
}
long double TimeSinceLastFrame()
{
QueryPerformanceFrequency(&liPerfFreq);
QueryPerformanceCounter(&liCurrent);
ddFrameTime=(liCurrent.QuadPart-liPrevious.QuadPart)/long double(liPerfFreq.QuadPart)*1000;
liPrevious.QuadPart=liCurrent.QuadPart;
return ddFrameTime;
}
private:
LARGE_INTEGER liCurrent;
LARGE_INTEGER liPrevious;
LARGE_INTEGER liPerfFreq;
LARGE_INTEGER liStart;
long double ddFrameTime;
};


Just call TimeSinceLastFrame() on each loop and multiply the result against your movable objects (multiplied by your movement speed).

eg

long double ddTSLF=cTimer->TimeSinceLastFrame()/1000; // Puts this into milliseconds
[pseudo] object1move(ddTSLF*55) // 55 is the objects speed
[pseudo] object2move(ddTSLF*100) // 100 is the objects speed

This topic is closed to new replies.

Advertisement