Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Shader compiler bug leads to extremely slow alpha-testing on mobile.

Discussion in 'Shaders' started by Arycama, Sep 25, 2019.

  1. Arycama

    Arycama

    Joined:
    May 25, 2014
    Posts:
    183
    I have submitted a bug report already, but am posting this here for other people to discover, and
    incase anyone has any suggestions or someone from Unity can weigh in further.

    I know alpha-testing has a higher performance cost on tile-based mobile GPUs, maybe this is the reason why no one seems to have looked into, or fixed this issue. However, I have been trying to get scenes with lots of foliage running more efficiently on older devices such as a Galaxy S4, and while looking through the compiled shader code for GLES 2/3 I noticed that discard instructions were being replaced with:

    GLES 3:
    Code (CSharp):
    1. if(((int(alpha < _Cutoff) * int(0xffffffffu)))!=0){discard;}
    GLES 2:
    Code (CSharp):
    1. if(((int(alpha < _Cutoff) * -1))!=0){discard;}
    I confirmed that this compiled code is present on device after build using the Snapdragon Profiler. I then wrote a GLSL shader with the same functionality. It was not cross-compiled into the integer operations above, and retained the correct code.

    Code (CSharp):
    1. if (alpha < _Cutoff) discard;
    This turned out to be a huge performance boost. In a screen mostly covered with grass, the FPS on an S4 went from roughly 10fps to above 30.

    Integer operations are much more expensive on Gpus than float operations, conversions and comparisons may take many more cycles than float or simple conditional checks.

    This seems like a big oversight given how common alpha-testing is, and how it is already more expensive than usual on mobile devices. Many existing projects could be losing several FPS if not more purely due to this issue, and as a consequence have probably gone to great lengths to avoid alpha-testing as much as possible.

    Here is a screenshot of the profiler, with the data on the left showing the custom-GLSL shader, and the data on the right showing the cross-compiled HLSL shader. The performance difference is very substantial.

    upload_2019-9-25_15-57-43.png

    Below is the scene in question. (Ignore the FPS, as this was from the editor, but the exact camera angle/position/shader was used on device (Galaxy S4).

    Unity_2019-09-25_15-46-57.png

    The only solution I was able to come up with is using a custom GLSL shader. However this is not practical as it requires always running the editor in -force-glcore mode, or having duplicate GLSL and CG shaders wherever alpha-testing is required. This is not friendly for workflow and is likely to lead to bugs and errors, especially in complex uber-shader setups. (Which is what we use, so there are lots of different shader features within the same shader. Having to duplciate that complicated setup for alpha-tested shaders is a lot of extra work and should not be neccssary)

    Any feedback/discussion/suggestions is welcome. but this is something that should be fixed asap by Unity.

    Bug report link:
    https://fogbugz.unity3d.com/default.asp?1186752_ukog09hgg1v7bv1m
     
    joshuacwilde likes this.
  2. joshuacwilde

    joshuacwilde

    Joined:
    Feb 4, 2018
    Posts:
    725
    Is this gonna get backported to 2019.4?