- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我编写了一个简单的基准测试来了解 VBO 的使用情况。从逻辑上来说,它的作用非常简单:
// enable states
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
// bind vertexes
glBindBuffer(GL_ARRAY_BUFFER, vbos_[0]);
glVertexPointer(3, GL_FLOAT, 0, 0);
// normal
glBindBuffer(GL_ARRAY_BUFFER, vbos_[1]);
glNormalPointer(GL_FLOAT, 0, 0);
// indexes
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbos_[2]);
// draw n_i_ triangles using offset of index array
glDrawElements(GL_TRIANGLES, n_i_, GL_UNSIGNED_INT, 0);
// deactivate vertex array
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
// bind with 0, so, switch back to normal pointer operation
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
sceneVBO
告诉要绘制多少个相同的实例):
for(const auto& i : sceneVBO) {
glPushMatrix();
glColor3fv(i.rgb);
glTranslatef(i.posX, 0.0f, i.posZ);
glRotatef(angle*i.r_speed, 0.0f, 1.0f, 0.0f);
vboTest->draw(); // Executes step 3
glPopMatrix();
}
下面是一些引用编号(w/u/s 是 wall/user/system 的计时,以 msec 为单位)。
对于此测试,我渲染了 100 个实例完全相同的 VBO(即 sceneVBO
包含 100 个元素,所有这些元素都引用非常相同 3 个 VBO - 顶点、法线和索引)。
已加载 [bunny.obj] 34835/69666(Tris/Vertexes)
FPS: 333.3 CPU (ms/frame): 3.0/0.8/2.0 (w/u/s) 总时间 (ms): 14999.5/4000.4/10000.2 (w/u/s) 帧数: 5000
已加载[dragon.obj] 50000/100000(Tris/Vertexes)
FPS: 217.4 CPU (ms/frame): 4.6/1.4/3.0 (w/u/s) 总时间 (ms): 22999.6/6999.7/15000.9 (w/u/s) 帧数: 5000
已加载 [buddha.obj] 543524/1087474(Tris/Vertexes)
FPS: 27.5 CPU (ms/frame): 36.4/10.4/26.0 (w/u/s) 总时间 (ms): 181999.9/51999.8/130000.3 (w/u/s) 帧数: 5000
因此我的问题是,为什么 VBO 顶点大小与用户/系统 CPU 时间成正比?
我知道如果 GPU 有更多的三角形要绘制,则需要更长的时间,但为什么要花费更多的 CPU 用户/系统时间?
我不会重新发送每一帧的顶点/法线或索引 - 所有应该都保存在 GPU 内存中(数组缓冲区用 GL_STATIC_DRAW
填充) - 我预计绘制帧需要更长的时间,但 CPU 使用率相对较低(用户和系统)。
或者驱动程序 (nVidia 352.63)/GL 是否在 glXSwapBuffers
上处于事件状态?
我预计w所有时间都会增加,但坦率地说没有用户服务器和系统系统时间...
诗。当然垂直同步被禁用。
最佳答案
您的代码中有一些内容可能值得怀疑。
您正在使用立即模式,这意味着您的 API 调用依赖于已弃用的行为,而您的驱动程序可能对这些行为进行了糟糕的优化。
// enable states
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
// bind vertexes
glBindBuffer(GL_ARRAY_BUFFER, vbos_[0]);
glVertexPointer(3, GL_FLOAT, 0, 0);
// normal
glBindBuffer(GL_ARRAY_BUFFER, vbos_[1]);
glNormalPointer(GL_FLOAT, 0, 0);
// indexes
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbos_[2]);
// draw n_i_ triangles using offset of index array
glDrawElements(GL_TRIANGLES, n_i_, GL_UNSIGNED_INT, 0);
// deactivate vertex array
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
// bind with 0, so, switch back to normal pointer operation
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
您强调,这段代码每个实例只调用一次,但由于 OpenGL 的工作方式,它和 DX9(OpenGL 的立即模式最相似)都不能很好地映射到显卡的实际功能,在这些用于正确设置状态的 API 调用中可能会发生很多事情。例如,您对 glVertexPointer
的调用必须设置状态以从正确的内存段中读取,如果您的缓冲区对象特别大,这可能是一个不简单的操作,因为必须为 GPU 启动以运行着色器的每个线程设置这些指针。
Or is it that the driver (nVidia 352.63)/GL has an active spin on
glXSwapBuffers
?
我也不排除这种可能性。它确实必须定期查询显卡以查明命令是否已完成执行,因此 Nvidia 可以选择将此功能实现为忙等待。
底线是,如果您担心 OpenGL 中的 CPU 开销,您可能希望研究一些 AZDO techniques (适用于OpenGL 4.3+),或者考虑学习DirectX 12 (适用于 Windows 10)或 Vulkan (适用于 Windows 10 以外的任何系统)
关于c++ - 为什么 VBO 顶点大小与用户/系统 CPU 时间使用量成正比?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36156772/
我有一个 45Gb 的表,大约有 76M 行和 150 列。 当我运行以下简单查询时: SELECT count(*) FROM my_table WHERE `column_of_interest`
如果数组已满并且其大小增加 1 以插入新元素,则插入 N 个元素的时间可以计算为 1+2+ .. N = N^2/2。 (声明长度为 size+1 的新数组并将元素复制到新数组)。 我无法理解,如果不
我是一名优秀的程序员,十分优秀!