采用Intel HD和NVidia GPU的OpenGL程序

时间:2014-11-13 11:58:05

标签: c++ opengl glsl gpu nvidia

我是OpenGL的新手,我希望有人向我解释程序如何使用GPU。

我有一个三角形数组(包含3个点的类)。以下是绘制它们的代码(我知道这些函数已被删除)。

glBegin(GL_LINES);
for(int i=0; i<trsize; ++i){
    glVertex3d((GLdouble)trarr[i].p1().x(), (GLdouble)trarr[i].p1().y(), (GLdouble)trarr[i].p1().z());
    glVertex3d((GLdouble)trarr[i].p2().x(), (GLdouble)trarr[i].p2().y(), (GLdouble)trarr[i].p2().z());
    glVertex3d((GLdouble)trarr[i].p3().x(), (GLdouble)trarr[i].p3().y(), (GLdouble)trarr[i].p3().z());
}
glEnd();

我还使用用于旋转,转换等的已删除功能

当数组大小超过50k时,程序运行速度很慢。 我试图只使用英特尔高清或仅使用NVidia gtx860M(默认的NVidia程序允许选择GPU),但它们都非常慢。也许Intel HD的工作速度更快。

那么,为什么这两个GPU之间没有区别? 使用着色器会使程序更快地运行吗?

3 个答案:

答案 0 :(得分:2)

可能的瓶颈是在顶点上循环,访问数组并拉出顶点数据每次渲染50000次,然后将数据发送到GPU进行渲染。

使用VBO确实会更快,并且压缩提取数据并在初始化时将其发送到GPU的成本。

即使使用用户内存缓冲区也会加快速度,因为您不会调用50k函数,但驱动程序只能对相关数据进行memcopy。

答案 1 :(得分:1)

  

当数组大小超过50k时,程序运行速度很慢。

在中间模式下绘制时的主要瓶颈是,所有顶点都必须在每个帧中从程序存储器传输到GPU内存。 GPU和CPU之间的总线在它可以传输的数据量上受到限制,因此最好的猜测是,50k三角形的数量远远超过总线可以传输的数量。另一个问题是,驱动程序必须处理你在CPU上发送给他的所有命令,这也可能是一个很大的开销。

  

那么,为什么这两个GPU之间没有区别?

英特尔HD卡和NVIDIA卡之间存在巨大的性能差异,但它们之间的总线可能相同。

  

使用着色器可以更快地运行程序吗?

它不会直接受到着色器用户的好处,但肯定是将这些顶点存储在gpu内存上(参见VBO / VAO)。第二个改进是,你可以只使用一次绘制调用来渲染整个VBO,这减少了cpu必须处理的指令量。

答案 2 :(得分:0)

与具有显着不同性能潜力的两个GPU看到相同的性能肯定表明您的代码受CPU限制。但我非常怀疑其他答案/评论中有关性能瓶颈的一些理论。

  • 一些简单的计算表明,内存带宽根本不应该发挥作用。拥有50,​​000个三角形,每个三个顶点,每个顶点24个字节,您每帧查看3,600,000个字节的顶点数据。假设你的目标是60帧/秒,这是一个超过200 MB /秒。这不到现代PC内存带宽的1%。
  • 现代GPU上最直接模式的最实用的实现是驱动程序将所有数据收集到缓冲区中,然后在缓冲区填满时立即提交所有数据。所以不需要大量的内核调用,每个顶点的数据肯定不会单独发送到GPU。

驱动程序开销很可能是主要罪魁祸首。每个三角形有50,000个三角形和3个API调用,每帧150,000次API调用,如果您的目标是60帧/秒,则为每秒900万次API调用。那太多了!对于每个电话,您都会:

  • 在您自己的代码中进行循环和数组访问。
  • 实际的函数调用。
  • 论证传递。
  • 驱动程序代码中的状态管理和逻辑。

一个重要的方面使得这比你需要的更糟糕:你为坐标使用double值。与使用float值相比,这需要传递的数据量翻倍。由于OpenGL顶点流水线以单精度(*)运行,因此驱动程序必须将所有值转换为float

我怀疑即使使用已弃用的立即模式调用,如果您开始使用float用于所有坐标(您自己的存储,并将它们传递给OpenGL),您也可以获得显着的性能提升。您还可以使用glVertex*()调用的版本,该调用采用带有指向向量的指针的单个参数,而不是3个单独的参数。对于glVertex3fv()向量,这将是float

转向维多利亚州立大学当然是真正的解决方案。只要顶点数据不随时间变化,它就会减少数量级的API调用次数,并避免任何数据复制。

(*)OpenGL 4.1增加了对double顶点属性的支持,但它们需要使用特定的API函数,只有在单精度浮点数不够精确时才有意义。