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

[Question] - Render only on changes #48

Closed
iandanforth opened this issue Apr 25, 2018 · 5 comments
Closed

[Question] - Render only on changes #48

iandanforth opened this issue Apr 25, 2018 · 5 comments

Comments

@iandanforth
Copy link

Description

My app is hogging power. When I look at a perf recording I see constant GPU activity even when there are no state changes. I'd like to use react-pixi-fiber in such a way as it only re-renders as needed. I've tried turning off autostart, enabling the shared ticker, and calling .update() on the ticker in a few places but this is buggy and doesn't feel like the right way.

What is the proper way to make sure that RPF is only asking pixi to re-render when something has changed?

Thanks in advance!

@michalochman
Copy link
Owner

Hey @iandanforth, technically RPF is not asking PixiJS to re-render at all – it's the PIXI.Application's ticker that calls render() on each frame by default.

This is not the most elegant way, but have you tried using app from the context and calling this.context.app.render() each time you want to update?

Take a look at this sandbox I've prepared, there are no updates until you click the bunny: https://codesandbox.io/s/6vmn15867z

@iandanforth
Copy link
Author

Thanks @michalochman for the thought and time. The example was especially appreciated. I have implemented this and it works! There may be a better way though that I wanted to get your input on.

Currently I disable the PIXI rendering loop

    // Take control of rendering
    stageOptions.autoStart = false;
    stageOptions.sharedTicker = true;
    const ticker = PIXI.ticker.shared;
    ticker.autoStart = false;
    ticker.stop();

And then use the render method from context as suggested. However I had the following issue. I have a list of animated components which all needed to be able to get 30-60 fps re-renders. Because the animations can overlap they were calling render() many more than 60 times per second. To fix this I ended up creating a throttled version of app.render()

  static contextTypes = {
    app: Proptypes.object
  }

  static childContextTypes = {
    renderStage: Proptypes.func
  };

  constructor(props, context) {
    super(props);
    // use throttle() method from underscore
    this.renderStage = throttle(() => {
      context.app.render();
    }, 20);
  }

  getChildContext() {
    return {
      renderStage: this.renderStage
    };
  }

Alternate Idea

The other thing I haven't tried yet is to create a custom ticker for the app that runs a RAF loop, but only
actually updates/renders the stage IFF there is a 'dirty' flag set.

Any time a CustomPIXIComponent was updated it could set the flag. Any number of components could do this and you'd still end up with only 1 frame being rendered at RAF frequency.

This might be a generally useful strategy for react-pixi-fiber because there's a strong assumption that re-renders should be tied directly to component updates. The current default has the stage re-render regardless of a component update.

@michalochman
Copy link
Owner

michalochman commented May 2, 2018

@iandanforth I'll give it a thought, although it's not a priority for me.

The primary concern of RPF is handling updates to PixiJS scene tree, not the rendering process itself. I also think your use-case is not that common, usually you want to animate each frame, because each frame is different, otherwise the scene is static.

If you have time, feel free to investigate and open PR.


Instead of throttling I would recommend a loop checking for dirty flag like you describe as "Alternate Idea", e.g.:

let dirty = false;

function loop() {
  if (dirty) {
    dirty = false;
    app.render();
  }

  requestAnimationFrame(loop);
};

loop();

Then whenever you update, you would set dirty = true.

@iandanforth
Copy link
Author

iandanforth commented May 2, 2018

Thanks again! I certainly don't know what the common case is for RPF. My app is mostly static until users start interacting with it (https://iandanforth.github.io/thought-experiment/#/simulation) so this may apply only to me.

@linonetwo
Copy link

Discussing continued here #237

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants