【发布时间】:2020-12-10 10:49:20
【问题描述】:
我想知道是否有人知道 HLSL InterlockedAdd 是否会进行某种优化,特别是当它用于单个全局原子计数器时(所有线程的附加值都是恒定的) 通过大量线程。
我在网上找到的一些信息表明,原子添加会产生严重的争用问题: https://developer.nvidia.com/blog/cuda-pro-tip-optimized-filtering-warp-aggregated-atomics/
当然,上面的文章是为 CUDA 写的(也有点旧,可以追溯到 2014 年),而我对 HLSL InterlockedAdd 很感兴趣。为此,我为 Unity 编写了一个虚拟 HLSL 着色器(据我所知,通过 FXC 编译为 d3d11),我在单个全局原子计数器上调用 InterlockedAdd,这样附加值始终是所有阴影片段都相同。有问题的 sn-p(在http://shader-playground.timjones.io/ 中运行,通过 FXC 编译,优化 lvl 3,着色模型 5.0):
**HLSL**:
RWStructuredBuffer<int> counter : register(u1);
void PSMain()
{
InterlockedAdd(counter[0], 1);
}
----
**Assembly**:
ps_5_0
dcl_globalFlags refactoringAllowed
dcl_uav_structured u1, 4
atomic_iadd u1, l(0, 0, 0, 0), l(1)
ret
然后我稍微修改了代码,而不是总是添加一些常量值,我现在添加了一个在片段之间变化的值,如下所示:
**HLSL**:
RWStructuredBuffer<int> counter : register(u1);
void PSMain(float4 pixel_pos : SV_Position)
{
InterlockedAdd(counter[0], int(pixel_pos.x));
}
----
**Assmebly**:
ps_5_0
dcl_globalFlags refactoringAllowed
dcl_uav_structured u1, 4
dcl_input_ps_siv linear noperspective v0.x, position
dcl_temps 1
ftoi r0.x, v0.x
atomic_iadd u1, l(0, 0, 0, 0), r0.x
ret
我在 Unity 中实现了上述 sn-ps 的等价物,并将它们用作我的片段着色器来渲染全屏四边形(当然,没有输出语义,但这无关紧要)。我使用 Nsight Grphics 分析了生成的着色器。可以说两次绘制调用之间的差异是巨大的,基于第二个 sn-p(InterlockedAdd with variable value)的片段着色器要慢得多。
我还使用 RenderDoc 进行了捕获以检查程序集,它们看起来与上面显示的相同。汇编代码中没有任何内容表明存在如此巨大的差异。然而,区别就在那里。
所以我的问题是:在单个全局原子计数器上使用 HLSL InterlockedAdd 时是否进行了某种优化,使得附加值是一个常数? GPU驱动程序是否有可能以某种方式重新排列代码?
系统规格:
- NVIDIA Quadro P4000
- Windows 10
- 团结 2019.4
【问题讨论】:
标签: gpgpu hlsl gpu direct3d11