Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: A (possible) solution to rendering performance optimisation  (Read 3388 times)

0 Members and 1 Guest are viewing this topic.

AnhBao

  • Newbie
  • *
  • Posts: 13
    • View Profile
    • Email
Hi guys. I have been using SFML for 2 months. As I learned the command queue system, I made a small test that you can move a tank. I decided to add accelerate each time unit, rather than keep velocity frame-independent.
The code looks like this:

void World::adaptEntityVelocity(Entity& entity, sf::Time dt)
{
    static constexpr float a = 500.0f;//acceleration
    static constexpr float msp = 400.0f;//max speed
    float velo = entity.getVelocity();
    //clamp velo to [-msp,msp]
    velo = std::min(msp, std::max(- msp, velo));
    if(velo > 0)
        entity.setVelocity(std::max(0.0f, velo - a * dt.asSeconds()));
    if(velo < 0)
        entity.setVelocity(std::min(0.0f, velo + a * dt.asSeconds()));
}
//...
adaptEntityVelocity(mPlayer, dt);
//...
mPlayer.move(mPlayer.getVelocity() * dt.asSeconds();

It worked just find until I use sf::RenderWindow::setFrameLimit(). It somehow makes the player moves slightly faster in 60 fps (compared to ~450 fps without setting limit) and crazily fast in 10fps. I think the problem is the time Game::update() and Game::processInput() system is also affected by setFrameLimit(). So I decided not to use setFrameLimit(), but I don’t want to let the game run as fast as possible because that hurts GPU. But if I only limit render frequency the CPU will run massively fast and consume lots of energy (same when you run an endless while() loop). Then I come up with an idea: limit Game::render() to 60 fps and game loop to 500fps. This is the code:

void Game::run()
{
    sf::Clock dtClock;
    sf::Time timeSinceLastFrame = sf::Time::Zero;
    while(mWindow.isOpen())
    {
        sf::Time elapsed = dtClock.restart();
        //limit loops per second;
        if (elapsed < sf::seconds(0.002f))
        {
            sf::sleep(sf::seconds(0.002f) - elapsed);
            elapsed += dtClock.restart();
        }
        timeSinceLastFrame += elapsed;
        while(timeSinceLastFrame >= TIMEPERFRAME)
        {
            timeSinceLastFrame -= TIMEPERFRAME;
            processInput();
            update(TIMEPERFRAME);
        }
        updateStat(elapsed);
        render(elapsed); // pass a time variable to count and set limit
    }
}

Render function:

void Game::render(sf::Time dt)
{
    mRenderTime += dt;
    if(mRenderTime >= sf::seconds(1.0f / 60.0f))
    {
        mRenderCount ++;
        mRenderTime -= sf::seconds(1.0f / 60.0f);

        mWindow.clear(sf::Color(0x00000000ff));

        mWorld.draw();

        mWindow.setView(mWindow.getDefaultView());
        mWindow.draw(mStatistics);
        mWindow.display();
    }
}
 

So what I want to know is would this work on any OP with various speed? Or is it just in my own laptop?

P/s: this is what I got after all: a decent render rate and a limited loops per frame


eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10801
    • View Profile
    • development blog
    • Email
Re: A (possible) solution to rendering performance optimisation
« Reply #1 on: July 11, 2021, 04:05:01 pm »
setFramerateLimit as well as VSync will affect your whole game loop, it can't just magically know what counts as rendering and what as game logic. ;)

The generally recommended way is to used fixed time steps for your physics and potentially run that at a higher rate than your frame rate.

This article puts it very well: https://gafferongames.com/post/fix_your_timestep/
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/