私は何週間もの間、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 ではなく、すべてのオペレーティング システム機能 (ウィンドウ アニメーション、ドラッグ アンド ドロップ スクロールなど) に起因する一般的な遅延です。