首页 > 解决方案 > 调整窗口大小时 Direct3D11 崩溃和/或故障

问题描述

我目前正在将渲染引擎从 OpenGL 移植到 Direct3D11

它在我的开发机器上运行良好,但现在已将其发布给一些 beta 测试人员,2 名测试人员报告了调整窗口大小的问题(一个崩溃,另一个 UI 冻结)。由于它可以在我的机器上运行,而且我在代码中看不到任何错误,我希望有更多 Direct3D 经验的人能够发现我做错了什么。

下面的代码是窗口调整大小时发生的相关代码(m_stencilview 等是指向 Com 对象的智能指针,D3D_CHECK 是用于检查结果的宏包装器)

m_stencilview.Clear();

m_stencil.Clear();

m_rendertargetview.Clear();


ctx.OMSetRenderTargets(0, 0, 0);
    
D3D_CHECK(m_swpchain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, 0));
   

ComPtr <ID3D11Texture2D> framebuffer;

D3D_CHECK(m_swpchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&framebuffer));

D3D_CHECK(engine.m_device->CreateRenderTargetView(framebuffer, 0, &m_rendertargetview));

标签: direct3d11

解决方案


请注意,一个关键问题是:

ctx.OMSetRenderTargets(0, 0, 0);

这根本不会清除设置的渲染目标。您实际上需要传递一个 nullptr 数组来清除绑定:

ID3D11RenderTargetView* nullViews [] = { nullptr };
ctx.OMSetRenderTargets(1, nullViews, nullptr);

如果您使用的是“多个渲染目标”,那么您必须传递多个 nullptr,这就是数组简单易用的原因。

此外,您需要在运行时检查HRESULT来自。ResizeBuffers目前你只是把它当作它总是会成功,这是不正确的。

特别是,您需要同时检查ResizeBuffersPresent的返回值DXGI_ERROR_DEVICE_REMOVEDDXGI_ERROR_DEVICE_RESET.

运行时出现这种情况的最常见原因是在应用程序运行时在后台更新设备驱动程序。如果驱动程序崩溃并重新启动,或者 GPU 硬件挂起和超时,也会发生这种情况。

您有两个基本选择:

(a) 出现“您必须立即重新启动此应用程序”之类的消息框出现致命错误。这很蹩脚,但至少很清楚发生了什么。

(b) 更好的响应是基本上执行 Direct3D 9 应用程序对“丢失设备”所做的操作:销毁所有 Direct3D 对象并重新创建它们。

dxcap -forcetdr您可以通过在 Direct3D 应用程序运行时从开发人员命令提示符(以管理员身份打开)运行,使用最新的 Visual Studio 版本测试此行为。

有关“丢失设备”处理的完整游戏循环,请参见GitHub 。

另请参阅超时检测和恢复 (TDR)


推荐阅读