float in RWTexture<float4> 输出不一致的值,具体取决于它在 if 语句的哪一侧

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

我正在尝试编写一个写入 RWTexture2 中的红色通道的 HLSL 计算着色器,但是当我尝试读取值时,我发现不一致,这完全取决于我是将赋值放在任意值之前还是之后if 语句:

具体例子。我只调度一个线程 shader.Dispatch(1, 1, 1)

在分派以下代码后从 AppendStructureBuffer 读取时,returns 是一个值为 255 的条目。

RWTexture2D<float4> gridModel;
AppendStructuredBuffer<float> outlierIndeces;

[numthreads(1, 1, 1)]
void IdentifyBorderPoints(uint3 id : SV_DispatchThreadID)
{
    if (id.x == 0)
    {
        gridModel[id.xy] = float4(255, 0, 0, 0);
        outlierIndeces.Append(gridModel[id.xy].r);
    }
}

但是将赋值移到 if 语句之外会使它变成 return 1。然而,据我所见,这应该仍然只是 255:

RWTexture2D<float4> gridModel;
AppendStructuredBuffer<float> outlierIndeces;

[numthreads(1, 1, 1)]
void IdentifyBorderPoints(uint3 id : SV_DispatchThreadID)
{
    gridModel[id.xy] = float4(255, 0, 0, 0);
    if (id.x == 0)
    {
        outlierIndeces.Append(gridModel[id.xy].r);
    }
}

作为完整性检查,注释掉作业使其成为 return 0:

RWTexture2D<float4> gridModel;
AppendStructuredBuffer<float> outlierIndeces;

[numthreads(1, 1, 1)]
void IdentifyBorderPoints(uint3 id : SV_DispatchThreadID)
{
    //gridModel[id.xy] = float4(255, 0, 0, 0);
    if (id.x == 0)
    {
        outlierIndeces.Append(gridModel[id.xy].r);
    }
}

我深入研究了编译后的代码,我也看到了不同之处: 以下编译代码来自赋值发生在 if 语句之前的示例:

// Input signature:
//
// Name                 Index   Mask Register SysValue  Format   Used
// -------------------- ----- ------ -------- -------- ------- ------
// no Input
//
// Output signature:
//
// Name                 Index   Mask Register SysValue  Format   Used
// -------------------- ----- ------ -------- -------- ------- ------
// no Output
      cs_5_0
      dcl_globalFlags refactoringAllowed
      dcl_uav_structured u0, 4
      dcl_uav_typed_texture2d (float,float,float,float) u1
      dcl_input vThreadID.xy
      dcl_temps 2
      dcl_thread_group 1, 1, 1
   0: store_uav_typed u1.xyzw, vThreadID.xyyy, l(255.000000,0,0,0)
   1: if_z vThreadID.x
   2:   mov r0.x, l(0)
   3:   mov r0.yzw, vThreadID.yyyy
   4:   ld_uav_typed_indexable(texture2d)(float,float,float,float) r0.x, r0.xyzw, u1.xyzw
   5:   imm_atomic_alloc r1.x, u0
   6:   store_structured u0.x, r1.x, l(0), r0.x
   7: endif 
   8: ret 
// Approximately 0 instruction slots used

这是示例中的编译代码,其中赋值发生在 if 语句之后:

// Input signature:
//
// Name                 Index   Mask Register SysValue  Format   Used
// -------------------- ----- ------ -------- -------- ------- ------
// no Input
//
// Output signature:
//
// Name                 Index   Mask Register SysValue  Format   Used
// -------------------- ----- ------ -------- -------- ------- ------
// no Output
      cs_5_0
      dcl_globalFlags refactoringAllowed
      dcl_uav_structured u0, 4
      dcl_uav_typed_texture2d (float,float,float,float) u1
      dcl_input vThreadID.xy
      dcl_temps 1
      dcl_thread_group 1, 1, 1
   0: if_z vThreadID.x
   1:   mov r0.x, l(0)
   2:   mov r0.yzw, vThreadID.yyyy
   3:   store_uav_typed u1.xyzw, r0.xyzw, l(255.000000,0,0,0)
   4:   imm_atomic_alloc r0.x, u0
   5:   store_structured u0.x, r0.x, l(0), l(255.000000)
   6: endif 
   7: ret 
// Approximately 0 instruction slots used

我不完全理解编译代码,但似乎只有在赋值发生在 if 语句之后的情况下,才将值 255 赋给结构化 buffy。

附加信息:我正在使用 Unity 的着色器编译器来编译代码。我使用的Unity版本是2018.3.14f1.

我得到了一些帮助,我们解决了问题。在 Unity 中,我使用具有以下设置的 RenderTexture 初始化了 gridModel:

texture = new RenderTexture(512, 512, 1, RenderTextureFormat.ARGB32);
texture.depth = 0;
texture.enableRandomWrite = true;
texture.Create();

然后我将它发送到着色器:

int identifyBorderPointsKernel = cShader.FindKernel("IdentifyBorderPoints");
cShader.SetTexture(identifyBorderPointsKernel, "gridModel", texture);

但是问题出现了,因为 RenderTextureFormat.ARGB32 中的每个通道都是一个 8 位浮点通道,因此将我的 int 固定为 1。通过用浮点值代替 0.4 替换 255,无论我在何处执行作业。

我在 if 语句的两边收到差异的原因是,在 if 语句内部发生赋值的情况下,编译器直接将值赋值给 appendbuffer 而没有费心首先从纹理加载,因此该值从未被限制。