floooh / sokol

minimal cross-platform standalone C headers
https://floooh.github.io/sokol-html5
zlib License
6.72k stars 472 forks source link

Reminder: pause/continue in sokol_app.h #301

Open floooh opened 4 years ago

floooh commented 4 years ago

See here: https://twitter.com/andsve/status/1264513943051153408

Basically:

sapp_pause() skip calling the frame callback and buffer flip until sapp_continue() is called. This would be useful (amonst others) for event-driven application which only need to render on input events.

martincohen commented 4 years ago

I'm not sure what non-desktop platforms do, but I'd like to point out a few things. (And I'm also sure you already considered these)

Problem I see with this is that you'd lose periodic per-frame update call, which might be used to do app-specific optimizations or tasks:

So what I'd propose is a redraw flag (perhaps via a function similar to sapp_consume_event):

This approach also makes you not having to worry about pairing pause/continue calls.

floooh commented 4 years ago

Some more brain-dumping after more feedback from that twitter thread:

For the two reasons above it's probably better to not ever stop calling the frame callback at regular intervals, but instead let the application decide whether it wants to do any rendering (or other expensive stuff) inside the frame callback, and instead tell sokol-app whether a frame-swap is needed.

Some (discarded) alternatives to not calling the frame callback:

If no frame-swap is taking place, the frame-callback-rate must be throttled with a sleep() on some platforms (this is already happening in some cases as a special workaround. For instance;

https://github.com/floooh/sokol/blob/786c003e0fed12175533dd98c847ab005158d753/sokol_app.h#L5078-L5083

Some ideas how to communicate the frame-swap to sokol-app:

...all in all I'm currently favouring the sapp_swap() function together with a new "bool explicit_swap" member in sapp_desc.

floooh commented 4 years ago

Some other minor things:

hb3p8 commented 4 years ago
  • let the user decide how long to sleep in such "no-swap frames" (but this might be counterproductive on e.g. the browser platform where the whole page might become laggy, so probably not a good idea)

Could we even do it in browsers at all? :)

Manuzor commented 4 years ago

One thing that may help a little with the OPs goal is to not render at all if the window isn't focused. If there was something like sapp_has_focus(), and the user was able to control buffer swaps (e.g. sapp_swap() as mentioned above), they'd keep the ability to update periodically but can choose to only update/render parts of their system when running in "background mode".

While I would like to be able to use sokol_app.h for such a use case myself, I wonder: Is this maybe out of scope?

floooh commented 4 years ago

@Manuzor from what I've seen, most platforms don't allow such a fine level of control for when the draw callback is called, e.g. on the web platform, a hidden tab might be completely deactived or called with an extremely low frequency (you can check this for instance here https://floooh.github.io/tiny8bit/ when opening the emulators in a hidden tab, or switching away from a running emulator, the emulation will essentially freeze until the tab is brought to the foreground again).

Similar issues with putting applications on mobile platforms into the background.

One intended way to keep track of such things are the various sokol-app events (like SUSPENDED/RESUMED and ICONIFIED/RESTORED), but those might behave slightly differently on different platforms, and AFAIK on the web platform, it's not possible to detect if a tab is "slowed down" because it's a background tab (I haven't looked all that hard though)

prime31 commented 4 years ago

The way SDL does this works really well for event driven apps. They have a method SDL_WaitEventTimeout(n) that returns the next event as soon as it arrives or sleeps for n milliseconds. Something like that provides a nice balance between keeping things responsive and sleeping as long as possible while waiting for an event.

laserbeam3 commented 3 years ago

This may be an old/irelevant issue, I hope it's ok to necro it. I also want to only render on event, not every frame to save on battery/GPU usage. To achieve this, on a local fork, I made frame_cb return a bool instead of void. If the return value is false, I skip the framebuffer flip call in sokol_app.h and I sleep some arbitrary amount of time.

This is rudimentary, it may not be the desired approach, and I've only added this behaviour in sokol_app.h for 1 single platform. However, this solution avoids a lot of event complexity and lets me manage when I want to skip frames, and when I don't. This also lets me manually decide I need to render frames when some animations are ongoing (irrespective of whether events took place or not).

Instead of using the return value of frame_cb, a skip_rendering_this_frame() call may work.

Think this strategy might work in a more general case?

floooh commented 3 years ago

Thanks for the feedback! The issue isn't dead, just a bit neglected ;) I might also be a bit paralyzed towards bigger sokol_app.h changes because the next "big thing" for sokol_app.h will be multiwindow-support, and I'm not sure how much it makes sense to do (somewhat deep) changes like "lazy rendering" until multi-window is done.