Hello Guest

Author Topic: Understanding draw calls  (Read 15335 times)

dakeese

  • 2D Toolkit
  • Jr. Member
  • *
  • Posts: 50
    • View Profile
Understanding draw calls
« on: January 30, 2013, 12:16:12 am »
I've read in the past (a couple years ago so this probably relates to 3GS era hardware) that you can have up to 10 draw calls per frame before it starts becoming your bottleneck.

So with tk2d, are the following assumptions of mine correct?
  • There is one draw call per frame per sprite collection sheet that has at least one sprite at least partially in the camera frustrum. So tk2d batches all visible sprites of each sprite collection sheet into one mesh, which becomes one draw call.
  • A sprite is on screen if any part of it is in the frustrum of the camera, or if it belongs to a static sprite batcher that has any part of itself within the frustrum.

Does Unity basically take care of all of this for tk2d using its built in dynamic batching? Or does tk2d handle frustrum checks?

One thing I don't understand about Unity's dynamic batching is: doesn't it bog down the CPU for Unity to be checking every single dynamic mesh against the frustrum every frame?  I know older game engines used the VIS system to block out the maps so only a few large blocks had to be checked against the frustrum. Maybe that old method is analogous to occlusion areas in Unity Pro. I'm still not clear on Unity Pro's static batching. How does it decide whether objects are close enough to each other to group together, or does it even bother with separating objects with the same material into multiple groups to prevent the giant group from always being partially visible?

With tk2d, should we be messing with the "static" checkbox at all, or just use the tk2dStaticSpriteBatcher to handle that kind of thing?
« Last Edit: January 30, 2013, 12:42:28 am by dakeese »

unikronsoftware

  • Administrator
  • Hero Member
  • *****
  • Posts: 9709
    • View Profile
Re: Understanding draw calls
« Reply #1 on: January 30, 2013, 08:30:20 am »
Your assumptions are correct. Kinda.
You've ignored what happens when you have more than one sprite collection visible at a time. At this point they are all sorted by Z, and batched according to sprite collection. Eg.
AAA BB AAA = 3 draw calls.
AAAAAA BB = 2 draw calls.
Which is why its always better to group by sprite collection on Z as well, when you can afford to.


About Unity dynamic batching - yes it costs quite a bit on CPU to check this. However, it ends up costing less than multiple draw calls and thus ends up being a win. The batching system tests each sprite, and then puts it into a big buffer to be drawn in one go with other sprites.

Unity Pro's static batching could help, but the static sprite batcher works, does almost the same thing and works in Unity Free too. You also have full control over what gets batched together, and the colliders are merged too, so I would say, in most cases, it would be a win for you to use the static sprite batcher over static batching in Unity.

Draw calls aren't nearly as bad as they used to be... You can have a few more than 10 draw calls on more modern hardware...

dakeese

  • 2D Toolkit
  • Jr. Member
  • *
  • Posts: 50
    • View Profile
Re: Understanding draw calls
« Reply #2 on: January 31, 2013, 02:37:47 am »
That was extremely helpful, thank you!

So when it comes to dynamic sprites, such as enemy characters or particles, we could improve CPU usage potentially by disabling the renderers of groups of sprites that are known to be off screen?  For example, write a component that has a radius value big enough to always encompass all its dynamic sprite children, and check that circle/sphere against the frustrum each LateUpdate to decide whether all its dynamic sprite children's renderers should be enabled or not this frame.

unikronsoftware

  • Administrator
  • Hero Member
  • *****
  • Posts: 9709
    • View Profile
Re: Understanding draw calls
« Reply #3 on: January 31, 2013, 08:29:08 am »
Well just disable the entire gameobject if you can do that, that'll be the most efficient thing to do. Only if you can do it on a group of things at a time though.

fattie

  • 2D Toolkit
  • Full Member
  • *
  • Posts: 106
    • View Profile
Re: Understanding draw calls
« Reply #4 on: February 01, 2013, 09:18:46 am »
"You've ignored what happens when you have more than one sprite collection visible at a time. At this point they are all sorted by Z, and batched according to sprite collection."

Unikron, to be clear ...

I'm wondering, does that go literally by _sprite collection_, or in fact by _atlas_ ?
« Last Edit: February 03, 2013, 09:01:39 am by fattie »

unikronsoftware

  • Administrator
  • Hero Member
  • *****
  • Posts: 9709
    • View Profile
Re: Understanding draw calls
« Reply #5 on: February 01, 2013, 04:58:26 pm »
Its atlases, not sprite collections. Which is why I try to dissuade people from using the multiple atlas feature... :) The whole thing turns into an epic nightmare if you have multiple sprites from differnet sprite collections, each with multiple atlas, all playing animations out of phase with each other...

fattie

  • 2D Toolkit
  • Full Member
  • *
  • Posts: 106
    • View Profile
Re: Understanding draw calls
« Reply #6 on: February 01, 2013, 06:12:44 pm »
Great, thanks for that. That is fantastic information to know, if one is managing memory.

Great stuff...

Madrayken

  • 2D Toolkit
  • Newbie
  • *
  • Posts: 21
    • View Profile
Re: Understanding draw calls
« Reply #7 on: February 03, 2013, 08:59:40 am »
Hmm. So, in a 3D game using sprites for foliage, maybe additive alpha particle effects should be kept separate, and not use 2Dtoolkit, but some other means instead?

unikronsoftware

  • Administrator
  • Hero Member
  • *****
  • Posts: 9709
    • View Profile
Re: Understanding draw calls
« Reply #8 on: February 03, 2013, 12:38:13 pm »
Hmm. So, in a 3D game using sprites for foliage, maybe additive alpha particle effects should be kept separate, and not use 2Dtoolkit, but some other means instead?

No? You'll have the same draw call overhead whatever way you decide to do it. If you're in 3D, and desperately want to keep batching for that and the foliage sprites, why not just use premultiplied alpha - you can mix normal + additive sprites in the same atlas / drawcall that way.

In sprite collection settings, tick "Premultiplied alpha". Switch your material(s) to use a "Premul______" shader from the default "Blend______" shaders. Your sprites should now look identical. Now when you edit individual sprites, there will be an "Additive" tickbox you can tick to make the sprite additive.

Madrayken

  • 2D Toolkit
  • Newbie
  • *
  • Posts: 21
    • View Profile
Re: Understanding draw calls
« Reply #9 on: February 04, 2013, 10:56:08 am »
I'm now using tk2d/PremulVertexColor and it seems to work.

There is a slight issue in that I had adjusted the shaders to use 'Linear' fog (and used the Normal Generation = Normals Only, as suggested elsewhere). This works perfectly if I use a non-PreMul-alpha shader, but leaves a big box if I use premultiplied alpha. Are fog and pre-multiplied alpha incompatible?

unikronsoftware

  • Administrator
  • Hero Member
  • *****
  • Posts: 9709
    • View Profile
Re: Understanding draw calls
« Reply #10 on: February 04, 2013, 10:48:11 pm »
How do you apply fog?
(And why do you have normals on?)

Madrayken

  • 2D Toolkit
  • Newbie
  • *
  • Posts: 21
    • View Profile
Re: Understanding draw calls
« Reply #11 on: February 04, 2013, 11:57:57 pm »
I'm using the default fog in the renderer settings. As for turning on normals, I'm was doing it because I had read this post:

http://unikronsoftware.com/2dtoolkit/forum/index.php?topic=915.0

(Of course the normals are for the lighting, and nothing to do with the fog). I'm just trying to get pre-mult alpha working with fog... and maybe a basic light colour later on (one step at a time).

dakeese

  • 2D Toolkit
  • Jr. Member
  • *
  • Posts: 50
    • View Profile
Re: Understanding draw calls
« Reply #12 on: February 05, 2013, 10:19:57 pm »
Your assumptions are correct. Kinda.
You've ignored what happens when you have more than one sprite collection visible at a time. At this point they are all sorted by Z, and batched according to sprite collection. Eg.
AAA BB AAA = 3 draw calls.
AAAAAA BB = 2 draw calls.
Which is why its always better to group by sprite collection on Z as well, when you can afford to.


About Unity dynamic batching - yes it costs quite a bit on CPU to check this. However, it ends up costing less than multiple draw calls and thus ends up being a win. The batching system tests each sprite, and then puts it into a big buffer to be drawn in one go with other sprites.

Unity Pro's static batching could help, but the static sprite batcher works, does almost the same thing and works in Unity Free too. You also have full control over what gets batched together, and the colliders are merged too, so I would say, in most cases, it would be a win for you to use the static sprite batcher over static batching in Unity.

Draw calls aren't nearly as bad as they used to be... You can have a few more than 10 draw calls on more modern hardware...

Question about the sorting process: is it done in the toolkit code, or does Unity automatically do this for all non-opaque meshes?

Reason I ask is I'm wondering if I mix in opaque meshes that are not toolkit sprites, do I have to somehow force a front to back draw order for them myself to avoid unnecessary pixel draws.

unikronsoftware

  • Administrator
  • Hero Member
  • *****
  • Posts: 9709
    • View Profile
Re: Understanding draw calls
« Reply #13 on: February 05, 2013, 11:05:42 pm »
The sorting is done by Unity. You don't need to do anything.