我有一个用于渲染OpenGL场景的代码。在没有Visual Studio的情况下启动时,此代码会导致许多页面错误。 paintGL()
中显示的代码仅是那里发生的一小部分,但花费的时间最多。
示例代码:
void prepareData() {
std::vector<int> m_indices; // vector of point indices, that should be connected
std::vector<float> m_vertices; // vector of the 3d points
/*
fill the vectors
*/
}
void MyGLWidget::paintGL() {
glBegin(GL_TRIANGLE_STRIP);
for (unsigned int i=0; i < m_indices.size(); i++)
{
// search end of strip
if (m_indices[i] < 0)
{
// store end of strip
endStrip = i;
// we need at least three vertices for a triangle strip
if (startStrip+2 < endStrip)
{
// draw strip
for (unsigned int j=startStrip; j<endStrip; j++) {
idx = 3 * m_indices[j];
glVertex3dv(m_vertices[idx]));
}
}
// store start of next strip
startStrip = i+1;
}
}
glEnd();
}
这就是问题所在:当数据更改并进行计算时,paintGL()
的下一次调用非常慢,因为访问新值会导致很多页面错误。
当数据不变时,paintGL()
将达到应有的速度。
两个数据向量都可能变得非常大,通常我们的大小为1000万个索引和1500万个顶点。
我的问题是,当重新计算要显示的值时,如何使paintGL
更快?
当使用Visual Studio(两个Releae版本)启动应用程序时,没有那么多页面错误,并且比平常更快。 Visual Studio如何实现该目标,我也可以做到这一点,而无需Visual Studio监视我的应用程序。
问题已经在这里描述,但是现在我已经找到了问题的根本原因:Release Build is faster, when started from Visual Studio than started “normally”
其他信息:C++/opengl application running smoother with debugger attached
答案 0 :(得分:2)
增加的页面错误负载只是真正糟糕的渲染循环的第二个症状。现代GPU在顶点和索引数据的(大/小)缓冲区上运行。使用glBegin
…glEnd
中间模式时,驱动程序被迫在原位创建此类缓冲区。为了加快速度,有很多启发式方法,包括驱动程序还会标记页面,以便在页面内容发生更改时通知它们,以便仅在需要时才重新创建缓冲区。
将其重写以在顶点数组中使用索引的三角形,这是GPU和OpenGL驱动程序最有效的模式。
即使客户端顶点阵列也可以极大地加快速度,因为驱动程序随后可以合并缓冲区副本。当然,最好的办法是,只要将m_vertices
放在顶点缓冲区对象中即可。
#include <vector>
#include <utility>
// overloaded wrappers to deduce the
// GL type from the type of the index buffer vector
namespace gl_wrap {
void DrawElements(
GLenum mode, GLsizei count,
std::vector<GLubyte> const &idx_buffer,
size_t offset )
{
glDrawElements(mode, count, GL_UNSIGNED_BYTE, idx_buffer.data()+offset);
}
void DrawElements(
GLenum mode, GLsizei count,
std::vector<GLushort> const &idx_buffer,
size_t offset )
{
glDrawElements(mode, count, GL_UNSIGNED_SHORT, idx_buffer.data()+offset);
}
void DrawElements(
GLenum mode, GLsizei count,
std::vector<GLuint> const &idx_buffer,
size_t offset )
{
glDrawElements(mode, count, GL_UNSIGNED_INT, idx_buffer.data()+offset);
}
}
void MyGLWidget::paintGL() {
glBegin(GL_TRIANGLE_STRIP);
std::vector<std::pair<size_t,size_t>> strips;
size_t i_prev = 0, i = 0;
for( auto idx : m_indices ){
++i;
if( idx < 0 ){
strips.push_back(std::make_pair(i_prev, i-i_prev));
i_prev = i;
}
}
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_DOUBLE, 0, m_vertices.data());
for( auto const &s : strips ){
gl_wrap::DrawElements(GL_TRIANGLE_STRIP, m_indices.data(), s.second, s.first);
}
glDisableClientState(GL_VERTEX_ARRAY);
}