• Runtimes
  • AS3/Starling lots of draw calls and low performance

Related Discussions
...

EDIT : Quite sure each slot += draw call 😢

I have a single character rendered via the Starling framework.

Yet I have 30 draw calls for a single character even though the texture is packed into an atlas...

No state changes that I am aware of (such as alpha), smoothing set to "none" even set blend mode to "none"
as well, finally no meshes.

Running in release with all the debug code disabled 🙁

On the Nexus10 two characters can reduce the fps from 60 to under 30.

Any ideas?

I have 30 slots in the animation, and it uses 30 draw calls. So my guess is that it is drawing
each slot with a different batch or something?

P.S : I ran Adobe Scout profiler, it looks like the problem is to do with uploading data
to the GPU. But I am using the latest version of Starling, and the draw calls seem way too high.

Also, I am using an xml version of the Texture-Packer and using the StarlingAtlasAttachmentLoader with it.

The FPS overlay that comes with starling, certainly does not rack up the draw call amount 😉

(I was expecting 1 draw call, even on both characters as they share the same atlas, same spine export etc)


I set a breakpoint in "SkeletonSprite::renderMeshes":

private function renderMeshes (support:RenderSupport, alpha:Number) : void {
      if (!batchable) {
         _polygonBatch.begin(support, alpha, blendMode);
         addToBatch(_polygonBatch, support, alpha, null);
         _polygonBatch.end();
      } else if (!_batched) {
      [u][b]   support.popMatrix();[/b][/u]
         _polygonBatch.begin(support, alpha, blendMode);
         addToBatch(_polygonBatch, support, alpha, transformationMatrix);
         for(var i:int = parent.getChildIndex(this) + 1, n:int = parent.numChildren; i < n; ++i) {
            var skeletonSprite:SkeletonSprite = parent.getChildAt(i) as SkeletonSprite;
            if (!skeletonSprite || !skeletonSprite.batchable || skeletonSprite.blendMode != blendMode) break;
            skeletonSprite._batched = true;
            skeletonSprite.addToBatch(_polygonBatch, support, alpha, skeletonSprite.transformationMatrix);
         }
         _polygonBatch.end();
         support.pushMatrix();
         support.transformMatrix(this);
      } else
         _batched = false;
   }

And found that in some-way, batching is disabled.

Could that be responsible for the high draw count?! And if so, how do I solve it.

I'm afraid I don't know enough about the subject to be of any help here 🙁
Nate who is the programmer behind Spine is away this week for a wedding, but I've marked this thread for him so when he is back he will take a look at it and reply as fast as he can. Sorry for the wait 🙁
Hopefully someone else will be able to chip in, in the meantime.

Daniel over on the starling forum is usually really helpful, maybe he will know what causes the high amount of draw calls.

Thank you Shiu,

I will jump over to the Starling forum and see if I can find a answer there in the meantime... 🙂

If it can't be solved, is there a way I can work around having 30 slots in my skeleton? (I assume slots are the core aspect of rendering)

I have considered frame-by-frame exports, but it would be a massive pain and ruin the immersion 🙁

I can't help on this, but in my experience, using Spine + Starling I don't have draw calls issues. If all the animation sprites are in a single SpriteSheet (texture packer for me too) I only have one draw call.

bali33 wrote

I can't help on this, but in my experience, using Spine + Starling I don't have draw calls issues. If all the animation sprites are in a single SpriteSheet (texture packer for me too) I only have one draw call.

Thanks for that, sound's like it could be me all along... xD

Anyhow, I think today I will find out:
[] Does the standard json output have an effect over the xml atlas export
[*] What is causing the "batch" flag to be disabled
[*] If I try some simple characters, will it do the same

Hopefully it is my fault, :rofl:


Well I have removed 2 slots from the skeleton, and the draw calls reduced by 2.

So the slots are relative to the draw calls. Very odd 🙁

I also checked out the example "starling spine boy" animations, and it had a single draw call.

Then I checked the "goblin starling" example, and noticed it had over 20 draw calls.

What is making the goblin have so many draw calls!?!


Just created my own small animation, THREE DRAW CALLS!!?!

Could someone verify that it is drawing three calls per frame? 😃

It has a skin called "TestSkin" that you will need to manually set (we removed the default skin as a test to see if it was the culprit).

It might be related to using an XML file instead of a JSON file. Will need to wait for Nate to look into it.

SOLVED IT! 😃 :rofl:

It was using the following code to create the skeleton:

new SkeletonAnimation(_skeleData, true, _stateData);

The "true" flag I believe forces each slot to be rendered as a mesh, and thus break GPU batching!

If I use:

new SkeletonAnimation(_skeleData, false, _stateData);

It works as expected!

Silly mistake on my end that took over half a day to solve 🙁

Happy it is fixed now though!

Thank you all for the help, I hope to show you some of the Spine animations in the future!

Awesome! thank you for sharing 🙂

5 days later

Ok, but why mesh models have so low performance?

I repeat my question 2 months ago:
viewtopic.php?p=13946#p13946

"I noticed that skeleton with meshes generates quite a lot draw calls (1 draw call per attachment, it doesn't matter that all images are in one atlas). An implementation uses PolygonBatch class, but I don't see too much profit from this way (a similar name to QuadBatch suggests that it will be fast, but it isn't). Any chance for more effecient solution? For example, 1 draw call per atlas, like in version without meshes?"

13 days later
Pancho wrote

Ok, but why mesh models have so low performance?

I repeat my question 2 months ago:
viewtopic.php?p=13946#p13946

"I noticed that skeleton with meshes generates quite a lot draw calls (1 draw call per attachment, it doesn't matter that all images are in one atlas). An implementation uses PolygonBatch class, but I don't see too much profit from this way (a similar name to QuadBatch suggests that it will be fast, but it isn't). Any chance for more effecient solution? For example, 1 draw call per atlas, like in version without meshes?"

I noticed such low performance when rendering skinned meshes with the starling Skeleton from the Spine starling runtime as well. Looking into the issue I was able to get draw calls from 31+ to just 1.

Changed line 176 of SkeletonSprite.as from:

polygonBatch.add(image.texture, worldVertices, verticesLength, uvs, triangles, r, g, b, a, slot.data.additiveBlending, matrix);

to

polygonBatch.add(image.texture.root, worldVertices, verticesLength, uvs, triangles, r, g, b, a, slot.data.additiveBlending, matrix);

When pass sub textures from an atlas like the Spine Starling SkeletonSprite.as class does, the Polygon Batch flushes (uploading to GPU) for each image body part of the character, which is not ideal and results in a separate draw call for each texture/body part. This is because textures derived from an atlas main texture is a SubTexture that simply refers to the root Concrete texture that is the whole sprite sheet. The purpose of using a sprite sheet and batching is to have one draw call and better performance. So by passing the root (Concrete Texture) instead of the SubTexture the texture being passed to the PolygonBatch class never changes and stopped flushing in the middle of batch render calls.

@Nate hopefully this can be added to the official Starling Spine runtime...

Ha! gamebuilders, you are absolutely right. It works awesome, very simple mistake, huge consequences, so programming in a nutshell. 🙂 Thank you very much.

Nate, Shiu, it's a obligatory fix to Starling runtime.

I'll make Nate aware of this. Thanks for the detailed explanation! 🙂

12 days later

@gamebuilders your solution really solve draw batch problem! thank you so much

However after i changed SkeletonSprite.as, when i test goblin-ffd spine animation, i cant spawn many skeletons (tried 10 animations)

I got RangeError: Error #3669: Bad input (at flash.display3D::VertexBuffer3D/uploadFromVector() )

Digging deeper, it seems PolygonBatch.as buffers may be the culprit