Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Investigate smarter approaches to frame limiting #218

Open
17cupsofcoffee opened this issue Dec 20, 2020 · 4 comments
Open

Investigate smarter approaches to frame limiting #218

17cupsofcoffee opened this issue Dec 20, 2020 · 4 comments
Labels
Area: Game Loop Issues relating to the main game loop. Area: Platform Issues relating to the platform layer Type: Investigation Ongoing investigations and unanswered questions.

Comments

@17cupsofcoffee
Copy link
Owner

Summary:
In 0.5.6, we switched from doing std::thread::yield_now at the end of the game loop to doing a 1ms std::thread::sleep. This was to avoid issues some people were having with high CPU usage when the game is minimized or when vsync is turned off.

This appears to be due to the fact that std::thread::yield_now doesn't guarentee the thread will yield - it'll only yield if there's work to do elsewhere. std::thread::sleep, on the other hand, guarentees that we'll yield for some amount of time, putting an effective cap on the max FPS and preventing the game from maxing the CPU core. This is the approach used by Love2D's default game loop, and I've not noticed any ill effects from it there.

That said, I would like to investigate whether there's a smarter approach to this, as sleeping for 1ms in all cases seems like a bit of a clunky solution (e.g. if the game is running slowly, you might want that extra headroom rather than a millisecond being wasted). I'm not entirely sure if it's necessary though.

Why is this needed?
Just for my own peace of mind, and to make sure that we're not leaving any performance on the table.

@17cupsofcoffee 17cupsofcoffee added Area: Game Loop Issues relating to the main game loop. Type: Discussion Area: Platform Issues relating to the platform layer labels Dec 20, 2020
@17cupsofcoffee 17cupsofcoffee added Type: Feature Request Improvements that could be made to the code/documentation. Type: Investigation Ongoing investigations and unanswered questions. and removed Type: Discussion Type: Feature Request Improvements that could be made to the code/documentation. labels Dec 24, 2020
@17cupsofcoffee
Copy link
Owner Author

17cupsofcoffee commented Jun 22, 2021

By the looks of it, the high CPU usage when minimized is due to MacOS itself disabling vsync for windows that aren't visible 🤦 It's been reported on SDL itself too, and GLFW has implemented a workaround.

@17cupsofcoffee
Copy link
Owner Author

After doing a bit of research, it sounds like the most reliable way to do framerate capping is to use something like spin_sleep, which spends as much time as possible sleeping the thread and then busy loops for the remainder - this allows for much higher precision than relying on the OS scheduler alone.

FNA recently moved to using something like this as well (though the logic is a bit weird due to them inheriting the behaviour from XNA - they only do it for fixed timestep, with no built-in support for interpolated rendering).

Most people should probably still use vsync for frame limiting, but I'll look into adding this as another option (maybe in 0.7, as I'd like to tweak some of the timing APIs).

@sumibi-yakitori
Copy link
Contributor

sumibi-yakitori commented Nov 4, 2021

It's off-topic to ask you a question about English, but do English-speaking people refer to doing a busy loop as "spin"?

@17cupsofcoffee
Copy link
Owner Author

Yeah, looping to pause the thread while you wait for something to happen (rather than sleeping) is sometimes referred to as a 'spin loop', 'spin waiting', or just 'spinning'.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: Game Loop Issues relating to the main game loop. Area: Platform Issues relating to the platform layer Type: Investigation Ongoing investigations and unanswered questions.
Projects
None yet
Development

No branches or pull requests

2 participants