4

一个有趣的错误出现了,我没有运气。在使用本机代码的窗口化 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,目前无法更新。有没有人见过这个问题,或者知道为什么我不能重置我的设备?

更新:我相信我找到了解决方案,但仍然对上面列出的第二个代码段的失败感到困惑。在让 DirectX Debug 运行时通过远程调试工作后,我意识到 Reset 功能一直失败的原因是因为有未释放的资源。但是,如答案中所示应用完全相同的发布代码时,解决了该问题。我确实验证了程序在调用恢复函数之间没有创建 D3DPOOL_DEFAULT 对象。如果执行此问题的代码段中所示的重置,Direct3D 的结构中是否存在可能导致问题的东西?

4

2 回答 2

3

我最终测试了一个使用 DirectX 进行图形处理的不同程序,只是为了看看问题是否出在一个程序上。另一个应用程序从 Windows XP 中的显示器拔出或 KVM 切换中恢复,没有任何问题。这两个程序之间的主要区别在于,工作的程序使用 DXUT 来管理 Direct3d,而我在一个不起作用的程序中进行所有手动管理。在梳理了 DXUT 源代码后,我注意到他们使用单步方法进行设备恢复,该方法不依赖于D3DERR_DEVICELOST在返回值之前从 TestCooperativeLevelD3DERR_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),此代码确实会产生多次重置的副作用。

于 2009-09-24T20:49:54.170 回答
2

不久前,我有类似的症状,开发了一个多显示器应用程序。拔出显示器本身不会显示为丢失的 DX 设备 - “设备”是操作系统级别的软件抽象,并且在拔出显示器时 不会丢失。

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

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

于 2009-09-22T19:59:41.363 回答