Search Unity

Question Shaders gone from 0.6MB in 2019.4.9 to 350MB in 2020.3.12

Discussion in 'Shaders' started by kike_heartful, Jul 29, 2021.

  1. kike_heartful

    kike_heartful

    Joined:
    Apr 18, 2020
    Posts:
    30
    Hi

    We've recently upgraded a project from Unity 2019.4.9 to 2020.3.12, for a future patch.

    After the upgrade, our Windows builds of the game have gone from dedicating 0.6MB of memory to "Shader", to 350MB. In other platforms we've seen it go from 0.6Mb to 540MB.
    This is causing the game to crash on consoles, on which we cannot afford to lose 540MB.

    I've tried to disable every shader debug or log feature, but shaders are still taking the same room.
    We're using addressables, but so did we on 2019. We've created some new groups for the new builds, but not nearly enough to explain a 1000x increament in shader memory usage. No matter how many repeated shaders we have, there's no way we could have gone from 0.6Mb to 350MB, to say nothing of 540MB.
    Still, to verify that was not the problem, I've packed almost all shaders in our game into the addressables' Default group. But it's changed nothing. So it does not seem to be a matter of shaders being replicated hundreds or thousands of times.

    To make sure it's not something we're doing wrong, I've created a new project with just URP imported, and generated a development build for both PC and the console. In both builds, the URP sample scene uses 23MB for shaders alone, with barely anything in there. That's a lot more than the 0.6MB Unity 2019 used for our whole game.

    Can someone at Unity give some insight into what's going on here? I think I'll submit a bug report, once I run some more tests.

    2019.4:
    Shaders_MemoryProfiler_201949.png

    2020.3:
    Shaders_MemoryProfiler_2020312_Win.png

    2020.3 detail of shaders:
    Shaders_MemoryProfiler_2020312_Win_Detail.png
    On the console build, SpeedTree goes from the 33Mb in here to 98MB, and Lit from 73MB to 90MB.
     
    joeee19 likes this.
  2. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,028
    Hi!
    At some point we fixed memory attribution (that is, how we classify where allocated memory belongs) for shaders. Before that, all memory allocations done for shaders would go to "ShaderLab"; after the fix it's showing up for the actual shader.

    To check if that's really the case, you can try upgrading your 2019.4 project to 2019.4.20f1. You should see the same picture as with 2020.3.
     
  3. kike_heartful

    kike_heartful

    Joined:
    Apr 18, 2020
    Posts:
    30
    I don't think that's the case, since there's no "ShaderLab" memory block taking those 540MB on the console's 2019 build, nor 350MB on the 2019 PC build. The 2020 builds are clearly using extra memory, according to the memory captures from Memory Profiler.

    Plus, I can't see how compiled shaders would ever use more memory than all the meshes and textures in the scene.
     
  4. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,028
    Well, this depends on the amount of variants in the included shaders and the target platform.

    You can check the Editor log after you've done a build. It should contain info per shader on how many variants went in and what's the data size before compression.
    Here's an example:
    Code (CSharp):
    1. Compiling shader "Universal Render Pipeline/Lit" pass "ForwardLit" (fp)
    2.     4608 variants, starting stripping...
    3.     finished in 0.01 seconds. 512 variants left
    4.     starting compilation...
    5.     [ 61s] compiled 157 variants
    6.     [122s] compiled 303 variants
    7.     [182s] compiled 483 variants
    8.     finished in 186.06 seconds. Local cache hits 12, remote cache hits 0, compiled 500 variants
    9. ...
    10. Serialized binary data for shader Universal Render Pipeline/Lit in 0.01s
    11.     metal (total internal programs: 576, unique: 574)
    12. Compressed shader 'Universal Render Pipeline/Lit' on metal in 0.23s from 10.30MB to 0.71MB
     
  5. kike_heartful

    kike_heartful

    Joined:
    Apr 18, 2020
    Posts:
    30
    My question is, has this changed so much between 2019 and 2020 for it to make a difference of 2 orders of magnitude? Has URP added thousands of variants to Lit and the SpeedTree shaders?
    Because I don't think that's the case. It looks more like Unity is keeping lots of debug info on every shader, or keeping everything uncompressed in memory all the time, or something in that vein.

    On the console in question, our 2019 builds started gameplay with around 600MB of available memory, and 2020 builds start with less than 200MB, so something is off. And that's memory as reported by the console itself, not Unity's memory profiler.
     
  6. BattleAngelAlita

    BattleAngelAlita

    Joined:
    Nov 20, 2016
    Posts:
    400
    Looks like typical define hell. Did you upgrade URP to newer version too?
     
  7. kike_heartful

    kike_heartful

    Joined:
    Apr 18, 2020
    Posts:
    30
    Yes, we've upgraded from
    "com.unity.render-pipelines.universal": "7.3.1"
    to
    "com.unity.render-pipelines.universal": "10.5.0"

    So do you think something is greedily adding each and every shader variant into the build?
    I finally have the time to check what's going on in more detail, so I'm going to generate a new build and check the log thoroughly.
     
  8. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,028
    Two orders of magnitude are unlikely.
    It's not "each and every variant", but "all possible permutations of multi_compile in the pass + material usage for shader_features", which then gets stripped using IPreprocessShaders interface. If URP added more multi_compile variants between 7.3.1 and 10.5.0, you're likely to get more variants in the build.
     
  9. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,028
    I would still suggest to check the logs - they should contain real data about variants that go into the build.