glDrawElements 在驱动程序中崩溃 | 调试提示
glDrawElements crashes in the driver | debugging hints
简短版本:如何调试glDrawElements/glDrawElementsInstanced
内部的崩溃(内存访问异常/nullptr 异常)?
长版本:您有一条 OpenGL 渲染代码的路径,它使用VAOs
,并通过调用glDrawElements
或glDrawElementsInstanced
提交渲染。 该代码路径在大多数情况下都能正常工作。 我们谈论的是"编辑器代码",这意味着:数据可以是任何几何图形,并且很可能经常更改。
但有时在提交可重现的数据更改后,它只是在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优化的崩溃。
相关文章:
- 当回溯以零开始时,如何调试崩溃
- 在linux上调试巨大的C++项目
- 为什么使用__LINE_的代码在发布模式下在MSVC下编译,而不是在调试模式下
- 如何针对特定情况调试和修复此双自由内存损坏问题
- 正在VS调试器中监视映射条目
- 使用调试/崩溃报告将应用程序部署到客户端
- VC++本机单元测试,找不到调试符号
- 如何在C++生成器中禁用"使用调试.dcus"
- 使用vscode调试时,GDB意外退出
- 即使使用调试编译标志,表达式也是"optimized out"
- 调试 CUDA MMU 故障
- 有没有办法提示用户使用哪种数据类型作为模板 c++
- 小字符串优化(调试与发布模式)
- 调试和自由执行中的信号处理
- 调试编译的服务器在数据库打开时崩溃
- Visual Studio 调试优化如何工作?
- 如何配置Visual Studio Code以使用cygwin,cmake和gcc进行调试
- 从 exe 文件 (Visual Studio ) 启动时调试断言失败
- glDrawElements 在驱动程序中崩溃 | 调试提示
- Visual studio调试工具提示-隐藏变量