GLSL,信号量?

时间:2012-05-18 12:42:30

标签: opengl concurrency glsl

我之前已经遇到过这样的问题:我希望通过执行以下操作来混合图像单元中的颜色值:

vec4 texelCol = imageLoad(myImage, myTexel);
imageStore(myImage, myTexel, texelCol+newCol);

在多个片段对'myTexel'具有相同值的情况下,这显然是不可能的,因为无法在imageLoad和imageStore命令之间创建原子性,而其他shaderinvocations可能会更改其间的纹素颜色。 / p>

现在有人告诉我,人们通过使用uint纹理上的原子命令创建信号量来解决这个问题,这样着色器会在访问texel之前以某种方式在while循环中等待,并且只要它是空闲的,就会自动写入itno整数纹理来阻止其他片段着色器调用,处理颜色纹理元素,并在完成后再次以原子方式释放整数纹素。

但我无法理解这是如何真正起作用的,以及这些代码会是什么样子?

真的可以这样做吗?可以将GLSL片段着色器设置为在while循环中等待吗?如果有可能,有人可以举个例子吗?

1 个答案:

答案 0 :(得分:8)

是的,您可以这样做,但只有在混合了事物的订单时才会这样做。否则你需要使用通常的技术。

基本上你只是在实施spinlock。只有一个锁定变量,你才能拥有整个纹理的锁定。

首先需要一张与原子操作相同的图像。它必须是GL_R32UI的整数纹理,并且uimage格式为r32ui才能匹配。它应该用0来初始化。原子图像和“混合”图像都必须声明为“连贯”。

  1. 在原子整数图像上的位置执行imageAtomicCompSwap操作。您将其与0进行比较,并且您将其设置为1的值。

  2. 如果#1返回1,则表示其他人拥有该锁。回到步骤#1。

  3. 如果#1返回0,那么您现在可以独占访问texel(因为texel现在有1个,这要归功于比较/交换操作)。继续。

  4. 执行混合操作。在混合操作后发出memoryBarrier

  5. 执行imageAtomicExchange,其值为0.这会解锁螺旋锁。

  6. 这种作用的原因是由于原子。 GLSL确保原子是原子的。 imageAtomicCompareSwap执行读/条件修改/写操作作为原子序列。并且因为它是原子的,所以不可能其他着色器调用以抢占或中断操作。这意味着着色器运行的线程数无关紧要:如果其中100个调用imageAtomicCompareSwap(..., 0, 1),其中只有一个将获得1作为返回值,其余的将获得0(对于相同的texel,当然)。

    因此只有一个线程会获得锁定;其他人必须等待。

    memoryBarrier()函数的使用将确保等待的其他线程在读取时将获取修改后的数据。同样,您需要使用coherent限定符来处理您正在执行此操作的图像。