1

我尝试使用 glsl 计算着色器实现 32x32x32 3D 纹理的传播方案,如果我可以只执行一次着色器来进行 x 次迭代,那就太好了。

我有 3 个纹理,一个是源,一个是目标,第三个是所有东西。每次迭代都必须交换源和目标。伪代码看起来像 OpenGL:

glUseProgram(computeShaderId);
glBindImageTexture(0, srcTexId, 0, GL_TRUE, 0, GL_READ_WRITE, GL_RGBA32F);
glBindImageTexture(1, targetTexId, 0, GL_TRUE, 0, GL_READ_WRITE, GL_RGBA32F);
glBindImageTexture(2, accumulateTexId, 0, GL_TRUE, 0, GL_READ_WRITE, GL_RGBA32F);
glDispatchCompute(32,32,32);

GLSL:

#version 430
layout (local_size_x = 1, local_size_y = 1, local_size_z =1) in;
layout(rgba32f) uniform image3D srcTex;
layout(rgba32f) uniform image3D targetTex;
layout(rgba32f) uniform image3D accumulateTex;

void main() {
  ivec3 currentPos = ivec3(gl_GlobalInvocationID.xyz);

  for (int i=0;i<8;i++){
    //accumulate the values of the 6 neighbours (top,bottom,left,right,front,back)
    //by usind the current sourceTexture
    //this involes  loadImage 
    vec4 neighbourValues=getValuesFrom6Neighbours(currentPos, currentSource);

    storeImage(currentTarget,currentPos,neighbourValues);

    vec4 value=loadImage(accumTex,currentPos);
    storeImage(accumTex,currentPos,neighbourValues+value);

    //the texture are swapped, which I have a solution for so no problem here
    swapSrcAndTarget();

    //here is the Problem how to synchronize all different shader invocations?
    someKindOfBarrier();
  }

问题是由于纹理的大小,我无法在一个工作组中完成所有这些工作。它会在一个工作组中,我可以使用 barrier() 就可以了。由于纹理的交换,我需要在从下一次迭代再次读取之前更新所有值。有人知道这是否可能吗?

谢谢马克

4

1 回答 1

0

正如您所说的那样,所有内容都无法放入活动线程中,所以我不认为这是直接可能的,除非您接受会有错误(当您读取的一半值可能来自更新之前或之后)。换句话说,所有线程都必须完成第一次 ping,然后才能继续进行 pong。由于一次只物理执行了一部分线程,因此将通道放入循环中是行不通的。

我能想到两件事。

  1. 将问题分解为可以适应的图块,但是在完成内核/调度之前,图块边缘之间将没有通信(邻居可能是陈旧的)。
  2. 实现您自己的调度,并使用 atomic opts 尝试获取任务,直到完成完整的 ping 操作(意味着手动同步)。只有在 memoryBarrier() 之后才能继续进行乒乓球比赛。根据经验,这可能比将 glDispatchCompute 放入 for 循环中要慢得多。
于 2013-09-10T07:21:38.680 回答