I usually tell people that sleeps only belong in one place in their code and they should make linters complain if it pops up anywhere else. The place is the method they call to poll. And even then it's better to wait for something than poll to see if we're ready.
This, though, seems to be trying to sleep to slow down frame rate. What the? Maybe it's intended as some way to make all users' experiences suck equally even if they have fast boxes. Maybe. And depending on the actual scenario maybe it makes sense to handle this with a "better" sleep.
The problem as stated is not a solved problem because it's not generally anything anyone would want to do.
In fact, people might have left this intentionally hard to do to discourage its use.
The problem is knowing how long the actual render is going to take. Scenes can vary vastly in complexity and predicting how long they will take to render a priori is extremely difficult.
And despite what some people and games seem to think, vsync isn't an optional feature that you can turn on or off, it's something that must always be enabled since it's essential to display correct graphics.
That kind of code usually works best with a fixed "framerate"/tickrate, but for performance reason that rate is set at something like 20 ticks per second. If your framerate is a multiple of that and graphics and physics runs on the same thread that's trivial (e.g. do physics every third frame for 60fps), but what if you move it to a different thread and some of your users have 75hz monitors? Now you have to sleep, or waste resources.
Tons of games do it (console ports are guilty of fixed 30FPS), and it really sucks.
The game "is" the physics engine (esp. in cases of networked games); while the graphics engine is simply an "observer" of the output of the physics engine, trying to interpolate/extrapolate graphics frames given a stream of physics frames.
Do physics at 30FPS in one thread; draw graphics as fast as you can in a separate thread; and at the beginning of each render frame, get the latest physics integration-state, and how much time it's been since it was calculated, and extrapolate object displacements+rotations (incl. the camera) linearly from existing velocities. Those changes will be so small, and corrected by the next physics-step so soon, that it'll almost always look correct.
The only reason to not do this, is if you can't afford concurrent execution (i.e. you only have a single CPU core and interrupts are expensive), and you also don't have a practical Lowest Common Multiple frequency to run an event-loop at. Which is something that was maybe true in the gameboy era, but hasn't been true for at least 30 years.
Thinking this might be "intentionally hard" rather than "non-realtime operating systems are just sloppy" is silly.
Or to conserve power, why burn CPU and render at hundreds of fps when the output is limited to 60 or even 30?
I don’t need my machine loaded at 100% when playing slay the spire or dungeons of into the breach.
Not really, you can calculate how long had passed since the last physics recalculation and use that as a delta between frames.
They choose a time that computation happens. But computation should instead be done as soon as possible, and the output delayed to the necessary time.
For example, in an animation, you don't need to wake up the CPU every 16ms to compute the next frame. You should instead just compute all the frames and send it off to the GPU to display in order and with the right timings.
For example, consider a game server that must handle inputs from multiple clients. It can't just compute everything and queue it off to the network because a user input may change the entire game world. A "computation" loop provides a consistent model of which all the game interaction happens.
This is fundamentally not a solution for any problem where you're reading input from outside. If that animation is reacting to user input, rendering the frames 100ms ahead will create 100ms or more of "input lag" that the user can see and feel and they hate it.
You can still compute ahead if you have a good guess what inputs you'll receive (eg. You predict that no keys will be pressed), but you have to be happy to throw away the results if your prediction was wrong.
The whole point of a CPU is to be general purpose. A CPU isn't optimal for anything. The magic of a computer is that it makes "anything" possible. Why would you want to ban sleep? If somebody makes a crappy arcade game with terrible latency and jitter, good for them. Someone not yet familiar with the nuances of "sleep" will learn a lot faster building some crappy but functional programs than they will trying to learn a modern graphics API. A seasoned expert will readily barf out a crappy program with some sleep calls in it when they know it's good enough to solve the problem at hand.
But I do agree that it would be much more helpful if tutorials for Arduino would promote using timers and interrupts.
1: https://docs.microsoft.com/en-us/windows/win32/api/timeapi/n...
As for Windows, use CreateWaitableTimerEx, with a CREATE_WAITABLE_TIMER_HIGH_RESOLUTION flag.
https://docs.microsoft.com/en-us/windows/win32/api/timeapi/n...
https://duc.avid.com/showthread.php?t=334589
Winamp had a ton of special purpose code in it just to compensate for bad clocking and timing in consumer sound cards so that you could play back audio at proper rates without gaps or glitches.
Mobile seems to be no better - I remember getting fed up playing rhythm games on a Motorola phone I owned because, I kid you not, the hardware audio clock would occasionally run backwards.