【问题标题】:OpenGL: How to write into a texture channel by channel, by sampling and rendering to the same textureOpenGL:如何通过采样和渲染到相同的纹理逐个通道写入纹理通道
【发布时间】:2014-11-25 23:51:14
【问题描述】:

场景是: 我有一个纹理 A。 有3个循环。每个循环将一个通道写入纹理 A。 3 次循环后,A 中的 3 个通道全部更新。

着色器是这样的:

vec3 tmpVec3 = texture(inputTexture0, vUV).rgb; // inputTexture0 is texture A tmpVec3[channelIndex_P] = texture(inputTexture1, vUV).r;  // write one channel from inputTexture1

color = vec4(tmpVec3, 1.0);

它渲染到纹理A,即inputTexture0。 这样通过渲染和采样同一个纹理,我可以通过一个纹理节省内存。

但是,结果并不理想。

我阅读了文章“Sampling and Rendering to the Same Texture”。 它说:

“这意味着它可以做你想做的事,采样器可能会获取旧数据, 采样器可能会得到一半旧数据和一半新数据,或者它可能会得到垃圾 数据。这些都是可能的结果。”

但是由于特定像素的写入数据总是在获取特定像素的数据之后发生,为什么不可能呢?

另一篇文章“Sampling from and rendering to the same texture and parallel sorting / hashing” 它说:

"但是如果每个帧缓冲区像素中的结果都是 写入该像素的片段之一,而不是组合 来自多个片段的值,这个功能仍然是 对于在 glsl 中实现的并行排序/散列算法很有用。”

我不明白上面的话。它是否说在某些情况下可以使用“采样和渲染到相同的纹理”并具有定义的结果。那么该怎么做呢?如何解决我目前的情况,因为我想保存一个纹理变量。

【问题讨论】:

  • 您的目标是什么版本的 OpenGL? GL4 有图像加载/存储可以帮助你,但你必须自己实现同步。
  • OpenGL 3.2。我的困惑是:在这里我总是写入与之前读取相同的像素。那么为什么它不起作用呢?第二个链接意味着在某些情况下它可以工作?
  • 您可以在 NV 硬件上使用 texture barriers 来做到这一点。我不知道其他供应商是否曾经采用过该扩展,考虑到它在添加计算机着色器和图像加载/存储时基本上已经过时了。
  • 谢谢。那么请您解释一下为什么我的情况无法解决,因为兴趣过程的写入和读取不是同时进行的。

标签: opengl textures fragment-shader


【解决方案1】:

那么请您解释一下为什么我的情况无法解决,因为兴趣过程的写入和读取不是同时进行的。

它们绝对是同时处理的,我认为您不了解着色器是如何在 GPU 上调度的。片段着色器不会串行运行,并且您对纹理的写入尝试不一定会在并行调用读取相同纹理之前完成(也不能保证纹理内存不会被缓存;对内存的更改不可见) .

这就是您需要障碍的原因。纹理屏障(NV 特定扩展)或通用内存屏障将导致着色器调用在屏障处停止,直到着色器的每个实例都完成读取或写入,然后继续。这将防止可能导致读取错误数据的数据危害。

要在 GL3 类实现中执行此操作,纹理屏障可能是您唯一的选择。在 GL4.2+ 中,图像加载/存储将是首选方法,一些较旧的实现通过 GL_ARB_shader_image_load_store 扩展支持这一点。

但是,如果没有这些事情,您现在尝试执行的操作会调用未定义的行为。您需要某种同步结构才能正确执行此操作,这就是障碍的用武之地。

【讨论】:

  • 谢谢。但我就是不明白。如果片段着色器不串行运行,在我的示例中,即使我不让采样和渲染相同的纹理发生,也必须在写入之前进行读取以使着色器工作:我的理解哪里错了?
  • @user1914692:不,这种行为只适用于连贯记忆。在对纹理进行采样之前,片段着色器的输出不需要被写入并且缓存无效,实际上通常不需要,除非您使用带有coherent 限定符的图像加载/存储。此外,相邻的片段将采样一个 2x2 的纹素窗口(如果您使用GL_LINEAR 过滤,这是默认设置),甚至还不会计算相邻的纹素。
  • @user1914692:着色器从来没有打算按照您现在尝试使用它们的方式工作,因此 GLSL 编译器会执行各种缓存和其他优化,当您尝试读/写相同的内存。但是创建的扩展允许您同步和禁用这些优化,这样您所做的事情就不会产生未定义的行为。
  • 对不起,我有点笨。对于一个着色器程序中的代码,它是串行的,对吗?如果不是串行的,我们可以在shader程序中随机换行。或者你能给我一些链接来更彻底地理解它吗?
  • @user1914692:我真的不知道如何比我已经知道的更好地解释它。读取和写入同一内​​存会产生未定义的行为,因为着色器不应该以这种方式工作。您可以轻松地结束读取缓存值。您需要一致的内存来确保对纹理内存所做的更改是可见。您还需要同步,因为正如您的问题所解释的那样,您在三个循环中执行此操作。在完成写入之前,您不想再次读取纹理内存。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-10
  • 2015-05-10
  • 1970-01-01
  • 2015-11-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多