Simple C ++ SFML program with high CPU utilization

I am currently working on a platformer and am trying to implement timestep, but for frame rate limits of more than 60, the processor load increases from 1% to 25% or more.

I made this minimal program to demonstrate this problem. In the code that describes the problem and what I tested, there are two comments (lines 10-13, lines 26-30).

Please note that the FPS stuff is not relevant to the problem (I think).

I tried to keep the code short and simple:

#include <memory> #include <sstream> #include <iomanip> #include <SFML\Graphics.hpp> int main() { // Window std::shared_ptr<sf::RenderWindow> window; window = std::make_shared<sf::RenderWindow>(sf::VideoMode(640, 480, 32), "Test", sf::Style::Close); /* When I use the setFramerateLimit() function below, the CPU usage is only 1% instead of 25%+ (And only if I set the limit to 60 or less. For example 120 increases CPU usage to 25%+ again.) */ //window->setFramerateLimit(60); // FPS text sf::Font font; font.loadFromFile("font.ttf"); sf::Text fpsText("", font, 30); fpsText.setColor(sf::Color(0, 0, 0)); // FPS float fps; sf::Clock fpsTimer; sf::Time fpsElapsedTime; /* When I set framerateLimit to 60 (or anything less than 60) instead of 120, CPU usage goes down to 1%. When the limit is greater, in this case 120, CPU usage is 25%+ */ unsigned int framerateLimit = 120; sf::Time fpsStep = sf::milliseconds(1000 / framerateLimit); sf::Time fpsSleep; fpsTimer.restart(); while (window->isOpen()) { // Update timer fpsElapsedTime = fpsTimer.restart(); fps = 1000.0f / fpsElapsedTime.asMilliseconds(); // Update FPS text std::stringstream ss; ss << "FPS: " << std::fixed << std::setprecision(0) << fps; fpsText.setString(ss.str()); // Get events sf::Event evt; while (window->pollEvent(evt)) { switch (evt.type) { case sf::Event::Closed: window->close(); break; default: break; } } // Draw window->clear(sf::Color(255, 255, 255)); window->draw(fpsText); window->display(); // Sleep fpsSleep = fpsStep - fpsTimer.getElapsedTime(); if (fpsSleep.asMilliseconds() > 0) { sf::sleep(fpsSleep); } } return 0; } 

I do not want to use SFML setFramerateLimit (), but my own implementation is with sleep, because I will use fps data to update my physics, etc.

Is there a logical error in my code? I do not see this, since it works with a frame rate limitation of, for example, 60 (or less). Is it because I have a 60 Hz monitor?

PS: Using SFML window-> setVerticalSync () does not change the results

+6
source share
2 answers

I answered another similar question with this answer.

The fact is that this does not quite help you using CPUs, but I tried your code and it works fine when using 1% cpu at 120 FPS (and much more). When you create a game or interactive media with a "game cycle", you do not want to lose sleep performance, you want to use as much processor time as the computer can give. Instead of sleeping, you can process other data, such as file uploads, a path search algorithm, etc., or just don’t put restrictions on rendering.

I provide some useful links and code, here it is:


A similar question: Movement without restriction of a C ++ SFML frame .

What you really need is a fixed time step. Take a look at the game SFML source code development book. Here's an interesting snippet from Application.cpp :

 const sf::Time Game::TimePerFrame = sf::seconds(1.f/60.f); // ... sf::Clock clock; sf::Time timeSinceLastUpdate = sf::Time::Zero; while (mWindow.isOpen()) { sf::Time elapsedTime = clock.restart(); timeSinceLastUpdate += elapsedTime; while (timeSinceLastUpdate > TimePerFrame) { timeSinceLastUpdate -= TimePerFrame; processEvents(); update(TimePerFrame); } updateStatistics(elapsedTime); render(); } 

If this is not exactly what you want, see β€œ Fix your timestep! ” Which Laurent Gomila himself linked to in the SFML forum.

+4
source

I suggest using the setFrameRate limit because it is initially implemented in SFML and will work much better. To receive the elapsed time you must:

 fpsElapsedTime = fpsTimer.getElapsedTime(); 

If I had to implement something like this, I would do:

 /* in the main loop */ fpsElapsedTime = fpsTimer.getElapsedTime(); if(fpsElapsedTime.asMillisecond() >= (1000/framerateLimit)) { fpsTimer.restart(); // All your content } 

Another thing, use sf :: Color :: White or sf :: Color :: Black instead of (sf :: Color (255,255,255))

Hope this help :)

+1
source

All Articles