首先应该清楚什么可能导致驱动程序内部崩溃。在大多数情况下,这是糟糕的内存访问。
什么可能导致访问驱动程序内部的坏内存?
GL_ELEMENT_ARRAY_BUFFER
-binding 以某种方式改变(因此给定的参数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 优化的崩溃。