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

Metal version of shader limits precision to half

Discussion in 'Shaders' started by WillemKokke, Jul 20, 2016.

  1. WillemKokke

    WillemKokke

    Joined:
    Sep 6, 2014
    Posts:
    31
    Unity 5.3.5p8, OSX

    Hi, I have the following shader, which should copy a RenderTexture.Depth to a RenderTexture.RFloat using

    Code (CSharp):
    1. commandBuffer.Blit (new RenderTargetIdentifier(depthTexture), new RenderTargetIdentifier(depthTextureCopy), depthCopyMaterial);
    Code (CSharp):
    1. Shader "Hidden/WKDepthCopy"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex ("Texture", any) = "" {}
    6.     }
    7.  
    8.     SubShader
    9.     {
    10.         Pass
    11.         {
    12.              ZTest Always Cull Off ZWrite Off
    13.  
    14.             CGPROGRAM
    15.             #pragma vertex vert
    16.             #pragma fragment frag
    17.  
    18.             #include "UnityCG.cginc"
    19.  
    20.             sampler2D_float _MainTex;
    21.             uniform float4 _MainTex_ST;
    22.  
    23.             struct appdata_t {
    24.                 float4 vertex : POSITION;
    25.                 float2 texcoord : TEXCOORD0;
    26.             };
    27.  
    28.             struct v2f {
    29.                 float4 vertex : SV_POSITION;
    30.                 float2 texcoord : TEXCOORD0;
    31.             };
    32.  
    33.             v2f vert (appdata_t v)
    34.             {
    35.                 v2f o;
    36.                 o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
    37.                 o.texcoord = TRANSFORM_TEX(v.texcoord.xy, _MainTex);
    38.                 return o;
    39.             }
    40.  
    41.             float4 frag (v2f i) : SV_Target
    42.             {
    43.                 return tex2D(_MainTex, i.texcoord);
    44.             }
    45.             ENDCG
    46.  
    47.         }
    48.     }
    49. }
    This seems to work except for on iOS Metal (iPhone 6s plus) where there is visible banding in my effect due to precision issues.

    When I look at the compiled shader output I get the following for gles, which correctly keeps everything in highp precision:

    Code (CSharp):
    1. #ifdef FRAGMENT
    2.     uniform highp sampler2D _MainTex;
    3.     varying highp vec2 xlv_TEXCOORD0;
    4.     void main ()
    5.     {
    6.       highp vec4 tmpvar_1;
    7.       tmpvar_1 = texture2D (_MainTex, xlv_TEXCOORD0);
    8.       gl_FragData[0] = tmpvar_1;
    9.     }
    10. #endif
    However if I look at the relevant part of the Metal fragment shader I see this:

    Code (CSharp):
    1. struct xlatMtlShaderInput
    2. {
    3.   float2 xlv_TEXCOORD0;
    4. };
    5.  
    6. struct xlatMtlShaderOutput
    7. {
    8.   half4 _glesFragData_0 [[color(0)]];
    9. };
    10.  
    11. struct xlatMtlShaderUniform
    12. {
    13. };
    14.  
    15. fragment xlatMtlShaderOutput xlatMtlMain (xlatMtlShaderInput _mtl_i [[stage_in]], constant xlatMtlShaderUniform& _mtl_u [[buffer(0)]], texture2d<float> _MainTex [[texture(0)]], sampler _mtlsmp__MainTex [[sampler(0)]])
    16. {
    17.   xlatMtlShaderOutput _mtl_o;
    18.   float4 tmpvar_1;
    19.   tmpvar_1 = _MainTex.sample(_mtlsmp__MainTex, (float2)(_mtl_i.xlv_TEXCOORD0));
    20.   _mtl_o._glesFragData_0 = half4(tmpvar_1);
    21.   return _mtl_o;
    22. }
    _glesFragData_0 is declared as half4, and there seems to be nothing I can do about that.

    Does anybody know whether I'm missing something, or is this a bug in the metal shader generation?

    Thanks,
    Willem