我是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之间没有区别? 使用着色器会使程序更快地运行吗?
答案 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个三角形和3个API调用,每帧150,000次API调用,如果您的目标是60帧/秒,则为每秒900万次API调用。那太多了!对于每个电话,您都会:
一个重要的方面使得这比你需要的更糟糕:你为坐标使用double
值。与使用float
值相比,这需要传递的数据量翻倍。由于OpenGL顶点流水线以单精度(*)运行,因此驱动程序必须将所有值转换为float
。
我怀疑即使使用已弃用的立即模式调用,如果您开始使用float
用于所有坐标(您自己的存储,并将它们传递给OpenGL),您也可以获得显着的性能提升。您还可以使用glVertex*()
调用的版本,该调用采用带有指向向量的指针的单个参数,而不是3个单独的参数。对于glVertex3fv()
向量,这将是float
。
转向维多利亚州立大学当然是真正的解决方案。只要顶点数据不随时间变化,它就会减少数量级的API调用次数,并避免任何数据复制。
(*)OpenGL 4.1增加了对double
顶点属性的支持,但它们需要使用特定的API函数,只有在单精度浮点数不够精确时才有意义。