Metal shader stripping removes fog for some multi_compile combination | Unity 2021.2.8

Seeing very odd behaviour with SSAO and FOG and the use of multi compile.

I have a v basic shader

Shader "SSAO_FOGtest"
{
  SubShader
    { 
        Tags {"RenderPipeline" = "UniversalPipeline" "RenderType"="Opaque" "Queue"="Geometry" }
      
        Pass
        {             
            Name "ForwardLit"

            ZTest LEqual
            Blend One Zero

            HLSLPROGRAM

            #pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE
            #pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS
            #pragma multi_compile_fragment _ _SCREEN_SPACE_OCCLUSION
            #pragma multi_compile_fog

            #pragma vertex cs
            #pragma fragment fs

            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

            struct Attributes
            {
                float3 positionOS   : POSITION;
                half3 normalOS      : NORMAL;
                half4 tangentOS     : TANGENT;
                float2 uv           : TEXCOORD0;
            };

            struct Varyings
            {
                float4 positionWSAndFogFactor   : TEXCOORD1;
                float4 positionCS               : SV_POSITION;
            };

            Varyings cs(Attributes input)
            {
                VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS);
              
                Varyings output;
                output.positionCS = vertexInput.positionCS;
                output.positionWSAndFogFactor = float4(vertexInput.positionWS, ComputeFogFactor(vertexInput.positionCS.z));

                return output;
            }

            half4 fs(Varyings input) : SV_TARGET
            {
                half3 col= MixFog(half3(1,1,1), input.positionWSAndFogFactor.w);
                return half4(col,1);
            }
          
            ENDHLSL
        }
    }
}

And these shader keywords combos

            #pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE
            #pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS
            #pragma multi_compile_fragment _ _SCREEN_SPACE_OCCLUSION
            #pragma multi_compile_fog

When I compile metal shader variants, no variants with both FOG_EXP2 and _SCREEN_SPACE_OCCLUSION set appear, i.e. they are stripped, even though they don’t conflict.

If I remove

#pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE

or

#pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS

Doesn’t matter which. Then recompiling the shader, FOG_EXP2 and SSAO appear in variant combinations that are compiled.

I’m guessing that this is a bug in the Shader Stripping logic, does anyone know if there tend to be issues with Unity incorrectly stripping valid combinations?

This hit me after upgrading and seeing missing shaders due to variants being stripped that are unexpected to be stripped.

(Note changing fog stripping settings in project → graphics doesn’t change the behaviour)

Hi!
Which Unity version are you using?

Hey, sorry I put it in the title but should’ve included it in the post! :slight_smile:

2021.2.8

Are you sure you’re not looking into vertex variants? The SSAO keyword is fragment only.
What do you use to check the variants in the build?

Via the unity shader compiler from the inspector and then checking the code output:

7839570--993705--ubug.gif

To demo the gif, I made a fresh urp project in 2021, copied the OP shader code into a new shader file, compiled the metal version, and inspected the compiled code.

Also just re-noting that this behaviour differs from 2020.3 where there are compiled variants mixing the two keywords.

Hey! I can verify that there is a bug :slight_smile: Fortunately it’s only affecting 2021.2. The fix is incoming.

Thanks for reporting this!

(Edit: Removed broken issue tracker link)

Hit this exact issue this week. Not isolated to Metal, can confirm for D3D and GLES as well so I assume it doesn’t matter which API.

Thanks for the update Juho! I can’t follow that issue tracking link however? :frowning:

7848543--995451--Screenshot 2022-01-28 at 12.38.43.png

Ah, sorry about the broken link. It appears that the public issue tracker entry was removed as I changed the internal bug case to be a backport instead of a bug in the mainline. Not sure how to fix it :frowning:
Anyhow, the bug fix is in the processing and hopefully lands asap. I’ll poke this thread again when I know the exact version.

Nice one! Out of curiosity will the fix land in the URP package, or is it a unity-core fix?

It’s a core fix

Oops, just found this after I submitted the bug report.

For what it’s worth, it doesn’t need some fancy keyword setup to replicate, I think just the existence of 3 more keywords triggers it.

It also has nothing to do with URP. (I’m using built-in)

In the submitted bug report I replicated it just by using the default unlit shader and:

            #pragma multi_compile_fog
            #pragma multi_compile _ A_KEYWORD
            #pragma multi_compile _ OMG_A_KEYWORD
            #pragma multi_compile _ ANOTHER_KEYWORD

Is there any other work around for this besides removing all the multi compiles?

IIRC the bug only shows up if the last multi_compile directive has more than two keywords, including the possible “_”.
Builtin shortcuts such as “multi_compile_fog” are added after the regular ones, which is why the repro by @AcidArrow is also triggering this.

The fix will be in 2021.2.12f1

@Juho_Oravainen

There is also an issue with multi_compile_instancing in Unity versions 2021.2.8 and later. Procedural instancing shader variants are not included in builds. Will this also be fixed in 2021.2.12f1?

Any issues with shader variants missing from the build that started happening around 2021.2.8 is very likely due this same root cause and will be fixed in 2021.2.12f1

any date for that update?

It should be out Feb 16th if the release process goes smoothly.