14

私は何週間もの間、C# のさまざまな種類のレンダリング ライブラリを検索してテストしてきました。これまでのところ、マルチウィンドウのレンダリング設定でうまく機能するライブラリは 1 つも見つかりませんでした。要件は、12 台以上のモニター設定 (財務チャート) でプログラムを高速コンピューターで遅延なく実行できることです。各ウィンドウは毎秒複数回更新する必要があります。これを実行している間、CPU は多くの集中的でタイム クリティカルなタスクを実行する必要があるため、負荷の一部を GPU にシフトする必要があります。そこで、ハードウェア レンダリング、つまり DirectX または OpenGL が介入します。

WindowsフォームでGDI +を試してみましたが、私のニーズには遅すぎると考えました。OpenTK (Windows フォーム コントロール上) を介して OpenGL を試してみましたが、かなり高速に見えました (実行するテストがまだいくつかあります) が、適切に動作させるのは非常に困難です (適切なテキスト レンダリング ライブラリを見つけたりプログラムしたりするのは困難です)。最近、SharpDX を介して Windows フォームで DirectX9、DirectX10、Direct2D を試しました。ウィンドウごとに個別のデバイスを試し、単一のデバイス/複数のスワップ チェーン アプローチを試みました。これらはすべて、複数のウィンドウでのパフォーマンスが非常に低下しました。たとえば、ターゲット FPS を 20 に設定し、異なるモニターで 4 つの全画面ウィンドウを開くと、オペレーティング システム全体が非常に遅くなり始めます。レンダリングは単に画面を黒くクリアするだけで、プリミティブはレンダリングされません。このテストでの CPU 使用率は約 0% で、GPU 使用率は約 10% でした。ここで何がボトルネックなのか理解できませんか? 私の開発用コンピューターは非常に高速で、i7 2700k、AMD HD7900、16GB RAM であるため、テストは間違いなくこのコンピューターで実行する必要があります。

比較として、C++/Win32 API の 1 つのデバイス/複数のスワップ チェーンでいくつかの DirectX9 テストを行ったところ、4 モニターのワークスペース全体に広がる 100 のウィンドウを開くことができ (3D ティーポットがその上で回転)、それでも完全に責任のあるオペレーティング システムを使用できました (fps はもちろん、レンダリング ウィンドウでは、100 の同時レンダリングを実行すると予想される約 5 にかなり落ちます)。

C# でマルチウィンドウ レンダリングを行う良い方法を知っている人はいますか? または、そのパフォーマンスを得るために C++ でプログラムを書き直す必要がありますか? C++ ルートに進む前に、OpenGL にもう一度挑戦していると思います。ここで調査結果を報告します。

参照のためのテスト方法:

C# DirectX one-device multiple swapchain テストでは、この優れた回答の方法を使用しました: Display Different images per monitor directX 10

Direct3D10 バージョン:

次のように d3d10device と DXGIFactory を作成しました。

D3DDev = new SharpDX.Direct3D10.Device(SharpDX.Direct3D10.DriverType.Hardware,
            SharpDX.Direct3D10.DeviceCreationFlags.None);
DXGIFac = new SharpDX.DXGI.Factory();

次に、次のようにレンダリング ウィンドウを初期化します。

var scd = new SwapChainDescription();
scd.BufferCount = 1;
scd.ModeDescription = new ModeDescription(control.Width, control.Height,
      new Rational(60, 1), Format.R8G8B8A8_UNorm);
scd.IsWindowed = true;
scd.OutputHandle = control.Handle;
scd.SampleDescription = new SampleDescription(1, 0);
scd.SwapEffect = SwapEffect.Discard;
scd.Usage = Usage.RenderTargetOutput;

SC = new SwapChain(Parent.DXGIFac, Parent.D3DDev, scd);

var backBuffer = Texture2D.FromSwapChain<Texture2D>(SC, 0);
_rt = new RenderTargetView(Parent.D3DDev, backBuffer);

各レンダリング反復で実行される描画コマンドは単純です:

Parent.D3DDev.ClearRenderTargetView(_rt, new Color4(0, 0, 0, 0));
SC.Present(0, SharpDX.DXGI.PresentFlags.None);

DirectX9 バージョンは非常に似ています。

デバイスの初期化:

PresentParameters par = new PresentParameters();
par.PresentationInterval = PresentInterval.Immediate;
par.Windowed = true;
par.SwapEffect = SharpDX.Direct3D9.SwapEffect.Discard;
par.PresentationInterval = PresentInterval.Immediate;
par.AutoDepthStencilFormat = SharpDX.Direct3D9.Format.D16;
par.EnableAutoDepthStencil = true;
par.BackBufferFormat = SharpDX.Direct3D9.Format.X8R8G8B8;

// firsthandle is the handle of first rendering window
D3DDev = new SharpDX.Direct3D9.Device(new Direct3D(), 0, DeviceType.Hardware, firsthandle,
    CreateFlags.SoftwareVertexProcessing, par);

レンダリング ウィンドウの初期化:

if (parent.D3DDev.SwapChainCount == 0)
{
    SC = parent.D3DDev.GetSwapChain(0);
}
else
{
    PresentParameters pp = new PresentParameters();
    pp.Windowed = true;
    pp.SwapEffect = SharpDX.Direct3D9.SwapEffect.Discard;
    pp.BackBufferFormat = SharpDX.Direct3D9.Format.X8R8G8B8;
    pp.EnableAutoDepthStencil = true;
    pp.AutoDepthStencilFormat = SharpDX.Direct3D9.Format.D16;
    pp.PresentationInterval = PresentInterval.Immediate;

    SC = new SharpDX.Direct3D9.SwapChain(parent.D3DDev, pp);
}

描画ループのコード:

SharpDX.Direct3D9.Surface bb = SC.GetBackBuffer(0);
Parent.D3DDev.SetRenderTarget(0, bb);

Parent.D3DDev.Clear(ClearFlags.Target, Color.Black, 1f, 0);
SC.Present(Present.None, new SharpDX.Rectangle(), new SharpDX.Rectangle(), HWND);
bb.Dispose();

複数のスワップチェーンと 1 つのデバイス コードを使用した C++ DirectX9/Win32 API テストは次のとおりです。

[C++] DirectX9 マルチウィンドウ テスト - Pastebin.com

これは、Kevin Harris の素敵なサンプル コードを修正したものです。

編集:

明確にするために、私の主な問題は、ここでマルチウィンドウ レンダリングを行うときの低 fps ではなく、すべてのオペレーティング システム機能 (ウィンドウ アニメーション、ドラッグ アンド ドロップ スクロールなど) に起因する一般的な遅延です。

4

5 に答える 5

4

ここでは DirectX の話だけですが、同じような問題が一度あったことを覚えています (1 台の PC で 5 つのグラフィックス カードと 9 つの画面)。

多くの場合、フルスクリーンスイッチはモニターで垂直同期を有効にしたいようです.Presentはスレッド化できないため、垂直同期を使用する画面が多いほど、ドロップが大きくなります(0〜16ミリ秒待機するため)現在の呼び出し。

私たちの場合の解決策は、最大化されたウィンドウを作成し、境界線を削除することでした。これは理想的ではありませんが、長方形を描画する 10 fps から標準速度 (60) に戻りました。

コードサンプルが必要な場合は、用意しますのでお知らせください。

また、テストのために、c#/slimdx/dx11 を使用してエンジンに 30 個のウィンドウを作成し、基本的なシェーディングで球体をレンダリングしましたが、それでも 40 fps をはるかに超えていました。

于 2012-11-03T22:18:31.420 に答える
3

この種のシナリオを実行する機会はありませんでしたが、私が確信しているのは、マネージド ラッパーを使用してもまったく問題がないということだけです。C++ コードでもまったく同じ問題が発生するでしょう。

また、説明では、システムにインストールされているグラフィックカードの数がかなり不明です。また、「 DirectX Graphics Infrastructure (DXGI): Best Practices」には、発生する可能性のある多くの問題が記載されているため、より厳密に従う必要があります。フルスクリーン用に正しくスワップチェーンを設定してフルスクリーンで別のグラフィックス カードを実行することは問題ありません (「blit」の代わりに「flip」を使用します。これについては msdn doc を参照してください)。ただし、最大化されたウィンドウでアプリを実行している場合は、ブリットが干渉してラグが発生するため、そのパフォーマンスは良好です。

複数のデバイス、スレッドごとに 1 つのデバイスを使用する単一のマルチスレッド アプリケーションを完全に作成でき、それらは物事を正しくスケジュールできるはずです... しかし、繰り返しますが、私はこの種のシナリオの経験がないので、ある種の GPU スケジューリングが存在する可能性があります。この特定のケースの問題。

DXGI のセットアップを注意深く行っても問題が解決しない場合は、GPUViewを使用して全体をデバッグし、これらの問題をより注意深く確認することをお勧めします。これはまさにこの種のシナリオを対象としていますが、この種のツールで診断を行う方法を理解するには少し時間がかかるでしょう. 最後の GDC 2012 では、GPUView に関する 1 つの講演もありました: GPUView を使用して DirectX 11 ゲームを理解する (Jon Story)は、おそらく読む価値があります。

于 2012-11-06T12:33:06.323 に答える
3

同様の問題があります (3 台以上のグラフィックス カードを使用して 9 台以上のモニターで 3D ビューをレンダリングする必要があります)。サード パーティのレンダリング ライブラリは、複数のアダプターはもちろん、複数のモニターにまたがる複数のウィンドウで非常に貧弱であることが判明したため、未加工の DirectX11 を使用することにしました。(ほとんどのエンジンはフルスクリーン ゲーム用に設計されているようで、ウィンドウ ビューが苦手な傾向があります)。SlimDX や SharpDX などのサードパーティ レイヤーを使用するのではなく、コア レンダラーを直接 C++ で記述し、C++/CLI を介してアプリケーションが必要とする単純な API を公開することを最終的に決定しました。これにより、パフォーマンスが最大化され、保守性の問題が最小限に抑えられます (依存バグ修正などについてはサードパーティ ベンダーに問い合わせてください)。

ただし、皆さんと同じように、単一のプロセス (それぞれが独自のスレッドでレンダリング) から 9 つのビューをレンダリングした場合、パフォーマンスが非常に低い (フレーム レートが非常に低い) ことがテストでわかりました。ただし、9 つの個別のプロセス (ビュー/モニターごとに 1 つ) を実行した場合、パフォーマンスは期待どおり (優れたもの) でした。

そのため、より良いソリューションを求めて無益にネットをトロールすることに何日も費やした結果、単純にレンダラーを別のプロセスで実行することにしました。いずれにせよレンダラーは複数の PC での配布をサポートする必要があるため、私たちにとって完全に悪い解決策というわけではありません。つまり、この機能を必要なときだけではなく永続的に使用することを意味します。

(これが回答として役立つかどうかはわかりませんが、より良いトリックが見つからない場合に備えて、複数のグラフィックカードで機能する他のソリューションがあるかどうかも知りたいと思っています)

于 2012-11-03T22:58:49.793 に答える
1

ネイティブ コードへの呼び出しのセキュリティ チェックが無効になっていることを確認します (経由SuppressUnmanagedCodeSecurityAttribute)。

関連するスタック ウォーキングはパフォーマンス キラーです。

于 2012-11-03T23:22:22.863 に答える