编写代码,不会引起很多页面错误

时间:2019-03-15 13:49:18

标签: c++ visual-studio opengl

我有一个用于渲染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

1 个答案:

答案 0 :(得分:2)

增加的页面错误负载只是真正糟糕的渲染循环的第二个症状。现代GPU在顶点和索引数据的(大/小)缓冲区上运行。使用glBeginglEnd中间模式时,驱动程序被迫在原位创建此类缓冲区。为了加快速度,有很多启发式方法,包括驱动程序还会标记页面,以便在页面内容发生更改时通知它们,以便仅在需要时才重新创建缓冲区。

将其重写以在顶点数组中使用索引的三角形,这是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);
}