2017-08-10 100 views
1

OpenGL红皮书版本8(GL 4.3)示例11.19将imageLoad()放置在while循环中,保持轮询,直到前一个基元的至少一个片段已更新此值。这本书说GLSL memoryBarrier()

例11.19显示了一个非常简单的内存障碍用例。它允许 片段之间的某种程度的排序得到保证。在 functionUsingBarriers()的顶部,使用一个简单的循环等待内存位置的内容 到达我们当前的原始ID。 因为我们知道 没有来自同一个基元的两个片段可以落在相同的 像素上,所以我们知道当我们在 函数的主体中执行代码时,来自前一个基元的至少一个片段是 处理。然后我们使用非原子操作来修改我们的 片段位置处的内存内容。我们发信号给其他着色器 调用,我们通过写入最初在函数顶部轮询的共享内存位置 来完成调用。

为了确保我们的修改的图像内容写回之前其他着色器调用内存 开始进入函数体中,我们使用 彩色图像的更新和 原始计数器强制排序之间内存屏障通话。

然而,GL规范4.3表示由另一个调用书面

有一个调用民调内存假定其他调用已经启动,可以完成其写入

那么我们怎么能确保先前原语的片段调用已启动并完成其写入?

邮政SRC代码

#version 420 core 

layout (rgba32f} uniform coherent image2D my_image; 

// Declaration of function 
void functionUsingBarriers(coherent uimageBuffer i) 

{ 

    uint val; 

    // This loop essentially waits until at least one fragment from 
    // an earlier primitive (that is, one with gl_PrimitiveID - 1) 
    // has reached the end of this function point. Note that this is 
    // not a robust loop as not every primitive will generate 
    // fragments. 
    do 
    { 
     val = imageLoad(i, 0).x; 
    } while (val != gl_PrimitiveID); 

    // At this point, we can load data from another global image 
    vec4 frag = imageLoad(my_image, gl_FragCoord.xy); 

    // Operate on it... 
    frag *= 0.1234; 
    frag = pow(frag, 2.2); 

    // Write it back to memory 
    imageStore(my_image, gl_FragCoord.xy, frag); 

    // Now, we’re about to signal that we’re done with processing 
    // the pixel. We need to ensure that all stores thus far have 
    // been posted to memory. So, we insert a memory barrier. 
    memoryBarrier(); 

    // Now we write back into the original "primitive count" memory 
    // to signal that we have reached this point. The stores 
    // resulting from processing "my_image" will have reached memory 
    // before this store is committed due to the barrier. 
    imageStore(i, 0, gl_PrimitiveID + 1); 

    // Now issue another barrier to ensure that the results of the 
    // image store are committed to memory before this shader 
    // invocation ends. 
    memoryBarrier(); 
} 
+0

并非我们所有人都有这本书。你能否真正向我们提供这个例子中正在发生的事情的具体细节?特别是,“以前的原始”是什么意思? –

+0

嗨尼科尔,我已经更新了这个问题。请重新阅读。 –

回答

0

此代码(以及随之而来的文字)是错误的废话。此声明:

因为我们知道,从同一原始的没有两个片段可以在同一像素上的土地,我们知道,当我们正在执行的函数体的代码,至少一个碎片从之前的基元已经被处理。

即使我们假设,在网格中的原语不重叠(几乎在一般合理的假设),这意味着正是没什么对GPU的跨越原语分配工作。

OpenGL规范阐明了这一点:

同一着色器类型的调用的相对顺序是不确定的。在基元B上工作时,由着色器发出的存储可能会完成前 到基元A的存储,即使基元A在原始基元 B之前指定。这甚至适用于片段着色器;而片段着色器输出 总是以原始顺序写入帧缓冲区,片段着色器调用执行的存储不是。

...

上着色器调用顺序的上述限制还使一个单一的组原语不可实现的内某些形式的着色器调用之间 同步。例如,具有由另一个调用写入的一个调用轮询内存假定另一个调用已经启动并且可以完成其写操作。这种保证唯一的情况是 一个着色器调用的输入是从上一阶段 中的着色器调用的输出中生成的。

是,OpenGL规范特意叫了这一点的东西,你不能做。我不知道如何进入官方的OpenGL书籍,但你的直觉是正确的:这是完全错误的。这实际上是为什么ARB_fragment_shader_interlock存在的原因:否则,你不能做这样的事情。

+0

非常感谢。你的澄清维持我的怀疑。我怀疑我的直觉,因为这个代码示例来自权威的OpenGL红皮书! –