Jump to content

  • Log In with Google      Sign In   
  • Create Account

Advice to lock frame rate


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
11 replies to this topic

#1 Hanksha   Members   -  Reputation: 200

Like
0Likes
Like

Posted 29 December 2013 - 07:26 PM

Hi!
 
I'm on a project of a 2D platform action game (it's my first "ambitious" project, I've just been able to finish mini game) code in C++ with SDL2.
 
I need some advice about how to lock the frame rate (by lock I understand that it's lock for frame rate to go higher but not lower). 
On my game the movement of the player is frame based, 6 pixel per frame (or 8 pixel when running), I've not been able to understand correctly the time based movement (At least to understand enough to write my own code), I thought to lock frame rate is my best solution. The game will not be graphically heavy so I guess it will not be a big deal since most of the computer could run it.
 
I've been able to write the following code:
 
- My game loop:

#define FRAMERATE 60

void CMain::GameLoop()
{
    while (windowEvent->GetMainEvent()->type != SDL_QUIT)
    {
    timerFps = SDL_GetTicks();


    windowEvent->Begin();


    SDL_GetMouseState(&MouseX, &MouseY);


    Player->Update();
    environment->Update();


    environment->DrawBack();
    environment->DrawFront();
    
    Player->Draw();

    windowEvent->End();
    
    timerFps = SDL_GetTicks() - timerFps;

        if(timerFps < 1000/FRAMERATE)
        {
            SDL_Delay((1000/FRAMERATE) - timerFps);
        }
    }
}

 Detail of functions used:

void CWindow_Event::Begin()
{
    SDL_PollEvent(mainEvent);
    SDL_RenderClear(renderer);
}

void CWindow_Event::End()
{
    SDL_RenderPresent(renderer);
}

When I check my frame rate with other tools, it indicates a fps around 65 (not steady), I notice on other 2D game (e.g Rogue Legacy or Spelunky) the frame rate is really stable 60.
So I guess there is something wrong in my code, and maybe it will look horrible for some of you. What should I change?
 
(ps: I have many question on other topic related to my project, should I open a topic for each or put everything in here?
pps: Sorry for my english, it's not my mother tongue.)



Sponsor:

#2 eduardo_costa   Members   -  Reputation: 329

Like
0Likes
Like

Posted 29 December 2013 - 08:07 PM

On any platform you could control the rate of update and render with this simple algorithm

 

float dt; //delta time in seconds

float clock; //last time sample in seconds

float render_timer; //time control for rendering

 

dt = 0.0;

render_timer = 0.0; //init the render timer

clock = getTime(); //API callback to get the current time in seconds

 

while(true) //game loop

{

   dt = getTime() - clock; //get the current delta time for this frame

   clock = getTime(); //updates the clock to check the next delta time

 

   update(); //update stuff;

 

   if(render_timer >= (1.0f/60.0f)) //checks if the frame is ready to render

   {

      render(); //render your stuff

      render_timer -= (1.0f/60.0f); //do not set to zero, remove the accumulated frame time to avoid skipping

   }

 

   render_time += dt; //updates the render timer

 

}



#3 Vortez   Crossbones+   -  Reputation: 2704

Like
0Likes
Like

Posted 29 December 2013 - 08:52 PM

I never understood why ppl would lock their framerate manually rather than letting vsync do it's job...



#4 ultramailman   Prime Members   -  Reputation: 1585

Like
2Likes
Like

Posted 29 December 2013 - 10:33 PM

On any platform you could control the rate of update and render with this simple algorithm

...

Can somebody explain why this is downvoted?



#5 Hanksha   Members   -  Reputation: 200

Like
0Likes
Like

Posted 30 December 2013 - 12:03 AM

On any platform you could control the rate of update and render with this simple algorithm
 

 

 

I think I'm doing pretty much the same:

#define FRAMERATE 60
int timererFps;

while (true)
    {
        timerFps = SDL_GetTicks(); // SDL_GetTicks() gives the number of milliseconds since the program start.
                                   // I initialize the timer.

        update(); //update stuff...

        timerFps = SDL_GetTicks() - timerFps; //I get the time it took to update and draw;

        if(timerFps < 1000/FRAMERATE) // if timerFps is < 16.6666...7 ms (meaning it loaded the frame too fast)
        {
            SDL_Delay((1000/FRAMERATE) - timerFps); //delay the frame to be in time
        } 
        render(); // render stuff...
    }

Am I not correct?

 

ps: I just noticed I was rendering before to delay, I correct it, now I'm around 58fps.

 

 

 

 

I never understood why ppl would lock their framerate manually rather than letting vsync do it's job...

 

Because I don't know how to enable vsync with SDL2 I didn't see such thing.



#6 ultramailman   Prime Members   -  Reputation: 1585

Like
2Likes
Like

Posted 30 December 2013 - 01:47 AM


I think I'm doing pretty much the same

 

I think yours and eduardo's are different. Your algo will update, render and wait some time as filler to make it 16 millisec per frame (1 update per render with waiting), while eduardo's will update multiple times until 16 millisecs or more has passed before rendering (one or more updates per render without waiting).

 

For more information, look at the article Fix your timestep! on the internet, it talks about various kinds of game loops.



#7 Hanksha   Members   -  Reputation: 200

Like
0Likes
Like

Posted 30 December 2013 - 02:10 AM

Ah thank you I understand the difference, so are they equivalent or the one of eduardo is better to implement?



#8 Vortez   Crossbones+   -  Reputation: 2704

Like
2Likes
Like

Posted 30 December 2013 - 10:01 AM

Because I don't know how to enable vsync with SDL2 I didn't see such thing.

 

I never used SDL, but judging from that post and my opengl experience, i guess you didn't use double buffering. Double buffering will remove any tearing effect on fast moving scenes, and lock your framerate for you as a bonus by default.


Edited by Vortez, 30 December 2013 - 10:08 AM.


#9 jHaskell   Members   -  Reputation: 1087

Like
1Likes
Like

Posted 30 December 2013 - 10:10 AM

Ah thank you I understand the difference, so are they equivalent or the one of eduardo is better to implement?

 

 

With frame based movement, they are most definitely NOT equivalent.  Quite the opposite, actually.  Multiple updates will cause multiple frame-based moves in a single 'frame'.  With frame based movement, you want only a one to one ratio of updates and renders.

 

Your fps fluctuations are possibly due to the precision of SDL_GetTicks, which is inadequately documented.  The precision of this call is platform dependent, but may be as poor as 10ms, which would prevent you from precisely locking down your framerate.  Even at it's documented 1ms accuracy you'll have trouble precisely locking down your framerate as the difference between 60fps and 65fps is only a bit over 1ms (16.66ms per frame vs 15.38ms per frame).

 

The real solution is to take the time and learn time based movement and get away from frame based movement.  Otherwise, look at using a sub-ms resolution high performance counter, which is going to be very platform dependent.  On Windows, look at QueryPerformanceCounter/QueryPerformanceFrequency.



#10 Hanksha   Members   -  Reputation: 200

Like
0Likes
Like

Posted 30 December 2013 - 05:52 PM

 

Because I don't know how to enable vsync with SDL2 I didn't see such thing.

 

I never used SDL, but judging from that post and my opengl experience, i guess you didn't use double buffering. Double buffering will remove any tearing effect on fast moving scenes, and lock your framerate for you as a bonus by default.

 

 

I think I found the better way, looking at the function SDL_SetVideoMode (which I think doesn't exist in SDL2) I notice a flag that I didn't see before SDL_RENDERER_PRESENTVSYNC , I just add it to my renderer creation function:

 

renderer = SDL_CreateRenderer(window,-1,SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);

 

Now the fps is stable 60. (But I wonder if this vsync can be still disable by the user)

 

So I guess now my best call is to really work on time based movement.

 

Thanks everyone for the help!



#11 PunCrathod   Members   -  Reputation: 337

Like
0Likes
Like

Posted 31 December 2013 - 11:37 AM

 

I think I found the better way, looking at the function SDL_SetVideoMode (which I think doesn't exist in SDL2) I notice a flag that I didn't see before SDL_RENDERER_PRESENTVSYNC , I just add it to my renderer creation function:

 

renderer = SDL_CreateRenderer(window,-1,SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);

 

Now the fps is stable 60. (But I wonder if this vsync can be still disable by the user)

 

 

This is a bad idea. If your movement rate is based on fps. Enabling vsync will not do what you want. This is because vsync is not quaranteed to be 60hz. It depends on your gpu and display and settings. If you have a 75hz or 120hz display and your gpu supports it and have it enabled then with vsync your game will run at 75fps or 120fps. Or even worse if you are using a 1080i tv as a screen with 30hz progressive setting it will lock the fps to 30. And as you had already guessed users indeed can disable vsync from the driver settings.

 

You really need to use high preformance timers. Either by forcing updates to 60hz or adjusting movement rate with deltatime.


Edited by PunCrathod, 31 December 2013 - 11:38 AM.


#12 eduardo_costa   Members   -  Reputation: 329

Like
0Likes
Like

Posted 02 January 2014 - 01:52 PM

The purpose of multiple updates before rendering is splitting work in different steps before the render callbacks.

In a more hi-level solution, one could use different time-slices for different tasks and optimize the loop for a given application.

 

Like:

 

0ms                                              X ms                        16ms

Input Animation Update Physics                 Rendering Flush

 

Also, locking the rendering code in 60fps will avoid calling API commands like clear, shaders, swapbuffers, texture binding, ... in a rate greater than it is needed.

I had a great change in perfomance when I reduced the rate of calling of these commands.

In a worst case scenario locking at 40 or 30fps gave me more time to update other non-rendering stuff and the application performed even better!






Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS