我最近想开发OpenGL的计算着色器。在这个实验中,我想访问一个附加到FrameBufferObject的颜色纹理。当尝试使用布局(rgba32f)readonly image2D将纹理传递给计算着色器时,没有传入任何内容。我重写了计算着色器以使用sampler2D。采样器工作正常。
我还测试了gimage2D计算着色器只有纹理,没有附加到任何东西。这也按预期工作。
我没有找到任何文档说明使用gimage2D无法在计算着色器中访问附加到FBO的纹理。我还没有找到任何文档说明计算着色器无法写入FBO。
我想我的问题是为什么不能使用gimage2D在计算着色器中访问附加到FBO的纹理?有文件解释这个吗?
答案 0 :(得分:3)
“我想我的问题是为什么不能使用gimage2D在计算着色器中访问附加到FBO的纹理?”
您不使用gimage2D
,如果您在GLSL文档中看到以g
为前缀的类型,则它是通用类型。 (例如gvec<N>
,gsampler...
等。这意味着该函数对每种vec<N>
或sampler...
都有重载。在这种情况下,gimage2D
是简短的说法“...此函数接受image2D
,iimage2D
或uimage2D
”。
没有实际的gimage2D
类型,g
前缀的发明仅仅是为了保持GLSL文档简洁易读;)
我想你已经知道了这一点,因为问题中列出的唯一实际代码是使用image2D
,但事情的编写方式我不确定。
特别注意:GL_FRAMEBUFFER_BARRIER_BIT
。
计算着色器与渲染管道的各个阶段分开安排;他们有自己的单级管道。这意味着如果您在FBO附件中绘制某些内容,您的计算机着色器可能会在您开始绘制之前运行,或者计算着色器可能使用数据的(无效)缓存视图,因为渲染管道中所做的更改对于计算管道。内存障碍将有助于同步渲染管道和计算两者之间共享资源的管道。
渲染管道有很多隐式同步和多阶段数据流,为着色器提供非常简单的顺序排序(例如glDraw*
启动顶点 - >几何 - >片段),但计算管道几乎所有这些都有利于显式同步。使用计算着色器和图像加载/存储时,您需要考虑各种各样的危险,而不是传统的顶点/几何/曲面细分/片段。
换句话说,在计算着色器中声明某些coherent
以及 着色器级别 的适当屏障时,将处理计算着色器之间的同步调用,因为计算管道与渲染管道分开,它不会在计算着色器和片段着色器之间同步图像加载/存储。为此,您需要glMemoryBarrier (...)
来同步 命令级别 对内存资源的访问。 glDraw* (...)
(渲染管道的入口点)是来自glDispatch* (...)
(计算管道入口点)的单独命令,您需要确保为图像加载/存储正确排序这些单独的命令,以显示一致的行为。
没有内存屏障,无法保证执行顺序命令;只是他们产生的结果与你发布的顺序一致。在渲染管道中,它严格定义了每个着色器阶段的输入/输出,GL实现可以智能地重新排序命令,同时相对容易地保持此属性。对于计算着色器以及一般的图像加载/存储,I / O完全由运行时流程决定,如果没有一些帮助(内存障碍),它是不可能的。
TL; DR :如果使用采样器而非图像加载/存储,它的工作原理归结为一致性保证(或缺少保证)。图像加载/存储只需 不 保证图像的读取与写入图像的任何内容相关(严格排序),而是要求您明确同步访问到图像。这实际上是有益的,因为它允许您同时读取/写入相同的图像,而不会导致未定义的行为,但它需要您做一些额外的努力才能使其工作。