【问题标题】:Crash at draw call in nvoglv32.dll on new video card在新视频卡上的 nvoglv32.dll 中绘制调用崩溃
【发布时间】:2013-02-09 01:42:00
【问题描述】:

几天前,由于一些硬件更改,我设置了我的计算机并安装了一个新的 Windows 8 副本。其中,我将显卡从 Radeon HD 7870 更改为 Nvidia GTX 660。

再次设置 Visual Studio 11 后,我从 Github 下载了我的最后一个 OpenGL 项目并重建了整个项目。我从 Visual Studio 中运行了应用程序,但由于 nvoglv32.dll 而崩溃。

Application.exe 中 0x5D9F74E3 (nvoglv32.dll) 处的未处理异常:0xC0000005:访问冲突读取位置 0x00000000。

在旧环境中,应用程序按预期工作。我没有更改项目或源代码的任何内容。唯一的区别是 Visual Studio 安装的语言,现在是英语,以前是德语。因此我创建了一个新项目并采用了所有设置,但错误仍然存​​在。

为了定位崩溃,我注意到所有初始化(窗口、着色器……)都成功了,错误出现在绘图调用glDrawElements() 中,它引用了我的延迟渲染器的几何传递。

经过一番研究,我发现 nvoglv32.dll 来自 Nvidia,是关于一个名为 Compatible OpenGL ICD 的服务。这是否意味着我的应用程序以兼容模式运行?这听起来像是一种支持旧应用程序的模式,我希望我的应用程序以常规模式运行!顺便说一句,我为我的显卡安装了最新的稳定驱动程序。

说实话,我不知道如何解决这个崩溃问题。什么可能导致它以及如何解决它?

更新:我发现了一个关于我的问题的post on Geforce Forums。虽然没有回复,但作者可以通过更改两次 OpenGL 调用的顺序来解决问题。

大家好,

在研究了我的应用程序源代码几个小时后,我发现调用函数...

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, #)
glBindVertexArray(#)

...按此顺序会导致 nvoglv64.dll 崩溃。 将这些调用的顺序颠倒到...

glBindVertexArray(#)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, #)

...防止崩溃,并且表现得很好。

干杯, 罗伯特·格拉夫

由于我不使用顶点数组,我无法简单地进行此修复,但可能存在类似问题。我会报告我的进展。

更新:我完全不知道如何解决我的问题。我尝试了不同的视频驱动程序版本,但没有区别。我使用最少的着色器和简单的前向渲染完全重写了渲染器。但崩溃发生在第一次绘制调用时。

【问题讨论】:

  • 我从显示器切换到电视后开始得到这个

标签: visual-c++ opengl crash deferred-rendering


【解决方案1】:

最后我想出了一个解决崩溃的方法。

我用来创建窗口等的 SFML 框架提供了一个函数来重置上下文的 OpenGL 状态。我在创建窗口后立即调用它。

尽管我无法解释原因,但删除该函数调用解决了崩溃问题。可能是因为此时 GLEW 或其他东西尚未初始化。

sf::RenderWindow window;
window.create(VideoMode(1024, 768), "Window Title");
window.resetGLStates(); // removing this line fixed the crash
window.setVerticalSyncEnabled(true);

【讨论】:

    【解决方案2】:

    为了定位崩溃,我注意到所有初始化(窗口、着色器、...)都成功了,错误出现在绘图调用 glDrawElements() 处。

    很可能您的代码一直存在越界访问,但 AMD Radeon Catalyst 驱动程序确实保留了更多地址空间,或者提前捕获了它们。而现在你的 NVidia GeForce 驱动程序不支持了。

    要么您传递的 glDrawElements 数字太大,count 元素无法绘制,要么您的索引缓冲区包含索引超出顶点数组范围的值。如果是后者,那么您可能正在使用客户端顶点数组,因为 VBO 通常会捕获越界访问;这些也不会使您的客户端程序崩溃,而只会渲染垃圾。

    【讨论】:

    • 我想找到越界访问(如果存在),但我不知道它可能来自哪里。我专门为我的网格使用 VBO。在开发的早期,我遇到了你描述的问题,没有崩溃,但它只是呈现垃圾,但这个问题应该在一段时间前解决。今天我计算使用这条线绘制每一帧的元素数量。 int count; glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &count); glDrawElements(GL_TRIANGLES, count/sizeof(GLuint), GL_UNSIGNED_INT, 0);
    • @sharethis:您能否检查一下,在执行此操作时,您实际上绑定了 GL_ELEMENT_ARRAY_BUFFER。我还将count 初始化为0,并检查glGetBufferParameters 设置的值。还要检查每一步的 OpenGL 错误(请记住,您必须在循环中调用 glGetError 直到它返回 GL_NO_ERROR)。 – 我的直觉是,Radeon 驱动程序在缓冲区绑定方面有点草率,并且会返回一些有用的东西,即使在那种情况下他们不应该这样做。
    • 数组缓冲区绑定,count设置为144,没有OpenGL错误。我的方式,这里是related source code
    • @sharethis:这真的很好奇。太糟糕了,我现在没有可用的 Windows 8/NVidia 机器来重现这个。最后一个建议,然后我暂时没有建议,这相当绝望:每次进入渲染函数时调用glewInit() 怎么样?
    • @sharethis:通常的方法是禁用单个代码路径,一次一个,直到错误消失。处理器#ifdef 语句是你的朋友。找到负责的代码路径后,对它执行的每一步进行单步调试。此外,我还会在无缓冲写入访问中对每个变量和涉及到文件的计算进行大量调试日志记录。
    猜你喜欢
    • 2013-12-18
    • 1970-01-01
    • 2016-06-30
    • 1970-01-01
    • 2021-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多