Search Unity

No SV_Position in Fragment shader causes Texture to not show.

Discussion in 'Shaders' started by Demkeys, Jun 26, 2019.

  1. Demkeys

    Demkeys

    Joined:
    Nov 14, 2014
    Posts:
    32
    Hey everyone. I recently noticed that in my shader, when I don't mention a "float4 position : SV_POSITION" parameter in the fragment function, the texture being supplied to the material doesn't show. Instead what shows up is just one color from the texture.
    Here's my code with the "float4 position : SV_POSITION" parameter in the Fragment function:
    Code (CSharp):
    1. Shader "Custom/MyShader08"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex01 ("Texture01", 2D) = "white" {}
    6.     }
    7.     SubShader
    8.     {
    9.         Tags { "RenderType"="Opaque" }
    10.    
    11.         Pass
    12.         {
    13.             CGPROGRAM
    14.             #pragma vertex vert
    15.             #pragma fragment frag
    16.             #include "UnityCG.cginc"
    17.  
    18.             sampler2D _MainTex01;
    19.             float4 _MainTex01_ST;
    20.  
    21.             void vert(
    22.                 float4 position : POSITION,
    23.                 float2 texCoord0 : TEXCOORD0,
    24.                 out float4 oposition : SV_POSITION,
    25.                 out float2 otexCoord0 : TEXCOORD0
    26.                 )
    27.             {
    28.                 oposition = UnityObjectToClipPos(position);
    29.                 otexCoord0 = TRANSFORM_TEX(texCoord0, _MainTex01);
    30.             }
    31.  
    32.             float4 frag(
    33.                 float4 position : SV_POSITION,
    34.                 float2 texCoord0 : TEXCOORD0) : SV_Target
    35.             {
    36.                 float4 color = tex2D(_MainTex01, texCoord0);
    37.                 return color;
    38.             }
    39.             ENDCG
    40.         }
    41.     }
    42. }
    Here's the result. Texture shows up as it should.
    screencap2.png
    Here's my code without "float4 position : SV_POSITION" in the Fragment shader:
    Code (CSharp):
    1. Shader "Custom/MyShader08"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex01 ("Texture01", 2D) = "white" {}
    6.     }
    7.     SubShader
    8.     {
    9.         Tags { "RenderType"="Opaque" }
    10.    
    11.         Pass
    12.         {
    13.             CGPROGRAM
    14.             #pragma vertex vert
    15.             #pragma fragment frag
    16.             #include "UnityCG.cginc"
    17.  
    18.             sampler2D _MainTex01;
    19.             float4 _MainTex01_ST;
    20.  
    21.             void vert(
    22.                 float4 position : POSITION,
    23.                 float2 texCoord0 : TEXCOORD0,
    24.                 out float4 oposition : SV_POSITION,
    25.                 out float2 otexCoord0 : TEXCOORD0
    26.                 )
    27.             {
    28.                 oposition = UnityObjectToClipPos(position);
    29.                 otexCoord0 = TRANSFORM_TEX(texCoord0, _MainTex01);
    30.             }
    31.  
    32.             float4 frag(
    33.                 float2 texCoord0 : TEXCOORD0) : SV_Target
    34.             {
    35.                 float4 color = tex2D(_MainTex01, texCoord0);
    36.                 return color;
    37.             }
    38.             ENDCG
    39.         }
    40.     }
    41. }
    This is the result:
    screencap3.png

    I'm very new to writing shaders so there's definitely something I'm missing here. I'm not able to understand why an SV_POSITION parameter is required in the Fragment function when I'm not using it.
    I've tried looking online for an answer and couldn't find one. The Shader Semantics page doesn't mention it either.
     
    Last edited: Jun 26, 2019
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,339
    That’s very odd. Especially since the position value is stripped by the shader compiler anyway when it is included since it’s not being used.
     
  3. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,339
    Looking at the compiled shader, the reason can be found. However I'm not sure if this is a bug, or "user error".

    On Windows the working compiled shader looks like this:
    Vertex Shader
    Code (csharp):
    1. // Input signature:
    2. //
    3. // Name                 Index   Mask Register SysValue  Format   Used
    4. // -------------------- ----- ------ -------- -------- ------- ------
    5. // POSITION                 0   xyzw        0     NONE   float   xyz
    6. // TEXCOORD                 0   xy          1     NONE   float   xy
    7. //
    8. //
    9. // Output signature:
    10. //
    11. // Name                 Index   Mask Register SysValue  Format   Used
    12. // -------------------- ----- ------ -------- -------- ------- ------
    13. // SV_POSITION              0   xyzw        0      POS   float   xyzw
    14. // TEXCOORD                 0   xy          1     NONE   float   xy
    15. //
    16.       vs_4_0
    17.       dcl_constantbuffer CB0[3], immediateIndexed
    18.       dcl_constantbuffer CB1[4], immediateIndexed
    19.       dcl_constantbuffer CB2[21], immediateIndexed
    20.       dcl_input v0.xyz
    21.       dcl_input v1.xy
    22.       dcl_output_siv o0.xyzw, position
    23.       dcl_output o1.xy
    24.       dcl_temps 2
    25.    0: mul r0.xyzw, v0.yyyy, cb1[1].xyzw
    26.    1: mad r0.xyzw, cb1[0].xyzw, v0.xxxx, r0.xyzw
    27.    2: mad r0.xyzw, cb1[2].xyzw, v0.zzzz, r0.xyzw
    28.    3: add r0.xyzw, r0.xyzw, cb1[3].xyzw
    29.    4: mul r1.xyzw, r0.yyyy, cb2[18].xyzw
    30.    5: mad r1.xyzw, cb2[17].xyzw, r0.xxxx, r1.xyzw
    31.    6: mad r1.xyzw, cb2[19].xyzw, r0.zzzz, r1.xyzw
    32.    7: mad o0.xyzw, cb2[20].xyzw, r0.wwww, r1.xyzw
    33.    8: mad o1.xy, v1.xyxx, cb0[2].xyxx, cb0[2].zwzz
    34.    9: ret
    Fragment Shader
    Code (csharp):
    1. // Input signature:
    2. //
    3. // Name                 Index   Mask Register SysValue  Format   Used
    4. // -------------------- ----- ------ -------- -------- ------- ------
    5. // SV_POSITION              0   xyzw        0      POS   float    
    6. // TEXCOORD                 0   xy          1     NONE   float   xy
    7. //
    8. //
    9. // Output signature:
    10. //
    11. // Name                 Index   Mask Register SysValue  Format   Used
    12. // -------------------- ----- ------ -------- -------- ------- ------
    13. // SV_Target                0   xyzw        0   TARGET   float   xyzw
    14. //
    15.       ps_4_0
    16.       dcl_sampler s0, mode_default
    17.       dcl_resource_texture2d (float,float,float,float) t0
    18.       dcl_input_ps linear v1.xy
    19.       dcl_output o0.xyzw
    20.    0: sample o0.xyzw, v1.xyxx, t0.xyzw, s0
    21.    1: ret
    The parts to pay attention to are the signature description comments, and the matching dcl_input_ps and dcl_output lines. More specifically the register number and the v# and o# values after the dcl_* lines. SV_POSITION is register 0, TEXCOORD0 is register 1 for both the vertex and fragment shader, and that fact is mirrored by the vertex shader's dcl_output o1.xy and fragment shader's dcl_input_ps v1.xy for the texcoord data.

    For the broken shader, the vertex shader is identical, but the fragment shader is different.
    Code (csharp):
    1. // Input signature:
    2. //
    3. // Name                 Index   Mask Register SysValue  Format   Used
    4. // -------------------- ----- ------ -------- -------- ------- ------
    5. // TEXCOORD                 0   xy          0     NONE   float   xy
    6. //
    7. //
    8. // Output signature:
    9. //
    10. // Name                 Index   Mask Register SysValue  Format   Used
    11. // -------------------- ----- ------ -------- -------- ------- ------
    12. // SV_Target                0   xyzw        0   TARGET   float   xyzw
    13. //
    14.       ps_4_0
    15.       dcl_sampler s0, mode_default
    16.       dcl_resource_texture2d (float,float,float,float) t0
    17.       dcl_input_ps linear v0.xy
    18.       dcl_output o0.xyzw
    19.    0: sample o0.xyzw, v0.xyxx, t0.xyzw, s0
    20.    1: ret
    Notice, the TEXCOORD0 is now listed as being on register 0, but the vertex shader is using register 1 still! The resulting miss match appears to just pass float2(0.0, 0.0) into the shader instead of the expected UVs or even the position. Like I said before, I'm not entirely sure if this is user error, as I would expect the semantics to handle this out of order issue for you, or if it's a requirement that the layout of the vertex output and fragment input match for D3D11 (it didn't for D3D9).

    So, one solution / work arounds would be to just include SV_POSITION, obviously. As I mentioned in my previous post, it doesn't actually "do" anything having it there since the shader compiler already strips it from the compiled shader (as evidence of there being no dcl_input_ps_siv linear noperspective v0.xyzw, position in the fragment shader.

    Another would be to change the order of your outputs from the vertex shader so the TEXCOORD0 is before the SV_POSITION, which causes the TEXCOORD0 to use register 0.
     
    Demkeys likes this.
  4. Demkeys

    Demkeys

    Joined:
    Nov 14, 2014
    Posts:
    32
    Oh wow! Very interesting seeing a breakdown of the problem. This makes me think I should do a some research on GPU architecture and familiarize myself with the some of the GPU instruction set, not necessarily to write shader assembly, but rather to be able to try and debug issues by looking into the compiled assembly.
    So, I tried switching the order of outputs and putting TEXCOORD0 before SV_POSITION, and it worked. For now I guess I'll just add the SV_POSITION parameter. Thanks for all the info.
    Definitely interested in finding out more about what the issue is here.