glDrawElements 在驱动程序中崩溃 | 调试提示

glDrawElements crashes in the driver | debugging hints

本文关键字:调试 提示 崩溃 驱动程序 glDrawElements      更新时间:2023-10-16

简短版本:如何调试glDrawElements/glDrawElementsInstanced内部的崩溃(内存访问异常/nullptr 异常)?

长版本:您有一条 OpenGL 渲染代码的路径,它使用VAOs,并通过调用glDrawElementsglDrawElementsInstanced提交渲染。 该代码路径在大多数情况下都能正常工作。 我们谈论的是"编辑器代码",这意味着:数据可以是任何几何图形,并且很可能经常更改。

但有时在提交可重现的数据更改后,它只是在glDrawElements*驱动程序代码中崩溃(即 调用glDrawElements,函数参数正常,崩溃发生在glDrawElements内部)。

如何继续调试此问题?

附言:

  • 自我回答的问题:所有的研究工作都进入了答案!
  • 这是针对编辑器代码的。 对于简单的演示,此类崩溃主要是由于编码人员没有正确理解glDrawElements的要求引起的,因此代码路径要么有效,要么无效 - 在这些情况下,请参阅:
    • Crash on glDrawElements
    • glDrawElements 崩溃 (OpenGL 3.2/Windows 7)

首先,应该清楚可能导致驱动程序崩溃的原因。 在大多数情况下,这是错误的内存访问。

什么可能导致访问驱动程序内部的坏内存?

  • 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优化的崩溃。