2

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

有什么结论或想法吗?

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

4

2 回答 2

5

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

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

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

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

于 2013-07-15T04:12:41.867 回答
5

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

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

添加具有不同坐标的输出会使这大大复杂化。假设一个片段被一个着色器的两个或多个实例写入。为了确保正确的结果,GPU 可以将一个指定为授权而忽略另一个(它怎么知道哪个会写入?)或者您可以添加一个互斥体,让一个等待另一个完成。另一种选择是允许任何一个先完成的竞争条件。

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

于 2013-07-12T14:54:08.743 回答