Tasharen Entertainment Forum

Support => NGUI 3 Support => Topic started by: ivomarel on October 03, 2013, 02:16:15 AM

Title: LateUpdate eating away performance
Post by: ivomarel on October 03, 2013, 02:16:15 AM
Hey all,

I'm in a pretty far state of my game, built with Toolkit2D and NGUI (and about 10 other plugins, but I think irrelevant). I noticed my game is slow on many of the lower end mobile devices and when I checked with the profiler, I was surprised to see it was the NGUI LateUpdate method which was causing most of the lag. Upgrading to NGUI 3.0 did not help, in fact, it seems even slower.

Anything that comes to mind right away about what I might have done wrong? Or could there be a million reasons? I can get into more detail but I hope there's an obvious answer ;)

I added a screenshot of the profiler, it seems BetterList`1.Add() is making a lot of calls (17532).

Cheers guys

Title: Re: LateUpdate eating away performance
Post by: ArenMook on October 03, 2013, 04:10:40 AM
Deep profile does not give accurate results. Think of it like this... you have FunctionA that takes 100 ms to execute but only gets called once, and then you have FunctionB that takes 0.001 ms to execute, but it gets called 1000 times.

Math gives us:
100 * 1 = 100 ms to execute FunctionA once
0.001 * 1000 = 1 ms to execute FunctionB 1000 times.

Deep Profile adds X time to each function call. For the sake of this example, let's say it's 10 ms. Now suddenly the math becomes:

(100 + 10) * 1 = 110 ms to execute FunctionA
(0.001 + 10) * 1000 = 10,001 ms to execute FunctionB.

See the problem yet?
Title: Re: LateUpdate eating away performance
Post by: ivomarel on October 03, 2013, 04:16:44 AM
Hey ArenMook,

Thanks for the quick response. I see your point. Unfortunately, as usual, this raises more questions.

So you're saying this number of calls from this method should not influence performance (too much)?
Would there be a better way to test this?

Title: Re: LateUpdate eating away performance
Post by: ArenMook on October 03, 2013, 04:18:53 AM
I suggest having a look at what's causing the geometry to be rebuilt frequently, as that's what's ultimately leading to all those BetterList.Add calls. Frequently changing geometry should be moved to its own panel so that it doesn't affect other widgets.
Title: Re: LateUpdate eating away performance
Post by: nameles01 on October 03, 2013, 04:31:48 AM
Hello Ivo,

We've gained huge increases in performance by properly using the static flag on UIPanels - this will cause the geometry to stop rebuilding.
We're currently using a tween system for our UIPanels that can toggle the UIPanel to static once it stops tweening.

Of course we only apply this if the UIPanel doesn't have any geometry inside that changes normally.

Also be sure to disable panels once you've tweened them out of screen / they are no longer visibile. This will disable any geometry update and rendering.
Title: Re: LateUpdate eating away performance
Post by: ivomarel on October 03, 2013, 04:35:47 AM
Thanks nameles01 and ArenMook!

I am pretty sure it's because I have about 300 buildings in my screen, all with their own UILabel, but all UILabels are placed in the same panel.

The UILabel is only visible when the building is selected (and moves only when the building is moved) and I guess they should all be in separate UIPanels.

I'll give this a try and let you know if it worked.
Title: Re: LateUpdate eating away performance
Post by: nameles01 on October 03, 2013, 05:25:54 AM
I ran a test previously with 2.6.3 and the amount of UIPanels seemed irrelevant. Could've changed of course. Interested in your results.

Edit: I've found that in 3.0.1 the amount of UIPanels used makes a massive difference in performance (fewer=better), when exporting to Flash at least.

Edit2: My results for Flash will conflict yours on mobile - that platform is draw call limited and will always profit from using fewer panels since 1 panel == at least 1 new draw call. Therefore the irrelevancy I noticed in 2.6.3 most likely isn't there for you.
Title: Re: LateUpdate eating away performance
Post by: ivomarel on October 06, 2013, 09:49:26 PM
Hey nameles01, ArenMook, others ;)

Thanks for the extra information - a solution that I found was rather simple. Instead of giving each building it's own label, I move the label around based on which building is selected. Simple enough.

However, I also have some labels that are not only visible when the building is selected. They are visible until the building is tapped ("Tap me")-label. There are about 50 of these and like you said, adding multiple UI-panels will dramatically increase drawcalls. Also, just moving around the map will force the geometry to be rebuilt.

Can someone explain to me this rebuilding of geometry? Toolkit2D doesn't seem to have any issue with moving objects (I'd use Toolkit2D for my labels but I need to use a dynamic font). Is there any way around rebuilding geometry every time the labels move? Or can I use something else than a UIPanel - since they all z-sort together and it's all from the same atlas? Or is the dynamic font actually the cause of my problems?

So many questions, would love to get some answers!

Thanks guys
Title: Re: LateUpdate eating away performance
Post by: ArenMook on October 06, 2013, 09:54:29 PM
The widgets don't draw themselves. The panels are responsible for drawing widgets in an efficient, batched fashion. If widgets move, the geometry the panels created becomes invalid and has to be re-created. This is done by re-filling all the affected widgets, which is not a fast thing to do.

Moving panels is quick and efficient because nothing needs to be rebuilt.
Title: Re: LateUpdate eating away performance
Post by: ivomarel on October 06, 2013, 09:55:41 PM
So why does every panel need to be one drawcall? Or doesn't it?
Title: Re: LateUpdate eating away performance
Post by: ArenMook on October 06, 2013, 09:58:10 PM
Each panel can be 0 or more draw calls. 0 if it has no widgets, 1 if all widgets use the same atlas, 2+ if not. Panels create draw calls as necessary in order to draw the geometry in the correct fashion (in 3.0).
Title: Re: LateUpdate eating away performance
Post by: ivomarel on October 06, 2013, 10:01:14 PM
So for my problem:

I have 50 widgets in my screen (all from the same atlas)
I want to remove one widget without rebuilding all geometry

There is no options besides having multiple panels which leads to 50 drawcalls, even though the widgets are all from the same atlas with the same z-depth?

Title: Re: LateUpdate eating away performance
Post by: ArenMook on October 06, 2013, 10:10:43 PM
That's right. Best thing to do is to disable components you don't have visible. Are all 50 widgets visible and moving at the same time? If not, disable those that aren't.
Title: Re: LateUpdate eating away performance
Post by: ivomarel on October 06, 2013, 10:16:59 PM
Hey ArenMook,

Yes they are all 50 visible at the same time. Does it matter if they are moving? It's only the camera that's moving (zooming/translating - it's an RTS).

If there's no other solution, I might use images instead of text and do this in Toolkit2D.

 

Title: Re: LateUpdate eating away performance
Post by: ArenMook on October 06, 2013, 10:29:46 PM
If they aren't moving, turn the 'static' flag on on your UIPanel that draws them.
Title: Re: LateUpdate eating away performance
Post by: ivomarel on October 06, 2013, 10:38:17 PM
Hey ArenMook,

This does not seem to decrease my drawcalls. Since I'm developing for mobile, 50 extra drawcalls is very expensive. Or am I missing something?

Cheers,

Ivo
Title: Re: LateUpdate eating away performance
Post by: ArenMook on October 06, 2013, 10:39:18 PM
One panel set to static, 50 widgets inside it.
Title: Re: LateUpdate eating away performance
Post by: ivomarel on October 06, 2013, 10:40:45 PM
So I remove on widget and that requires all the geometry of 50 widgets to be rebuilt, correct?

Edit: Remove/move
Title: Re: LateUpdate eating away performance
Post by: ArenMook on October 06, 2013, 11:00:28 PM
Less posting more trying.
Title: Re: LateUpdate eating away performance
Post by: ivomarel on October 07, 2013, 12:09:14 AM
Hey ArenMook,

Fair enough - I guess your great support made me lazy.

So concluding, the edit in my post was actually essential.

Removing a widget is fine, it works fine, even in a static panel.

Moving is a different story as widgets can not scale, rotate or translate while in a static panel.

I can work with this. I'll give every building a widget all in one static UIPanel, which I'll disable on tap, while enabling a separate widget (for only that building) which tweens.

Thanks again ArenMook for the great support!