You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

HLSL计算着色器中如何实现多数据位的原子交换?

多纹理同步的原地3D落沙算法实现问题

我正在实现原地3D落沙算法,逻辑是让3D纹理中非零元素在下方位置为空(值为0)时向下移动一位。使用单uint原子操作时能正常运行,代码如下:

// from 是坐标xyz,to 是 xyz + (0, -1, 0)
uint toValueWas;
InterlockedCompareExchange(_texture[to], 0, _texture[from], toValueWas);
if (toValueWas == 0)
{
    _texture[from] = toValueWas;
}

但当需要扩展存储到另一张纹理_textureB时,两个纹理会出现不同步问题,问题代码如下:

uint toValueWas;
InterlockedCompareExchange(_texture[to], 0, _texture[from], toValueWas);
if (toValueWas == 0)
{
    _texture[from] = toValueWas;
    // 此处操作会导致与_texture不同步
    InterlockedExchange(_textureB[to], _textureB[from], _textureB[from]);
}

核心问题:有没有办法有效实现超过32位数据的原子交换?


可行解决方案

1. 利用64位原子操作(API支持时优先)

如果你的图形API(如DirectX 12、Vulkan)支持64位原子操作,可以将两个uint数据打包成一个uint64_t,存储到单个纹理通道或专用的64位纹理中,通过InterlockedCompareExchange64这类原子操作一次性完成交换,从根源上保证数据同步。

示例代码思路:

// 将两个纹理的对应值打包为64位整数
uint64_t fromPacked = (uint64_t)_texture[from] << 32 | _textureB[from];
uint64_t toPackedWas;

// 仅当目标位置的打包值为0(即两个纹理对应位置都为空)时,执行原子交换
InterlockedCompareExchange64(_packedTexture[to], 0, fromPacked, toPackedWas);

if (toPackedWas == 0) {
    // 将原位置的两个纹理值都置为0
    _texture[from] = 0;
    _textureB[from] = 0;
    // 目标位置已通过原子操作完成赋值,无需额外操作
}

2. 原子自旋锁实现同步

如果不支持64位原子操作,可以使用一张单独的锁纹理,每个位置对应一个自旋锁,确保对_texture和_textureB的操作是原子性的。

示例代码思路:

// 锁纹理:0表示未锁定,1表示锁定
while (InterlockedCompareExchange(_lockTexture[to], 1, 0) != 0) {
    // 自旋等待锁释放
}

// 锁定后检查目标位置是否为空
uint toVal = _texture[to];
uint toValB = _textureB[to];
if (toVal == 0 && toValB == 0) {
    // 执行双纹理值交换
    _texture[to] = _texture[from];
    _textureB[to] = _textureB[from];
    _texture[from] = 0;
    _textureB[from] = 0;
}

// 释放锁
InterlockedExchange(_lockTexture[to], 0);

注意:自旋锁在高并发场景下可能带来性能损耗,需根据实际运行环境调整优化。

3. 合并数据存储结构

将需要同步的多字段数据合并为一个结构体,使用支持结构体原子操作的GPU计算缓冲区(如结构化缓冲区),通过原子操作一次性交换整个结构体,避免多纹理的同步问题。


内容的提问来源于stack exchange,提问作者Jolly Theory

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 22:34:57