我们有一个 OpenGL 解算器。给定一个包含许多项目的列表,每个项目都有一个坐标和一个 float 值。我们运行一个计算着色器来计算这些项目的大小,并使用函数 imageAtomicAdd
和 float 扩展将值添加到
float图像中的现有值。这样,即使 2 个项目碰巧同时具有相同的坐标值,也能保证相加。
现在,我们需要使用js将其移动到WebGPU。我尝试在 float 纹理/缓冲区上寻找原子添加函数,但成功有限。所以,目前的代码是这样的
outputBuffer[coords] += floatValue; // TODO: fix!!
正如预期的那样,它可以工作,但没有保证。有些像素会闪烁,具体取决于哪个线程首先工作。
那么,我怎样才能安全地做到这一点呢?使用像
atomicAdd
这样的函数或者类似于 CUDA 的同步线程/屏障的函数?
这是一个基本的实现示例:
function quantizeFloatToUInt(floatValue) {
return Math.floor(floatValue * 10000);
}
@group(0) @binding(0) var<storage, read_write> outputBuffer : array<atomic<u32>>;
@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) global_id : vec3<u32>) {
let coords = calculateCoords(global_id);
let intValue = quantizeFloatToUInt(yourFloatValue);
atomicAdd(&outputBuffer[coords], intValue);
}
此示例经过简化。