最近Mach-Oの調査ばっかりやっているので、DirectX11とか触ってるとほっとします。
昨今では2つのディスプレイが繋がっていることも珍しくないと思います。
それぞれに対してDirectXアプリケーションのフルスクリーンやりたいとか、独立した複数ウィンドウでDirectXの描画やりたいとかそういうときにどうしたらよいかを実験してみました。
結論から言えば、複数のデバイスコンテキストを作る必要すら無く、レンダーターゲットビューとスワップチェインを複数持つことでこれらを実現出来ることがわかりました。デバイスが独立ではないのでリソースも共有出来ます。
初期化
DirectX11の初期化部分を説明します。
D3D11CreateDeviceAndSwapChain関数を使用して初期化することは出来ないようで、必要なオブジェクトを順番に作成していく必要があります。まずは D3D11CreateDevice関数でデバイスの初期化、続いて必要な数のスワップチェインの作成となります。
スワップチェインの作成はデバイスから直で出来ず、DXGIのオブジェクトを数回経由する必要があります。
これらの処理をざっくりと以下に示します。
IDXGIDevice1* pDXGI = NULL; IDXGIAdapter* pAdapter = NULL; IDXGIFactory* pFactory = NULL; D3D11CreateDevice( NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, NULL, 0, D3D11_SDK_VERSION, &pd3dDevice, NULL, &pDeviceContext ); pd3dDevice->QueryInterface( __uuidof(IDXGIDevice1), (void**)&pDXGI ); pDXGI->GetAdapter( &pAdapter ); pAdapter->GetParent( __uuidof(IDXGIFactory), (void**)&pFactory ); sd.OutputWindow = hWindow[0]; pFactory->CreateSwapChain( pd3dDevice, &sd, &pSwapChain[0] ); sd.OutputWindow = hWindow[1]; pFactory->CreateSwapChain( pd3dDevice, &sd, &pSwapChain[1] );
スワップチェインを作成できたら、それぞれのウィンドウ(場合によってはディスプレイ)に対してのバックバッファを作成しておきます。
これはpSwapChain[0]->CreateRenderTargetViewでいつも通りに作成する感じです。必要ならデプスステンシルも作成しておきます。
描画
描画の方は何も難しいことはありません。複数のレンダーターゲットを扱ったことがある人なら意識するような違いがないです。コードを以下に示します。
// 1つめWindowに対して描画 pDeviceContext->OMSetRenderTargets( 1, &pRenderTargetView[0], pDepthStencilView[0] ); pDeviceContext->ClearRenderTargetView( pRenderTargetView[0], clearColor ); pDeviceContext->ClearDepthStencilView( pDepthStencilView[0], D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0 ); // 適当にリソースをセットして描画処理. pDeviceContext->Draw( 4, 0 ); // 2つめWindowに対して描画 pDeviceContext->OMSetRenderTargets( 1, &pRenderTargetView[1], pDepthStencilView[1] ); pDeviceContext->ClearRenderTargetView( pRenderTargetView[1], clearColor2 ); pDeviceContext->ClearDepthStencilView( pDepthStencilView[1], D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0 ); // 適当にリソースをセットして描画処理. pDeviceContext->Draw( 4, 0 ); // それぞれのウィンドウに反映されるようにSwapChainのPresent pSwapChain[0]->Present( 0, 0 ); pSwapChain[1]->Present( 0, 0 );
まとめ
マルチウィンドウにすることでどのくらい2重でデータ持ちしないといけないかと心配しましたが、結構楽に実現出来ることがわかりました。スワップチェインが個別という程度で、他はマルチレンダーターゲットやっているときと変わらない感じです。
今回試してみたプログラムでは以下のようにリソースも1つでそれぞれに描画してみました。