Author Topic: 3.0 UIPanel Depth/DrawCall Management  (Read 24213 times)

Ferazel

  • Full Member
  • ***
  • Thank You
  • -Given: 1
  • -Receive: 2
  • Posts: 150
    • View Profile
3.0 UIPanel Depth/DrawCall Management
« on: September 24, 2013, 06:03:26 PM »
I started to get my project upgraded to NGUI 3.0, but I'm really concerned with how the UIPanel is breaking up the draw calls per the editor breakdown. In the past I have didn't use the depth of a widget really at all. I had been using the Z position of the widget in order to maintain depth ordering and creating new UIPanels if I needed to sandwich. However, after upgrading I ran into some problems.

UIPanel1
|
---Sprite Depth -1
---Label Depth 0

UIPanel2
|
---Sprite Depth -1
---Sprite Depth 1
---Label Depth 10

Assuming the labels use dynamic fonts, I expect UIPanel1 to be 2 draw calls and I expect UIPanel2 to be 2 draw calls. However, what I seem to be seeing is that the UIPanels are splitting their materials and draw calls on a global level rather than a per panel basis.

If I assign a unique depth to each widget the panels will seem to sort this properly. However, my game UI has a couple hundred widgets and if I have to maintain a unique depth for each widget at a global level it will be a huge PITA. I expected that the UIPanel would sort their draw calls on a per panel analysis of the depth of the widgets.

Is this global depth check a bug or is it intentional?
« Last Edit: September 30, 2013, 03:22:43 PM by Ferazel »

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: 3.0 UIPanel Draw Call Management
« Reply #1 on: September 24, 2013, 06:40:17 PM »
Which panel the widgets are in doesn't matter as much in 3.0. Panels only mean that draw calls will be split up, but the order in which widgets appear is based solely on depth. In your case, you will want to make sure that the depth of widgets on your first panel is lower than on your second (assuming you want one to be in front of the other).

mishaps

  • Jr. Member
  • **
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 65
    • View Profile
Re: 3.0 UIPanel Draw Call Management
« Reply #2 on: September 24, 2013, 07:05:33 PM »
I always work thinking about my panels as dividing my UI. I think it would be more intuitive if optionally you could specify panel-depth that all it's widgets adhered to. That way you always know whatever depth u put widgets on in a panel they won't go above/behind some other panel. 8)

Ferazel

  • Full Member
  • ***
  • Thank You
  • -Given: 1
  • -Receive: 2
  • Posts: 150
    • View Profile
Re: 3.0 UIPanel Draw Call Management
« Reply #3 on: September 24, 2013, 07:28:15 PM »
I'm disappointed that you feel this workflow is better. I hope I can convince you to change this. Or to have you help convince me why this change is an improvement.

From what I'm understanding in order to keep the UI optimized I would need to maintain a spreadsheet of depths for different areas of the UI so that I can make sure that I don't split materials on different depths causing unnecessary draw calls. There could be potentially thousands of widgets in a UI with all of the different dialogs/warnings/tutorials that could appear.

If we have potentially multiple layers of UI visible on the screen at any time. Each layer will need to have its own "depth range" that will need to assigned. Let's say that the dialog range is 200-500. Then on top of this, if there are multiple dialogs that share the dialog depth space, I would need to give each dialog a subset of that range. Otherwise in the Editor they are going to split because there are widgets that might conflict with each panel's atlasing. Then if we need to make a change of moving a chunk of the UI forward or backward in z-space this changing potentially every widget that has been created prior in order to make sure that they still fit in the appropriate z-depth? On top of that there is no multi-widget depth offset and must be done on a per widget basis?

I feel this is a disastrous change and very difficult to manage a UI a complicated as our last game's UI was (50+ dialogs/tutorials/etc.).

Before, I could slap the appropriate widgets into a parented panel. Check the UIPanel to see how many draw calls this panel had only factoring in its children. Adjust any depths internal to the panel and then not have to worry about other panels potentially interfering with this panel's draw calls. If I needed to adjust this panel's Z-Depth I could do it at the transform level and all of the internal widgets would maintain their internal depths.

If you feel that this new depth sorting is better, my recommendation would be as follows:
  • Make each UIPanel manage the draw call for the widgets under it like the prior system. It will not check/compare depths of widgets on other panels.
  • The Transform's Z position still has no impact so people don't get confused about render order there.
  • Add a field to UIPanel that would affect the offset of the children widgets by some depth offset value (like 100 for dialogs).

I BEG you to explain why you feel this new 3.0 UIPanel draw ordering is superior. I understand that you were inundated with support emails from users who didn't understand the old system. However, I feel the new system requires a significant amount of work to maintain and is less flexible to changes.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: 3.0 UIPanel Draw Call Management
« Reply #4 on: September 24, 2013, 08:00:15 PM »
You only have to worry about keeping depths reasonable among the stuff that's visible at the same time. If you have a window-based system like in Starlink, this is not an issue at all, for example -- since there only one window can be shown at a time. I basically didn't even have to alter any depths after upgrading to 3.0.

If you do have several windows that can appear in front of each other, such as I had in the Menu Example that came with NGUI, then it's an issue -- but all you have to do to fix it, is to select the root of one of the windows, and bring it to front via the NGUI menu. That's 4 mouse clicks -- one to select the object, one to open the NGUI menu, third to open the Selection sub-menu, and the last one to choose Bring to Front.

If you need to do this at run-time, you can do the same thing there. NGUITools.BringForward (not sure if it's in the D version, but it's there in the Pro version now at least). Even if it's not, I posted the code for it in another thread. It's basically NGUITools.AdjustDepth followed by NormalizeDepths, the latter of which is optional.

zazery

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 26
    • View Profile
Re: 3.0 UIPanel Draw Call Management
« Reply #5 on: September 26, 2013, 02:35:17 PM »
The new depth-only system works great and I'm glad you moved away from using z-position since it was prone to mistakes. I'm a big fan of the way UIPanels list draw calls to debug and optimize them. I was surprised to see some of my panels being broken up into 5+ draw calls. It turned out NGUI was splitting draw calls with adjacent panels (identical except in position) that weren't on screen.

I could reorder them, however, they are instances of the same prefab and there are panels below and above them. It's easy to bring a group of widgets to the front or back, but not moving them in between other panels without adjusting almost every other panel. In addition, I'm using NGUI as a 2D framework for my card game (a card is composed of ~16 widgets using 6 depths). I move cards between panels such as hand of cards panel that is anchored to the camera and the tabletop beneath it. Each player has a play space on the tabletop, which is a panel (the prefab mentioned earlier). Beneath the tabletop is the table background and above the hand are the menu panels. Moving a card between panels is not an easy task. Normalizing the depth is not an option since it doesn't leave depth space in between panels.

I like using the depth-only system so I wrote a Depth Tool that let's you define an offset for child widgets to start at and then it normalizes them. Simply add the UIDepthOffset script to any game object and enter an offset. Both relative and absolute positioning are supported so you can have nested UIDepthOffset scripts. It can also calculate how much depth is used by the child widgets, but it's not a cheap operation. I also wrote an editor window similar to the Panel Tool to visualize the UIDepthOffset scripts in the scene and added a NGUI menu option to recalculate all depths. I've been using my tool heavily for a day now and it's more intuitive than the old z-position system since it only uses depth.



I would like to see a similar system added to NGUI to manage the depth of groups of widgets like Ferazel recommends. However, I think the offset shouldn't be tied to UIPanel as you may want to do this for nested objects that are part of the same panel.

Ferazel

  • Full Member
  • ***
  • Thank You
  • -Given: 1
  • -Receive: 2
  • Posts: 150
    • View Profile
Re: 3.0 UIPanel Draw Call Management
« Reply #6 on: September 27, 2013, 02:41:40 PM »
I agree that having some information on WHAT is causing the depth conflict on a particular UIPanel would be helpful. I agree with zazery about having a depth management tool. Ideally, it would be a separate window that we could reference that displays the UIPanels and their associated depths and which panels have overlapping depths.

While we're brainstorming about depths. How about a "clean depths" button on the UIPanel that takes all of its children and removes any depth conflicts and may also have a depth offset. When the depths are normalized the lowest depth stays the same (or becomes the start depth value), depths that are the same will become previous used depth +1, empty depths are removed, then each widget's depths are set to be a unique depth on that panel, and we can easily resort the depths of that panel by doing this cleanup with a new start depth value.

Regardless, a global lookup of the depths that each UIPanel gameobject uses would just be helpful to diagnose where these conflicts in depth are occurring.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: 3.0 UIPanel Draw Call Management
« Reply #7 on: September 27, 2013, 06:17:47 PM »
The easiest way to resolve depth conflicts is to bring one panel forward by selecting it then hitting ALT+SHIFT+= to bring it to front. This also normalizes the depths.

Ferazel

  • Full Member
  • ***
  • Thank You
  • -Given: 1
  • -Receive: 2
  • Posts: 150
    • View Profile
Re: 3.0 UIPanel Draw Call Management
« Reply #8 on: September 30, 2013, 01:54:16 PM »
Hi ArenMook,

I'm finally back to work today after a being ill. So I'm slowly getting my UI system converted to the depth system. After a couple hours of converting work to this depth system, I'm still not convinced that this is an improvement.

While the Bring to Front helps at a macro setup level. I still want to stress that this still doesn't bring a comprehensive way of understanding the depths that are out there in the entire global space. Expecting the user to have this understanding is not as easy as it was prior. Previously, we could make assumptions that panels would not interfere with other panels in regards to draw call ordering. In 3.0 the depth space that have to be remembered and organized has increased significantly. For example, I was looking at my 2D UI panels trying to find the UIWidets with unique materials that were assigned depths that would be breaking my draw call batching only to realize that the problem was with panels that I was using in my 3D portion to display text and icons as well as dynamically instantiated effects and labels. :( It's infuriating to say the least and doesn't seem to have a solution.

I am trying to advocate for each UIPanel to have its own localized depths instead of trying to grasp all of the depths at a global level. While this singular depth it's nice in a simple UI like Starlink, most of the time designers are not thinking of us when they design their UIs. I have 2D UIWidgets which have at least 4 layers of overlapping windows (Tint & Highlighting, Base UI, Dialogs, FullScreen). Then these layering systems have conflicts in my 3D UIWidgets just makes it more complicated to manage. In my opinion it doesn't make sense at all that these completely different uses of NGUI would be interfering with each other at a global level.

Is there a workflow process that maybe I'm missing in order to help keep track of all of these panel depths? Is there a way I can make sure that instantiated panels don't interfere with panels that were created via the editor without having to call a line of code after every instantiation?

While it sounds like uGUI uses a more complicated algorithm for determining depth/draw call batching which sounds great. However, this depth issue is still a problem with NGUI as I mentioned above.

For other that might be reading this, how are you handling this change from <3.0? I've seen a couple people having problems with the transition too, but having other people here saying that "yes this is a problem, and it sucks" or "I've mitigated this problem by doing X,Y,Z" would help me out.

Thanks!
« Last Edit: September 30, 2013, 02:19:30 PM by Ferazel »

Nicki

  • Global Moderator
  • Hero Member
  • *****
  • Thank You
  • -Given: 33
  • -Receive: 141
  • Posts: 1,768
    • View Profile
Re: 3.0 UIPanel Draw Call Management
« Reply #9 on: September 30, 2013, 02:45:46 PM »
It takes some getting used to. I've been converting my project and so far, I've gotten around it by defining certain depths for things.

I have a base depth: screens = 0, popups = 50
then I split it up in
background elements 0-9+base
content level 10-19
fonts 20-29
overlay 30-39

and I have to make sure that some times they'll have to overlap because of weird design, but generally that's the rule of thumb.

We also have multiple cameras working so that we can have perspective 3d elements in the otherwise orthogonal 2d menu, so there's another headhache on top of it.

Furthermore, the colliders still work on a z position level, so I still have define constants for z position in the style of the depth positions above.


I love the new way the individual panels show their draw calls, but I wish there was a different window where I could see all panels in that sense. I also would like it to be easier to jump back and forth between the drawcall widget and back to the panel again, so you can quickly fix superfluous draw calls.

Ferazel

  • Full Member
  • ***
  • Thank You
  • -Given: 1
  • -Receive: 2
  • Posts: 150
    • View Profile
Re: 3.0 UIPanel Draw Call Management
« Reply #10 on: September 30, 2013, 03:18:37 PM »
Thanks for the response Nicki.

So basically, you have resorted to taking a spreadsheet approach to organizing the depths. Something that makes it difficult to globally think about.

I think the biggest issue I've had in the conversion is the problem is that I had a workflow of placing panels and then populating those panels knowing full well what order the individual widgets would render. Now I have to do that at a widget level thus 10x the amount of work it is to organize these panels.

For example, my project has the following layers on multiple UICameras and having all of the panels interact is presenting itself as a problem.

- 3D Text/Sprites (these are sprites and labels that are rendered with my 3D scene). These are procedurally instantiated from prefabs. So all prefabs must be updated to use this depth area.
- 2D Elements (happens in a 2D space, but below the UI)
- UI Standard
- Dialog 1 - Dialog Level (informational dialogs, query dialogs, etc.)
- Flying Notification Layer (Things that fly to areas on top of the UI).
- Dialog 2 - Full Screen Pause menu

It's a mess, but it's a complicated UI system for a complicated game. Using the new depth system has been problematic.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: 3.0 UIPanel Depth/DrawCall Management
« Reply #11 on: September 30, 2013, 07:13:21 PM »
You can use this UIPanelInspector.cs file to show all the draw calls instead of only those managed by the panel.

Ferazel

  • Full Member
  • ***
  • Thank You
  • -Given: 1
  • -Receive: 2
  • Posts: 150
    • View Profile
Re: 3.0 UIPanel Depth/DrawCall Management
« Reply #12 on: September 30, 2013, 07:39:20 PM »
Awesome thanks ArenMook! I loaded it up and it looks greatly helpful! I will do some more tests with it tomorrow.

ChrisR

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 33
    • View Profile
Re: 3.0 UIPanel Depth/DrawCall Management
« Reply #13 on: October 01, 2013, 07:26:16 AM »
I hope I won't step on any toes with this, but I'd just to help NGUI improve.

After using the new system for a couple of days, I have to agree with Farazel. While the new system is good in the sense it solves a problem that confused users before, the added effort that is necessary to keep draw calls down is turning out to be a big time consumer. It's harder for me to maintain a clear overview what's going on in the project, and building new UI elements is taking longer because I need to consider all other possible UI elements that are on screen at the same time.

It's also a big problem for dynamic interface elements. Before, I saved out root objects as prefabs (for example, Trading Cards), and we could instantiate these onto any other UI element. Now, we need to take that extra step of using BringForward a specific amount of times to make sure such a system doesn't balloon the draw calls to unacceptable levels. And this amount is dependent on the bit of UI the dynamic UI element will share the screen with. It just becomes confusing to keep track of it.

Making mistakes also impacts us more than before, because performance problems make it harder to test gameplay and code than visual errors.

Ferazels suggested some improvements, and I'd like to echo one in particular:

Quote
  • Make each UIPanel manage the draw call for the widgets under it like the prior system. It will not check/compare depths of widgets on other panels.

The first would solve all the issues that I currently have with the new system and make NGUI better than ever, I would think. :)
« Last Edit: October 01, 2013, 07:47:08 AM by ChrisR »

mishaps

  • Jr. Member
  • **
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 65
    • View Profile
Re: 3.0 UIPanel Depth/DrawCall Management
« Reply #14 on: October 01, 2013, 08:15:40 AM »
I feel if depth was per-UIpanel instead of global it might be more intuitive and easier to manage. Maybe a separate "panel-depth" or something for panels then