Search Unity

  1. If you have experience with import & exporting custom (.unitypackage) packages, please help complete a survey (open until May 15, 2024).
    Dismiss Notice
  2. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice

OnGUI call cost

Discussion in 'Immediate Mode GUI (IMGUI)' started by PaulAsh, Jan 24, 2011.

  1. PaulAsh

    PaulAsh

    Joined:
    Nov 29, 2010
    Posts:
    108
    Hello, I'm currently writing a game that involves a lot of interfaces that are contextual to objects. Which means they need to handle the GUI themselves otherwise I'm passing around objects a lot.


    but to the point, OnGUI calls are very costly. even when nothing happens in it, I can disable the object to make the OnGUI not get called. but then the object doesnt get updates. What I would really like is a way to JUST disable the OnGUI call specifically. Right now I use a wrapper script that handles the toggling.
     
  2. PaulAsh

    PaulAsh

    Joined:
    Nov 29, 2010
    Posts:
    108
    This is the solution I came up with at the moment

     
  3. pakfront

    pakfront

    Joined:
    Oct 6, 2010
    Posts:
    551
    Does this really save anything? My understanding was the the cost of OnGUI was due to the fact that it is a message and here you seem to be just sending another message from within OnGUI. So, by my understanding is it should be twice as slow as just using OnGUI(). If I am wrong, please enlighten me.
     
  4. Jaimi

    Jaimi

    Joined:
    Jan 10, 2009
    Posts:
    6,209
    Why not just have a central object manage it all, and have your individual items subscribe/unsubscribe to events on it when needed?
     
  5. Pia

    Pia

    Joined:
    Feb 16, 2009
    Posts:
    78
    You are right, OnGUI() calls are extremely costly, even if the OnGUI() method itself is totally empty. Therefore it is advisable to only have 1 OnGUI() in your whole project. To achieve this you can for example create a class named GUIManager or something like this, which keeps a list of all GUIs in your game and calls OnDraw() (or whatever you want to call them) methods on each of your GUI objects.
     
  6. ScienceFiction

    ScienceFiction

    Joined:
    May 28, 2008
    Posts:
    393
    Or you can avoid OnGUI all together by drawing your GUI in 3D space on a another camera depth. I just tried writing an OnGUI radar script and it takes my project's frame rate from >200fps to about 20fps. Unity really needs to fix this nonsense.
     
  7. pakfront

    pakfront

    Joined:
    Oct 6, 2010
    Posts:
    551
    BTW, I think this is what Jaimi and Pia are referring to. This has probably been covered before, but I've found that a GUIManager class combined with delegates works well. I /think/ it saves on quite a few cycles, but I don't have the profiler to test rigorously.
    Code (csharp):
    1.  
    2. public class GUIManager : MonoBehaviour
    3. {  
    4.     // Delegates for OnGUI draw
    5.     public delegate void DrawGUIHandler();
    6.    
    7.     //declare the event for the delegate
    8.     public static event DrawGUIHandler OnDrawGUI;
    9.  
    10.       //The only OnGUI call you'll need in the whole game
    11.        void OnGUI () {
    12.                 //check against null in case no Draws are registered
    13.         if (OnDrawGUI != null) OnDrawGUI();
    14.        }
    15. }

    Then in anything that need to draw a GUI,
    Code (csharp):
    1.    
    2.      void Awake() {
    3.         GUIManager.OnDrawGUI += new GUIManager.DrawGUIHandler(DrawGUI);
    4.      }
    5.     public void DrawGUI() {
    6.       / /your GUI code here
    7.     }
    8.  
    You can also handle state changes like this
    Code (csharp):
    1.  
    2.     GUIManager.DrawGUIHandler currentDrawGUI;
    3.     void Awake() {
    4.         GUIStateChangeTo(new GUIManager.DrawGUIHandler(DrawGUIA));
    5.     }
    6.    
    7.    
    8.     void GUIStateChangeTo(GUIManager.DrawGUIHandler changeTo) {
    9.         if (currentDrawGUI != null) {
    10.             GUIManager.OnDrawGUI -= currentDrawGUI;
    11.         }
    12.         currentDrawGUI = changeTo;
    13.         GUIManager.OnDrawGUI += currentDrawGUI;    
    14.     }
    15.    
    16.     void DrawGUIA() {
    17.         if (GUI.Button (new Rect ( 100, 110, 100, 20), "Switch To B")) {
    18.             GUIStateChangeTo(new GUIManager.DrawGUIHandler(DrawGUIB) );
    19.                 }
    20.     }
    21.    
    22.     void DrawGUIB() {
    23.         if (GUI.Button (new Rect ( 200, 110, 100, 20), "Switch To A")) {
    24.             GUIStateChangeTo(new GUIManager.DrawGUIHandler(DrawGUIA) );
    25.                 }
    26.     }
    27.  
     
    Last edited: Jan 28, 2011
  8. PaulAsh

    PaulAsh

    Joined:
    Nov 29, 2010
    Posts:
    108
    This is an old thread but Id like to respond to why my method is a saver, The differents is I can disable the GUIWrapper in its owner to prevent the onGUI message from occuring, thus saving the cost when its not active, but allowing the gameobject to control its own GUI without a manager.
     
  9. LarsP

    LarsP

    Joined:
    Mar 7, 2011
    Posts:
    10
    What does "very costly" mean concretely? Let's say in microseconds per call on an iPhone 4?

    Without concrete numbers, it's extremely easy to go way to far in fear based optimization and waste a lot of effort on optimizations that don't actually matter.
     
  10. PaulAsh

    PaulAsh

    Joined:
    Nov 29, 2010
    Posts:
    108
    very costly meaning, EXTREAMLY costly, you should try to limit your OnGUI Calls as much as possible
     
  11. ruudvangaal

    ruudvangaal

    Joined:
    May 15, 2017
    Posts:
    27
    A very old thread but in Unity 2021.3 it's still reasonably costly on my PC. Any use of OnGUI() triggers a call of GUIUtility.BeginGUI() which could take around 0.3ms (on PC, Intel i7). That might not seem much but when aiming for 180Hz for example you only have 5.5ms per frame. Also, even if no work was done in any of the OnGUI() functions it would still take time.

    I fixed it using PaulAsh's idea, where I added a small interface class to let a user define a 'PaintGUI()' function if it used an OnGUI wrapper (which is called by the wrapper class). You can then selectively disable the OnGUI component and the profiler will hopefully be happier.