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を使用していますが、現時点では更新できません。誰かが以前にこの問題を見たことがありますか、またはデバイスをリセットできない理由を知っていますか?

更新:私は解決策を見つけたと思いますが、それでも上記の2番目のコードセグメントの失敗に困惑しています。DirectXデバッグランタイムをリモートデバッグで動作させるようにした後、リセット機能が失敗し続ける理由は、解放されていないリソースがあったためであることに気付きました。ただし、回答に示されているように適用すると、まったく同じリリースコードで問題が解決しました。プログラムがrecover関数の呼び出しの間にD3DPOOL_DEFAULTオブジェクトを作成していないことを確認しました。この質問のコードセグメントに示されているように、リセットを実行すると問題を引き起こす可能性のあるDirect3Dの構造に何かがありますか?

4

2 に答える 2

3

グラフィックに DirectX を使用する別のプログラムをテストして、問題が 1 つのプログラムだけにあるかどうかを確認しました。もう一方のアプリケーションは、モニターのプラグを抜いたり、Windows XP で KVM を切り替えたりしても、問題なく回復しました。2 つのプログラムの主な違いは、動作するプログラムでは 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 が切り替えられている) 場合、複数回リセットされるという副作用があります。

于 2009-09-24T20:49:54.170 に答える
2

しばらく前に、マルチモニターアプリを開発して、同様の症状がありました。モニターのプラグを抜いても、失われた DX デバイスとして表示されませ。「デバイス」は OS レベルのソフトウェア抽象化であり、モニターのプラグを抜いても失われ ません。

なんらかの理由で、実行時にモニターのプラグが抜かれたことを検出する必要がある場合、Win32 API EnumDisplayMonitorsでさえ十分ではありません。投稿で詳しく説明されているように、この API は、「起動時、ログオン時、またはディスプレイ プロパティ コントロール パネルを開いたとき」にのみデフォルトで更新されるドライバー キャッシュを照会します。現在、nVidia のみを使用しており、 NvCplRefreshConnectedDevices (使用するには NvCpl.dll へのリンク) を介して強制キャッシュ更新機能を公開しています。ATI が同様の機能を公開しているかどうか、または公開する必要があるかどうかはわかりません。

さらに重要なことに、umplugging イベントによってリソースの回復が強制されると確信していますか?? 私の推測ではありません。

于 2009-09-22T19:59:41.363 に答える