Search Unity

float in RWTexture<float4> outputs inconsistent values depending on what side on an if-statement it

Discussion in 'Shaders' started by Freaking-Pingo, Jul 30, 2019.

  1. Freaking-Pingo

    Freaking-Pingo

    Joined:
    Aug 1, 2012
    Posts:
    310
    I am trying to write a HLSL compute shader that writes to the red channel in a RWTexture2 but I am seeing inconsistencies, when I try to read the value, all depending on whether I placed the assignment before or after an arbitrary if-statement. I am using is 2018.3.14f1.

    Concrete example. I am only dispatching a single thread
    Code (CSharp):
    1. shader.Dispatch(1, 1, 1)
    When reading from the AppendStructureBuffer after it has been dispatched the following code returns a single entry with a value of 255.

    Code (CSharp):
    1.  
    2. RWTexture2D<float4> gridModel;
    3. AppendStructuredBuffer<float> outlierIndeces;
    4.  
    5. [numthreads(1, 1, 1)]
    6. void IdentifyBorderPoints(uint3 id : SV_DispatchThreadID)
    7. {
    8.    if (id.x == 0)
    9.    {
    10.        gridModel[id.xy] = float4(255, 0, 0, 0);
    11.        outlierIndeces.Append(gridModel[id.xy].r);
    12.    }
    13. }
    But moving the assignment outside of the if-statement makes it return 1 instead. However, from what I can see, this should still just 255:
    Code (CSharp):
    1.  
    2. RWTexture2D<float4> gridModel;
    3. AppendStructuredBuffer<float> outlierIndeces;
    4.  
    5. [numthreads(1, 1, 1)]
    6. void IdentifyBorderPoints(uint3 id : SV_DispatchThreadID)
    7. {
    8.    gridModel[id.xy] = float4(255, 0, 0, 0);
    9.    if (id.x == 0)
    10.    {
    11.        outlierIndeces.Append(gridModel[id.xy].r);
    12.    }
    13. }
    As a sanity check, commenting out the assignment makes it return 0:

    Code (CSharp):
    1.  
    2. RWTexture2D<float4> gridModel;
    3. AppendStructuredBuffer<float> outlierIndeces;
    4.  
    5. [numthreads(1, 1, 1)]
    6. void IdentifyBorderPoints(uint3 id : SV_DispatchThreadID)
    7. {
    8.    //gridModel[id.xy] = float4(255, 0, 0, 0);
    9.    if (id.x == 0)
    10.    {
    11.        outlierIndeces.Append(gridModel[id.xy].r);
    12.    }
    13. }
    I dwelled deeper into the compiled code and there I am also seeing a difference: The following compiled code is from the example where the assignment happens before the if-statement:

    Code (CSharp):
    1. // Input signature:
    2. //
    3. // Name                 Index   Mask Register SysValue  Format   Used
    4. // -------------------- ----- ------ -------- -------- ------- ------
    5. // no Input
    6. //
    7. // Output signature:
    8. //
    9. // Name                 Index   Mask Register SysValue  Format   Used
    10. // -------------------- ----- ------ -------- -------- ------- ------
    11. // no Output
    12.      cs_5_0
    13.      dcl_globalFlags refactoringAllowed
    14.      dcl_uav_structured u0, 4
    15.      dcl_uav_typed_texture2d (float,float,float,float) u1
    16.      dcl_input vThreadID.xy
    17.      dcl_temps 2
    18.      dcl_thread_group 1, 1, 1
    19.    0: store_uav_typed u1.xyzw, vThreadID.xyyy, l(255.000000,0,0,0)
    20.    1: if_z vThreadID.x
    21.    2:   mov r0.x, l(0)
    22.    3:   mov r0.yzw, vThreadID.yyyy
    23.    4:   ld_uav_typed_indexable(texture2d)(float,float,float,float) r0.x, r0.xyzw, u1.xyzw
    24.    5:   imm_atomic_alloc r1.x, u0
    25.    6:   store_structured u0.x, r1.x, l(0), r0.x
    26.    7: endif
    27.    8: ret
    28. // Approximately 0 instruction slots used
    And this is the compiled code in the example where the assignment happens after the if-statement:

    Code (CSharp):
    1. // Input signature:
    2. //
    3. // Name                 Index   Mask Register SysValue  Format   Used
    4. // -------------------- ----- ------ -------- -------- ------- ------
    5. // no Input
    6. //
    7. // Output signature:
    8. //
    9. // Name                 Index   Mask Register SysValue  Format   Used
    10. // -------------------- ----- ------ -------- -------- ------- ------
    11. // no Output
    12.      cs_5_0
    13.      dcl_globalFlags refactoringAllowed
    14.      dcl_uav_structured u0, 4
    15.      dcl_uav_typed_texture2d (float,float,float,float) u1
    16.      dcl_input vThreadID.xy
    17.      dcl_temps 1
    18.      dcl_thread_group 1, 1, 1
    19.    0: if_z vThreadID.x
    20.    1:   mov r0.x, l(0)
    21.    2:   mov r0.yzw, vThreadID.yyyy
    22.    3:   store_uav_typed u1.xyzw, r0.xyzw, l(255.000000,0,0,0)
    23.    4:   imm_atomic_alloc r0.x, u0
    24.    5:   store_structured u0.x, r0.x, l(0), l(255.000000)
    25.    6: endif
    26.    7: ret
    27. // Approximately 0 instruction slots used
    I don't fully understand the compile code, but it seems like the value 255 is assigned to the structured buffy only in the case where the assignment happens after the if-statement.
     
  2. Freaking-Pingo

    Freaking-Pingo

    Joined:
    Aug 1, 2012
    Posts:
    310
    I received some assistance and we figured it out. In Unity I initialized gridModel using a RenderTexture with the following settings:

    Code (CSharp):
    1. texture = new RenderTexture(512, 512, 1, RenderTextureFormat.ARGB32);
    2. texture.depth = 0;
    3. texture.enableRandomWrite = true;
    4. texture.Create();
    And the I send it to the shader:

    Code (CSharp):
    1. int identifyBorderPointsKernel = cShader.FindKernel("IdentifyBorderPoints");
    2. cShader.SetTexture(identifyBorderPointsKernel, "gridModel", texture);
    But the problem occured because each channel in RenderTextureFormat.ARGB32 is an 8 bit float chhanel and therefore clamped my int to 1. By replacing the 255 with a float value instead 0.4, I got equal regardless of where I did the assignment.

    The reason I received a difference when placed on either side of the if-statement is because in the case where the assignment happend inside the if-statement the compiler assigned the value directly to the appendbuffer and didn't bother to load from the texture first hence the value was never clamped.
     
    Namey5, grizzly and bgolus like this.