OpenGL红皮书版本8(GL4.3)示例11.19将一个imageLoad()放在一个while循环中,保持轮询,直到至少有一个上一个原语片段更新了这个值。这本书说
示例11.19显示了一个非常简单的内存屏障用例。它保证了片段之间的某种程度的有序性。在
functionUsingBarriers()的顶部,使用一个简单的循环来等待内存位置的内容到达当前的原始ID。因为我们知道来自同一原语的任何两个片段都不能降落在同一个像素上,所以我们知道当我们在函数体中执行代码时,至少已经处理了前一个原语的一个片段。然后,我们使用非原子操作修改片段所在位置的内存内容。我们向其他着色器调用发出信号,我们是通过写入最初在函数顶部轮询的共享内存位置来完成的。 为了确保修改后的图像内容在其他着色器调用开始到函数主体之前写回内存,我们在彩色图像更新和原始计数器之间使用对memoryBarrier的调用来执行排序。
然而,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();
}发布于 2017-08-10 14:08:09
这段代码(以及它附带的文本)是错误的无稽之谈。请考虑这一声明:
因为我们知道来自同一原语的任何两个片段都不能降落在同一个像素上,所以我们知道,当我们在函数体中执行代码时,至少已经处理了前一个原语中的一个片段。
即使我们假设网格中的原语不重叠(一般情况下几乎不是一个合理的假设),这也意味着GPU在原语之间的工作分配没有任何意义。
OpenGL规范明确了这一点:
同一着色器类型调用的相对顺序未定义。使用原语B时由着色器发出的存储可能会在原语A的存储之前完成,即使原语A是在原语B之前指定的,这甚至适用于片段着色器;虽然片段着色器输出总是以原语顺序写入帧缓冲区,但片段着色器调用执行的存储不是。 ..。 上述对着色器调用顺序的限制也使得单个原语集中的着色器调用之间的某些形式的同步无法实现。例如,一个调用轮询内存由另一个调用编写,假设另一个调用已经启动并可以完成其写操作。做出这种保证的唯一情况是,一个着色器调用的输入是从以前阶段的着色器调用的输出中生成的。
是的,OpenGL规范明确地将此称为您无法做的事情。我不知道这是如何进入OpenGL的官方书籍,但你的直觉是正确的:这是完全错误的。这就是为什么ARB_fragment_shader_interlock存在的原因:否则,您就不能做这样的事情。
https://stackoverflow.com/questions/45604114
复制相似问题