为什么此几何着色器会使我的程序减慢这么多?


27

我有一个OpenGL程序,正在渲染一个地形网格物体。我将顶点放置在顶点缓冲区中,但还没有在片段着色器中真正着色它们。我一次添加了一个几何着色器。

在添加几何体着色器之前,当我仅对流水线的片段和顶点着色步骤进行编程时,我获得的帧率约为30+。足够使我看不到任何断断续续的情况。添加几何体着色器后,我每秒获得大约5帧。为什么?这是整个几何着色器:

#version 420

layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;

void main()
{
    for (int i = 0; i < gl_in.length(); i++)
    {
        gl_Position = gl_in[i].gl_Position;
        EmitVertex();
    }
    EndPrimitive();
}

这不是OpenGL在没有几何着色器的情况下所做的吗?

Answers:


40

这不是OpenGL在没有几何着色器的情况下所做的吗?

不,不是。GS是可选步骤,而不是默认步骤。

为了使OpenGL执行几何着色器,它必须执行所谓的“ 原始程序集 ”。当您通过渲染一系列三角形时GL_TRIANGLE_STRIP,OpenGL会进行内部处理,将每3个相邻的顶点转换为一个单独的三角形,并适当地修改缠绕顺序。

通常,当不使用GS时,此过程执行一次。但是,当您使用GS时,必须在GS执行之前执行它。但是它也必须 GS 之后执行,因为GS可以输出完全不同的原始类型(例如,四边形)。

因此,现在您要使系统基本上不做任何额外的工作。毕竟,OpenGL无法假设您的GS没有执行任何操作(这是无法确定的问题)。

此外,存在GS时,许多优化不再起作用。考虑索引渲染。

来自元素数组缓冲区的每个索引将从顶点着色器产生相同的输出。因此,GPU通常会将这些输出缓存在T&L后缓存中。如果发现缓存中已存在索引,则不会再次运行VS。它只是从缓存中获取数据。

它是什么”?“它”是…… 原始装配单元。是的,使用GS时会运行两次。索引缓存的东西?它仅适用于GS 的输入

那么,GS的输出会怎样?好吧,这取决于硬件。但是它必须进入某种内存缓冲区。问题就在这里:那个缓冲区根本没有索引。这就像glDrawArrays的情况。

因此,如果您发送的索引缓冲区0, 1, 2, 0, 2, 3,则会在T&L后缓存中转换为4个顶点。但是,GS后顶点的缓冲区现在有6个顶点。GS后缓冲区占用更多空间。因此,如果您遇到无法正确创建T&L优化后的三角形列表或条带的麻烦,并且像您那样翻转了直通GS,则基本上可以消除这种优化带来的一半性能提升。

这不是没有用,但确实很痛。

此外,许多GL 3.x级GPU(又称DX10)具有较小的GS后缓冲区。缓冲区越小,您可以同时激活的GS调用就越少。因此,您的硬件实际上是GS的瓶颈。由于镶嵌是4.x类硬件的一大功能,因此大多数此类硬件具有足以使较重的GS使用可行的缓冲区。

因此,使用GS更可能使您的代码顶点处理成为瓶颈。当然,您总是可以通过使顶点着色器和片段着色器更加复杂来利用它,因为这在当时只是免费的性能。

有关GS引起的减速的更多信息,请阅读本文

这是关于GS的基本经验法则:永远不要使用GS,因为您认为它会加快渲染速度。当它使您想做的事情成为可能时,应该使用它如果您想做的是优化,请使用其他方法。

一般的例外情况是:


我正在尝试通过获取每个多边形的最高高度并减去其最低高度来计算其陡度。但是,如果几何着色器一定会使我的速度减慢这一数量,那么我认为我可能可以在顶点着色器中创造性地进行操作。
2013年

1
@Avi请注意,三角形的最高点和最低点不会使您陡峭;您需要所有这三点。
sam hocevar

2
就个人而言,我总是发现实例化对于点精灵比GS更有用。
Maximus Minimus 2013年

1
点精灵的异常是否会泛化为的着色器layout(points) in;?还是固定输出大小?还是两者兼而有之?
菲利普(Philip)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.