是否可以在 gl_FragColor 中写入一堆像素?

Yeh*_*mov 2 opengl opengl-es

有没有人熟悉某种OpenGL 魔法来摆脱在片段着色器计算一堆像素而不是只有 1 个?尤其是这个问题对于 OpenGL ES 来说很热门,实际上这意味着移动平台的缺陷,并且需要以更准确(在性能意义上)的方式来处理它。

有什么结论或想法吗?

PS,由于 GPU 架构组织,它是已知的着色器,它为每个纹理 monad 并行运行。但也许有技术可以将它从一个像素提升到一组像素,或者实现您自己的 glTexture 组织。通过这种方式,可以在 GPU 中更快地完成很多工作。

Jus*_*ers 5

OpenGL 不支持在着色器中写入多个片段(意味着具有不同的坐标),这是有充分理由的,它会阻碍 GPU 并行计算每个片段的能力,这是其最大的优势。

着色器的结构起初可能看起来很奇怪,因为整个程序只为一个顶点或片段编写。你可能想知道为什么你不能“看到”相邻部分发生了什么?原因是着色器程序的一个实例为每个输出片段同时在每个核心/线程上运行,因此它们必须彼此独立。并行、独立的处理允许 GPU 快速渲染,因为处理一批像素的总时间仅与单个最密集的像素一样长。

添加具有不同坐标的输出使这变得非常复杂。假设单个片段由着色器的两个或多个实例写入。为了确保正确的结果,GPU 可以指定一个作为权限并忽略另一个(它如何知道哪个将写入?)或者您可以添加一个互斥锁,并让一个等待另一个完成。另一种选择是允许与先完成者有关的竞争条件。

无论哪种方式,这都会极大地减慢过程,使着色器变得丑陋,并引入不正确和不可预测的行为。


小智 5

首先,您可以从 OpenGL 3 及更高版本中的单个片段着色器计算多个输出。一个帧缓冲对象可以附加多个 RGBA 表面(渲染缓冲对象),并通过使用 gl_FragData[n] 而不是 gl_FragColor 为每个表面生成一个 RGBA。请参阅第 5 版 OpenGL SuperBible 的第 8 章。

但是,只能为每个缓冲区中相同的 X、Y 像素坐标生成多个输出。这与旧样式片段着色器只能生成一个输出并且不能更改 gl_FragCoord 的原因相同。OpenGL 保证在渲染任何图元时,只有一个片段着色器将写入目标帧缓冲区中的任何 X、Y 像素。

如果片段着色器可以在不同的 X、Y 坐标处生成多个像素值,则它可能会尝试写入与同一片段着色器的另一次执行相同的目标像素。如果片段着色器可以更改像素 X 或 Y,则相同。这是尝试更新共享内存问题的经典多线程问题。

解决它的一种方法是说“如果发生这种情况,结果是不可预测的”,这从程序员的角度来看很糟糕,因为它完全不受您的控制。或者片段着色器将不得不锁定它们正在更新的像素,这会使 GPU 变得更加复杂和昂贵,并且性能会下降。或者片段着色器将以某种定义的顺序执行(例如从左上到右下)而不是并行执行,这不需要锁,但性能会更糟糕。