Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Why must SV_POSITION be the first output?

Discussion in 'Shaders' started by RC-1290, May 10, 2014.

  1. RC-1290

    RC-1290

    Joined:
    Jul 2, 2012
    Posts:
    639
    Hey everyone,

    While writing a custom Vertex Fragment shader, I noticed that the scene's skybox went missing whenever an object using it was selected in the scene view, and that the same would happen in the game view for camera's using Deferred Lighting if an object using the shader was displayed.

    After some digging, I found that the this was caused by SV_POSITION being the last output of the vertex shader, when using #pragma target 3.0.
    Here's some example code that demonstrates the problem:
    Code (csharp):
    1. Shader "Custom/SemanticOrderTest" {
    2.     Properties {
    3.         _MainTex ("Main Texture", 2D) = "white" {}
    4.     }
    5.     SubShader {
    6.         Tags { "RenderType"="Opaque" }
    7.  
    8.         Pass {
    9.             Tags { "LightMode" = "ForwardBase" }
    10.             CGPROGRAM
    11.             #pragma vertex vert
    12.             #pragma fragment frag
    13.             #pragma target 3.0
    14.  
    15.             #include "UnityCG.cginc"
    16.            
    17.             sampler2D _MainTex;
    18.             float4 _MainTex_ST;// Required for TRANSFORM_TEX
    19.            
    20.  
    21.             struct fragmentInput{
    22.                 float2 uv : TEXCOORD0;
    23.                 float4 position : SV_POSITION;// Make this the first struct member to 'fix' the skybox problem.
    24.             };
    25.  
    26.             void vert(appdata_base v , out fragmentInput o ){
    27.                 o.position = mul (UNITY_MATRIX_MVP, v.vertex);
    28.                 o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);// Apply Scale and Bias settings
    29.             }
    30.             fixed4 frag(fragmentInput i) : COLOR {
    31.                 return fixed4( i.uv, 0, 1.0);
    32.             }
    33.             ENDCG
    34.         }
    35.     }
    36. }
    SV_POSITION as last vertex shader output:
    $xzgapRn.jpg

    SV_POSITION as first vertex shader output:
    $LGe1QZX.jpg

    You might wonder why you would put SV_POSITION as last input. All examples I have seen have SV_POSITION as first output, but after trying to access the data in the fragment shader and getting the following error:
    I figured it was a waste of inputs, and removed it from the fragment input struct, outputting it separately from the vertex shader.

    In DirectX 11 mode, you need to use the same order of input variables in the fragment shader, as the order of output variables from the vertex shader.

    The following code works fine for D3D9, but in D3D11, the uv parameter will be empty:
    Code (csharp):
    1. struct vertexOutput{
    2.     float4 position : SV_POSITION;
    3.     float2 uv : TEXCOORD0;
    4. };
    5. struct fragmentInput{
    6.     float2 uv : TEXCOORD0;
    7.     float4 position : SV_POSITION;
    8. };
    Out of order Semantics in DX11:
    $kTn1BtK.jpg

    So that's why I first started placing SV_POSITION as last in the output struct, because it would maintain the order of the input struct for the fragment shader.

    But that leaves the question why the order in which you define SV_POSITION and other output semantics matters, as I described at the top of the post.
    While this might be a bug, I feel like I'm missing something important. Does anyone have an idea for how the order in which output variables are defined affects the Skybox?
     
  2. WhiskyJoe

    WhiskyJoe

    Joined:
    Aug 21, 2012
    Posts:
    143
    I can only guess, but as far as I know, it's because SV_POSITION will not transfer on to the fragment input, where the POSITION semantic does. I tried doing this in my own skybox shader, but it seems to work here so it might be a bug.

    So unless you're using the SV_POSITION for a reason, perhaps you can use the POSITION semantic and see if that helps.
     
  3. RC-1290

    RC-1290

    Joined:
    Jul 2, 2012
    Posts:
    639
    Thanks for the suggestion.
    But using the POSITION semantic for the vertex shader's position output gives the same result.
     
  4. WhiskyJoe

    WhiskyJoe

    Joined:
    Aug 21, 2012
    Posts:
    143
    I just figured I forgot to compile it for DX11 :rolleyes:, but I get the same issue. Better yet, I can't seem to get my skybox in any way in whatever order with whatever semantic I use. It was just a quick try so I might overlooked something though.

    Anyway, if using SV_POSITION as the first value works, why not just keep it that way. I know I have read somewhere that having the position in your fragment struct was needed for something (interpolation perhaps?) when I was breaking my neck when I just started with shader programming and didn't know that I could only access stuff with the TEXCOORD semantic and it gave me the same error you have when I tried to just get the Position.

    I just started with DX11 though so I can't really say anything much more useful other than I know google has an answer somewhere :p Good luck though. :)
     
  5. RC-1290

    RC-1290

    Joined:
    Jul 2, 2012
    Posts:
    639
    I do keep it that way. The thing is that it surprises me that a local change in a shader can have such a significant impact on the rest of the scene. It's affecting global state, so I kind of expect to see bugs related to the behavior in the future. That's why I would like to understand how this happens, and I haven't been able to figure it out on my own yet.

    It's a problem for shader model 3 and up, not just Shader model 5 (DX11). The effect shows up in non-DX11 mode too.
     
  6. WhiskyJoe

    WhiskyJoe

    Joined:
    Aug 21, 2012
    Posts:
    143
    It could be a bug in that case, I always target shader model 3.0 and that's how I initially tried to reproduce your problem which I couldn't. It seemed to work just fine with any combination/variation. When I compiled it with shader model 5 I wasn't able to get my skybox to show in any way. The card I have supports DX11 so it shouldn't be that.

    I have no clue obviously how Unity is handling DX11 under the hood, but it might be so that due to how the constant buffers in DX11 can be laid out, unity expects a certain structure in the in/output structs to optimize it as much as possible and keep it consistent with the structure inside the Unity source code.
     
  7. RC-1290

    RC-1290

    Joined:
    Jul 2, 2012
    Posts:
    639
    Hmmm, then I guess it's hardware/ driver specific. Buggy enough to report.