2015-10-20 271 views
6

サンプルプログラムでフルスクリーンサポートを追加している間、ちょっと迷惑な振る舞いに遭遇しました。DirectX11スワップチェーンとウィンドウがフルスクリーン状態を失う

フルスクリーンウィンドウの作成は機能しますが、フルスクリーンウィンドウを含む出力上のウィンドウ(別のアプリケーションから)を移動すると、自動的にウィンドウに戻ります。

この動作を防ぐ方法はありますか?(フルスクリーンウィンドウはウィンドウに戻らないため)

参考までに、これは小さなスタンドアロンの例です(問題は簡単に複製できます)。

また、これが便利な場合は、Windows 8.1を実行しています。

私はすでに代わりに破棄のFlipSequentialを使用するのと同じ、いや成功の両方、WindowAssociationFlagsとSwapChainFlagsを変更しようとしました

SharpDX.DXGI.Factory2 factory = new SharpDX.DXGI.Factory2(); 
SharpDX.DXGI.Adapter adapter = factory.GetAdapter(0); 

var renderForm1 = new RenderForm("Form 1"); 
factory.MakeWindowAssociation(renderForm1.Handle, SharpDX.DXGI.WindowAssociationFlags.IgnoreAll); 

Device device = new Device(adapter, DeviceCreationFlags.BgraSupport); 

SharpDX.DXGI.SwapChainDescription sd = new SharpDX.DXGI.SwapChainDescription() 
{ 
    BufferCount = 2, 
    ModeDescription = new SharpDX.DXGI.ModeDescription(0, 0, new SharpDX.DXGI.Rational(50, 1), SharpDX.DXGI.Format.R8G8B8A8_UNorm), 
    IsWindowed = true, 
    OutputHandle = renderForm1.Handle, 
    SampleDescription = new SharpDX.DXGI.SampleDescription(1,0), 
    SwapEffect = SharpDX.DXGI.SwapEffect.Discard, 
    Usage = SharpDX.DXGI.Usage.RenderTargetOutput, 
    Flags = SharpDX.DXGI.SwapChainFlags.None 
}; 

var swapChain1 = new SharpDX.DXGI.SwapChain(factory, device, sd); 

renderForm1.Left = 1922; //Just hardcoded here to move window to second screen 
renderForm1.Width = 1920; 
renderForm1.Height = 1080; 
renderForm1.FormBorderStyle = FormBorderStyle.None; 

swapChain1.SetFullscreenState(true, null); 
swapChain1.ResizeBuffers(2, 1920, 1080, SharpDX.DXGI.Format.R8G8B8A8_UNorm, SharpDX.DXGI.SwapChainFlags.AllowModeSwitch); 

var resource = Texture2D.FromSwapChain<Texture2D>(swapChain1, 0); 
var renderView = new RenderTargetView(device, resource); 

RenderLoop.Run(renderForm1,() => 
{ 
    device.ImmediateContext.ClearRenderTargetView(renderView, new SharpDX.Color4(1, 0, 0, 1)); 
    swapChain1.Present(1, SharpDX.DXGI.PresentFlags.None); 
}); 

編集:私はまた、MicrosoftからC++のサンプル(ちょうど取らDirectX11基本的なチュートリアルを試してみました し、フルスクリーンスイッチを追加した場合)、これは同じ動作につながります。したがって、これはSharpDX特有の問題ではありません。

メッセージループを見て、これが発生すると、最初のフルスクリーンモードがウィンドウに戻され、WM_DISPLAYCHANGEメッセージが表示されます)。

答えて

3

これは予想される動作のようです。フルスクリーンの排他モードのスワップチェーンを使用している場合、関連するウィンドウのフォーカスが失われた場合、システムは自動的にアプリケーションをフルスクリーンモードからウィンドウモードによってウィンドウモードに戻します。

1台のモニタでは、ほとんどの場合、アプリケーションのウィンドウがディスプレイを満たす大きさになっている限り動作します。ユーザーはマウスを使用してウィンドウのフォーカスを変更することはできず、フォーカスを切り替えるにはALT + TABのようなものが必要です。

複数のモニタでは、実際の問題です。別のディスプレイで別のウィンドウをクリックすると、アプリのフォーカスが失われ、フルスクリーンモードが再び切り替わります。また、複数のモニターでフルスクリーンの排他モードを設定できないような制限もあります。

さらに、Windows Vista以降では、「排他的」モードという概念は幻想であり、GPUは常に共有されます。 「フォーカス」アプリケーションは、フルスクリーンであるかスクロール・ウィンドウであるかにかかわらず、優先順位が高くなります。

  1. 表示モードを設定するとともに、ディスプレイを埋めるような大きウィンドウで、伝統的なフルスクリーンの「排他的」モードを使用してください:あなたは、フルスクリーンのスタイルの経験のための3つの選択肢があり、Windowsのデスクトップアプリがために

    これはユーザが一般的にWindows用に設定したものではない可能性があります。ここにはIsWindowed = falseがあります。

  2. ウィンドウのサイズをフル表示(つまり最大化)に設定します。ウィンドウスタイルを使用して、ウィンドウにフルスクリーンスタイルのエクスペリエンス(WS_POPUP)をもたらすフレームがないことを確認できます。ここにはIsWindowed = trueがありますので、DXGIがあなたに1ケースを使用させないように、DXGI_MWA_NO_ALT_ENTERを設定してください。
  3. IsWindowed = trueと2と同じことができます。画面に合ったサイズのフチ無しウィンドウが表示されますが、表示モードはシステムのデフォルト以外のものに変更されます。これは一般に「偽のフルスクリーン」と呼ばれます。アプリケーションを終了するたびに表示モードが元に戻ります。

1には、ここで説明したマルチタスクと焦点に関するすべての問題があります。 2と3はシステム通知や他のポップアップをゲーム上に表示し、モード切り替えを強制しません。 2と3は、マルチモニタの設定では、1つのディスプレイでゲームをプレイし、別のディスプレイで他のアプリケーションを使用することができます。マルチタスキングの場合、ほとんどの人がフレーム枠付きの古典的なウィンドウスタイルを好みます。

WindowsストアフルスクリーンモードのUWPの考え方は、基本的には上記の2と同じです。 UWPで表示モードを変更することはできません。

フルスクリーン設定のデバッグは非常に困難です。複数のモニタを使用すると、2と3は別の画面でデバッガと連携できます。真のフルスクリーン排他モードの場合、実際には唯一のオプションは別のPCからのリモートデバッグを使用することです。

1と3のもう1つの問題は、表示モードを表示と同期させないように設定して、ユーザーにはUIがなく、終了する方法がないシステムにすることができることです。理想的には、適切なドライバ設定では、DXGI列挙リストにはサポートされていないモードが含まれていませんが、それは認識すべき点です。このため、表示モードを選択するためのUIにはタイムアウトが必要です。将来表示モードが同期できない場合は、キーボードを使用してアプリケーションを中止する方法が適切かどうかを確認する必要があります。上記の2のように既存の表示モードを使用することは、常に最も安全なオプションです。

上記のフルスクリーン排他モード(1)を使用する主な理由は、バックバッファ/フロントバッファの 'blit'ではなく 'flip'を得ることです。現代のシステムでは、これは無視できる性能差です。それを使用することの苦痛を経験するもう一つの理由は、SLI/CrossfireマルチGPUレンダリングを単一のディスプレイに表示するためです。このシナリオを実際に動作させるためには他にも数多くの最適化が必要ですが、かなりニッチです。詳細については、ベンダー最適化ガイドを検索する必要があります。

最新のゲームのほとんどは、フルスクリーンの「排他的」モードではなく、偽フルスクリーンを使用しています。彼らは、多くのユーザーが(ヒントをオンラインで見たり、IMや外部音声チャットなどを利用したりして)再生中にマルチタスクができるように、真のウィンドウモードを使用する機能を提供します。 SLA/Crossfireのための調整された高性能ゲームをサポートしたいと思うAAAのWindowsのデスクトップゲームはフルスクリーンの排他的なモードを提供するが、これは完全に働くためにいくつかの仕事を必要とし、いくつかのDXGIコードより多くの仕事を必要とする。

私が使用した別の回避策は、何もありませんここでは、いくつかの試みと裁判後DXGI OverviewDirectX Graphics Infrastructure (DXGI): Best Practices

+0

好奇心のために(Windows8.1またはWindows 10を考えて)、DirectX9 Full Screenを使って同じ動作に遭遇するでしょうか? – catflier

+0

Direct3D 9のフルスクリーンモードのエミュレート方法にはいくつかの違いがあると思いますが、Windows Vistaでは "デバイスの紛失"シナリオが実際には存在しないので、この動作も同様にエミュレートされます。同じ状況。 –

+0

デフォルトではdx9では実際にはフォーカスが失われるとすぐに隠れますが、少なくともそれは容易に騙される可能性があるため、現時点で唯一の方法はリソースを共有するためです。 – catflier

2

を参照してくださいが理想的ですが、すべてが何らかの形でモード変更を取得するよりも優れています。

1 /フルスクリーンウィンドウの中央にカーソルを置き、もう一度コントロールを取得するキーボードショートカットを使用します。 これは理想的ではありません。なぜなら、私たちの部品が稼働している間は何もできませんが、少なくとも偶発的な "災害の発生"を防ぎます。キーボードの操作も妨げません。

2 /共有テクスチャを持つDX9レンダラを使用します。 DX9スワップチェーンは親ウィンドウをデスクトップに設定できるため、別の場所に移動するときにフォーカスを失うことはありません。 フォーカスされたウィンドウを上に置くと、移動中に見える境界が少ししか表示されませんが、それはすべてを失うことより少し受け入れられます。 将来の証拠ではありませんが、しばらくの間は実際のままと推測されます。Windows 7と無効にDWMサービス

3 /滞在期間:

もはやWindowsの8で動作しますが、私のユースケースでは、私がのために働くほとんどのメディア企業は、Windows 7上で残っているので、しません、それは有効のまま少なくとも5年から10年間

4 /フォアグラウンド

にDX11ウィンドウを強制的に基本的に連続してフォーカスを取得するために別のウィンドウを避けるためにSetForegroundWindowを呼び出します。

5 /プレゼンテーションレベルでの防止モード切り替え。

私のアプリケーション上で、私はプレゼンテーションは(現在の呼する前に)、私は以下のルーチンを使用が発生した場合にアクセスを持っているので

-getフォアグラウンドウィンドウハンドルフォアグラウンドハンドルは、私たちのフルスクリーンウィンドウである場合には、(GetForegroundWindowを使用して)、単にcall通常通り。

フォアグラウンドハンドルがフルスクリーンウィンドウでない場合は、次の操作を行います。目に見えない重なり合ったウィンドウでもフルスクリーンロスが発生するため、視認性チェックは不要です。 コールGetWindowRect境界を取得し、モニターの位置が交差点を実行するために:私たちの最前面ウィンドウがモニターに重なっている場合

-VERIFY(真剣に、これは...ちょうどそう悪いです)。

また、DXGI_PRESENT_TESTフラグを使用して、スワップチェーンでPresentを呼び出します。ウィンドウが重なっている場合は、現在の呼び出しは、ウィンドウが重なる場合DXGI_STATUS_OCCLUDED

を返し、どちらか、それを隠すか、別のモニタでそれを移動します(どこでもそれが重なっていないので): ShowWindowSetWindowPosは、このタスクのためにaperfect適合しています。

これを繰り返すテストは、閉塞状態を返さないまでループを呼び出しません(ウィンドウがメッセージをすぐに処理しなかった可能性があるので、これは重要です)。閉塞した旗が消えたら、いつも通りに電話をかけてください。

関連する問題