You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

HLSL中RWTEXTURE2D的InterlockedAdd及Compute Shader问题求助

问题分析与解决方案

嘿,我来帮你拆解下这个问题——你遇到的情况其实是HLSL里RWTexture2D原子操作的一个常见坑,完全匹配你描述的独显返回64、集显返回32的现象,下面给你详细说清楚:

1. 核心原因:纹理格式不支持原子加法

HLSL的InterlockedAdd对RWTexture2D有个严格的限制:它只支持无符号整数格式的纹理(比如R32_UINTR32G32_UINT这类)。如果你把RWTexture2D声明成了浮点格式(比如R32_FLOAT),编译器可能不会直接报错,但不同GPU硬件会出现未定义行为:

  • 像NVIDIA/AMD的独显,它们的Wavefront(SIMD线程分组)大小是64,这类硬件会把浮点纹理的原子操作限制在单个Wavefront内,所以最终计数就变成了64;
  • Intel集成显卡的Wavefront大小通常是32,自然就返回32了。

这正好对应你看到的结果,不是线程没执行,而是硬件不支持浮点纹理的全局原子加法,只让单个SIMD组的线程生效了。

2. 具体修正步骤

按照下面的方法调整代码,就能得到预期的1024结果:

第一步:把RWTexture2D改成整数格式

不管是HLSL里的声明,还是CPU端创建纹理资源时的格式,都要改成无符号整数类型。比如HLSL里这样写:

RWTexture2D<uint> outputTexture : register(u0);

第二步:正确调用InterlockedAdd

针对整数纹理,调用InterlockedAdd的语法要对应上,假设你所有线程都操作同一个(x,y)像素,代码大概是这样:

[numthreads(32, 32, 1)] // 32*32=1024,刚好是最大线程组大小
void CS(uint3 dispatchThreadID : SV_DispatchThreadID)
{
    // 这里用(0,0)做测试,你可以换成自己目标的(x,y)坐标
    uint oldValue;
    InterlockedAdd(outputTexture[uint2(0, 0)], 1, oldValue);
}

第三步:CPU端读取时注意格式匹配

从GPU读数据到CPU的时候,要确保读取的是整数格式的资源,之后如果需要浮点值再做转换就行。

3. 额外要检查的点

  • 确认你确实是用单个线程组执行的——如果是多个线程组操作同一个像素,结果会比1024大,但你的情况是更小,所以这个可能性不大;
  • 检查资源绑定有没有错:HLSL里的寄存器和CPU端创建的纹理格式必须完全对应,不然也可能出现写入失效的情况。

总结

说白了就是浮点纹理不支持全局原子加法,不同GPU对这种非法操作的处理不一样,导致只统计了单个SIMD组的线程数。换成整数格式的RWTexture2D后,InterlockedAdd就能正常做全局原子累加,最终每个(x,y)的值就会是你预期的1024了。

内容的提问来源于stack exchange,提问作者F.Eazism

火山引擎 最新活动