glDrawElements вылетает в драйвере | подсказки отладки

Короткая версия: Как может произойти сбой (исключение плохого доступа к памяти / исключение nullptr) внутри glDrawElements/glDrawElementsInstanced отлаживаться?

Длинная версия: у вас есть путь к коду рендеринга OpenGL, который использует VAOsи совершает рендеринг через вызов glDrawElements или же glDrawElementsInstanced, Этот кодовый путь работает правильно большую часть времени. Мы говорим о "коде редактора", что означает: данные могут быть любой геометрии и с большой вероятностью будут часто меняться.

Но иногда после внесения воспроизводимых изменений данных просто происходит сбой в glDrawElements* код водителя (т.е. glDrawElements вызывается, параметры функции в порядке, сбой происходит внутри glDrawElements).

Как вы можете продолжить отладку этой проблемы?

PS:

  • вопрос с автоответчиком: все исследовательские усилия пошли на ответ!
  • это нацелено на код редактора. Для простых демонстраций такие сбои в основном вызваны тем, что кодировщик неправильно понимает требования glDrawElements, и, как таковой, путь кода будет либо работать, либо нет - в этих случаях см.:

1 ответ

Решение

Сначала должно быть ясно, что может вызвать сбои в драйвере. В большинстве случаев это плохой доступ к памяти.

Что может вызвать доступ к плохой памяти внутри драйвера?

  • GL_ELEMENT_ARRAY_BUFFERпривязка изменилась как-то (таким образом glDrawElements может вызвать доступ за пределы памяти этого объекта)
  • GL_ELEMENT_ARRAY_BUFFERсодержимое изменилось, возможно, ссылаясь на неинициализированные / несуществующие данные вершин (доступ VBO за пределы)
  • любой из связанных GL_ARRAY_BUFFER данные объектов были изменены, поэтому больше не содержали ссылочные данные вершин (доступ VBO за пределы)
  • или даже больше таких изменений. Нарушения доступа внутри glDrawElements* в основном означает, что к любому объекту, связанному в состоянии VAO, был получен доступ за пределами.

Без дополнительного кода отладки эти нарушения доступа очень трудно уловить. Я предлагаю вставить отладочный вывод прямо перед вызовом glDrawElements*, Выходные данные Debug должны запрашивать все доступные привязки и информацию, чтобы вы могли сравнить параметры "когда он работает" с "когда он падает" и выяснить, что искать, затем.

Моя функция отладки выглядит так:

void debugVAOState(std::string baseMessage)
{
    baseMessage.append( " ... querying VAO state:\n" );
    int vab, eabb, eabbs, mva, isOn( 1 ), vaabb;
    glGetIntegerv( GL_VERTEX_ARRAY_BINDING, &vab );
    glGetIntegerv( GL_ELEMENT_ARRAY_BUFFER_BINDING, &eabb );
    glGetBufferParameteriv( GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &eabbs );

    baseMessage.append( "  VAO: " + std::to_string( vab ) + "\n" );
    baseMessage.append( "  IBO: " + std::to_string( eabb ) + ", size=" + std::to_string( eabbs )  + "\n" );

    glGetIntegerv( GL_MAX_VERTEX_ATTRIBS, &mva );
    for ( unsigned i = 0; i < mva; ++i )
    {
        glGetVertexAttribiv( i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &isOn );
        if ( isOn )
        {
            glGetVertexAttribiv( i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &vaabb );
            baseMessage.append( "  attrib #" + std::to_string( i ) + ": VBO=" + std::to_string( vaabb ) + "\n" );
        }
    }
    OutputDebugString( baseMessage.c_str() );
}

Это все еще просто и выводит только наиболее ценную информацию, чтобы увидеть, изменились ли вышеупомянутые привязки как-то. Но это помогло мне найти многочисленные сбои, которые произошли от агрессивной оптимизации OpenGL.

Другие вопросы по тегам