- 수정됨
performance help
I'm running a handful of animations (Widget) instances on a page at once, and it slows computers to a crawl, kicks on their CPU fans, and in some cases locks up their mouse/computer completely. Is there something I can do to make it perform better? Would switching to the canvas renderer be better or worse? Help
Can you send me a link to the page? How many widgets are you running in parallel? What's the complexity of your skeletons (#bones, #vertices in meshes, etc.)?
It's live on my teachable site at flexboxzombies.com Each level has from 2 - 8 widgets at a time, and swaps out some of them for new ones as the levels progress. My skeletons are broken up into a lot of different layers, about 65 or so slots/attachments.
Not using any meshes. Here is one of my json files if that helps https://gist.github.com/geddski/4641917f047d030b6d8de054f3bfec03
OK, I see what I can do. The biggest problem is that each widget has its own separate canvas that's composited with the rest of the DOM via CSS as far as I can see. That incurs a big performance penalty for WebGL context enabled canvases. Also, each widget does its own registration with requestAnimationFrame. Now, as per the spec those should get coalesced into a single tick that hits the screen refresh rate. But browsers are meh...
I think the best avenue to improve the situation is to manually make sure only a single requestAnimationFrame call is made for all widgets. Based on what I saw in the course material, there's also no need to redraw the widgets all the time, so an API to tell the widget to not re-render itself could be good, e.g. once an animation is done.
I see what I can do. Btw, i've also tried to recreate the context loss issue on Chrome on Window, but couldn't repro it so far. I keep looking.
I ran a few quick experiments. Coalescing the requestAnimationFrame calls does nothing for CPU usage/performance. The way to go is to pause the widget once the animation is done playing.
The widget API already has a method called "pause" which you can use to prevent the widget from further rendering until you call "play". This will bring CPU usage down to essentially 0 and fits your application.
In your lectures, some events, e.g. modification of the CSS by the user, triggers an animation to be played back. In that case, simply call "setAnimation" followed by "play", then register a callback. Here's a minimal example that will play the "run" animation of Spineboy, then stop rendering (Note: this requires the latest 3.6-beta for the possibility of specifying the callbacks to widget.setAnimation)
<html>
<script src="../../build/spine-widget.js"></script>
<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
<body>
<center>
<div id="spine-widget" style="margin-bottom: 20px; width: 640px; height: 480px;"></div>
</center>
</body>
<script>
spineWidget = new spine.SpineWidget("spine-widget", {
json: "assets/spineboy.json",
atlas: "assets/spineboy.atlas",
animation: "run",
backgroundColor: "#00000000",
debug: true,
success: function (widget) {
spineWidget.setAnimation("run", {
start: function (entry) {},
interrupt: function (entry) {},
end: function(entry) {},
dispose: function(entry) {},
complete: function(entry) {
spineWidget.pause();
},
event: function(entry) {}
});
}
});
</script>
</body>
</html>
With the current state of WebGL, I'm afraid there's no way to get CPU usage down to 0% when doing continuous rendering. The manual pausing is the best we can offer at the moment.
Thank you for looking into this! I'll try the pausing tip and report back.