Author Topic: Solved performance issue, but is there better ?  (Read 8075 times)

Legna

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 25
    • View Profile
Solved performance issue, but is there better ?
« on: January 04, 2013, 01:24:23 PM »
Hello,

I am making a game involving lots of GUI : inventory, stats, skills, stash, merchant, loader and so on.

I hade great performance issue because my moving camera. I solved 25% of this issue by moving my panels in a fake anchor in my scene who where static, not moving and hidden. Each time i need a panel, i change its parent and put it into the main camera anchor to show it after doing weird stuff like removing static and reactivating panel :

Code sample to desactivate my fake panel after moving my window :
  1.                 GameObject.Find("PanelFake").GetComponent<UIPanel>().widgetsAreStatic = true;
  2.                 GameObject.Find("PanelFake").GetComponent<UIPanel>().enabled = false;
  3.  

Even with that, the profiler told me 50% of my CPU usage was consumed by UIPanel.LateUpdate and without vsync, i was caped at 70 fps.

By disabling ingame my fake anchor, i found my fps where going back to 250 fps. So i made 2 method to enable and disable everything inside. This is a raw example (i dont care the time it take, the game is paused when a window is shown) :

  1.         public void enableFakePanel() {
  2.                 GameObject.Find("PanelFake").GetComponent<UIPanel>().enabled = true;
  3.                 GameObject.Find("PanelFake").GetComponent<UIPanel>().widgetsAreStatic = false;
  4.  
  5.                 UISprite[] spriteChilds = GameObject.Find("PanelFake").GetComponentsInChildren<UISprite>();
  6.                 foreach (UISprite child in spriteChilds) {
  7.                                 child.enabled = true;
  8.                 }
  9.                 UIButton[] buttonChilds = GameObject.Find("PanelFake").GetComponentsInChildren<UIButton>();
  10.                 foreach (UIButton child in buttonChilds) {
  11.                                 child.enabled = true;
  12.                 }
  13.                 UILabel[] labelChilds = GameObject.Find("PanelFake").GetComponentsInChildren<UILabel>();
  14.                 foreach (UILabel child in labelChilds) {
  15.                                 child.enabled = true;
  16.                 }
  17.                 UISlicedSprite[] slicedSpriteChilds = GameObject.Find("PanelFake").GetComponentsInChildren<UISlicedSprite>();
  18.                 foreach (UISlicedSprite child in slicedSpriteChilds) {
  19.                                 child.enabled = true;
  20.                 }
  21.                 UIImageButton[] UIImageButtonChilds = GameObject.Find("PanelFake").GetComponentsInChildren<UIImageButton>();
  22.                 foreach (UIImageButton child in UIImageButtonChilds) {
  23.                                 child.enabled = true;
  24.                 }
  25.         }
  26.         public void disableFakePanel() {
  27.                 UISprite[] spriteChilds = GameObject.Find("PanelFake").GetComponentsInChildren<UISprite>();
  28.                 foreach (UISprite child in spriteChilds) {
  29.                                 child.enabled = false;
  30.                 }
  31.                 UIButton[] buttonChilds = GameObject.Find("PanelFake").GetComponentsInChildren<UIButton>();
  32.                 foreach (UIButton child in buttonChilds) {
  33.                                 child.enabled = false;
  34.                 }
  35.                 UILabel[] labelChilds = GameObject.Find("PanelFake").GetComponentsInChildren<UILabel>();
  36.                 foreach (UILabel child in labelChilds) {
  37.                                 child.enabled = false;
  38.                 }
  39.                 UISlicedSprite[] slicedSpriteChilds = GameObject.Find("PanelFake").GetComponentsInChildren<UISlicedSprite>();
  40.                 foreach (UISlicedSprite child in slicedSpriteChilds) {
  41.                                 child.enabled = false;
  42.                 }
  43.                 UIImageButton[] UIImageButtonChilds = GameObject.Find("PanelFake").GetComponentsInChildren<UIImageButton>();
  44.                 foreach (UIImageButton child in UIImageButtonChilds) {
  45.                                 child.enabled = false;
  46.                 }
  47.                 GameObject.Find("PanelFake").GetComponent<UIPanel>().widgetsAreStatic = true;
  48.                 GameObject.Find("PanelFake").GetComponent<UIPanel>().enabled = false;
  49.         }
  50.  

With that piece of code, i'm back to 200 fps. So i gained nearly 3 times of cpu usage with this trick.


So, after all that stuff, my question is : is there a true and clean way to do this in NGUI ? Something who will totally disable the widget and processing inside a panel ?


ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Solved performance issue, but is there better ?
« Reply #1 on: January 04, 2013, 01:27:52 PM »
Ugh. GameObject.Find is bad enough for performance, but you do it MANY times? Why don't you cache the value like so?

GameObject go = GameObject.Find("PanelFake");

When you move something, move panels. Moving widgets, or something else within a panel will cause the entire buffer to be rebuilt, reducing performance significantly. If you have anchors in a panel and you move a camera, that's like moving the anchor -- in other words, things get rebuilt. Get rid of the anchors.

Cripple

  • TNP Alpha
  • Full Member
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 117
    • View Profile
Re: Solved performance issue, but is there better ?
« Reply #2 on: January 04, 2013, 02:24:39 PM »
Can't you just disable the parent ?
Graphicstream Dev.

Legna

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 25
    • View Profile
Re: Solved performance issue, but is there better ?
« Reply #3 on: January 04, 2013, 03:06:27 PM »
Hello,

Thank you for your answers.

As i said, the gameobject.find is only used when i call a window to be shown, and there, i dont really care performance because the timescale is  set to 0 : the game is paused. Of course i use an optimized version, i put here the raw version for reading comprehension.

My main problem is that, when no panel is shown nore moved, with the panels set as static and the uipanel disabled, the UIPanel.Lateupdate still use 70% of my framerate. So my two method give me the 70% back, but i'm sure there is a better way right ?

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Solved performance issue, but is there better ?
« Reply #4 on: January 04, 2013, 08:23:22 PM »
As Cripple said:
  1. NGUITools.SetActive(GameObject.Find("PanelFake"), false);
...to disable, and to enable:
  1. NGUITools.SetActive(GameObject.Find("PanelFake"), true);

Legna

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 25
    • View Profile
Re: Solved performance issue, but is there better ?
« Reply #5 on: January 05, 2013, 06:16:26 AM »
Hello,

I tested with this call, but the results are the same :



On profiler with this method, this is what the comsumption is  :



When i use my method who disable every single item in it i obtain :



Here's an example of panels i put in a static anchor while playing :

« Last Edit: January 05, 2013, 06:25:25 AM by Legna »

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Solved performance issue, but is there better ?
« Reply #6 on: January 05, 2013, 07:23:45 AM »
Eh? That makes no sense. SetActive flat out disables the game object, so nothing underneath it is even active. Your method simply turns off widgets 1 at a time.

The only thing different is the SetActive won't mark the panel as static, so you still have to do that.

Legna

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 25
    • View Profile
Re: Solved performance issue, but is there better ?
« Reply #7 on: January 05, 2013, 07:28:08 AM »
Well,  I ensure you the benchmarks are true and the nguitools disable still consume me three times more resources than doing one by one...

I won't come on this board to lie :0)

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Solved performance issue, but is there better ?
« Reply #8 on: January 05, 2013, 07:30:38 AM »
Try marking the panel as static after you enable the game object.

Legna

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 25
    • View Profile
Re: Solved performance issue, but is there better ?
« Reply #9 on: January 05, 2013, 07:34:45 AM »
I tried this method also (both unity and nguitools static)  with the same performance issue so far.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Solved performance issue, but is there better ?
« Reply #10 on: January 05, 2013, 07:45:06 AM »
Well, then that's simply not possible. I'd look closer at what you are (or aren't) doing there, because all you do is disable widgets one at a time (which can also be done by GetAllComponentsInChildren<UIWidget>() btw), while my suggestion flat out disables the entire game object.

As long as the panel is static, position/rotation/scale checks won't be performed, resulting in no time spent in LateUpdate.

Legna

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 25
    • View Profile
Re: Solved performance issue, but is there better ?
« Reply #11 on: January 05, 2013, 08:04:38 AM »
So long then, I'll stay with my ugly method.

Thank you a lot for your time on my concern.

Cripple

  • TNP Alpha
  • Full Member
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 117
    • View Profile
Re: Solved performance issue, but is there better ?
« Reply #12 on: January 05, 2013, 08:46:57 AM »
Do you use Unity 4 ?

Btw :

Your game looks cool :)
Did your marked your environment objects as static ? On one screen we can see 54 draw calls with only 1 skinned mesh, the UI, some objects and the decor.
« Last Edit: January 05, 2013, 08:54:35 AM by Cripple »
Graphicstream Dev.

Legna

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 25
    • View Profile
Re: Solved performance issue, but is there better ?
« Reply #13 on: January 05, 2013, 09:11:10 AM »
Hello,

Yes i do use unity 4. Actually there is lots of drawcalls, but i am working a lot with Bitgem who sell the dungeons assets and props to improve polycount and drawcall drasticly. But so far, it runs good on Xperia play, S3, Nexus7 and TF201.

Edit : The drawcall is also killed by the texel value in my lightmapping settings, trying to work on it or to found a lightmap optimized so all object with same material uses the same lightmap atlas...

Btw, GetAllComponentsInChildren<UIWidget>() worked great also, thank you ArenMook
« Last Edit: January 05, 2013, 11:38:20 AM by Legna »

Legna

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 25
    • View Profile
Re: Solved performance issue, but is there better ?
« Reply #14 on: January 05, 2013, 09:44:52 AM »
Amazing test, by disabling my anchor and my main panel who have only 50 tris and a bunch of widget, i reach 400 to 600fps...