调整窗口大小时Direct3D11崩溃和/或故障

调整窗口大小时Direct3D11崩溃和/或故障,direct3d11,Direct3d11,我目前正在将一个渲染引擎从OpenGL移植到Direct3D11 它在我的开发机器上运行良好,但是现在已经发布给了一些beta测试人员,两个测试人员报告了一个调整窗口大小的问题(一个崩溃,另一个UI冻结)。由于它在我的机器上工作,我看不出代码中有任何错误,我希望有更多Direct3D经验的人能够发现我做错了什么 下面的代码是窗口调整大小时发生的相关代码(m_stencilview等是指向Com对象的智能指针,D3D_CHECK是用于检查结果的宏包装器) m_stencilview.Clear()

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

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

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

m_stencilview.Clear();
m_模具。清除();
m_rendertargetview.Clear();
ctx.OMSetRenderTargets(0,0,0);
D3D_检查(m_swpchain->ResizeBuffers(0,0,0,DXGI_格式未知,0));
ComPtr帧缓冲区;
D3D_检查(m_swpchain->GetBuffer(0,u uuidof(ID3D11Texture2D),(void**)和framebuffer));
D3D_检查(engine.m_设备->CreateRenderTargetView(帧缓冲区、0和m_rendertargetview));

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

ctx.OMSetRenderTargets(0, 0, 0);
这根本不会清除“设置渲染目标”。您需要实际传递一个nullptr数组以使其清除绑定:

ID3D11RenderTargetView* nullViews [] = { nullptr };
ctx.OMSetRenderTargets(1, nullViews, nullptr);
如果使用“多个渲染目标”,则必须传递多个nullptr,这就是为什么这里的数组简单且易于使用的原因

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

特别是,您需要检查
ResizeBuffers
Present
,查看返回值
DXGI\u ERROR\u DEVICE\u REMOVED
DXGI\u ERROR\u DEVICE\u RESET

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

您有两个基本选择:

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

(b) 更好的应对方法是基本上像Direct3D 9应用程序为“丢失的设备”所做的那样:销毁所有Direct3D对象并重新创建它们

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

有关完整的游戏循环以及“丢失设备”的处理,请参阅


另请参见

仔细检查您是否确实按照预期释放了渲染目标视图,或者com指针是否同时获得了其他所有者!与仍然排队的命令一样,尚未提交的延迟上下文也可能导致问题。因此,在拆掉旧的交换链之前,确保
Flush
。所以我要试试冲水。当窗口调整大小时,我是否也应该重新创建交换链?即使您(或多或少)确定,我也会确切地告诉您引用计数是否已降至0,资源是否已释放。谢谢,我必须检查响应。但是,在运行时不需要销毁所有D3D对象就无法安全地调整缓冲区的大小吗?您可以在运行时调整缓冲区的大小,但这是此“设备已删除”事件的两个故障点之一(以及
Present
),因此您不能假设函数总是返回
s_OK
。也就是说,我更新了代码中另一个问题的答案。
ID3D11RenderTargetView* nullViews [] = { nullptr };
ctx.OMSetRenderTargets(1, nullViews, nullptr);