【问题标题】:OpenGL performance: VBOs/Vertex shader vs. glEnableClientState/glVertexPointer and glMultMatrix vs glUniformMatrixOpenGL 性能:VBO/顶点着色器与 glEnableClientState/glVertexPointer 和 glMultMatrix 与 glUniformMatrix
【发布时间】:2015-10-07 13:10:40
【问题描述】:

我对 OpenGL 相当陌生。我刚开始学习着色器,尤其是顶点和片段着色器。我的理解是,当通过着色器完成操作时,您可以获得相当显着的性能提升,因为着色器在 GPU 上运行。

但是,我已经尝试对这个主题进行一些研究,并且我似乎发现了一些关于这个问题的不同意见,至少在顶点着色器方面是这样。

渲染如下对象与使用 glMultMatrixd 之类的调用进行转换之间的主要区别是什么:

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);

    glVertexPointer(3, GL_FLOAT, 0, &vertices[0]);
    glNormalPointer(GL_FLOAT, 0, &normals[0]);

    glDrawArrays(GL_TRIANGLES, 0, vertices.size() / 3);

    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);

vs 使用如下所示的 VAO/VBO 设置,我将转换矩阵设置为着色器中的统一变量并在那里进行转换。

glBindVertexArray(vaoHandle);
glBindBuffer(GL_ARRAY_BUFFER, bufferHandle[0]);


glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_STATIC_DRAW);

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);

glBindBuffer(GL_ARRAY_BUFFER, bufferHandle[1]);
glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(float), normals.data(), GL_STATIC_DRAW);

glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);

.....

glBindVertexArray(vaoHandle);
glDrawArrays(GL_TRIANGLES, 0, vertices.size() / 3);

请注意...我不在乎下面的代码有什么问题。同样,我只是想知道实际上是否存在性能差异,为什么?这两种方法的引擎盖下发生了什么?为什么一个会比另一个更快/更慢?转换也是如此。为什么使用统一的顶点着色器比使用 glMultMatrix 更快?

【问题讨论】:

    标签: c++ performance opengl graphics glsl


    【解决方案1】:

    GPU 最终执行的内容在任何至少半新的 GPU 上对于这两种情况都基本相同。我认为在相当长的一段时间内没有人构建过真正为固定管道配备专用硬件的 GPU。对于桌面 GPU,我相信这种转变发生在大约 10 多年前(在那之前的几年里,它们已经是可编程的,但仍然有固定功能的硬件)。对于移动 GPU,向纯可编程 GPU 的过渡发生在后来,但也发生在相当长的一段时间之前。

    如果您使用固定管道,驱动程序会根据您设置的固定功能状态为您生成着色器代码。因此,您真正比较的是从传递给驱动程序的 GLSL 编译的着色器,以及驱动程序根据状态值生成的着色器。

    着色器显然在这两种情况下都将在 GPU 上运行,因此除此之外并没有根本区别。

    现在,您可能会问:哪个更有效?一般没有办法说。一些注意事项包括:

    • 由驱动程序为固定功能状态生成的着色器可能具有优势,因为它们经过大量调整,最有可能在着色器程序集中。这主要是针对工作站级 GPU 完成的,其中许多软件使用传统固定功能 OpenGL 的时间要长得多。

    • 您在 GLSL 中编写的着色器的优势在于,它们完全满足您的需求,没有别的。因此,从这个意义上说,它们可能更适合您的精确用例。当然,驱动程序从固定功能状态生成的相应着色器也可以高度精简,但它不在您的控制范围内。尤其是如果您关心各种平台上的性能,坦率地说,我不会相信所有 GPU 供应商都能为我生成高效的着色器代码。

    当然,编写自己的着色器代码具有除此之外的主要优势。它允许您完成固定管道无法完成的事情。即使在固定管道可以完成这项工作的情况下,一旦您掌握了编写 GLSL 代码的窍门,使用着色器通常也会更容易。

    【讨论】:

      【解决方案2】:

      主要的性能差异不是来自使用着色器,而是来自使用 VBO。

      在第一个示例中,verticesnormals 驻留在客户端内存(也称为应用程序内存)中。每当绘制它们时,这些数组就会被复制到图形卡中,这可能需要很长时间。

      与此相反,第二个示例将所有相关值存储在位于图形内存中的 VBO 中。因此数据已经存储在最佳位置,绘图无需复制。

      【讨论】:

      • 谢谢!这正是我正在寻找的答案。那么一个着色器(至少是一个顶点着色器),真的不能提供任何性能优势吗?
      • 我可以,这取决于你做什么,但总的来说我会拒绝。它所做的肯定是提供更多功能。
      • @user3827379:过去十年中构建的 GPU 无论如何都没有任何硬连线的顶点处理,因此从 GPU 的角度来看,不使用着色器和使用着色器并没有太大区别.在 2015 年使用已弃用的固定功能管道和矩阵堆栈确实没有多大意义。
      • 好吧,我听说过很多,但为什么在这种情况下?就像我有一个遗留应用程序使用 glMultMatrixd 的第一个示例方法而不是具有统一变量的顶点着色器一样,使用着色器/统一方法进行转换有什么好处?与我的第一种方法相比,我使用 VAO/VBO 获得了性能提升,但是是否可以将 VAO/VBO 与矩阵堆栈而不是着色器一起使用?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-25
      • 2011-05-24
      • 1970-01-01
      • 2013-12-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多