Search Unity

Watch out with Half precision in old Mobile

Discussion in 'Shaders' started by resetme, Sep 25, 2017.

  1. resetme

    resetme

    Joined:
    Jun 27, 2012
    Posts:
    204
    Want to share this discover i did today.

    Testing our game and leaving the mobile for some minutes playing we found out that many of the texture looks pixelated, bad tilling, blurry and the phone was kinda hot. (the texture quality get worse and worse with time)

    Looking for a solution and moving some code i found out that using Half precision was the problem,
    before all my vars were HALF and now i change like 5% of them to FLOAT and the game is running faster, no more pixelated textures, bad tiling or melting phone (still get hot but it take a lot longer).

    UV coord and deformations the UV where the ones i change back to FLOAT.

    The device i test was nexus 5. those problems never show up in faster devices anyway.

    Just a Tip.
     
  2. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,025
    FYI: some GPUs that are being used in Android devices don't provide support for float in fragment shaders at all, only half and fixed (it's not a requirement to have float in fragment shaders in OpenGL ES 2).
     
  3. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    5,461
    Just one of the many reasons OpenGLES 2.0 needs to die..
     
    hippocoder likes this.
  4. resetme

    resetme

    Joined:
    Jun 27, 2012
    Posts:
    204
    going to do more test with other cellphones we have here at the company, but by now using float in some case have helped a lot.

    Thank you for the input Alek, having unity master giving tips is priceless!
     
  5. Johannski

    Johannski

    Joined:
    Jan 25, 2014
    Posts:
    826
    Hm, very interesting. Just to be clear on that. If I want to target devices from lets say nexus 5 and up, does it make sense to avoid halfs all together? I think I read in the documentation that this is the case for fixed precision values, but I'm not completely sure.
    And what about e.g. color values in the frag shader. I think almost all shaders I write and saw from others use a fixed4 as return value, so whats the best practice here?
     
  6. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,025
    If you're targeting only devices that have OpenGL ES 3 support, you don't need to worry about lack of high precision in fragment shaders, it's a requirement in the standard.
    In general it's best to use the lowest precision possible, since it might positively affect the battery life, frame rate and device temperature. For the colors that end up on the screen, for example, it's enough to use fixed precision. For texture UVs it's usually enough to have half precision.
     
  7. Johannski

    Johannski

    Joined:
    Jan 25, 2014
    Posts:
    826
    Thanks for your reply! That is the rule of thumb I was using for writing my shaders, but then I'm wondering why @resetme had a performance boost when he changed the values to floats again. What is the explanation for that?
     
  8. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,025
    @Johannski it's very hard to say, what exactly caused this, and whether it's specific to the combination of device/driver that was under test or not. It could, for example, have been caused by the shader doing conversions from one precision to another needlessly, or the hardware trying to emulate something it doesn't support. But it's all guesswork :)
     
    yang1128 likes this.
  9. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    For older mobiles, beware of conversion costs. You're probably fine using half or float for vertex but these are bad in frag, fixed is best there.

    But the problems come when converting between float/half to fixed. While float and half are probably the same on some of them, fixed is not, and there's a cost on older hardware.
     
  10. AcidArrow

    AcidArrow

    Joined:
    May 20, 2010
    Posts:
    11,794
    That would be nice, but it seems that when using GL ES 3.0, Unity overrides a lot of the precision choices and does whatever it wants. For example, textures in frag are always lowp, no matter what you write in CG.

    Also, by default it does super weird casts from one precision to another for lightmaps.

    So this:
    Code (csharp):
    1. fixed4 frag(v2f i) : SV_Target
    2. {
    3.    fixed4 c = tex2D(_MainTex, i.uv);
    4.    c.rgb *= DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap, i.lmuv));
    5.    return c;
    6. }
    Becomes this:

    Code (csharp):
    1. void main ()
    2. {
    3.    lowp vec4 c_1;
    4.    lowp vec4 tmpvar_2;
    5.    tmpvar_2 = texture2D (_MainTex, xlv_TEXCOORD0);
    6.    c_1.w = tmpvar_2.w;
    7.    mediump vec4 tmpvar_3;
    8.    tmpvar_3 = texture2D (unity_Lightmap, xlv_TEXCOORD1);
    9.    lowp vec4 color_4;
    10.    color_4 = tmpvar_3;
    11.    mediump vec3 tmpvar_5;
    12.    tmpvar_5 = (2.0 * color_4.xyz);
    13.    c_1.xyz = (tmpvar_2.xyz * tmpvar_5);
    14.    gl_FragData[0] = c_1;
    15. }
    Notice how the lightmap is originally taken as mediump, then is cast to lowp, then is cast to mediump, then is combined with the MainTex in lowp. I don't think there's any valid reason for any of those casts.

    ...
     
    Last edited: Sep 27, 2017
  11. resetme

    resetme

    Joined:
    Jun 27, 2012
    Posts:
    204
    I did more test with older phones and the problem is solved, had all the phones playing for 10 minutes.
    Nexus 5, samsung s6, many old sony xperia.

    The problem was inside the uv rotation and polar coordinates uv effect, after some seconds or minutes the texture quality start pixelating and the tiling become visible, the phone get slower and hotter.

    For example one 128x128 texture that have circular points after 1 minute it start getting pixelated that the circular points transform to rectangles, lol.

    changing the half to float fixed the issues, maybe is related with atan2 and length.
     
  12. FuzzyQuills

    FuzzyQuills

    Joined:
    Jun 8, 2013
    Posts:
    2,871
    Do all these phones use a Mali GPU? It sounds like the texture coordinates themselves are far outside the 0..1 range, and for some reason, if it goes too far out, Mali GPUs will start pixelating stuff.
    I once got this issue with a water distortion shader on my really old Mali-based tablet, the solution is to clam or wrap the coordinates into the 0..1 range. (Being as you're using atan2, you'll want to wrap around to avoid snapping)
    As for the overheating/slowdown, no idea what's going on there.
     
  13. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    FYI you should be doing that for PC too. Even with a full 32 bit float, if you're panning the UVs over time it will eventually start to lose precision and pixelate. Technically even with the wrap you're still going to run into precision issues eventually as the panning motion will start to stutter, and the UV might start to shift, but the wrap should prevent it from pixelating the texture.
     
    cyuxi likes this.
  14. resetme

    resetme

    Joined:
    Jun 27, 2012
    Posts:
    204
    tank you guys, really useful stuff here!
     
  15. cyuxi

    cyuxi

    Joined:
    Apr 21, 2014
    Posts:
    49
    Sorry to bump up.
    Is the proper way of doing the "Wrap" by using "frac"??
    like this:
    float2 _TimeSpeed = (float2((_Uspeed* _Time.g),(_Time.g*_vspeed)));
    float2 _FlowUV1= (i.uv0+ frac(_TimeSpeed*_FlowSpeed));
    fixed4 _Flowmap_var = tex2D(_Flowmap,TRANSFORM_TEX(_FlowUV1, _Flowmap));
    float2 _FlowUV2= (i.uv0+ frac(_TimeSpeed+float2(_Flowmap_var.r,_Flowmap_var.r)*_FlowIntensity));
    fixed4 _Maintex_var = tex2D(_Maintex,TRANSFORM_TEX(_FlowUV2, _Maintex));
     
  16. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Yes.
     
    Beauque and cyuxi like this.