为什么在Windows XP中拔出显示器后Direct3D不能恢复?
一个有趣的问题出现了,我没有运气。在使用本机代码窗口化的Direct3D9程序,我处理丢失的设备使用类似于下面的内容:为什么在Windows XP中拔出显示器后Direct3D不能恢复?
void MyClass::RecoverFromDeviceLost(LPDIRECT3DDEVICE9 deviceToRecover, D3DPRESENT_PARAMETERS devicePresentParams)
{
HRESULT hr = deviceToRecover->TestCooperativeLevel();
if(hr == D3DERR_DEVICELOST) {
//Code to shutdown all D3DPOOL_DEFAULT allocated objects
}else if(hr == D3DERR_DEVICENOTRESET){
hr = deviceToRecover->Reset(&devicePresentParams);
if(SUCCEEDED(hr))
{
//Code to rebuild all D3DPOOL_DEFAULT objects
}
}
}
能正常工作在Vista上,但似乎对XP的重大问题。如果显示器拔掉,或者通过KVM切换到PC,我永远不会收到D3DERR_DEVICELOST
。我收到的TestCooperativeLevel唯一的返回值是D3DERR_DEVICENOTRESET
。每次调用Reset都会给出一个D3DERR_INVALIDCALL。我试图通过这样做强制程序使用关机代码:
...
else if(hr == D3DERR_DEVICENOTRESET){
hr = deviceToRecover->Reset(&devicePresentParams);
if(SUCCEEDED(hr))
{
//Code to rebuild all D3DPOOL_DEFAULT objects
}else {
//Duplicate of code to shutdown all D3DPOOL_DEFAULT objects
}
}
...
但是没有改变。此问题似乎只影响Windows XP(到目前为止在SP2,SP3上测试过)。我正在使用2007年8月的DXSDK,目前无法更新。有没有人见过这个问题,或有任何想法,为什么我不能重置我的设备?
更新:我相信我有found a solution,但我仍然感到困惑的是上面列出的第二个代码段的失败。在获得DirectX Debug运行时以完成远程调试后,我意识到Reset函数保持失败的原因是因为没有发布资源。但是,如答案中所示应用完全相同的发布代码解决了该问题。我确实确认该程序不是在调用recover函数之间创建D3DPOOL_DEFAULT对象。 Direct3D的结构中是否存在如果执行重置(如本问题的代码段所示)会导致问题的问题?
我结束了测试使用DirectX图形,只是为了看看问题是否只是用一个程序不同的程序。另一个应用程序从Windows XP中的监视器拔出或KVM切换中恢复正常。这两个程序之间的主要区别在于,工作人员使用DXUT来管理Direct3d,而我在所有没有工作的人员进行手动管理。通过DXUT源代码梳理后,我注意到,他们用一个单一的步骤方法,设备恢复并不依赖于D3DERR_DEVICELOST
从TestCooperativeLevel的D3DERR_DEVICENOTRESET
返回值之前返回。下面的代码似乎已经解决了这一问题:
void MyClass::RecoverFromDeviceLost(LPDIRECT3DDEVICE9 deviceToRecover, D3DPRESENT_PARAMETERS devicePresentParams)
{
HRESULT hr = deviceToRecover->TestCooperativeLevel();
if(hr == D3DERR_DEVICELOST) {
//Device is lost and cannot be reset yet
return;
}
//Code to shutdown all D3DPOOL_DEFAULT allocated objects
hr=deviceToRecover->Reset(&devicePresentParams);
if(SUCCEEDED(hr)){
//Code to rebuild all D3DPOOL_DEFAULT objects
}
}
此代码具有复位多次的副作用如果监视器被拔出(或KVM开关),用于在延长的时间周期。
前阵子I had similar symptoms,开发了多显示器应用。显示器的拔出不不目前本身作为一个丢失DX设备 - “设备”是一个操作系统级软件抽象,它是不在显示器拔出丢失。
如果出于任何原因需要检测运行时拔下显示器,甚至Win32 API EnumDisplayMonitors也不足以满足要求。如the post中详细描述的,该API查询仅在“启动,登录或打开显示属性控制面板”时默认更新的驱动程序高速缓存。现在,我们与nVidia的唯一工作,他们通过做NvCplRefreshConnectedDevices暴露力缓存更新功能(链接到NvCpl.dll使用它)。不能说,如果ATI公开类似的功能,或者即使他们需要。
而且更重要的是 - 你一定的umplugging事件不会迫使您恢复您的资源?我的猜测不是。
说得对,拔掉事件并不强制恢复Vista中的资源。我需要支持非NVIDIA显卡,但是我会查看驱动程序缓存并查看是否能将我带到某个地方。 – bsruth 2009-09-22 20:37:06
我遇到了类似的情况,其中TestCooperativeLevel()返回了D3DERR_DEVICENOTRESET,但对Reset()的调用会失败。当TestCooperativeLevel()返回D3DERR_DEVICELOST时,我释放了D3DPOOL_DEFAULT对象。该决议是等到TestCooperativeLevel()返回D3DERR_DEVICENOTRESET; – Chris 2013-12-10 23:25:31