【问题标题】:GLSL, semaphores?GLSL,信号量?
【发布时间】:2012-05-18 12:42:29
【问题描述】:

我之前已经遇到了一个问题,我想通过执行以下操作在图像单元中混合颜色值:

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

在多个片段可以为“myTexel”具有相同值的情况下,这显然是不可能的,因为无法在 imageLoad 和 imageStore 命令之间创建原子性,并且其他着色器调用可能会更改其间的纹素颜色。

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

但我无法思考这究竟是如何工作的,以及这样的代码会是什么样子?

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

【问题讨论】:

  • @awoodland:内存屏障不能让同阶段运行的其他着色器读取内存。
  • 查看我对stackoverflow.com/a/16802075/1388799 的回答,了解当前有效的解决 Nvidia Kepler 卡上 GLSL 信号量问题的解决方案。

标签: opengl concurrency glsl


【解决方案1】:

基本上,您只是在实现spinlock。只不过不是一个锁变量,而是整个纹理的锁。

从逻辑上讲,您所做的事情是有道理的。但就 OpenGL 而言,这实际上是行不通的

请看,OpenGL 着色器执行模型指出,调用以相对于彼此之间很大程度上未定义的顺序执行。但是自旋锁只有在保证各个线程之间的向前进展的情况下才起作用。基本上,自旋锁要求正在旋转的线程不能使执行系统饿死它正在等待的线程。

OpenGL 提供没有这样的保证。这意味着一个线程完全有可能锁定一个像素,然后停止执行(无论出于何种原因),而另一个线程出现并阻塞该像素。被阻塞的线程永远不会停止执行,拥有锁的线程永远不会重新开始执行。

这在真实系统中如何发生?好吧,假设您有一个片段着色器调用组在三角形的一些片段上执行。它们都锁定了像素。但是由于锁定区域内的条件分支,它们在执行中出现了分歧。执行的分歧可能意味着其中一些调用被转移到不同的执行单元。如果目前没有可用的,那么它们会有效地暂停,直到有可用的可用。

现在,假设出现了一些其他片段着色器调用组,并在发散组之前分配了一个执行单元。如果该组尝试自旋锁定来自发散组的像素,则它实质上是在使发散组的执行时间不足,等待永远不会发生的偶数。

现在显然,在真正的 GPU 中存在不止一个执行单元,但您可以想象,由于存在大量调用组,这种情况完全有可能偶尔会阻塞工作。

【讨论】:

  • 我不明白为什么整数纹理应该是屏幕大小。这意味着每个片段有一个锁值。但是要写入的图像的每个纹素不应该有一个锁定值吗?
  • @Mat:图像的纹素比屏幕的像素多吗?提前了解这些会有所帮助。
  • 有时更多,通常更少。这取决于具体情况。那么片段着色器会一直停留在while循环中,直到实际满足条件? GLSL 是否不能以某种方式保证着色器返回并因此在着色器调用旋转时间过长时终止它?
  • @Mat:GLSL 不会做任何此类事情。但是,司机可能会。这不会导致无限循环(因此 Window 不会杀死您的应用程序),但驱动程序或硬件可能会自动终止运行时间过长的着色器。或者它可能不会。
  • 这是一个老话题了,但是你用这种方法不会有死锁的风险吗?*
猜你喜欢
  • 2017-08-24
  • 2020-02-16
  • 1970-01-01
  • 2011-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多