Author Topic: Slow frames when enabling panels with many widgets  (Read 11958 times)

jfperusse

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 3
    • View Profile
Slow frames when enabling panels with many widgets
« on: January 21, 2014, 04:22:56 PM »
Hi,

We are currently using version 3.0.8 f7 and have one performance issue we are not sure how to fix.

The way our menus work is that each menu has its own panel. When we switch between menus (e.g. chapter selection to level selection), we disable the panel object of the previous menu (base object of the menu) and enable the next one.

For our level selection menu, we have about 720 widgets on 4 different pages, for a total of 4440 triangles.

When we display this menu, there is a slow frame which is in part caused by the following calls:

- UIRect.OnEnable -> ... -> UIWidget.CreatePanel -> UIPanel.AddWidget (11.1% of the frame)
- UIRect.OnEnable -> ... -> UIWidget.CreatePanel -> UIPanel.Find (10.0% of the frame)

This is normally calculated on start, but when panels are disabled and enabled again, widgets are dissociated from their parent panel (RemoveFromPanel()).

Is there something wrong in the way we use NGUI? Would it be possible to avoid removing widgets from their panel when they are disabled and enabled again?

Thanks a lot!

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Slow frames when enabling panels with many widgets
« Reply #1 on: January 22, 2014, 02:19:18 AM »
When a widget is enabled it must find its UIPanel parent and notify it that the draw call must be re-created. That's what you're seeing. You're not doing anything wrong, and no you can't keep widgets in their panel. Disabled widgets don't exist from panel's point of view.

jfperusse

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 3
    • View Profile
Re: Slow frames when enabling panels with many widgets
« Reply #2 on: January 24, 2014, 03:23:02 PM »
Well, in our case, most widgets will always have the same parent.

I was thinking of adding a parameter on panels or widgets, something like "rememberParentPanel". The widgets could still call "RemoveFromPanel()", which would clear the actual "panel" pointer. But when looking for the parent later on (when the panel and widgets are enabled again), if we have rememberParentPanel and the panel has been seen before, we could avoid calling FindInParents and simply setting the panel pointer to the last valid value.

Do you see any problem with such a solution?

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Slow frames when enabling panels with many widgets
« Reply #3 on: January 24, 2014, 10:19:00 PM »
Why? Finding a parent is a quick operation. Registering is a bit slower. If you're going down the route of not removing widgets, then make sure that the panel knows how to handle widgets that are disabled and inactive. I can venture a guess and say that this optimization you're trying to do won't yield much, but will instead come and bite you in the ass in a month or two. Be careful with such optimizations.

helmesjo

  • Full Member
  • ***
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 116
    • View Profile
Re: Slow frames when enabling panels with many widgets
« Reply #4 on: April 03, 2014, 02:00:00 AM »
Has there been any improvements on this lately? We are experiencing a noticeable spike when swopping screens. We are still on 3.5.1, waiting for the 3.5.6 update! (+1 for implementing nested scrollview support so quickly after my request! ;) ).

Only found this in 3.5.4 which might help:
  • NEW: Cached buffers are now per-draw call rather than global, reducing memory allocations.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Slow frames when enabling panels with many widgets
« Reply #5 on: April 03, 2014, 09:50:56 PM »
There will always be a spike when you enable a game object widgets as children as those widgets need to find a panel, register with the panel, and -- more costly -- create or update draw calls. I don't think much has changed in the 3.5.X cycle that would affect this.

Nicki

  • Global Moderator
  • Hero Member
  • *****
  • Thank You
  • -Given: 33
  • -Receive: 141
  • Posts: 1,768
    • View Profile
Re: Slow frames when enabling panels with many widgets
« Reply #6 on: April 04, 2014, 02:25:28 AM »
If you really want to remove the lag of registering a new widget, try moving the widget off-screen instead of setting it inactive. I'm not sure it's much of an improvement, but then the references would be kept and it shouldn't spike as much.

blechowski

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 10
    • View Profile
Re: Slow frames when enabling panels with many widgets
« Reply #7 on: April 04, 2014, 05:03:32 AM »
I see a reoccurring performance problem that people have with enabling/disabling widgets.
It seems to be a basic use case for many.
I know that ArenMook has worked on the improvements in this area. Thanks!

@ArenMook
Is there a way to get it even more efficient?
I was thinking of adding a new state to widgets:
Visible/Hidden. It would indicate to Panel whether widget should be drawn, but without clearing any of the references. The less is required to change the better.
Of course when widget becomes Disabled then it also be made Hidden. When becomes Enabled then also Visible. Thus Existing behavior of Enabling/Disabling widgets would not change.
What your thoughts about it? Is there a better way of doing this?
Thanks for your hard work!

Nicki

  • Global Moderator
  • Hero Member
  • *****
  • Thank You
  • -Given: 33
  • -Receive: 141
  • Posts: 1,768
    • View Profile
Re: Slow frames when enabling panels with many widgets
« Reply #8 on: April 04, 2014, 05:16:05 AM »
So, the issue is actually not that the UIPanel keeps or loses the reference, it's that the Panel has another dedicated drawing class (UIDrawCall) which uses the custom geometry that UIpanel supplies and draw stuff on the screen with that. So making UIPanel "lose reference" just means that it doesn't provide the geometry from the given widget.

Each time a new widget needs to be added, the entire geometry from that panel needs to be rebuilt, which takes time. There's no real way around this part, since moving widgets around has the same effect.

Arguably, you can make a certain part of the geometry be drawn as normal but with alpha = 0, so it's not visible, but I'm not sure this is a healthy structure at all.

blechowski

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 10
    • View Profile
Re: Slow frames when enabling panels with many widgets
« Reply #9 on: April 04, 2014, 06:02:33 AM »
Thanks for the reply!

So, the issue is actually not that the UIPanel keeps or loses the reference, it's that the Panel has another dedicated drawing class (UIDrawCall) which uses the custom geometry that UIpanel supplies and draw stuff on the screen with that. So making UIPanel "lose reference" just means that it doesn't provide the geometry from the given widget.
Thanks for explaining. Still I see UIPanel as the one responsible for facilitating this process :)

Each time a new widget needs to be added, the entire geometry from that panel needs to be rebuilt, which takes time. There's no real way around this part, since moving widgets around has the same effect.
I think you are wrong, because when moving a widget, there is a possibility of changing panels, widget position etc., thus the need to rebuilt geometry. But when I simply want to hide the widget and I know that it will not change it's panel/drawcall then the geometry would not have to be rebuilt.

Arguably, you can make a certain part of the geometry be drawn as normal but with alpha = 0, so it's not visible, but I'm not sure this is a healthy structure at all.
I do not know how to solve it internally. Thanks for the pointer.
But why do you think this is not a healthy structure?
For me it is a fixed cost, instead of having big performance problems when enabling, disabling widgets.
This could be a nightmare on mobile. Similar situation is with shaders, that needs to be warmed up before usage.
Unity recognized this problem with shaders and added Shader.WarmupAllShaders, so that we can prevent big perf drops during gameplay:
http://docs.unity3d.com/Documentation/ScriptReference/Shader.WarmupAllShaders.html

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Slow frames when enabling panels with many widgets
« Reply #10 on: April 04, 2014, 10:22:03 PM »
Quote
I think you are wrong, because when moving a widget, there is a possibility of changing panels, widget position etc., thus the need to rebuilt geometry. But when I simply want to hide the widget and I know that it will not change it's panel/drawcall then the geometry would not have to be rebuilt.
It doesn't matter what happens -- whether you change the alpha, color, move the widget, or enable/disable it, either way it will cause the draw call(s) to be rebuilt. This is where the hit lies, and as Nicki pointed out there is no way around it -- custom flag or no custom flag.

helmesjo

  • Full Member
  • ***
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 116
    • View Profile
Re: Slow frames when enabling panels with many widgets
« Reply #11 on: May 21, 2014, 07:16:22 AM »
It doesn't matter what happens -- whether you change the alpha, color, move the widget, or enable/disable it, either way it will cause the draw call(s) to be rebuilt. This is where the hit lies, and as Nicki pointed out there is no way around it -- custom flag or no custom flag.

(sorry for writing in multiple threads, but this is exactly my issue)

Well, did anything special change since NGUI 2.x then? Because this was not an issue back then. As it is now, there is no way around it. Toggling alpha on panels brings in other bugs with clipped child-panels etc., & just moving it "off screen" is not an expandable solution (and kind of a hack).
Not sure why this solution was favoured (or whatever changed), but it breaks the whole principle of Unity. Activating/Deactivating game objects should be the most efficient way of stopping/starting something, ideally changing some flags tops. Adding anything more than minimal calculations in these calls is not a viable solution (you say it's mostly quick operations, but obviously it's still an issue. Disabling/Enabling 500+ widgets should be no problem even on phones).

ShinyMark

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 11
    • View Profile
Re: Slow frames when enabling panels with many widgets
« Reply #12 on: May 21, 2014, 09:41:17 AM »
This is an issue in our game as well on NGUI 3.5.7. At the root of every UI pop-up the player sees is a panel. Usually only 1 or 2 are visible at a time. We enable/disable the root of these panel/widget hierarchies to toggle visibility state.

When enabling one of these panels there is a huge spike on the CPU and many mono heap allocations. When enabled, our in-game store (simply sprites, buttons and text labels) causes a 1 to 2 megabyte mono heap allocation to occur. Our code doesn't allocate anything when this happens, it's just a gameobject.setactive operation. This isn't something that happens only once when the store is instantiated; it happens every time the user opens it.

In almost all of our panels the order of widgets never changes and no widgets are added at runtime to the prefab the UI was instantiated from. This seems like a common use case and something that should be fast.

I guess we can refactor the code to never disable these panels and just move them off camera when they shouldn't be visible but I agree with a previous poster... that solution seems like a hack.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Slow frames when enabling panels with many widgets
« Reply #13 on: May 21, 2014, 12:13:03 PM »
Quote
Toggling alpha on panels brings in other bugs
Can you elaborate on that, and is it something related to http://www.tasharen.com/forum/index.php?topic=9442.msg45270#msg45270 ?

helmesjo

  • Full Member
  • ***
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 116
    • View Profile
Re: Slow frames when enabling panels with many widgets
« Reply #14 on: May 21, 2014, 02:42:39 PM »
Can you elaborate on that, and is it something related to http://www.tasharen.com/forum/index.php?topic=9442.msg45270#msg45270 ?

Actually, I don't have that setup anymore, but it was kinda like this:

- Panel A
-- ScrollView A (Soft Clipping)
--- Widgets

Setting the alpha of Panel A to 0 on start (I think), and then back to 1 later on will cause the panel to not render until dragged. I also noticed some issues when having nested panels and dragging the alpha back and forth quickly (widgets in nested panels would sometimes not draw until panel dragged). There was also issues when fiffling with a widget (Swop Panel A for a widget). There was some issues with the clipped widgets (in ScrollView A) not being set to "Not Visible" even though they where outside the clipping-area.

I think if you just setup a simple inception-scene (nested panels & widgets in a few different combinations), you'll find most of the bugs mentioned above.

Also, if both panels in the example above is set to soft clipping, Panel A will not set ScrollView A (the child panel) to "not visible" even though it's being clipped by Panel A. Obviously this is a special-case because of the new support of nested panels, but it should also hide child-panels for efficiency.

Edit. The fix you linked did not work for the case of:

- Widget
-- Panel A (soft clip)
--- Panel B (constrained)

Setting the Widget.alpha = 0f; at start, then swopping it to 1 later will cause Panel B to draw nothing until refreshed (dragged in my case).
« Last Edit: May 21, 2014, 05:15:29 PM by helmesjo »