我一直在尝试用Metal组合一个落砂游戏,该游戏使用计算机着色器完成工作。最初的工作看起来还不错,直到遇到以下问题:
在一次更新中,粒子1A和1B都可以流入空间T。
顺序
在顺序循环中,我了解了如何简单地将1A移至T,然后在评估1B时,我看到该空间已被填充。
并行
我的问题是,使用GPU,检查1A和1B的代码都在不同的线程上运行,因此在一个更新循环中,它们都可以移动到位置T,实际上杀死了其中一个。
那么我的问题是,我可以对此做出并行解决方案,还是只能依次解决?
这是我的计算代码,为640 x 480网格中的每个像素运行一个GPU线程:
struct Particle {
float4 color;
int live;
int particleType;
};
kernel void calculateFrame(
device Particle *src [[buffer(1)]],
device Particle *dst [[buffer(2)]],
uint2 threadgroup_position_in_grid [[ threadgroup_position_in_grid ]],
uint2 thread_position_in_threadgroup [[ thread_position_in_threadgroup ]],
uint2 threads_per_threadgroup [[ threads_per_threadgroup ]]) {
uint2 gid = threadgroup_position_in_grid;
int index = (gid * 640) + gid;
Particle particle = src[index];
Particle bottom = src[toLinear( gid + uint2( 0, 1))]; //bottom
Particle bottomLeft = src[toLinear( gid + uint2(-1, 1))]; //bottom left
Particle bottomRight = src[toLinear( gid + uint2( 1, 1))]; //bottom right
if (particle.live == 1 && particle.particleType == SAND) { // move down
if (bottom.live == 0) {
dst[index].live = 0;
dst[toLinear( gid + uint2( 0, 1))].particleType = particle.particleType;
dst[toLinear( gid + uint2( 0, 1))].color = particle.color;
dst[toLinear( gid + uint2( 0, 1))].live = 1;
}
else if (bottomLeft.live == 0) { // move down to the left if clear
dst[index].live = 0;
dst[toLinear( gid + uint2( -1, 1))].particleType = particle.particleType;
dst[toLinear( gid + uint2( -1, 1))].color = red;
dst[toLinear( gid + uint2( -1, 1))].live = 1;
}
else if (bottomRight.live == 0) { // move down to the right if clear
dst[index].live = 0;
dst[toLinear( gid + uint2( 1, 1))].particleType = particle.particleType;
dst[toLinear( gid + uint2( 1, 1))].color = red;
dst[toLinear( gid + uint2( 1, 1))].live = 1;
}
else { // cant move
dst[index] = src[index];
}
}
if (particle.particleType == WALL) {
dst[index] = particle;
dst[index].live = 1;
}
if (particle.particleType == ERASER) {
dst[index].color = blue;
dst[index].live = 0;
}
}