Another Post about Draw Calls

Hi Guys,

So, my current UI is using somewhere between 90-280 draw calls. This is for a couple of reasons, many of which leave me dumbfounded, and previous posts have not really answered my questions:

  1. Objects that are off screen (or outside the drawing canvas) still generate draw calls. Is this expected behavior?
  2. Sprites that are part of the same atlas still generate many draw calls. For example, I have a list of 41 portraits, that are masked out by an image. This list generates as much as 9 draw calls.
  3. Each piece of text is a draw call. Are there any plans to do something like what TextMesh Pro does? Or should I just switch to that? Also, that seems very difficult, given that TextMeshPro does not draw to a canvas, so I wouldn’t be able to just attach text mesh pro objects to ui elements
  4. Invisible objects are a draw call. This is true wether I alpha out the Image component or the Canvas Group component. And actually to be honest, this is inconsistent. I’ve seen it where a canvas group alpha set to 0 will remove the draw call, but most of the time it won’t. And most of the time setting the image alpha to 0 has no effect as well.

I am also not having a problem I read about where having UI elements on top of each other is what is creating additional draw calls. I have the same draw calls if i move the elements that are layered on top of each out and separate them as i do when they are on top of each other.

The only thing that absolutely affects DC’s (as is expected) is disabling the game object. But handling a million disabled GO’s would be too difficult to tackle.

Looking forward to some thoughts on the subject.

The bug report is #646032

bump. Is anyone else experiencing these issues?

[quote]

  1. Objects that are off screen (or outside the drawing canvas) still generate draw calls. Is this expected behavior?
    [/quote]Only if a vertex belonging to that mesh is within any camera view frustum, depending on visible layers.

[quote]
2. Sprites that are part of the same atlas still generate many draw calls. For example, I have a list of 41 portraits, that are masked out by an image. This list generates as much as 9 draw calls.
[/quote]They’ll only batch if the materials use the same settings. Sometimes, depth will cause them not to batch as efficiently (for example a sprite on a different atlas is in between). Sprites of different scales might not batch either - but you’ll have to test. Unity5 afaik is ok with different scales.

Additionally, referencing a material in code will cause it to instantiate (create a unique material and a unique draw call). Use .sharedMesh if you want to avoid this. Check during playmode if you have any (instanced) materials.

[quote]
3. Each piece of text is a draw call. Are there any plans to do something like what TextMesh Pro does? Or should I just switch to that? Also, that seems very difficult, given that TextMeshPro does not draw to a canvas, so I wouldn’t be able to just attach text mesh pro objects to ui elements
[/quote]Sounds very wrong really. Are you sure that you have dynamic batching ticked on in player settings at all? TextMeshPro rocks regardless and is simply the best text solution.

[quote]
4. Invisible objects are a draw call. This is true wether I alpha out the Image component or the Canvas Group component. And actually to be honest, this is inconsistent. I’ve seen it where a canvas group alpha set to 0 will remove the draw call, but most of the time it won’t. And most of the time setting the image alpha to 0 has no effect as well.
[/quote]Alpha = 0 is never invisible. It just means it’s still drawn with alpha = 0. To remove it from rendering, disable .renderer or SetActive(false).

1 Like

Thanks for your response.

Ok - that definitely is, and is not, what is happening here. For example, I have a camera that is only set up for showing inventory. To test what you are saying, I set it lightyears (10,000 distance) away from all the other game objects and canvases, etc. This camera is in charge of viewing 1 thing, the inventory canvas. There was a masked out part of the inventory, tipping into the camera. When I moved the inventory further away from the camera, the draw calls went away. But I’ve seen it where this is also not the case, for example, testing the example scenes in the unity 4.6 RC1 project, this did not work.

However, the main UI is a Screen Space Overlay. So the elements that are outside the overlay are not visible to any camera, the main cameras in the game cull out ui elements, and yet i am still being penalized for UI elements outside the canvas’ overlay space.

What if the UI’s images have no material attached to them? Would that break batching? should i place materials on all the images i use in the UI? The default for any button or image is to have no material. I also do not touch these materials in any way.

Yup, I have unity pro, and all batching is clicked. To use TextMeshPro, I’m guessing i’d need to move everything out of being in screen space overlay, and use a camera, right? because screen space overlay does not display objects like TextMeshPro, or sprites, etc.

Well, I’ve done some digging and some experiments, I’ve carefully reconstructed my entire GUI piece by piece and watched what happened to the Draw Call Count as I did it. I thought I’d post my findings here for anyone who is interested:

  1. I had read that overlapping can cause increased draw calls. What I didn’t realize was how finicky the issue of an overlap can be. Some images in my GUI have an invisible buffer, if text is beneath that sliver, even though it’s invisible, I saw as many as 5 increased DC’s. Also, speaking of text, try to keep it on top of everything. Hiding it behind elements makes it go bonkers for some reason.

  2. For whatever reason, moving GUI elements out of the screen overlay space or overlay camera space, does not reduce draw calls. My experiments were not 100% conclusive. Sometimes i saw a decrease, but 95% of the time i did not. So if you have anything sitting on off screen that you like to bring in in an animated fashion, disable/enable it while it’s offscreen. Do a quick test, disable it while it’s off screen to see if it’s saving you anything.

  3. If you built your GUI before RC1, consider rebuilding it

  4. Try to stay away from masked lists. I have to say the whole issue of alpha’d out images still causing draw calls is a big problem. This is not the case in EZ GUI or nGUI. So my image that holds the portrait of the hero? I use a script with an array holding all the portraits. My shop with a list of weapons to buy? That one is still a list. Thankfully performance is not a problem when that is active, because you aren’t playing the game.

  5. Neither Alpha = 0 or Canvas Group Alpha = 0 reduces draw calls. If you want to save a DC, you’ll have to disable the GameObject.

After all this work, I was able to reduce my GUI from 90 Draw Calls to 11 while the main HUD is active.

2 Likes

Hi Drowning Monkeys,

what I’ve just noticed is if you have UI elements grouped within a canvas it increases DCs. Best options would be use only one main canvas, or use empty game objects to group elements. I’ve got all UI assets in one atlas, and I’ve got only one DC for whole UI + one DC for text.

Hope it’ll help!

1 Like

Well, this information in the tutorial project would be nice, or FAQ, or something. Thank you for researching this, and many thanks for posting it. Makes sense now that I read it, but it definitely didn’t seem intuitive (to me.)

1 Like

Setting Canvas Group Alpha to 0 does save draw calls, if you also attach a Canvas to the same GameObject.

Could you post a screen or something of your hierarchy?

It’s something like this:

+ UICanvas
  > Group_1 (empty game object)
    * Group_1_1 (empty game object)
      - Image
      - Image
    * Group_1_2 (empty game object)
      - Image
      - Image
    * Group_1_3 (empty game object)
      - Image
      - Image
  > Group_2 (empty game object)
    * Group_2_1 (empty game object)
      - Image
      - Button (with image)
    * Group_2_2 (empty game object)
      - Image
      - Button (with image)
    * Group_2_3 (empty game object)
      - Image
      - Button (with image)
  > Group_3 (empty game object) [this is where game credits are]
    * Image
    * Image
    * Background
    * Mask
      - Whole text group (Empty game object)
        | Text_1
        | Text_2
        | Text_3
        | Text_4
    * Close button (with image)

I might own you a bit of explanation why I have so many groups. In my game (there are some gifs and pngs on my twitter if you want to take a look) UI is composed of signs on sticks and lines, so I’m using a lot of sliced images, which compose bigger picture. At the same time all of them are being animated (because why not?), and it seemed easier to me to group them and animate them at once.

Add a componet Rectmask2d on screen space overlay canvas could resolve the first question.