StageXL icon indicating copy to clipboard operation
StageXL copied to clipboard

Any way to pause the render loop if nothing is happening?

Open kevmoo opened this issue 8 years ago • 12 comments

In my crazy outdated bot_web retained silly - https://github.com/kevmoo/bot_web.dart/tree/master/lib/src/bot_retained

I kept track of dirty information and I wouldn't render frames unless something changed.

Any way to do this with StageXL? I see that the render events keep pumping, even if nothing is going on.

kevmoo avatar Feb 07 '17 20:02 kevmoo

Hi,

Yes you can do this! Please take a look at the StageRenderMode enum.

You can set the stage.renderMode property to one of the following values:

  1. Auto - you will see continuous rendering
  2. Once - the stage will be rendered once at the next render event
  3. Stop - the stage will not be rendered

If you change something on the Stage, you can set the "Once" value and you will get an updated stage. After this render event the property will automatically change it's value to "Stop". So every time you want the stage to be rendered you set it back to "Once".

I wonder why i have no example for this, i will add this to some of the examples soon!

bp74 avatar Feb 08 '17 07:02 bp74

When trying to automate this behaviour, I found it best to extend RenderLoop, overriding advanceTime and setting the StageRenderModeaccording to some conditions, before calling the super function:

  • check if Juggler has something going on via hasAnimatables – if true, go for AUTO, else ONCE
  • check if any ENTER_FRAMElisteners are present – if true, go for AUTO, else ONCE

This should suffice for a lot of use cases.

For more complex applications, I haven't yet been able to find an elegant solution for:

  • MOUSE_MOVE, MOUSE_WHEEL, TOUCH_MOVE – if you have an implementation not relying on ENTER_FRAME or Juggler, it is necessary to set StageRenderModeto ONCEin the listeners of your implementation.
  • RESIZE – if you employ a liquid/responsive layout, you probably want this event to activate AUTO, but it is sometimes tricky to find the best point in time when to switch back to ONCE
  • Shaders – If your shader requires a full frame rate, you need to set to AUTO
  • I think there was more, but I can't remember

If I had the time, I would go for a centralized RenderModeManager (singleton?), which ensures that all of the above plays well with each other – we don't want accidental resets to ONCE. Alternatively, we could nag @bp74 to add this to Juggler, as opt-in functionality :-)

nilsdoehring avatar Feb 08 '17 11:02 nilsdoehring

I'd love to have this be auto-magic, @nilsdoehring – I've implemented it before.

No clue how easy here. I just don't like tabs burning CPU when nothing is moving. Makes the mobile users sad.

kevmoo avatar Feb 08 '17 15:02 kevmoo

@kevmoo, would you be able to provide any pointers, preferably in ActionScript? (because easiest to port)

I'm motivated to revisit the case, especially since my implementation is faulty, but if disabled, would melt down the CPU in the example linked above. Will follow up, here.

nilsdoehring avatar Feb 08 '17 15:02 nilsdoehring

@kevmoo, would you be able to provide any pointers, preferably in ActionScript? (because easiest to port)

@nilsdoehring sadly, no. Not sure if there is a way to do it generically.

One improvement: it'd be nice to just have a requestFrame method on stage. If called before drawing (and a frame is already requested) – no-op. If called during a frame, make sure a frame is scheduled.

kevmoo avatar Feb 08 '17 16:02 kevmoo

The starling framework in v2.0 implemented auto-magic idle mode :) But you won't get it for free, basically every change to one of the DisplayObject or DisplayObjectContainer properties and several other trigger will mark the display tree as dirty. It's nice for applications where most of the time nothing changes, but it hurts performance for games where each frame is different.

bp74 avatar Feb 08 '17 17:02 bp74

@bp74 @kevmoo I did a PR with a first attempt, would love your thoughts on it.

nilsdoehring avatar Feb 13 '17 17:02 nilsdoehring

@kevmoo After exchange with @bp74 in the PR (thanks!), here's a gist of a RenderLoop that works with the current StageXL API (1.1.0).

nilsdoehring avatar Feb 14 '17 09:02 nilsdoehring

I will work on this feature over the weekend. The code will be very similar to the one fromNils, i will keep you posted.

bp74 avatar Feb 15 '17 07:02 bp74

I implemented this by using a Once and Stop stage modes. Invalidating an object in my GUI framework causes the Stop to go to a Once. I have to keep track of Canvas Resizes as well.

This is a feature one wants on a GUI framework (like I use), but would be expensive to set up in a game framework.

audioMirror avatar May 23 '17 19:05 audioMirror

Anything new? Starting to realize this is a big deal for battery drain.

unicomp21 avatar Oct 21 '17 11:10 unicomp21

Could it be simple as just checking whether or not the juggler has work to do? Then it's on the dev, if he wants to save battery, to make sure animation stops after a period of idle time from user.

unicomp21 avatar Oct 21 '17 11:10 unicomp21

There is a very simple trick. First you set stage.RenderMode to StageRenderMode.AUTO_INVALID which will only render the Stage if someone called the stage.invalidate() method. Next, you derive your own Juggler from the standard Juggler and override the advanceTime method. In this method, check if the hasAnimatable property is true, and in this case call stage.invalidate().

If all your animations use an instace of your Juggler, everything should work as expected.

This would be easy to implement in StageXL itself. But i don't want to make the stagexl.animation library (where Juggler exists) dependent on the stagexl.display library (where Stage exists). I was thinking about some magic to make this work, but never figured out a way that makes me happy. Hope this helps.

bp74 avatar Oct 21 '17 11:10 bp74