Укороченная версия: Как может произойти сбой (недопустимый доступ к памяти исключение / исключение nullptr) внутри glDrawElements/glDrawElementsInstanced
отлаживаться?
Длинная версия:
У вас есть путь к коду рендеринга OpenGL, который использует VAOs
и совершает рендеринг через вызов glDrawElements
или же glDrawElementsInstanced
, Этот кодовый путь работает правильно большую часть времени. Мы говорим о «коде редактора», что означает: данные могут быть любой геометрии и с большой вероятностью будут часто меняться.
Но иногда после внесения воспроизводимых изменений данных просто происходит сбой в glDrawElements*
код водителя (т.е. glDrawElements
вызывается, параметры функции в порядке, сбой происходит внутри glDrawElements
).
Как вы можете продолжить отладку этой проблемы?
P.S .:
Сначала должно быть ясно, что может вызвать сбои в драйвере. В большинстве случаев это плохой доступ к памяти.
Что может вызвать доступ к плохой памяти внутри драйвера?
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.
Других решений пока нет …