29

当我读到这个(来自OpenGL wiki)时,我很震惊:

glTranslate、glRotate、glScale

这些硬件加速了吗?

不,没有已知的 GPU 可以执行此操作。驱动程序在 CPU 上计算矩阵并将其上传到 GPU。

所有其他矩阵运算也在 CPU 上完成:glPushMatrix、glPopMatrix、glLoadIdentity、glFrustum、glOrtho。

这就是为什么这些函数在 GL 3.0 中被认为已弃用的原因。您应该拥有自己的数学库,构建自己的矩阵,将矩阵上传到着色器。

很长一段时间以来,认为大多数 OpenGL 函数都使用 GPU 进行计算。我不确定这是否是一个普遍的误解,但经过一段时间的思考,这是有道理的。由于状态切换太多,旧的 OpenGL 函数(2.x 和更早版本)确实不适合实际应用程序。

这让我意识到,可能许多 OpenGL 函数根本不使用 GPU。

所以,问题是:

哪些 OpenGL 函数调用不使用 GPU?

我相信知道上述问题的答案将帮助我成为一个更好的 OpenGL 程序员。请分享您的一些见解。

编辑:

我知道这个问题很容易导致优化级别。这很好,但这不是这个问题的意图。

如果有人知道不使用 GPU 的某个流行实现(如 AshleysBrain 建议的、nVidia/ATI 和可能依赖于操作系统的)上的一组 GL 函数,那就是我所追求的!

合理的优化指南稍后会出现。让我们关注这个主题的功能。

编辑2:

本主题不是关于矩阵转换如何工作的。还有其他 主题

4

5 回答 5

41

男孩,这是一个很大的话题。

首先,我将从显而易见的开始:由于您从 CPU 调用函数(任何函数),它必须至少部分在 CPU 上运行。所以真正的问题是,有多少工作是在 CPU 上完成的,有多少是在 GPU 上完成的。

其次,为了让GPU能够执行一些命令,CPU必须准备一个命令描述来传递。这里的最小集合是一个命令令牌,描述要做什么,以及要执行的操作的数据。CPU 如何触发 GPU 执行命令也有些重要。由于大多数时候,这很昂贵,CPU 并不经常这样做,而是将命令批处理到命令缓冲区中,并简单地将整个缓冲区发送给 GPU 处理。

所有这一切都表明,将工作传递给 GPU 并不是一项自由活动。该成本必须与仅在 CPU 上运行该功能相提并论(无论我们在谈论什么)。

退后一步,你必须问问自己为什么需要 GPU。事实是,纯 CPU 实现可以完成这项工作(正如 AshleysBrain 提到的)。GPU 的强大之处在于它的设计可以处理:

  • 专门的任务(光栅化、混合、纹理过滤、blitting ......)
  • 高度并行的工作负载(DeadMG 在他的回答中指出了这一点),当 CPU 更多地设计为处理单线程工作时。

这些是决定芯片内容的指导原则。任何可以从中受益的东西都应该在 GPU 上运行。其他任何东西都应该在 CPU 上。

顺便说一句,这很有趣。GL 的某些功能(主要是在弃用之前)实际上并没有明确描述。显示列表可能是此类功能的最佳示例。只要保留 GL 显示列表的语义(在一般的)。所以一些实现只选择将显示列表中有限的调用子集推送到计算格式,并选择简单地在 CPU 上重放命令流的其余部分。

选择是另一个不清楚在 GPU 上执行是否有价值的问题。

最后,我不得不说,API 调用与 CPU 或 GPU 上的工作量之间几乎没有相关性。状态设置 API 倾向于只修改驱动程序数据中某处的结构。它的效果只有在调用 Draw 或类似的东西时才可见。

很多 GL API 都是这样工作的。到那时,询问glEnable(GL_BLEND)是在 CPU 还是 GPU 上执行是没有意义的。重要的是调用 Draw 时是否会在 GPU 上进行混合。因此,从这个意义上说,大多数GL 入口点根本没有加速。

我还可以稍微扩展一下数据传输,但 Danvil 谈到了它。

我将以小“软件路径”结束。从历史上看,无论硬件特殊情况是什么,GL 都必须努力规范。这意味着如果硬件没有处理特定的 GL 功能,那么它必须模拟它,或者在软件中完全实现它。这种情况有很多,但让很多人印象深刻的是GLSL开始出现的时候。

由于没有实用的方法来估计 GLSL 着色器的代码大小,因此决定 GL 应该将任何着色器长度视为有效。含义很明确:要么实现可以采用任意长度着色器的 h/w(当时不现实),要么实现 as/w 着色器仿真(或者,正如一些供应商选择的那样,根本不符合要求)。所以,如果你在片段着色器上触发了这个条件,你的整个GL 很可能最终都在 CPU 上执行,即使你有一个空闲的 GPU,至少对于那个绘图来说。

于 2010-04-26T20:52:21.520 回答
10

问题可能应该是“哪些函数占用了意想不到的大量 CPU 时间?”

为投影和视图保留一个矩阵堆栈并不是 GPU 可以比 CPU 处理得更好的事情(相反......)。另一个例子是着色器编译。为什么要在 GPU 上运行?有一个解析器、一个编译器……,它们只是普通的 CPU 程序,比如 C++ 编译器。

例如,潜在的“危险”函数调用是glReadPixels因为数据可以通过有限的总线从主机 (=CPU) 内存复制到设备 (=GPU) 内存。在这个类别中还有类似glTexImage_Dor的函数glBufferData

所以一般来说,如果你想知道一个 OpenGL 调用占用了多少 CPU 时间,试着了解它的功能。并注意所有将数据从主机复制到设备并返回的功能!

于 2010-04-26T13:06:17.153 回答
8

通常,如果一个操作是针对某事物的,它将发生在 GPU 上。一个例子是实际的变换——每个顶点都完成一次。另一方面,如果它在每个大型操作中只发生一次,它将在 CPU 上 - 例如创建变换矩阵,每次对象状态更改时只执行一次,或者每帧执行一次。

这只是一个一般性的答案,一些功能会反过来出现 - 以及依赖于实现。但是,通常情况下,这对程序员来说并不重要。只要您在进行游戏模拟或其他任何事情时让 GPU 有足够的时间来完成它的工作,或者拥有可靠的线程模型,您就不必担心太多。

@向 GPU 发送数据:据我所知(仅使用 Direct3D),这一切都是在着色器中完成的,这就是着色器的用途。

于 2010-04-26T17:53:17.447 回答
5

glTranslate, glRotate and glScale change the current active transformation matrix. This is of course a CPU operation. The model view and projection matrices just describes how the GPU should transforms vertices when issue a rendering command.

So e.g. by calling glTranslate nothing is translated at all yet. Before rendering the current projection and model view matrices are multiplied (MVP = projection * modelview) then this single matrix is copied to the GPU and then the GPU does the matrix * vertex multiplications ("T&L") for each vertex. So the translation/scaling/projection of the vertices is done by the GPU.

Also you really should not be worried about the performance if you don't use these functions in an inner loop somewhere. glTranslate results in three additions. glScale and glRotate are a bit more complex.

My advice is that you should learn a bit more about linear algebra. This is essential for working with 3D APIs.

于 2010-04-26T14:56:11.397 回答
2

有 OpenGL 的软件渲染实现,因此可能没有OpenGL 函数在 GPU 上运行。还有一些硬件不支持硬件中的某些渲染状态,所以如果你设置了某个状态,切换到软件渲染,再一次,GPU 上不会运行任何东西(即使那里有)。因此,我认为“GPU 加速功能”和“非 GPU 加速功能”之间没有明显区别。

为了安全起见,请让事情尽可能简单。简单的顶点渲染和 Z 缓冲等基本功能最有可能是硬件加速的,所以如果你能坚持以最小的状态变化,你最有可能保持硬件加速。这也是最大化硬件加速渲染性能的方法——显卡喜欢保持在一个状态,只是处理一堆顶点。

于 2010-04-26T13:39:46.133 回答