Написать код, который не вызывает много сбоев страниц - PullRequest
2 голосов
/ 15 марта 2019

У меня есть код для рендеринга сцены 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() работает так же быстро, как и должно быть.
Оба вектора данных могут быть очень большими, обычно у нас есть размеры, такие как 10 миллионов индексов и 15 миллионов вершин.

У меня вопрос, как мне добиться ускорения paintGL, когда значения для отображения рассчитываются заново?
Когда приложение запускается с Visual Studio (обе сборки Releae), ошибок страниц не так много, и это происходит быстрее, чем обычно. Как Visual Studio достигает этого и может ли я это делать без визуального контроля студии моего приложения.

Проблема уже была описана здесь, но теперь я выяснил причину проблемы: Release Build быстрее, когда запускается из Visual Studio, чем запускается «нормально»

Дополнительная информация: Приложение C ++ / opengl, работающее более плавно с подключенным отладчиком

1 Ответ

2 голосов
/ 15 марта 2019

Увеличенная загрузка сбоев страниц является второстепенным признаком действительно плохого цикла рендеринга. Современные графические процессоры работают с (большими / -ными) буферами вершинных и индексных данных. При использовании промежуточного режима glBeginglEnd драйвер вынужден создавать такие буферы на месте. Чтобы ускорить процесс, существует множество эвристик, в том числе драйверы, которые также помечают страницы так, чтобы они получали уведомления, если содержимое страниц изменяется, и буферы создаются заново только при необходимости.

Перепишите его, чтобы использовать индексированные треугольники в массиве вершин. В этом режиме лучше всего работают графические процессоры и драйверы 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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...