Possible fragment optimization for standard URP shaders?

The OutputAlpha() function is called in all standard URP shaders, such as BakedLit:

finalColor.a = OutputAlpha(finalColor.a, _Surface);

Internally, the check to determine if the shader is opaque is not performed conditionally.

half OutputAlpha(half alpha, bool isTransparent)
{
    if (isTransparent)
    {
        return alpha;
    }
    else
    {
        #if defined(_ALPHATEST_ON)
            // Opaque materials should always export an alpha value of 1.0 unless alpha-to-coverage is available
            return IsAlphaToMaskAvailable() ? alpha : 1.0;
        #else
            return 1.0;
        #endif
    }
}

Why does check use the _Surface variable instead of the _SURFACE_TYPE_TRANSPARENT keyword? A little higher in the code, AlphaDiscard (_ALPHATEST_ON keyword) and AlphaModulate (_ALPHAMODULATE_ON keyword) are completely under conditional compilation.

When _Surface=1 is set, the _SURFACE_TYPE_TRANSPARENT keyword is also always enabled.

If we surround this with conditional compilation:

#ifdef _SURFACE_TYPE_TRANSPARENT // or #if defined(_SURFACE_TYPE_TRANSPARENT) || defined(_ALPHATEST_ON)
finalColor.a = OutputAlpha(finalColor.a, _Surface);
#else
finalColor.a = 1.0;
#endif

This will give the following gain (GLES3x):

In the URP sources, I couldn’t find a case where _Surface and _SURFACE_TYPE_TRANSPARENT have different values. The following code is used everywhere. Can anyone clarify the purpose of _Surface?

It is the material property used to toggle on or off the keyword (for shader static branching). It is basically an editor friendly serialized value to toggle that feature.

I wrote above that unlike all other places, there is no conditional compilation (#if) here. Each fragment shader has an extra instruction + multiplication by vec4 instead of vec3.

Now a shader guru should come and say that it’s faster this way :grin:

Yea, I agree with your first post. That is strange that function is like that.

I’ve reviewed the C# section of the URP multiple times, and they always change together.

I really hope someone from the Unity team responds. It’s hard to believe such a simple bug could exist.

If you think this is an oversight, please report a bug.
That said, it’s very unlikely this would have any noticeable impact on the performance.