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

GLSL ES precision specifiers

Discussion in 'Shaders' started by Jimmy Haden, Aug 27, 2010.

  1. Jimmy Haden

    Jimmy Haden

    Joined:
    Aug 17, 2010
    Posts:
    10
    I asked this in the iPhone forum, but thought I'd give it a chance here instead. It seems Unity is setting precision specifiers automatically in GLSL ES shaders with no way of overriding (VERTEX_P as higp, FRAGMENT_P as mediump). This makes it really hard to squeeze out that extra bit of performance (since there is a 2x theoretical throughput between each level according to the SGX specification). Is there any way to manually override this?
     
  2. ReJ

    ReJ

    Unity Technologies

    Joined:
    Nov 1, 2008
    Posts:
    378
    You can redefine VERTEX_P and FRAGMENT_P by simply defining them at the top of your shader file.

    Example:
    Code (csharp):
    1. #define VERTEX_P mediump
    2. #define FRAGMENT_P lowp
     
  3. ChezDoodles

    ChezDoodles

    Joined:
    Sep 13, 2007
    Posts:
    107
    Adding the VERTEX_P and FRAGMENT_P defines produce pink output instead of the regular super-simple textured output normally produced by the shader. Works fine in the editor, but turns pink when run on devices (iPad iPhone4).
    When removing VERTEX_P and FRAGMENT_P, the shader works fine on the devices.
    It makes no difference if I use lowp, normalp or even highp.


    Code (csharp):
    1. Shader "OGLES2_Test" {
    2.   Properties {
    3.     _MainTex ("Base (RGB)", 2D) = "white" {}
    4.   }
    5.   SubShader {
    6.     Tags { "Queue" = "Geometry" }
    7.     Pass {
    8.       GLSLPROGRAM
    9. [COLOR="red"]#define VERTEX_P highp
    10. #define FRAGMENT_P lowp
    11.  [/COLOR]     #ifdef VERTEX
    12.         varying vec2 uv;
    13.         void main() {
    14.           gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    15.           uv = gl_MultiTexCoord0.xy;
    16.         }
    17.       #endif
    18.            
    19.       #ifdef FRAGMENT
    20.         uniform sampler2D _MainTex;
    21.         varying vec2 uv;
    22.            
    23.         void main() {
    24.           gl_FragColor = texture2D(_MainTex, uv);
    25.         }
    26.       #endif
    27.       ENDGLSL
    28.     }
    29.   }
    30. }
    Any ideas?
     
  4. Tct1856

    Tct1856

    Joined:
    Jan 22, 2010
    Posts:
    104
    Pink means, the shader didn't compile, check the logs
     
  5. ChezDoodles

    ChezDoodles

    Joined:
    Sep 13, 2007
    Posts:
    107
    Included is the LOG file (from running on iPhone4, but iPad give the same output).
    Seems like something is wrong with the setup for fragment shader and how VERTEX_P is defined.


    Code (csharp):
    1. GL_APPLE_framebuffer_multisample GL_APPLE_rgb_422 GL_APPLE_texture_format_BGRA8888 GL_APPLE_texture_max_level GL_EXT_blend_minmax GL_EXT_discard_framebuffer GL_EXT_read_format_bgra GL_EXT_shader_texture_lod GL_EXT_texture_filter_anisotropic GL_IMG_read_format GL_IMG_texture_compression_pvrtc GL_OES_depth24 GL_OES_depth_texture GL_OES_fbo_render_mipmap GL_OES_mapbuffer GL_OES_packed_depth_stencil GL_OES_rgb8_rgba8 GL_OES_standard_derivatives GL_OES_texture_float GL_OES_texture_half_float GL_OES_vertex_array_object
    2.  
    3. Creating OpenGLES2.0 graphics device
    4.  
    5. [COLOR="red"]-------- GLSL info log: ERROR: 0:27: 'VERTEX_P' : syntax error syntax error
    6. ERROR: Parser found no code to compile in source strings.
    7. Failed to compile vertex shader [/COLOR]
    8. #define SHADER_API_OGLES20 1
    9. #define tex2D texture2D
    10. #define highp_vec2 highp vec2
    11. #define mediump_vec2 mediump vec2
    12. #define lowp_vec2 lowp vec2
    13. #define highp_vec3 highp vec3
    14. #define mediump_vec3 mediump vec3
    15. #define lowp_vec3 lowp vec3
    16. #define highp_vec4 highp vec4
    17. #define mediump_vec4 mediump vec4
    18. #define lowp_vec4 lowp vec4
    19. #define highp_mat2 highp mat2
    20. #define mediump_mat2 mediump mat2
    21. #define lowp_mat2 lowp mat2
    22. #define highp_mat3 highp mat3
    23. #define mediump_mat3 mediump mat3
    24. #define lowp_mat3 lowp mat3
    25. #define highp_mat4 highp mat4
    26. #define mediump_mat4 mediump mat4
    27. #define lowp_mat4 lowp mat4
    28. #define highp_float highp float
    29. #define mediump_float mediump float
    30. #define lowp_float lowp float
    31. #define gl_ModelViewProjectionMatrix glstate_matrix_mvp
    32. uniform highp_mat4 glstate_matrix_mvp;
    33. #define gl_Vertex _glesVertex
    34. attribute VERTEX_P vec4 _glesVertex;
    35. #define gl_MultiTexCoord0 _glesMultiTexCoord0
    36. attribute VERTEX_P vec4 _glesMultiTexCoord0;
    37. #line 9
    38. #define VERTEX_P highp
    39. #define FRAGMENT_P lowp
    40.      
    41.  
    42. varying VERTEX_P vec2 uv;
    43. void main() {
    44. gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    45. uv = gl_MultiTexCoord0.xy;
    46. }
    47.  
    48. (Filename: /Applications/buildAgent/work/68355d6e5d19d587/Projects/../Runtime/GfxDevice/opengles20/GpuProgramsGLES20.cpp Line: 702)
    49. Unsupported: OGLES2_Test
    50.  

    Have anyone been able to successfully use VERTEX_P and FRAGMENT_P in a OGLES2 shader?
     
  6. Tct1856

    Tct1856

    Joined:
    Jan 22, 2010
    Posts:
    104
    What if you write #define VERTEX_P highp after #ifdef VERTEX and #define FRAGMENT_P lowp after #ifdef FRAGMENT
     
  7. ChezDoodles

    ChezDoodles

    Joined:
    Sep 13, 2007
    Posts:
    107
    Tried that - didn't help.
     
  8. ChezDoodles

    ChezDoodles

    Joined:
    Sep 13, 2007
    Posts:
    107
    I just posted to the iPhone beta list a FIX for those who want to experiment with precision modifiers in their EGLES2 shaders:

    Just include the following right after your GLSLPROGRAM statement, and do not include VERTEX_P nor FRAGMENT_P statements.
    Then, instead of using float, vec2, vec3, vec4, mat2, mat3, mat4 - use the new types instead.
    The shaders will compile and work BOTH in the editor and on the device.

    Without using precision modifiers, my sample scene (4 textures mixed together, vertex lighting-diffuse + separate specular) ran on an iPhone 4 HD at 17FPS with 100% render utilization, 17% tiler utilization according to the OpenGL ES profiler. After reducing the precision where I could (like texture colors, texture mixer values, etc), the same scene now ran at 30FPS, with 61% render utilization and 17% tiler utilization - that is a 2.5x performance increase without touching any shader logic!

    Code (csharp):
    1. #ifdef SHADER_API_OGLES20
    2.         #define _highp_vec2 highp vec2
    3.         #define _mediump_vec2 mediump vec2
    4.         #define _lowp_vec2 lowp vec2
    5.         #define _highp_vec3 highp vec3
    6.         #define _mediump_vec3 mediump vec3
    7.         #define _lowp_vec3 lowp vec3
    8.         #define _highp_vec4 highp vec4
    9.         #define _mediump_vec4 mediump vec4
    10.         #define _lowp_vec4 lowp vec4
    11.         #define _highp_mat2 highp mat2
    12.         #define _mediump_mat2 mediump mat2
    13.         #define _lowp_mat2 lowp mat2
    14.         #define _highp_mat3 highp mat3
    15.         #define _mediump_mat3 mediump mat3
    16.         #define _lowp_mat3 lowp mat3
    17.         #define _highp_mat4 highp mat4
    18.         #define _mediump_mat4 mediump mat4
    19.         #define _lowp_mat4 lowp mat4
    20.         #define _highp_float highp float
    21.         #define _mediump_float mediump float
    22.         #define _lowp_float lowp float
    23. #else
    24.         #define _highp_vec2 vec2
    25.         #define _mediump_vec2 vec2
    26.         #define _lowp_vec2 vec2
    27.         #define _highp_vec3 vec3
    28.         #define _mediump_vec3 vec3
    29.         #define _lowp_vec3 vec3
    30.         #define _highp_vec4 vec4
    31.         #define _mediump_vec4 vec4
    32.         #define _lowp_vec4 vec4
    33.         #define _highp_mat2 mat2
    34.         #define _mediump_mat2 mat2
    35.         #define _lowp_mat2 mat2
    36.         #define _highp_mat3 mat3
    37.         #define _mediump_mat3 mat3
    38.         #define _lowp_mat3 mat3
    39.         #define _highp_mat4 mat4
    40.         #define _mediump_mat4 mat4
    41.         #define _lowp_mat4 mat4
    42.         #define _highp_float float
    43.         #define _mediump_float float
    44.         #define _lowp_float float
    45. #endif
    Ps.
    Credit should really go to the unity devs - this is almost the same set of defines that unity3 adds to your shader code when you define VERTEX_P and FRAGMENT_P - except there is a glitch which makes everything crash.
     
  9. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    I don't see a point in this, because you can define the precision of individual structures. For example, this works:

    Code (csharp):
    1. varying lowp vec2 uv;
    But not having a global way to set precision makes the code quite annoying to read and write. Is there a solution yet? Is this a bug that needs to be reported? This code sample from Apple just causes an error in Unity:

    Code (csharp):
    1. default precision highp;
     
  10. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    Still waiting.
     
  11. Aras

    Aras

    Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,770
    Most of the thread above is not relevant to Unity 3.2 and later (all that HIGH_P stuff etc.).

    So... Jessy, can you post a full shader that is causing problems? :)
     
  12. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    Because of surface shaders?

    It's not a problem with a particular shader. The problem is that I generally want to work at a certain precision, and Unity, as far as I know, forces me to put a precision specifier in front of everything unless I'm good with the defaults, which wastes time and space, because I generally am not. Here's an example where a client had no time to do this stuff in Photoshop, and needed the controls in the shader. Writing "mediump" only once would have been appreciated (this is the first time I had a need for > lowp in the fragment shader):
    Code (csharp):
    1. Shader "Custom/Lightmap Levels + Mirrored Hemispheremap" {
    2.  
    3. Properties {
    4.     _Color ("Main Color", Color) = (1,1,1)
    5.     _LM_OutputBlack ("Shadow Color", Color) = (0,0,0)
    6.     _LM_InputBlack ("Shadows", Range(0,1)) = 0
    7.     _LM_InputWhite ("Highlights", Range(0,1)) = 1
    8.     _LM_Intensity ("Lightmap Intensity", Float) = 1
    9.     _Mixer ("Lightmap Channel Mixer (for reflection)", Color) = (0.222, 0.706, 0.072)
    10.     _ReflectionIntensity ("Reflection Intensity", Float) = 1
    11.     _MainTex ("Base (A=Specular)", 2D) = "white"
    12.     _Hemisphere ("Hemispheremap", 2D) = "black"
    13. }
    14.  
    15. SubShader {Pass {
    16.     GLSLPROGRAM
    17.     varying mediump vec3 lightmapScale, lightmapOffset;
    18.     varying mediump vec2 uv_mainTex, uv_lightmap, uv_hemisphere;
    19.        
    20.     #ifdef VERTEX
    21.     uniform mediump vec4 _MainTex_ST, unity_LightmapST;
    22.     uniform mediump vec3 _Color, _LM_OutputBlack;
    23.     uniform mediump float _LM_Intensity, _LM_InputWhite, _LM_InputBlack;
    24.     void main() {
    25.         gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    26.        
    27.         uv_mainTex = gl_MultiTexCoord0.xy * _MainTex_ST.xy + _MainTex_ST.zw;
    28.         uv_lightmap = gl_MultiTexCoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
    29.         // The same texture coordinates are used,
    30.         // whether the vector points toward or away from camera-forward.  
    31.         uv_hemisphere = reflect(
    32.             normalize((gl_ModelViewMatrix * gl_Vertex).xyz),
    33.             gl_NormalMatrix * gl_Normal
    34.         ).xy * .5 + .5; // Scale+translate to fit in 0-1 texture space.
    35.        
    36.         // Input Levels: (lightmap - _LM_InputBlack) / (_LM_InputWhite - _LM_InputBlack)
    37.         // Output Levels: Input Levels * (_Color * _LM_Intensity - _LM_OutputBlack) + _LM_OutputBlack
    38.         // Refactored for fragment performance, but clamp is necessary there.
    39.         lightmapScale = (_Color * _LM_Intensity - _LM_OutputBlack) / (_LM_InputWhite - _LM_InputBlack);
    40.         lightmapOffset = -_LM_InputBlack * lightmapScale + _LM_OutputBlack;
    41.     }
    42.     #endif
    43.    
    44.     #ifdef FRAGMENT
    45.     uniform mediump sampler2D _MainTex, unity_Lightmap, _Hemisphere;
    46.     uniform mediump vec3 _Mixer, _LM_OutputBlack;
    47.     uniform mediump float _ReflectionIntensity;
    48.     void main() {
    49.         mediump vec4 mainTex_spec = texture2D(_MainTex, uv_mainTex);
    50.         mediump vec3 lightmap = max(
    51.             texture2D(unity_Lightmap, uv_lightmap).rgb * lightmapScale + lightmapOffset, _LM_OutputBlack);
    52.         mediump vec3 reflection = mainTex_spec.a * dot(lightmap, _Mixer) * _ReflectionIntensity
    53.             * texture2D(_Hemisphere, uv_hemisphere).rgb;
    54.         gl_FragColor.rgb = mainTex_spec.rgb * lightmap + reflection;
    55.     }
    56.     #endif
    57.     ENDGLSL
    58. }}
    59.  
    60. }
     
    Last edited: Jun 11, 2012
  13. Aras

    Aras

    Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,770
    No, because we reworked the way we do precision qualifiers in the shaders. Those VERTEX_P etc. macros are gone as far as I remember.


    Ok, so just that I understand it correctly: the problem is that you can't put int "precision float mediump;" (or any other global precision statement) in your own GLSL shaders?

    If that's the case then indeed we should fix it. Did not cross my mind so far since most people just write Cg/HLSL to begin with, instead of GLSL.

    Out of curiosity - why you write in GLSL? To make stuff work on less platforms? :)
     
  14. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    Yes, that's all. I like the way Cg handles precision better, but...

    To ensure stuff works well on the platform that matters. :D The GLSL converter has, in the past, provided unintended results, specifically fixed4 translating to mediump under certain conditions, resulting in performance loss. I would help you make the converter better, by providing bug reports, but the code it provides is not readable without a lot of work, mostly reassigning variable names that make sense and removing redundant lines. Considering people generally come to me for "mobile" or "iOS" shaders, and iOS is the only platform I have been making anything for in my own time, it hasn't been worth it to me to write surface shaders / Cg. The time expense to make sure the GLSL is good is just too great; every source code update requires another translation adventure. With something like what I just posted, it's a better use of my time to write for OpenGL ES 2.0, and then follow up with another SubShader in Cg if necessary. I wish it were not like that. :(
     
    Last edited: Jun 11, 2012
  15. Arkade

    Arkade

    Joined:
    Oct 11, 2012
    Posts:
    654
    Hey, guys. Sorry for waking a sleepy thread but 2 follow-on questions (kinda)...

    1. What became of this (for GLSL code)?
    2. More importantly, how can one set the default GLSL precision specifier from Cg shader?

    Sorry if I've missed an obvious one! I've included "#pragma fragmentoption ARB_precision_hint_fastest" (I thought maybe?) but no precision specifier appears in CgBatchOutput.shader and using PerfHUD ES to see what's running on the Tegra3 (an Ouya), I see "precision highp float;" at the top of the fragment shader.

    Thanks in advance!
    Rupert.
     
  16. Alexey

    Alexey

    Unity Technologies

    Joined:
    May 10, 2010
    Posts:
    1,623
    well, that is way more complicated thingy then you imagine. It is actually an nvidia-endorsed workaround for the bug in their shader compiler (inside drivers). On the other hand - tegra operates on float32 always internally, so there is no slowdown due to using that (apart from needing more registers etc, but you can ignore it for now)
     
  17. Arkade

    Arkade

    Joined:
    Oct 11, 2012
    Posts:
    654
    Hi, @Alexey
    Thanks for the speedy and insightful reply! So the short version: don't worry about that default precision specifier on Tegra? (for now) (right?)

    I'm pretty new to shader writing so extra info like you supplied is gold :) I definitely didn't know that about the Tegra's internally always using float32! To again check I understood, one won't receive a performance benefit from using half/fixed (mediump/lowp) due to it needing to operate at lower precision but (as you hinted) one might get some benefit from the numbers packing better into registers (due to sub-highp consuming less space). Right? Guess I'll continue to 'aim as low as possible' for my variables ;-)

    I have another question on shader performance on Tegra but not related to this thread. Which forum area (or StackExchangey thing?) is best to post to? (the ShaderLab or Android one?)

    Thanks again!
    Rupert.
     
  18. Alexey

    Alexey

    Unity Technologies

    Joined:
    May 10, 2010
    Posts:
    1,623
    >>Guess I'll continue to 'aim as low as possible' for my variables
    well, yes. That will help everyone 8).
    Also, second note - do not forget that this default prec is just default - it wont override your own specifiers.

    >>I have another question on shader performance on Tegra but not related to this thread. Which forum area (or StackExchangey thing?) is best to post to? (the ShaderLab or Android one?)
    well i dunno - pick smth 8)