Force to use highp local variables in fragment shader on Android

Hello, I am using Unity 2020.1.0f1 and I need to get precise height data in fragment shader on Android.
This is necessary in order to draw beautiful elevation lines.

My shader (I’ve just simply modify and copy URP graph shader):

Shader "Unlit Master"
{
    Properties
    {
        [NoScaleOffset]SurfaceHeightfield("SurfaceHeightfield", 2D) = "black" {}
    }
    SubShader
    {
        Tags
        {
            "RenderPipeline"="UniversalPipeline"
            "RenderType"="Opaque"
            "Queue"="Geometry+0"
        }
       
        Pass
        {
            Name "Pass"
            Tags
            {
                // LightMode: <None>
            }
          
            // Render State
            Blend One Zero, One Zero
            Cull Back
            ZTest LEqual
            ZWrite On
            // ColorMask: <None>
           
       
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
       
            // Pragmas
            #pragma prefer_hlslcc gles
            #pragma exclude_renderers d3d11_9x
            #pragma target 3.5
            #pragma multi_compile_fog
            #pragma multi_compile_instancing
          
            // Keywords
            #pragma multi_compile _ LIGHTMAP_ON
            #pragma multi_compile _ DIRLIGHTMAP_COMBINED
            #pragma shader_feature _ _SAMPLE_GI
            // GraphKeywords: <None>
           
            // Defines
            #define ATTRIBUTES_NEED_NORMAL
            #define ATTRIBUTES_NEED_TANGENT
            #define ATTRIBUTES_NEED_TEXCOORD0
            #define VARYINGS_NEED_TEXCOORD0
            #pragma multi_compile_instancing
            #define SHADERPASS_UNLIT
           
            #define PREFER_HALF 0
            #define SHADER_HINT_NICE_QUALITY 1
       
            // Includes
           
            ...
       
            // --------------------------------------------------
            // Graph
       
            // Graph Properties
            CBUFFER_START(UnityPerMaterial)
            CBUFFER_END
            TEXTURE2D_FLOAT(SurfaceHeightfield);
            SAMPLER(samplerSurfaceHeightfield);
            float4 SurfaceHeightfield_TexelSize;
            SAMPLER(SamplerState_Linear_Clamp);
       
            // Graph Vertex
            // GraphVertex: <None>
           
            // Graph Pixel
            struct SurfaceDescriptionInputs
            {
                float4 uv0;
            };
           
            struct SurfaceDescription
            {
                float3 Color;
                float Alpha;
                float AlphaClipThreshold;
            };
           
            SurfaceDescription SurfaceDescriptionFunction(SurfaceDescriptionInputs IN)
            {
                SurfaceDescription surface = (SurfaceDescription)0;

                surface.Color = 
                    SurfaceHeightfield.Sample(SamplerState_Linear_Clamp, IN.uv0);

                surface.Alpha = 1;
                surface.AlphaClipThreshold = 0;

                return surface;
            }
       
           ...

            ENDHLSL
        }

        ...

    }
}

I have added line 57 and 58 by myself:

#define PREFER_HALF 0
#define SHADER_HINT_NICE_QUALITY 1

After I press “compile and show code” and see this in glsl:

...

#ifdef VERTEX
#version 300 es

...

in highp vec3 in_POSITION0;
in highp vec4 in_TEXCOORD0;
out highp vec4 vs_TEXCOORD0;
vec4 u_xlat0;
vec4 u_xlat1;
void main()
{
    u_xlat0.xyz = in_POSITION0.yyy * hlslcc_mtx4x4unity_ObjectToWorld[1].xyz;
    u_xlat0.xyz = hlslcc_mtx4x4unity_ObjectToWorld[0].xyz * in_POSITION0.xxx + u_xlat0.xyz;
    u_xlat0.xyz = hlslcc_mtx4x4unity_ObjectToWorld[2].xyz * in_POSITION0.zzz + u_xlat0.xyz;
    u_xlat0.xyz = u_xlat0.xyz + hlslcc_mtx4x4unity_ObjectToWorld[3].xyz;
    u_xlat1 = u_xlat0.yyyy * hlslcc_mtx4x4unity_MatrixVP[1];
    u_xlat1 = hlslcc_mtx4x4unity_MatrixVP[0] * u_xlat0.xxxx + u_xlat1;
    u_xlat0 = hlslcc_mtx4x4unity_MatrixVP[2] * u_xlat0.zzzz + u_xlat1;
    gl_Position = u_xlat0 + hlslcc_mtx4x4unity_MatrixVP[3];
    vs_TEXCOORD0 = in_TEXCOORD0;
    return;
}

#endif
#ifdef FRAGMENT
#version 300 es

precision highp float;
precision highp int;

...

UNITY_LOCATION(0) uniform highp sampler2D SurfaceHeightfield;
in highp vec4 vs_TEXCOORD0;
layout(location = 0) out highp vec4 SV_TARGET0;
mediump vec3 u_xlat10_0;
void main()
{
    u_xlat10_0.xyz = texture(SurfaceHeightfield, vs_TEXCOORD0.xy).xyz;
    SV_TARGET0.xyz = u_xlat10_0.xyz;
    SV_TARGET0.w = 1.0;
    return;
}

#endif

The problem is in line 41 :

mediump vec3 u_xlat10_0;

I need highp here. How can i archive that?

Perhaps #pragma fragmentoption ARB_precision_hint_nicest might do the trick!

Nope, does not work(

Unfortunately, as described here:
https://docs.unity3d.com/Manual/SL-ShaderPrograms.html

Directive “#pragma fragmentoption” deprecated and don’t do anything.

That’s very strange and interesting.

I have replaced line 95, 96 in shader by this:

surface.Color = SAMPLE_TEXTURE2D(SurfaceHeightfield, samplerSurfaceHeightfield, IN.uv0).xyz;

and then, success:

#ifdef FRAGMENT
#version 300 es

...

UNITY_LOCATION(0) uniform highp sampler2D SurfaceHeightfield;
in highp vec4 vs_TEXCOORD0;
layout(location = 0) out highp vec4 SV_TARGET0;
vec3 u_xlat0;
void main()
{
    u_xlat0.xyz = texture(SurfaceHeightfield, vs_TEXCOORD0.xy).xyz;
    SV_TARGET0.xyz = u_xlat0.xyz;
    SV_TARGET0.w = 1.0;
    return;
}

#endif

But if I change this line with (different SamplerState):

surface.Color = SAMPLE_TEXTURE2D(SurfaceHeightfield, SamplerState_Linear_Clamp, IN.uv0).xyz;

Again get precision reduction:

#ifdef FRAGMENT
#version 300 es

...

UNITY_LOCATION(0) uniform highp sampler2D SurfaceHeightfield;
in highp vec4 vs_TEXCOORD0;
layout(location = 0) out highp vec4 SV_TARGET0;
mediump vec3 u_xlat10_0;
void main()
{
    u_xlat10_0.xyz = texture(SurfaceHeightfield, vs_TEXCOORD0.xy).xyz;
    SV_TARGET0.xyz = u_xlat10_0.xyz;
    SV_TARGET0.w = 1.0;
    return;
}

#endif

Why this is happening?

This pragma doesn’t do anything.

Can you please submit a bug report?

Thank you for response!

Here it is:
https://fogbugz.unity3d.com/default.asp?1267645_besf6qcun6cpuf9v

1 Like

Hi!
I finally had time to take a look into this.
There’s two things here: one is that using SamplerState (which has no native counterpart in GLSL) effectively overrides the texture properties with what the SamplerState provides. This includes precision information, so the compiler thinks “no highp needed here”. Another issue is that SamplerState has currently no way to override the precision.
Can you set the texture filtering and clamping behaviour on the texture settings?

Hello! Yes, I already did that.
But this is part of a much larger problem.
Our artists work with Shader Graph, and now I have to convert each of their shaders into code format and make patches. I am a little sad about this situation. (

Why is that?
Is ShaderGraph generating SamplerState stuff?

Yes, ShaderGraph always creates custom SamplerState even if I do not use custom SamplerState ShaderGraph Node.
Plus there is no way to replace TEXTURE2D with TEXTURE2D_FLOAT only manual in code.
Plus there is no way to enable “#define PREFER_HALF 0” using ShaderGraph.

Got it.
I flagged your initial bug report as an improvement to the possible SamplerState overrides.

Do you mind submitting another bug report with these issues for the ShaderGraph area? :slight_smile:

Yeah, of course. I will do it today)

1 Like

Thank you!