我之前已经遇到了一个问题,我想通过执行以下操作来混合图像单元中的颜色值:
vec4 texelCol = imageLoad(myImage, myTexel);
imageStore(myImage, myTexel, texelCol+newCol);
在多个片段可以具有相同的'myTexel'值的场景中,这显然是不可能的,因为不能在imageLoad和imageStore命令之间创建原子性,并且其他shaderinvocations可以更改其间的texel颜色。
现在有人告诉我,人们正在解决这个问题,通过在uint纹理上使用原子命令创建信号量,这样着色器在访问texel之前会以某种方式等待while循环,一旦它空闲,原子地将其写入整数纹理以阻止其他片段着色器调用,处理颜色texel,并在完成时再次原子地释放整数texel。
但我无法理解这是如何工作的,这样的代码看起来会是什么样子?
这真的有可能吗?GLSL片段着色器可以设置为在while循环中等待吗?如果可能的话,谁能给予个例子?
1条答案
按热度按时间du7egjpx1#
基本上,你只是实现了一个spinlock。只不过不是一个锁变量,而是整个纹理的锁。
从逻辑上讲,你做的事情是有意义的。但就OpenGL而言,这 * 实际上不会工作 *。
看,OpenGL着色器执行模型声明调用以相对于彼此在很大程度上未定义的顺序执行。但是,自旋锁只有在保证各个线程之间的向前进展时才起作用。基本上,自旋锁要求正在自旋的线程不能使执行系统停止执行它正在等待的线程。
OpenGL提供 * 没有这样的保证 *。这意味着一个线程完全有可能锁定一个像素,然后停止执行(无论出于什么原因),而另一个线程沿着并阻塞该像素。被阻塞的线程永远不会停止执行,拥有锁的线程永远不会重新启动执行。
在真实的的系统中,这是如何发生的呢?好吧,让我们假设你有一个片段着色器调用组,对一个三角形的一些片段执行。它们都锁定了像素。但是,由于锁定区域内的条件分支,它们在执行中会发生分歧。执行的分散可能意味着这些调用中的一些被转移到不同的执行单元。如果此时没有可用的,则它们有效地暂停,直到有一个可用为止。
现在,让我们假设一些其他片段着色器调用组沿着,并在发散组之前被分配执行单元。如果该组试图对来自发散组的像素进行自旋锁定,它实际上是在耗尽发散组的执行时间,等待一个永远不会发生的事件。
现在很明显,在真实的的GPU中,有不止一个执行单元,但是你可以想象,有很多调用组在那里,这种情况完全有可能偶尔会卡住工作。