Search Unity

yield WaitForEndOfFrame GC cost

Discussion in 'Scripting' started by Dafu, Oct 10, 2018.

  1. Dafu

    Dafu

    Joined:
    Aug 22, 2006
    Posts:
    124
    Hello all!

    I need to do some rendering using the Graphics interface after the OnRenderImage() event, see Event Sequence:

    https://docs.unity3d.com/Manual/ExecutionOrder.html

    The only two options I could think of is doing my rendering in:
    Code (CSharp):
    1. OnGUI()
    or after:
    Code (CSharp):
    1. yield WaitForEndOfFrame()
    Both options are not ideal, OnGUI() creates lots of GC garbage (even with an empty implementation), and "yield WaitForEndOfFrame" is creating 40 bytes of garbage due to the required IEnumerator use for "yield" methods.

    I'm obsessed about GC impact on my project. I know 40 bytes is not a big deal, but humour my obsession for a moment, please. My entire project creates no garbage outside of initialization/shutdown code, with the exception of this OnGUI()/WaitForEndOfFrame() issue.

    Is there any other way of catching a render event after OnRenderImage()?

    Thank you.
     
  2. Antony-Blackett

    Antony-Blackett

    Joined:
    Feb 15, 2011
    Posts:
    1,778
    try keeping WaitForEndOfFrame as a static variable and using that instead of creating a new one each time.
     
  3. Dafu

    Dafu

    Joined:
    Aug 22, 2006
    Posts:
    124
    Yes I am doing that already. Here is my current setup:

    Code (CSharp):
    1.  
    2.         private WaitForEndOfFrame mEndOfFrameWait = new WaitForEndOfFrame();
    3.  
    4.         private IEnumerator OnPostRender()
    5.         {
    6.             RenderUser();
    7.  
    8.             // The yield causes some GC cost, 40 bytes in profiler. Not sure how to get around that...
    9.             yield return mEndOfFrameWait;
    10.  
    11.             RenderPixelSurfaces();
    12.         }
    13.  
    Even though I precreate WaitForEndOfFrame and reuse it, and I don't have any variables on the stack in OnPostRender() it still creates 40bytes of garbage. From my understanding this is because the callstack is retained after the "yield" statement and then reused when "yield" returns, the callstack would contain some minimal information including a class reference to mEndOfFrameWait, and thats where the 40 bytes comes from. I don't think there is any way around this with "yield". More on that here:

    https://stackoverflow.com/questions/35360100/how-does-gc-work-with-ienumerator-and-yield
     
  4. Antony-Blackett

    Antony-Blackett

    Joined:
    Feb 15, 2011
    Posts:
    1,778
    There are some assets on the store that are designed to replace coroutines and implement them more efficiently, if those 40 bytes are big issue you could try one of them.
     
  5. Dafu

    Dafu

    Joined:
    Aug 22, 2006
    Posts:
    124
    Interesting, I didn't think it was possible to replace WaitForEndOfFrame() but some assets do indeed claim to have figured it out. I'll dig around. Thank you!