4

以下の編集アップデートを参照してください。元の質問が変更されました!

DX11デバイスを使用する作業ウィンドウがあります。Alt + Enterを使用して全画面表示にしようとすると、問題が発生します。ウィンドウがフォーカスされていない場合、次のようなデバッグ出力が表示されます。

'MyGame.exe': Loaded 'C:\Windows\SysWOW64\D3D10SDKLayers.DLL', Cannot find or open the PDB file

そして警告

DXGI Warning: IDXGISwapChain::Present: Fullscreen presentation inefficiencies incurred due to application not using IDXGISwapChain::ResizeBuffers appropriately, specifying a DXGI_MODE_DESC not available in IDXGIOutput::GetDisplayModeList, or not using DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH

DX11ゲームは、特に実行の途中でD3D10SDKLayers.dllをロードしてはならないことをかなり確信しています。MSDNのドキュメントから、このdllはデバイスの作成時に読み込まれることがわかりまし if a device is created with the appropriate layer flag, this DLL is loaded automaticallyた。そこで、実行中にデバイス作成メソッドが何らかの形で呼び出されているかどうかを確認しましたが、呼び出されていません。ゲーム内にデバイス作成が存在するスポットは2つしかなく、どちらのスポットもヒットしていません。編集:MSDNを確認した後、このdllはデバッグdllにすぎず、他の目的なしに、警告自体を出力するためにロードされる可能性があります。

明示的な複製の場合:

1)Alt + Enterを6回(フルスクリーン遷移サイクル3回、両方向、ウィンドウの開始)、7日にdllがロードされ、警告がポップアップ表示されます。これは、ウィンドウのフォーカスに関係なく発生します。

メソッド呼び出し階層の要約(全画面表示):

1)ToggleFullscreen()-私のメソッド、Alt + Enterによって呼び出される唯一のメソッド
2)ResizeTargetAndBuffers()-私のメソッド、以下のサブメソッド
3)DXGISwapChain-> ResizeTarget(frontBufferDesc)はフロントバッファーを指定された解像度にサイズ変更します
4)DXGISwapChain-> GetFullscreenState ()フルスクリーン状態を判別する
5)DXGISwapChain-> SetFullscreenState(TRUE、NULL)フルスクリーンにする
6)ResizeDXGIBuffers(width、height、TRUE)myメソッド、サイズ変更バックバッファー、サブメソッド
7)DXGISwapChain-> ResizeBuffers(count、幅、高さ、フォーマット、フラグ)バックバッファのサイズを変更する
8)DXGISwapChain-> ResizeTarget(frontBufferDesc)は、リフレッシュレートの問題を防ぎます。MSDNのベストプラクティスに従って、RefreshRateメンバーがゼロになりました。
9)DXGISwapChain-> GetFullscreenState()を使用して、フルスクリーン状態を判別します

メソッド呼び出し階層の要約(ウィンドウ化される):

1)ToggleFullscreen()-私のメソッド、Alt + Enterによって呼び出される唯一のメソッド
2)ResizeTargetAndBuffers()-私のメソッド、以下のサブメソッド
3)DXGISwapChain-> ResizeTarget(backBufferDesc)はフロントバッファーを指定された解像度にサイズ変更します
4)DXGISwapChain-> GetFullscreenState ()フルスクリーン状態を判別する
5)DXGISwapChain-> SetFullscreenState(FALSE、NULL)フルスクリーンに移行
6)DXGISwapChain-> ResizeTarget(backBufferDesc)フロントバッファーのサイズをウィンドウの解像度に変更(一部の解像度の問題の解決に役立ちます)
7)ResizeDXGIBuffers(width、height 、FALSE)私のメソッド、バックバッファーのサイズ変更、以下のサブメソッド
8)DXGISwapChain-> ResetBuffers(count、width、height、format、flags)でバックバッファーのサイズを変更
9)DXGISwapChain-> GetFullscreenState()でフルスクリーン状態を判別

これの影響は非常に深刻です。Alt + Enterをキャッチする低レベルのキーボードフックは呼び出されなくなったため、Windowsは自動Alt + Enter処理を実行できます。これにより、ToggleFullscreenメソッドが完全にバイパスされ、ウィンドウがデスクトップ解像度に設定されます。これにより、バッファのサイズが間違ってしまい(設定しなかったため、ウィンドウが設定しました)、非効率的な警告が発生し、バッファサイズとウィンドウがフルスクリーンであるかどうかについての正しい知識がなくなったプログラムの変数をいじりますか否か。

これを引き起こしている可能性があるものについてのアイデアはありますか?

PSコードサンプルが必要な場合は、見たいものを具体的に示してください。可能であれば、それを提示しようと思います。コードリスト全体を掲載することはできません。

編集:デバイス作成コードは以下のとおりです。


         hr = D3D11CreateDevice(    pAdapter,
                                    driverType,
                                    NULL,
                                    rDeviceSettings.m_CreateFlags,
                                    &rDeviceSettings.m_eD3DDeviceFeatureLevel,
                                    1,
                                    D3D11_SDK_VERSION,
                                    &pGraphicsDevice,
                                    &eFeatureLevel,
                                    &pDeviceContextI
            );


            if ( FAILED( hr ) ) {
                pAdapter = NULL;
                // Remote desktop does not allow you to enumerate the adapter.  In this case, we let D3D11 do the enumeration.
                if ( driverType == D3D_DRIVER_TYPE_UNKNOWN ) { 
                    hr = D3D11CreateDevice( pAdapter,
                                            driverType,
                                            NULL,
                                            rDeviceSettings.m_CreateFlags,
                                            &rDeviceSettings.m_eD3DDeviceFeatureLevel,
                                            1,
                                            D3D11_SDK_VERSION,
                                            &pGraphicsDevice,
                                            &eFeatureLevel,
                                            &pDeviceContextI
                    );
                }

最初の呼び出しは99%の確率で成功します。つまり、リモートデスクトップを使用していない場合なので、ここではそれにのみ焦点を当てます。アダプター、driverTypeをD3D_DRIVER_TYPE_HARDWARE、m_CreateFlagsをD3D11_CREATE_DEVICE_DEBUG、m_eFeatureLevelをD3D_FEATURE_LEVEL_11_0として指定します。かなり標準的な呼び出しであり、常に成功します。

更新の編集1:いくつかの広範なデバッグの後、dllがロードされ、非効率性の警告が表示されると、いくつかの非常に興味深い状況が発生することがわかりました。それらは以下にリストされています:

1)VS2010デバッガーは、キーフックでブレークポイントをトリガーしなくなりました。
2)印刷出力がキーフックで機能しなくなりました。
3)ウィンドウが以前にサイズ変更可能だった場合、ウィンドウのサイズ変更
ができなくなる可能性があります。4)ウィンドウが移動できなくなる可能性があります。
5)3つのスレッドが終了します。

編集更新2:最初の編集更新には誤った仮定がある可能性があります。見つかった場合は削除します。低レベルのキーフックが呼び出されなくなったことが判明しました(ブレークポイントやprintステートメントが内部で機能しないため)。したがって、プログラム内の何かが誤って登録を解除すると、上記のすべての問題が発生します。 。これを明日テストしています...

更新の編集3:もう何が起こっているのかわかりません。自宅のコンピューターと職場のコンピューターで同じクリーンなプロジェクトをテストしたところ、異なる結果が得られました。自宅では、問題が発生することなくAlt + Enterを無期限に実行できますが、職場ではAlt + Enterを7回実行すると、キーフックが呼び出されなくなり、バッファの問題が発生します。

更新の編集4:より多くのテスト(作業中)。キーフックは、ウィンドウモードへの3回目の移行後に確実に削除されています。キーフックメソッド内に出力されなくなり、どのキーが押されたかに関係なく、ブレークポイントはトリガーされません。上記で説明した他のすべての問題は、このキーフックがToggleFullscreen()を呼び出さなかった結果であるため、これに関して別の質問を開くつもりです。参考までに、以下にキーフックコードを示します。


LRESULT _stdcall MyClass::WindowsKeyHook( s32 nCode, WPARAM wParam, LPARAM lParam ) {
    printf("Key hook called, nCode: %d. ", nCode);
    if( nCode < 0 || nCode != HC_ACTION )  { // do not process message 
        return CallNextHookEx( MyClassVar.GetWindowsKeyHook(), nCode, wParam, lParam );
    }
    printf(" Key hook status ok.\n");

    BOOL bEatKeystroke = FALSE;
    KBDLLHOOKSTRUCT* p = ( KBDLLHOOKSTRUCT* )lParam;
    switch( wParam ) {
        //NOTE: Alt seems to be a system key when it is PRESSED, but a regular key when it is released...
        case WM_SYSKEYDOWN:
            if(p->vkCode == VK_MENU || p->vkCode == VK_LMENU || p->vkCode == VK_RMENU) {
                MyClassVar.SetAltPressed(TRUE);
            }
            if(MyClassVar.IsAltPressed() && p->vkCode == VK_RETURN) {
                bEatKeystroke = TRUE;
                MyClassVar.SetAltEnterUsed(TRUE);
                printf("Alt+Enter used.\n");
            }
            break;
        case WM_SYSKEYUP:
            //NOTE: releasing alt+enter causes a SYSKEYUP message with code 0x13: PAUSE key...
            break;
        case WM_KEYDOWN:
            break;
        case WM_KEYUP: {
            if(p->vkCode == VK_MENU || p->vkCode == VK_LMENU || p->vkCode == VK_RMENU) {
                MyClassVar.SetAltPressed(FALSE);
            }
            bEatKeystroke = ( !MyClassVar.IsShortcutKeysAllowed() &&
                                ( p->vkCode == VK_LWIN || p->vkCode == VK_RWIN ) );
            break;
        }
    }

    if( bEatKeystroke ) {
        return 1;
    }
    else {
        return CallNextHookEx( MyClassVar.GetWindowsKeyHook(), nCode, wParam, lParam );
    }
}

printfステートメントは、6番目のAlt+Enterの直後までキーフックが呼び出されていることを示しています。これは、ウィンドウモードへの3回目の移行です。問題を引き起こすために、私が以前に思ったように、4回目のフルスクリーンに行く必要はありません。MyClassVarによって呼び出されるすべてのメソッドは、Windowsキーフックにタイムアウトがあることを知っているので、キーフックをできるだけ速く実行するためにインラインになっています。Alt + Enterの実際の処理は、MyClassのスレッドによって処理されます。

また、誰かがこれをコミュニティwikiではなくすることはできますか?この質問は、ウィキとして使用するにはあまりにも具体的すぎると思います。それが1つになった唯一の理由は、私が定期的に編集して更新していることです。

4

1 に答える 1

1

キーフックを完全に取り除くことで、この問題を解決しました。Alt+Enter を処理する適切な方法は、スワップ チェーンを作成してから を呼び出すことIDXGIFactory1::MakeWindowAssosciation( m_hWnd, DXGI_MWA_NO_ALT_ENTER)です。WM_SYSKEYDOWN次に、 と を使用して、Windows メッセージ プロシージャから独自のコードで Alt+Enter を処理できますWM_KEYUP。これが他の人に役立つことを願っています!これを機能させるのにかなりの時間を費やしました。自分のアプリで機能させるのに苦労している場合は、私にメッセージを送ってください。私がお手伝いします!

于 2012-02-03T01:54:16.190 に答える