Closed wenq1 closed 6 years ago
@wenq1 this is typical in games. Usually you want to use all available CPU because you're busy updating graphics, physics, ai, game logic and so on.
Having said that, it might be a good addition to provide this as an option in case you want to enable sleeping to lower power consumption and make a non-fullscreen game play nicer with the rest of the system.
@danielytics Not on mobile I believe. Busy loops means a huge deal for battery life. Nowadays even eglSwapBuffers () are vsync-ed to avoid extensive battery usage.
@wenq1 ah, of course, its much more important for mobile. I wasn't thinking clearly ;-)
Does EGL vsync for battery conservation purposes, rather than to avoid visual tearing?
Visual tearing will never occur on double-buffer backed systems. Reading and writing are always on complete buffers, never on buffers in progress. Performance-wise lockless double buffers are invented to address the issue.
Question asked here is of another scope. When you have a thread spawned (especially on mobile devices), you almost always need a handler based pattern to block somewhere, or you manually insert sleeps between loop iterations. Otherwise batteries will be tortured or considered fully utilized as a cookware.
You still need to wait for vsync before swapping the buffers to avoid tearing. Otherwise you may still have part of the screen rendered from one buffer and the rest from another. My question was whether vsync is also done because of battery, or if thats just a happy side-effect. Probably a mixture of the two. Anyway, I've taken this ticket off topic enough.. apologies!
Sure, that makes sense and I guess that's why mobile apps are inherently event-based (doing little or nothing until the user does something). Could ouzel perhaps get a little closer to this by providing configurable fixed timesteps (eg so that the developer can decide how often rendering (and ideally independently, game logic) updates are run)? Eg, if you could say "render at 60 Hz and update game logic at 15 Hz". Not quite event-triggered of course, but still a lot more control over battery use than currently. Maybe I'm talking BS though ;-)
There is no way to reliably fix the update thread to 15 Hz. I was considering that (and if you look at the commit history, it was implemented 2 years ago) a fixed update with sleeps, but sleeps are unreliable. They guarantee a minimum amount of time to sleep, but not maximum. For example, my game is updating all the logic at 60 Hz. I tried to add a sleep to force the update thread to run at 100 Hz and I got inconsistent update rate, that affected my game dramatically. Syncing the update thread with the render thread (vsync) is also a no-go, because every device can have its own refresh rate and usually it is not precisely 60 (I got 60.1 on some and 59.9 on others). If you are updating your physics exactly 60 times a second and you get a refresh rate that is something around 60, you will get have a double-update once in a while and that makes the game feel really glitchy.
"Otherwise you may still have part of the screen rendered from one buffer and the rest from another" - No that should never happen in double buffered systems, Otherwise either locks screwed up on single-buffered system or poor logic is in charge in multi-buffer backed systems.
Interesting read here: http://stackoverflow.com/questions/23666069/single-producer-single-consumer-data-structure-with-double-buffer-in-c
Completely off-topic above. Ignore me..
Fixed step rendering is .... yet another thing. Check this out: http://gafferongames.com/game-physics/fix-your-timestep/. It is a game-loop design pattern that makes physics more predictable, irrelevant of your implementation.
Ouzel chooses to use multithreading to implement game update part of the rendering. It is the cpu-hogging behaviour itself that incurred the question.
I was thinking something like this http://gafferongames.com/game-physics/fix-your-timestep/ where it makes a best effort to fix the timestep, but also allows multiple updates when enough "missed time" is accumulated. They did it for the purpose of physics, maybe its not suitable here. I know that getting it to be exactly X Hz is impossible...
EDIT: hah, posted the same link at almost the same time :D
No that should never happen in double buffered systems
Do you mean with hardware double buffering? Presumably that's because they will always wait for vsync, no?
If software double buffering is used (which, granted, in this day and age shouldn't be necessary), you still need to synchronise: when you SwapBuffers the screen might be halfway through the screen and it will start pushing pixels to the screen. The top half of the screen will still show the previous frames graphics. It would be corrected next time the screen starts from pixel 0, but unless you have some way of making sure every pixel was read from the buffer before swapping, you could end up with the same situation again and again. Even the wikipedia page on multi-buffering says that modern systems synchronise between swaps. (Going by your SO link: I'm not saying that "you" are drawing part into one buffer and part into the other; I'm saying that the GPU is drawing part of one buffer to the screen and part of the other buffer to the screen, causing the screen to contain a mix of buffers; the buffers themselves may be properly locked and this could still happen).
I would expect this to all be happening in hardware, but at least with my experience with OpenGL, when I set it up with double buffering, I still have to tell it I want vsync for it to use vsync and if I do not, I get tearing. (Maybe ES always does vsync, I have no experience with ES)
Yes, I have seen this article quoted many times and I have implemented a similar logic in my game, but it doesn't answer the question, how to fix the update rate of the game thread to the one the user wants (e.g. 15 Hz). As I mentioned above, using sleep is not an option. That is why I created a while loop and user can do whatever he wants in it. He can add an update callback to the engine and put a sleep in it if he wants to save resources. But I don't think this is something that has to go into the engine. Maybe you have better ideas?
@elnormous Am I correct in saying that the problem you hit was that its impossible to remove jitter?
either
or
There's obviously no way to guarantee that the timestep will always be exactly what you want, but if I read the article correctly (but maybe I didn't!) it sounds like the idea is to make sure that the same number of updates happen in a given timeframe. That is, you might not get 1 update every 16.6ms, but you will get exactly two in 33.2ms (more or less). Best effort kinda thing. But I'm not experienced enough to discuss beyond this. You have more experience than I do, so if it didn't work, then...
EDIT: Reading comprehension failure on my part, sorry! You already said:
you will get have a double-update once in a while and that makes the game feel really glitchy
How do you handle it in your game? I assume you're not using a physics engine that requires a fixed timestep. What happens if the framerate drops really low? Even if using purely time-based update logic, there will be jumps in this case. Are they less "glitchy" than with double-updates in the fixed timestep approach?
Say if you want 15hz update (66ms intervals), sleeping 80ms will be ok, and then just update (66ms) at a time. When deviations accumulates, say, you have slept for 3 times, you update once more at the last sleep. You'll get jitter surely.
Sleeping less, for example 10ms will give you smoother outcome and less jitter. Never sleep at close to the update rate or otherwise you might or might not get the extra update at some point in time.
To overcome the jitter issue, sleep a variable amount of time depending on the designed next (fraction of) frame time, say 60fps. This gives most predictable results when drawing occurs at a constant rate, say vsynced. When the framerate drops, the frame time will depart from the design, but with multi-threaded CPU-side updating will this ever happen?
Hi, you could read this thread from the cocos2d-x forum which is related http://discuss.cocos2d-x.org/t/cocos2d-x-windows-performance-issues-examined/27915 Leaving a game use 100% of the CPU is not good from my point of view, you're killing mobile and laptop batteries. Lots of game engines offer a kind of fixed update rate so even if it is difficult it is not impossible to implement it.
I will add an option to run the game thread in one of the two modes: 1) Run as often as possible (current way) 2) Run only once per v-sync
I added a oneUpdatePerFrame (the name could change) attribute (false by default) to the Engine class. Now the game thread will sleep until the next frame (so it will not run on 100% anymore). https://github.com/elnormous/ouzel/commit/f2f29dee20bb3429fefb6428710224399b07e148
Hi Elnormous, Great work on your multi-platform support!
I have a question tho regarding Engine::run (). Won't it be hogging the CPU as it is not event-triggered (blocking mode) nor has it sleep ()?