为什么在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开关),用于在延长的时间周期。

+0

我遇到了类似的情况,其中TestCooperativeLevel()返回了D3DERR_DEVICENOTRESET,但对Reset()的调用会失败。当TestCooperativeLevel()返回D3DERR_DEVICELOST时,我释放了D3DPOOL_DEFAULT对象。该决议是等到TestCooperativeLevel()返回D3DERR_DEVICENOTRESET; – Chris 2013-12-10 23:25:31

前阵子I had similar symptoms,开发了多显示器应用。显示器的拔出不目前本身作为一个丢失DX设备 - “设备”是一个操作系统级软件抽象,它是在显示器拔出丢失。

如果出于任何原因需要检测运行时拔下显示器,甚至Win32 API EnumDisplayMonitors也不足以满足要求。如the post中详细描述的,该API查询仅在“启动,登录或打开显示属性控制面板”时默认更新的驱动程序高速缓存。现在,我们与nVidia的唯一工作,他们通过做NvCplRefreshConnectedDevices暴露力缓存更新功能(链接到NvCpl.dll使用它)。不能说,如果ATI公开类似的功能,或者即使他们需要。

而且更重要的是 - 你一定的umplugging事件不会迫使您恢复您的资源?我的猜测不是。

+0

说得对,拔掉事件并不强制恢复Vista中的资源。我需要支持非NVIDIA显卡,但是我会查看驱动程序缓存并查看是否能将我带到某个地方。 – bsruth 2009-09-22 20:37:06