1
\$\begingroup\$

In my game loop,

m_currentFrameTimestamp = glfwGetTime(); // Get the current timestamp
if ((m_currentFrameTimestamp - m_lastFPSDisplayTimestamp) >= 0.25) { // If 1/4 of a second
                                                         // passed, update the FPS counter
    double renderTime = m_currentFrameTimestamp - m_lastFrameTimestamp; // Frame time
    m_fps = (unsigned int)round(1 / renderTime); // FPS
    std::string title = "MyGame ["s; 
    title += std::to_string(m_fps);
    title += " FPS]"s;
    glfwSetWindowTitle(m_window, title.c_str()); // The title
    m_lastFPSDisplayTime = m_currentFrameTime; // Reset the FPS update timer
}
m_lastFrameTime = m_currentFrameTime; // Reset the frame time timer

calculates the FPS from the frame time and displays it in the window title. However, with just this and glClear() above, the FPS displayed in the title is very unstable (with each FPS update, it changes from 46 FPS to 87 FPS and back), even though back in the initialization step, I enabled VSync, and my display's frequency is 60 Hz. Furthermore, using Fraps, I found out that the program actually runs at a stable 60 FPS. So, what's the problem with my FPS calculation code (more specifically, why is glfwGetTime() producing inaccurate results - my code, being way too simple, just can't be wrong, it's a very simple calculation that cannot give errors of any kind)?

\$\endgroup\$
3
\$\begingroup\$

The issue is that you calculate the FPS according to a single measurement, which means that any slight variation will cause a significant shift in results. Since the actual loop time varies due to system considerations, you'll get stabler results by averaging more calculations.

fpsCount = 0;
m_lastFPSDisplayTimestamp = glfwGetTime();
while(shouldRender()) {
    m_currentFrameTimestamp = glfwGetTime(); // Get the current timestamp
    if ((m_currentFrameTimestamp - m_lastFPSDisplayTimestamp) >= 0.25) {
        std::string title = "MyGame ["s; 
        title += std::to_string(fpsCount);
        title += " FPS]"s;
        glfwSetWindowTitle(m_window, title.c_str()); // The title
        fpsCount = 0;
        m_lastFPSDisplayTime = m_currentFrameTime;
    } else {
        fpsCount++;
    }
    m_lastFrameTime = m_currentFrameTime;
}
\$\endgroup\$
  • 1
    \$\begingroup\$ So, you think that the floating point time measured only once causes the problem, and it can be solved by averaging multiple measurements? Also, I tried your approach, it gave consistent 60 FPS results, so I'm accepting your answer. \$\endgroup\$ – Vladislav Toncharov Mar 31 at 3:40
  • 1
    \$\begingroup\$ @VladislavToncharov, it's not only that any single measurement is less precise, but also that the measurement itself is wrong. If you're trying to measure FPS, then you're counting the number of times a frame is rendered in a second. Why try to estimate it using a time calculation when it's easy to simply count frames? \$\endgroup\$ – nihohit Mar 31 at 5:51
  • \$\begingroup\$ While I think this is the correct approach for measuring FPS, I'm not sure the explanation in the opening line is sound. The asker's FPS variation suggest their frametime is oscillating between 12ms and 22ms, which seems extreme. Something else is surely happening here. \$\endgroup\$ – Jack Aidley Mar 31 at 9:14
-2
\$\begingroup\$

Could be missing something but am pretty sure a 4th of a second is way bigger than a 60th of a second. Might be weird quirks about that not sure. I'd personally just do something like.

void foo(){
    sleep(1.0f/1000);
    //if last frame is 60th of a second(or some other num)
    //draw window then display fps
}
//or
void foo(){
    //if last frame is 60th of a second(or some other num)
    //draw window then display fps
}

Depending on if your trying to benchmark it or not. Also the sleep function will need tweaking to get the right balance between preserving cpu usage and having stable fps. And there's a whole art to doing this right if your really wanting to.

\$\endgroup\$
  • \$\begingroup\$ Personally i avoid glfw and the like instead going for my own api which deals with sleaping/timing/drawing/networking ect. Where i'd just update the function bodies when using new hardware. \$\endgroup\$ – Blue_Pyro Mar 31 at 0:00
  • 2
    \$\begingroup\$ Sleeping for a constant time is a bad habit, since it doesn't take into account the time needed to calculate and draw the next scene. If you have an actual frame rate issue, this will only exacerbate it. \$\endgroup\$ – nihohit Mar 31 at 3:21
  • \$\begingroup\$ Your answer doesn't measure the FPS - my problem isn't VSync, but the measurement of frame time and FPS. \$\endgroup\$ – Vladislav Toncharov Mar 31 at 3:42
  • \$\begingroup\$ nihohit your very correct. And Vladislav your honestly right. I think you should simplify it though or try something different, while using your os's specific way of measuring time. Windows has clock() for this but i'm willing to bet your using linux. But you want something that measures in at least milli seconds. Sorry for not being uber helpful it's just alternative things to try. If it turns out to be a fault of glfw honestly i'd at least make your own time related lib that's easy to make cross platform. \$\endgroup\$ – Blue_Pyro Mar 31 at 5:02
  • \$\begingroup\$ I've avoided glfw because ti's event system isn't really up to scratch. It seems better suited for UI applications than realtime applications but could be wrong. \$\endgroup\$ – Blue_Pyro Mar 31 at 5:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.