Search Unity

Webgl performance and getProgramParameter

Discussion in 'Web' started by DriesVienne, Oct 21, 2020.

  1. DriesVienne

    DriesVienne

    Joined:
    Jun 22, 2013
    Posts:
    27
    Hi,

    Some context:
    In our current project targeting WebGL, we animate a scene with cinemachine camera's and Timeline.
    basically it's a runtime animated movie sequence.

    While testing for performance we report a good framerate,
    but noticed that at certain points, seemingly random., the player would hang for a significant amount of time.
    We also notice that, upon running the sequence a second time, the framedrops are much less significant, and the application runs almost smoothly.
    Naturally we're trying to figure out the cause of this delay, and optimize our build accordingly.

    Profiling the issue gives us clear and consistent output:
    (see image)

    the calls taking up significant amounts of time turn out to be 'getProgramParameter', preceded in the call stack by 'Bind(...)GPUProgramParameters', then 'SwitchProgram'.

    When noticing this issue, and trying to replicate it by running the player subsequent times;
    The time it takes for these calls decrease to such an amount that it's bearely noticable, making it very hard to pinpoint what is going on.

    I do not posses intimate knowledge of WebGl, and speculating could lead us far off track.
    Our questions are as follows:
    • What does this call do in context of our application?
    • What causes it.
    • Can we take actions to prevent this hang?
    I noticed a different thread which is possibly related:
    https://forum.unity.com/threads/wasm-getprogramparameter-freeze.600472/
    but I failed to find the mentioned bug report.

    Any help would be greatly appreciated.

    Greetings,
    Dries.
     

    Attached Files:

  2. jukka_j

    jukka_j

    Unity Technologies

    Joined:
    May 4, 2018
    Posts:
    953
    It is a known issue with web browsers that on Windows compiling shader programs (glLinkProgram) is really slow. This is due to Microsoft provided shader compiler for Direct3D11 (which browsers need to use on Windows) having a lot of performance issues. Microsoft has fixed that for Direct3D12, and in the future WebGPU will allow browsers to avoid this performance hiccup issue. But the web (and Unity) is not there yet unfortunately :(

    Shader compilation will occur on the first time a new object with a new material/shader combo enters the view. It also occurs at page startup time to load in the precompiled shaders, and it occurs if you call Warmup on the Shader Compilation Cache object (that might be URP only, I forget)

    Browsers employ a "shader compilation cache", where when you visit the page the second time, it will have the shaders already compiled, so that the costly MS D3D shader compiler will not need to be invoked. This should work quite well in Chrome on NVidia and AMD GPUs at least. Last time I heard Chrome+Intel was a bit problematic, although that was about two years ago, so may have improved considerably.

    One way to avoid this issue is to do one frame long "test renders" with the known offending materials during loading screen (e.g. add the bad object/material in the scene behind a loading screen, and then on the next frame remove it). Or to try to add the known special materials to the precompiled shaders list.

    There is also an ANGLE (Chrome+Firefox) bug about shader compilation being slow specifically when instancing is used. See https://bugs.chromium.org/p/chromium/issues/detail?id=1072132. To probe whether this is the issue, try removing GPU instancing from being used on the Materials.
     
  3. DriesVienne

    DriesVienne

    Joined:
    Jun 22, 2013
    Posts:
    27
    Thank you for the quick reply.

    This information is quite valuable, and directs us how to move forward.
     
  4. kostas-vs

    kostas-vs

    Joined:
    Sep 6, 2014
    Posts:
    4
    To anyone coming across this post, I had the same issue: long hangs of about 1-5 seconds soon after the scene starts, that show up in the Javascript Profiler as getProgramParameter calls.

    The only effective solution from jukka_j's suggestions was to disable instancing in materials.

    Make sure to not have ANY materials with instancing, as leaving even 1-2 of them will result in the aforementioned lags.

    With instancing off, there were no lags, or they were barely noticeable (100-200ms or so).

    Sure, it sucks to be unable to use instancing, but the negative impact in user experience due to the long hangs far outweighs the benefits of instancing.