PDA

View Full Version : FPS limiting problem



fragle
01-03-2006, 08:01 PM
Hi,

sorry if it's not in the right subforum, but it didn't feel quite right to put this in the graphics section either.. newbie section maybe? Anyway... on to the problem :)

I've been pondering recently, but could find no decent solution - how does one release unused process time? I mean - what i want is to limit my game to.. say 30fps, but use less than 100% cpu when the pc is capable of 60fps (i want it using 50% cpu or whatever in that situation).. Tried vsync (i'm using nehe OpenGL basecode btw), to no difference, slowing down with sleep(0) shaved a couple percent only and slowing down with sleep(your_favourite_number_here) is just not pretty...
So, i'd like to ask - what am i to do? :shock: Feel free to ask for clarifications or bash for anything including my confusing writing style, but i'd really want to know a better solution than the currently implemented sleep(n) hack..

Thanks in advance! ;)

cairnswm
02-03-2006, 06:01 AM
One of the problems with Sleep is that it doesn;t seem to let the rest of the windows processes function properly.

For one of my projects that uses the Windows GDI I wrote my own delay function :


procedure Delay(millis: integer);
Var
I,J : Integer;
Begin
J := Millis div 10;
For I := 0 to J do
Begin
Sleep(10);
//CheckMessages;
Application.ProcessMessages;
End;
End;

I'm not sure it works so much better than what you want tbut for me it allowed the screen to refresh even while speeping (If for example the player clicked on the title bar and moved the screen).

tux
02-03-2006, 07:32 AM
remember that sleep() isnt very acuret

JSoftware
02-03-2006, 08:28 AM
if i needed fps limiting in my game i would alter my gameloop to look like this:



procedure gameloop(fps: integer);
var quit: boolean;
lr, dt,t: int64;
begin
quit := false;
t := gettickcount;
lr := 0;
while not quit do
begin
dt := gettickcount;
quit := gamelogic((dt-t)/1000);
if &#40;lr+1000/fps&#41;<dt then
begin
render&#40;&#41;;
lr &#58;= dt;
end;
t &#58;= dt;
end;
end;


Please keep in mind i haven't tested this :wink: The great thing about this code is that the gamelogic will still proceed to update will it's not rendering resulting in smoother gameplay

tpascal
02-03-2006, 03:27 PM
You have to use one or more "timers" (dont confuse with timers events).
The idea is you have to include in your game loop a way to know how much time has elapsed since the last game loop interection.

The amount time elapsed between interactions are normally in millisecs, you need to use either gettickcount() or QueryPerformanceFrequency() functions to get the amount millisecs elapsed since midnigth (or since windows started, i dont remember), you store that info when you do a procces and then use that value later for calc how much milisecs has elapsed since the last time you did the procces, that way you know if it is time to do the procces again or to skip it in this loop interaction.

If you want to execute somthing just 30 times per secs then you just do 1000/30 = 33.33 milisecs and then keep checking in your loop that your procces is executed only if the amount millisecs elapsed are =>33.

You can use severals timers for different things in your game, for example i use timers for my animated textures, for my animated sprites, for the movement player, etc. Normally for the rendering rutine i dont use timers so the scene is rendered as fast as the machine can (while the app has focus), it is just the scene which is updated i controled time.


good luck.

tp.

technomage
02-03-2006, 06:11 PM
The following Thread should give you a pointer for a constant FPS..

http://www.gamedev.org/yabbse/index.php?board=10;action=display;threadid=2817

Dean

fragle
02-03-2006, 07:23 PM
Thanks for all the answers, but i guess i was too vague on one part of the problem and too broad on another :oops: I have actually already hacked in frame limiting into nehe basecode, but along with frame limiting, i'd also like to limit cpu usage as well...
Hmm... let's try an example: the computer can play my game at 60fps, and for that it uses 100% cpu time. Now when i limit it to 30fps, i'd like it to use less cpu time as well (it still uses 100% currently). If i were to limit my game to 1fps, i want cpu usage for my game to be practically zero as well. The problem with the loop is that it runs constantly whenever the game is given cpu time. To lower cpu usage, one way is to slow down the loop somehow, and that's where sleep() steps in. It reduces cpu usage, because sleep() itself does not use any and at the same time does not allow the loop to run. But i really don't want to use sleep() for my job, and would like to know a more elegant solution to this situation.. And that's all there is to my question. Hope it makes sense now ;) Sorry for the earlier misunderstanding! :oops:

And... thanks again for all the previous and future answers! :)

JSoftware
02-03-2006, 07:43 PM
Ahh.. what you want would be a Thread. Eventually you could get a threaded timer to ease the implementation job.
The disadvantage of a thread is just that it might not be syncronized with your gamelogic.
Can't give you any pointers on implementation of those as i haven't managed to do it myself :wink:

Regards

Traveler
02-03-2006, 07:53 PM
Perhaps this C snippet might be of some use, as an alternative for sleep()


/*
DelaySecs&#40;2.314&#41;;
will suspend execution for 2.314 seconds.
*/
#include <windows.h>
void DelaySecs&#40;float secs&#41; &#123;
Unsigned long int t = GetTickCount&#40;&#41; + &#40;1000L*secs&#41;;
while&#40; GetTickCount&#40;&#41; < t &#41;


&#123; /* Wait !!!*/&#125;
&#125;

source (http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=8645&lngWId=3)

JSoftware
02-03-2006, 07:54 PM
That would still use a heckload of CPU instructions and thus use up the cpu

Huehnerschaender
02-03-2006, 09:10 PM
Why don't you just use a timer and set the interval to 1000/FPS. Then when interval occurs you do your stuff. This should not use other CPU time, since your app is only working in the interval of timer. And the timer interval can be set in runtime, too.

alexione
03-04-2006, 09:27 PM
Well, you can't do it perfectly correct, but here's an idea:

WaitingTime := 0;
while not quit do
begin
// blah, blah, rendering, etc...
CurrentFPS := CalculateCurrentFPS;
WaitingTime := WaitingTime + 1000 div (NeededFPS - CurrentFPS);
if (WaitingTime > 0) then
Sleep(WaitingTime)
end;

Hope this helps...

User137
04-04-2006, 08:59 AM
Indeed, good old TTimer might be the best bet. Setting Timer.Interval 20 would give nice and smooth 50 fps while cpu usage is very low depending on rendering time.

jdarling
04-04-2006, 01:54 PM
I don't know how many times I've posted this link, but its often enough that I have it memorized. Read the following article and read it carefully. You will learn everything you want to know and once its implemented you will find that you didn't need it in the frist place. Best practices say using a spinlock with threading when doing graphics. Basic idea is lock in draw, unlock in flip. Of course really you should use a double and make use of tripple buffering, but thats another story all together.

In fact when it comes to Threading everyone who is even thinking of it should read this.

http://www.pergolesi.demon.co.uk/prog/threads/ToC.html

- Jeremy