Search Unity

Question DX11-specific HLSL syntax (for StructuredBuffers) don't work in surface shaders on android

Discussion in 'Shaders' started by Xtx, May 26, 2021.

  1. Xtx

    Xtx

    Joined:
    May 26, 2017
    Posts:
    6
    I can't get the following code to works on android. I want to use StructuredBuffers in a surface shader.

    I tried a simple test, without StructuredBuffer:

    Code (CSharp):
    1. Shader "Custom/Test"
    2. {
    3.     Properties
    4.     {
    5.         _Color ("Color", Color) = (1,1,1,1)
    6.         _MainTex ("Albedo (RGB)", 2D) = "white" {}
    7.         _Glossiness("Smoothness", Range(0,1)) = 0.5
    8.         _Metallic("Metallic", Range(0,1)) = 0.0
    9.     }
    10.         SubShader
    11.         {
    12.             Tags { "RenderType" = "Opaque" }
    13.             LOD 200
    14.  
    15.             CGPROGRAM
    16.             // Physically based Standard lighting model, and enable shadows on all light types
    17.             #pragma surface surf Standard fullforwardshadows
    18.  
    19.             // Use shader model 3.0 target, to get nicer looking lighting
    20.             #pragma target 5.0
    21.  
    22.         sampler2D _MainTex;
    23.  
    24.         struct Input
    25.         {
    26.             float2 uv_MainTex;
    27.         };
    28.  
    29.         half _Glossiness;
    30.         half _Metallic;
    31.         fixed4 _Color;
    32.  
    33.  
    34.         void surf (Input IN, inout SurfaceOutputStandard o)
    35.         {
    36.             fixed4 c = fixed4(1, 0, 0, 1);
    37.          
    38. #ifdef SHADER_API_D3D11
    39.            c = fixed4(0, 1, 0, 1);
    40. #endif
    41.        
    42.             o.Albedo = c.rgb;
    43.             // Metallic and smoothness come from slider variables
    44.             o.Metallic = _Metallic;
    45.             o.Smoothness = _Glossiness;
    46.             o.Alpha = c.a;
    47.         }
    48.         ENDCG
    49.     }
    50.     FallBack "Diffuse"
    51. }
    In Editor the plane will be blue, but on mobile it remains red.

    Another test:

    Code (CSharp):
    1.  
    2. Shader "Custom/Test2"
    3. {
    4.     Properties
    5.     {
    6.         _Color ("Color", Color) = (1,1,1,1)
    7.         _MainTex ("Albedo (RGB)", 2D) = "white" {}
    8.         _Glossiness("Smoothness", Range(0,1)) = 0.5
    9.         _Metallic("Metallic", Range(0,1)) = 0.0
    10.     }
    11.         SubShader
    12.         {
    13.             Tags { "RenderType" = "Opaque" }
    14.             LOD 200
    15.  
    16.             CGPROGRAM
    17.             // Physically based Standard lighting model, and enable shadows on all light types
    18.             #pragma surface surf Standard fullforwardshadows
    19.  
    20.             // Use shader model 3.0 target, to get nicer looking lighting
    21.             #pragma target 5.0
    22.  
    23. #ifdef SHADER_API_D3D11
    24.             StructuredBuffer<float> test;
    25. #endif
    26.  
    27.         sampler2D _MainTex;
    28.  
    29.         struct Input
    30.         {
    31.             float2 uv_MainTex;
    32.         };
    33.  
    34.         half _Glossiness;
    35.         half _Metallic;
    36.         fixed4 _Color;
    37.  
    38.  
    39.         void surf (Input IN, inout SurfaceOutputStandard o)
    40.         {
    41.             fixed4 c = fixed4(1, 0, 0, 1);
    42.          
    43. #ifdef SHADER_API_D3D11
    44.             if (test[0] == 0)
    45.                 c = fixed4(0, 1, 0, 1);
    46.             else if (test[0] == 1)
    47.                 c = fixed4(0, 0, 1, 1);
    48. #endif
    49.        
    50.             o.Albedo = c.rgb;
    51.             // Metallic and smoothness come from slider variables
    52.             o.Metallic = _Metallic;
    53.             o.Smoothness = _Glossiness;
    54.             o.Alpha = c.a;
    55.         }
    56.         ENDCG
    57.     }
    58.     FallBack "Diffuse"
    59. }
    60.  
    Same problem, in Editor- it will get color green or blue in function of value in StructuredBuffer, but on android it remains red.

    Code (CSharp):
    1.  
    2. public class TestD11Api : MonoBehaviour
    3. {
    4.     float[] buffer;
    5.     ComputeBuffer test;
    6.     // Start is called before the first frame update
    7.     void Start()
    8.     {
    9.         test = new ComputeBuffer(1, sizeof(float));
    10.         buffer = new float[1];
    11.         buffer[0] = 1.0f;
    12.         test.SetData(buffer);
    13.  
    14.         GetComponent<MeshRenderer>().material.SetBuffer("test", test);
    15.  
    16.         Debug.Log("Support compute shaders : " + SystemInfo.supportsComputeShaders);
    17.     }
    18. }
    19.  
    One more thing, the android device is S6 with OpenGL ES 3.2 and support compute shaders. On the other hand if do a vert&frag shader then StructuredBuffer works inclusive on android.

    I tried with 5.0 target model, but I want to use them in 3.5.
     
  2. Xtx

    Xtx

    Joined:
    May 26, 2017
    Posts:
    6
    up
     
  3. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,019
    #ifdef SHADER_API_D3D11 - this line says "Everything between me and the next #else or #endif is for D3D11 only".
    Android doesn't run D3D11.
     
  4. Xtx

    Xtx

    Joined:
    May 26, 2017
    Posts:
    6
    @aleksandrk I was thinking that Unity surface shader's interpreter transforms D3D11 specific HLSL syntax in something that is understandable by target device API, considering that StructuredBuffer works in Unlit shaders on Android.

    So, how can I can get StructuredBuffers to work in surface shaders on Android and iOS? Or if I can't, what alternatives I have for it? I want an array with unknown size before runtime, I have many instances of the same shader with different sizes of array and don't want to waste memory defining all instances with a maximum size and also to manage all the time that maximum manually.
     
  5. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,019
    So, what happens if you remove the
    #ifdef
    s?
     
  6. Xtx

    Xtx

    Joined:
    May 26, 2017
    Posts:
    6
    Code (CSharp):
    1. Shader "Custom/Test2"
    2. {
    3.     Properties
    4.     {
    5.         _Color ("Color", Color) = (1,1,1,1)
    6.         _MainTex ("Albedo (RGB)", 2D) = "white" {}
    7.         _Glossiness("Smoothness", Range(0,1)) = 0.5
    8.         _Metallic("Metallic", Range(0,1)) = 0.0
    9.     }
    10.         SubShader
    11.         {
    12.             Tags { "RenderType" = "Opaque" }
    13.             LOD 200
    14.  
    15.             CGPROGRAM
    16.             // Physically based Standard lighting model, and enable shadows on all light types
    17.             #pragma surface surf Standard fullforwardshadows
    18.  
    19.             // Use shader model 3.0 target, to get nicer looking lighting
    20.             #pragma target 5.0
    21.  
    22. //#ifdef SHADER_API_D3D11
    23.             StructuredBuffer<float> test;
    24. //#endif
    25.  
    26.         sampler2D _MainTex;
    27.  
    28.         struct Input
    29.         {
    30.             float2 uv_MainTex;
    31.         };
    32.  
    33.         half _Glossiness;
    34.         half _Metallic;
    35.         fixed4 _Color;
    36.  
    37.  
    38.         void surf (Input IN, inout SurfaceOutputStandard o)
    39.         {
    40.             fixed4 c = fixed4(1, 0, 0, 1);
    41.            
    42. //#ifdef SHADER_API_D3D11
    43.             if (test[0] == 0)
    44.                 c = fixed4(0, 1, 0, 1);
    45.             else if (test[0] == 1)
    46.                 c = fixed4(0, 0, 1, 1);
    47. //#endif
    48.        
    49.             o.Albedo = c.rgb;
    50.             // Metallic and smoothness come from slider variables
    51.             o.Metallic = _Metallic;
    52.             o.Smoothness = _Glossiness;
    53.             o.Alpha = c.a;
    54.         }
    55.         ENDCG
    56.     }
    57.     FallBack "Diffuse"
    58. }
    59.  
    Gives me this error: Shader error in 'Custom/Test2': Unexpected identifier "StructuredBuffer". Expected one of: typedef const void inline uniform nointerpolation extern shared static volatile row_major column_major struct or a user-defined type at line 23

     
  7. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,019
    Ah, got it :)
    You can try to wrap it in
    #if !SHADER_TARGET_SURFACE_ANALYSIS
    instead of
    #ifdef SHADER_API_D3D11
    .
     
  8. Xtx

    Xtx

    Joined:
    May 26, 2017
    Posts:
    6
    Yes, it works. Thank you! :)

    Can you explain what it does? I haven't found this anywhere in docs.
     
  9. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,019
    SHADER_TARGET_SURFACE_ANALYSIS is set for surface shaders when generating surface shader code. That involves parsing HLSL, and the parser doesn't understand new (DX11) syntax. If you exclude the code, the parser will just skip it.