【问题标题】:Why won't Direct3D recover after unplugging a monitor in Windows XP?为什么在 Windows XP 中拔下显示器后 Direct3D 无法恢复?
【发布时间】:2010-11-30 12:43:26
【问题描述】:

一个有趣的错误出现了,我没有运气。在使用本机代码的窗口化 Direct3D9 程序中,我使用类似于以下内容处理丢失的设备:

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 功能一直失败的原因是因为有未释放的资源。但是,如答案中所示应用完全相同的发布代码时,解决了该问题。我确实验证了程序没有在调用恢复函数之间创建 D3DPOOL_DEFAULT 对象。如果按照本问题的代码段所示执行重置,Direct3D 的结构中是否存在可能导致问题的东西?

【问题讨论】:

    标签: c++ windows-xp directx direct3d


    【解决方案1】:

    不久前I had similar symptoms,正在开发一个多显示器应用程序。拔出显示器不会将自己显示为丢失的 DX 设备 - “设备”是操作系统级别的软件抽象,并且在拔出显示器时不会丢失。

    如果出于某种原因您需要在运行时检测监视器的拔出,即使是 Win32 API EnumDisplayMonitors 也不够用。如the post 中所述,此 API 查询驱动程序缓存,默认情况下仅在“启动、登录或打开显示属性控制面板”时更新。现在,我们只使用 nVidia,它们确实通过 NvCplRefreshConnectedDevices 公开了强制缓存更新功能(链接到 NvCpl.dll 以使用它)。不能说 ATI 是否公开了类似的功能,或者即使他们需要这样做。

    更重要的是 - 您确定 umplugging 事件确实会迫使您恢复资源吗?我的猜测不是。

    【讨论】:

    • 你说得对,拔出事件不会强制恢复 Vista 中的资源。我需要支持非 NVIDIA 卡,但我会查看驱动程序缓存,看看是否能引导我到某个地方。
    【解决方案2】:

    我最终测试了一个使用 DirectX 进行图形处理的不同程序,只是为了看看问题是否仅出在一个程序上。另一个应用程序从 Windows XP 中的显示器拔出或 KVM 切换中恢复,没有任何问题。这两个程序之间的主要区别在于,工作的程序使用 DXUT 来管理 Direct3d,而我在一个不起作用的程序中进行所有手动管理。梳理 DXUT 源代码后,我注意到他们使用单步方法进行设备恢复,该方法不依赖于在 D3DERR_DEVICENOTRESET 返回值之前从 TestCooperativeLevel 返回的 D3DERR_DEVICELOST。下面的代码似乎已经解决了这个问题:

    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),此代码确实会产生多次重置的副作用。

    【讨论】:

    • 我遇到了类似的情况,TestCooperativeLevel() 返回 D3DERR_DEVICENOTRESET,但对 Reset() 的调用会失败。当 TestCooperativeLevel() 返回 D3DERR_DEFAULT 时,我正在释放 D3DPOOL_DEFAULT 对象。解决方法是等到 TestCooperativeLevel() 返回 D3DERR_DEVICENOTRESET;
    猜你喜欢
    • 2018-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-02
    • 1970-01-01
    • 2011-03-06
    • 2011-05-25
    相关资源
    最近更新 更多