Search Unity

hlslcc outputs half precision types on metal

Discussion in 'Shaders' started by tibi_fake, May 16, 2019.

  1. tibi_fake

    tibi_fake

    Joined:
    Jul 31, 2018
    Posts:
    7
    hlslcc outputs half precision types on metal and this becomes a problem on iOS.
    Is there a way to disable the force to half option?
    Here is the problem demonstrated:
    Code (CSharp):
    1. /Input:
    2. Texture2D<float4> _MainTex;
    3. SamplerState sampler_MainTex;
    4. float _Asd;
    5. float4 frag (v2f i) : SV_Target
    6. {
    7.     float4 col = _MainTex.Sample(sampler_MainTex, i.uv);
    8.     col = pow(col, _Asd);
    9.     return col * 1000;
    10. }
    11. //Output (notice the u_xlat0 being float)
    12. fragment Mtl_FragmentOut xlatMtlMain(
    13.     constant FGlobals_Type& FGlobals [[ buffer(0) ]],
    14.     sampler sampler_MainTex [[ sampler (0) ]],
    15.     texture2d<half, access::sample > _MainTex [[ texture(0) ]] ,
    16.     Mtl_FragmentIn input [[ stage_in ]])
    17. {
    18.     Mtl_FragmentOut output;
    19.     float4 u_xlat0;
    20.     half4 u_xlat16_0;
    21.     u_xlat16_0 = _MainTex.sample(sampler_MainTex, input.TEXCOORD0.xy);
    22.     u_xlat16_0 = log2(u_xlat16_0);
    23.     u_xlat0 = float4(u_xlat16_0) * float4(FGlobals._Asd);
    24.     u_xlat0 = exp2(u_xlat0);
    25.     output.SV_Target0 = u_xlat0 * float4(1000.0, 1000.0, 1000.0, 1000.0);
    26.     return output;
    27. }
    Code (CSharp):
    1. //Input:
    2. Texture2D<float4> _MainTex;
    3. SamplerState sampler_MainTex;
    4. float _Asd;
    5. float4 frag (v2f i) : SV_Target
    6. {
    7.     float4 col = _MainTex.Sample(sampler_MainTex, i.uv);
    8.     col = pow(col, 4);
    9.     return col * 1000;
    10. }
    11. //Output (notice the u_xlat16_0 being half):
    12. fragment Mtl_FragmentOut xlatMtlMain(
    13.     sampler sampler_MainTex [[ sampler (0) ]],
    14.     texture2d<half, access::sample > _MainTex [[ texture(0) ]] ,
    15.     Mtl_FragmentIn input [[ stage_in ]])
    16. {
    17.     Mtl_FragmentOut output;
    18.     half4 u_xlat16_0;
    19.     u_xlat16_0 = _MainTex.sample(sampler_MainTex, input.TEXCOORD0.xy);
    20.     u_xlat16_0 = u_xlat16_0 * u_xlat16_0;
    21.     u_xlat16_0 = u_xlat16_0 * u_xlat16_0;
    22.     output.SV_Target0 = float4(u_xlat16_0) * float4(1000.0, 1000.0, 1000.0, 1000.0);
    23.     return output;
    24. }
    another one is that sampler2D_float compiles to texture2d<float,..> but Texture2D<float4> compiles to texture2d<half,..>
     
  2. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,023
    If you're talking about this, having the texture as float will fix it.

    And this looks like a bug. Can you please report it? Thanks!
     
  3. tibi_fake

    tibi_fake

    Joined:
    Jul 31, 2018
    Posts:
    7
    Could you do that? I don't have the project any more.
     
  4. MadeFromPolygons

    MadeFromPolygons

    Joined:
    Oct 5, 2013
    Posts:
    3,982
    You can still file a bug report, just without an attached project
     
  5. daxiongmao

    daxiongmao

    Joined:
    Feb 2, 2016
    Posts:
    412
    It seems this might not be fixed yet or I need to update?

    Pointing out key bits


    Code (CSharp):
    1.            Texture2D<float4> _ShadowMapTex;
    2.             SamplerState _ShadowMapSampler;
    returning just the texture read in the fragment shader
    return _ShadowMapTex.Sample(_ShadowMapSampler, shadow_uv).rrrr;
    produces
    Code (CSharp):
    1.     u_xlat10_0 = half(_ShadowMapTex.sample(_ShadowMapSampler, u_xlat0.xy).x);
    2.     output.SV_Target0 = float4(float4(u_xlat10_0));
    If i change the float4 from the texture definition to half4 i get this
    Code (CSharp):
    1.  u_xlat16_1 = _ShadowMapTex.sample(_ShadowMapSampler, u_xlat0.xy).x;
    2.     output.SV_Target0 = float4(half4(u_xlat16_1));
    Doesn't seem to matter, texture sampling is always half on metal.
     
  6. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,023
    @daxiongmao change _ShadowMapSampler to _ShadowMapTexSampler and it should work
     
  7. daxiongmao

    daxiongmao

    Joined:
    Feb 2, 2016
    Posts:
    412
    I renamed my samplerstate to

    Code (CSharp):
    1.          
    2. Texture2D<float4> _ShadowMapTex;
    3. SamplerState _ShadowMapTexSampler;
    4.  
    This was the fragment shader, i removed everything just to test
    Code (CSharp):
    1.              
    2. return _ShadowMapTex.Sample(_ShadowMapTexSampler , shadow_uv).rrrr;
    3.  
    But it still produces
    Code (CSharp):
    1.  
    2. -- Hardware tier variant: Tier 1
    3. -- Fragment shader for "metal":
    4. Set 2D Texture "_ShadowMapTex" to slot 0 sampler slot -1
    5. Shader Disassembly:
    6. #include <metal_stdlib>
    7. #include <metal_texture>
    8. using namespace metal;
    9. #if !(__HAVE_FMA__)
    10. #define fma(a,b,c) ((a) * (b) + (c))
    11. #endif
    12. #ifndef XLT_REMAP_O
    13.     #define XLT_REMAP_O {0, 1, 2, 3, 4, 5, 6, 7}
    14. #endif
    15. constexpr constant uint xlt_remap_o[] = XLT_REMAP_O;
    16. struct Mtl_FragmentIn
    17. {
    18.     float4 TEXCOORD3 [[ user(TEXCOORD3) ]] ;
    19. };
    20. struct Mtl_FragmentOut
    21. {
    22.     float4 SV_Target0 [[ color(xlt_remap_o[0]) ]];
    23. };
    24. fragment Mtl_FragmentOut xlatMtlMain(
    25.     sampler sampler_ShadowMapTexSampler [[ sampler (0) ]],
    26.     texture2d<float, access::sample > _ShadowMapTex [[ texture(0) ]] ,
    27.     Mtl_FragmentIn input [[ stage_in ]])
    28. {
    29.     Mtl_FragmentOut output;
    30.     float2 u_xlat0;
    31.     half u_xlat10_0;
    32.     u_xlat0.xy = input.TEXCOORD3.xy / input.TEXCOORD3.ww;
    33.     u_xlat0.xy = fma(u_xlat0.xy, float2(0.5, 0.5), float2(0.5, 0.5));
    34.     u_xlat0.xy = clamp(u_xlat0.xy, 0.0f, 1.0f);
    35.     u_xlat10_0 = half(_ShadowMapTex.sample(_ShadowMapTexSampler, u_xlat0.xy).x);
    36.     output.SV_Target0 = float4(float4(u_xlat10_0));
    37.     return output;
    38. }
    39.  
    Seems weird a name change might of fixed it? Am i missing something?
    If i don't define the samplerstate i get an error.

    Looking closer at the metal shader it does seem to be setting it to float. Just the actual function is getting converted for some reason.

    I am on Unity 2019.4.3f1 I am going to try the latest to see if anything changes.
     
  8. daxiongmao

    daxiongmao

    Joined:
    Feb 2, 2016
    Posts:
    412
    So I went and looked at this page again more closely and it does mention the naming thing.
    https://docs.unity3d.com/Manual/SL-SamplerStates.html

    But its
    “sampler”+TextureName
    When i name it this way the half restriction is gone.
    But that seems like it defeats the purpose of being able to reuse samplers with textures talked about in the same article.

    Code (CSharp):
    1. Texture2D<float4> _ShadowMapTex;
    2. SamplerState sampler_ShadowMapTex;
    3.  
    Is what seems to work and not force the output of the texture sample to be a half.
     
  9. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,023
    Sorry, I mixed postfix and prefix.

    At the moment it's not possible to specify the precision for a sampler, and a custom sampler overrides precision settings of the texture. We will add this functionality later.
     
  10. daxiongmao

    daxiongmao

    Joined:
    Feb 2, 2016
    Posts:
    412
    Thanks for the help though. Wish it fixed the issue I was seeing.
    Something seems up between pc and ios when reading from the texture. PC its smooth, IOS its blocky almost like nearest filtering is on.

    Actually i think its a hardware thing. And filtering is not supported for that type.
    https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf
     
  11. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,023
    This may well be the case. Try using a different texture format.
    Filtering full float formats is usually not supported on mobile HW - those formats consume a lot of bandwidth and are usually to be avoided.
     
  12. daxiongmao

    daxiongmao

    Joined:
    Feb 2, 2016
    Posts:
    412
    Yep, IOS supports filtering on R32, or RG16 not RG32.