我遇到了一种情况,我希望在HLSL中有一个InterlockedSubtract函数。InterlockedAdd对于整数很好,但是我只能使用uint的RWByteAddressBuffer --我使用的是每一个位,我不希望使用一个编码/解码函数来使ints的行为与uint完全一样。
我目前的解决办法如下:
uint oldValue = Source.Load(oldParent, y);
Source.InterlockedMin(oldParent, oldValue - 1, y);问题是,我理解这些操作有可能在几个线程中被混淆,如下所示:
Thread 1: Thread 2:
o1 = Source.Load(l) l = 10, o1 = 10
o2 = Source.Load(l) l = 10, o2 = 10
Source.InterlockedMin(l, o1 - 1) l = 9
Source.InterlockedMin(l, o2 - 1) l = 9尽管有两个调用,但这些值只会减少一次。
据我所知,我不能把它变成一条直线,因为编译后的指令无论如何都可以去同步。
有什么办法我错过了吗?我可以重构我的代码,使用另一个uint作为减法计数器,然后使用另一个内核从实际计数中减去这些,但是我更愿意将它保存在一个内核中。
发布于 2022-02-22 13:06:01
谢谢,彼得考兹,你说得很对。我做了一些非常简单的测试:
HLSL
#pragma kernel Overflow
RWByteAddressBuffer buff;
uint ByteIndex(uint3 id)
{
return (id.x + id.y * 8) * 4;
}
[numthreads(8,8,1)]
void Overflow (uint3 id : SV_DispatchThreadID)
{
uint originalValue;
buff.InterlockedAdd(ByteIndex(id), 1, originalValue);
}和C#
public ComputeShader shade;
private ComputeBuffer b;
private int kernel;
private uint[] uints = new uint[64];
private void Start()
{
for(int i = 0; i < 64; i++) { uints[i] = 4294967294; }
for(int i = 0; i < 64; i++) { Debug.Log(uints[i]); }
}
void Update()
{
if(Input.GetKeyDown(KeyCode.Space))
{
b = new ComputeBuffer(64, sizeof(uint));
b.SetData(uints);
kernel = shade.FindKernel("Overflow");
shade.SetBuffer(kernel, Shader.PropertyToID("buff"), b);
shade.Dispatch(kernel, 1, 1, 1);
b.GetData(uints);
b.Dispose();
for (int i = 0; i < 64; i++) { Debug.Log(uints[i]); }
}
}这清楚地表明了所期望的行为。
如果在HLSL中记录了这种行为,那就太好了,但至少我现在知道了。
https://stackoverflow.com/questions/71157748
复制相似问题