DirectX11 でマルチフルスクリーン その3

DirectX11 でマルチディスプレイ環境で全てのディスプレイでフルスクリーンモードとしたいのに SetFullscreenState が失敗してしまう件の続報です。
この症状は、 Windows10 Creators Update 適用環境でも発生します。おそらく RTM 版から挙動は変わっていないのでは、と思います。詳しくは、前回までの記事を参照してもらうとして、今回は「どうしてもフルスクリーンモードを使いたいんだ」ということで、1つの提案を出してみたいと思います。

提案手法

DirectX9 ではマルチディスプレイでフルスクリーンモードが成功するようになっています。
また、 DirectX9Ex であってもこの動きは変わらないようで、フルスクリーンモードを使うことができました。

DXGI が提供するサーフェース共有の仕組みを使い、 DirectX11 のレンダーターゲットのテクスチャを DirectX9 で使うことができます。これでフルスクリーンは DirectX9Ex の機能で提供し、描画内容は DirectX11 にて行うという役割分担を考えます。バックバッファは共有にできなかったので、 DirectX11 からectX9 のバックバッファへ一度コピーが発生します。

共有の実装

DirectX9 でレンダーターゲットのテクスチャを作成します。このとき、ハンドルを受け取るための変数をセットすることが必要になります。他にも共有のための条件がありますが、それは MSDN などの情報を参照してください。

HANDLE handle;
d3d9dev->CreateTexture(
  width, 
  height,
  1, 
  D3DUSAGE_RENDERTARGET, 
  D3DFMT_A8R8G8B8, 
  D3DPOOL_DEFAULT, 
  &textureD3D9[i], 
  &handle);

このハンドルを用いて、 DirectX11 でレンダーターゲットビューを作成します。
ハンドルは ID3D11Texture2D を示すものなので、以下のようにして作成を行います。

ID3D11Texture2D* renderTarget;
ID3D11RenderTargetView* renderTargetView;
d3d11->OpenSharedResource(handle, __uuidof(ID3D11Texture2D), &renderTarget);
d3d11->CreateRenderTargetView(renderTarget, nullptr, &renderTargetView);

DirectX11 ではスワップチェインが不要で、描画が終わったら Flush() 関数を呼び出す必要があります。その後 DirectX9 側では、 StretchRect を用いて、サーフェースのコピーを行います。今回どちらもビデオメモリ側にあるサーフェースのため、この関数を使う必要がありました。

実験

今までと同様にパフォーマンスについて確認してみました。
1920×1200 と 1280×1024 のデュアルディスプレイの環境でフルスクリーンモードとしたときの計測です。参考までに、仮想フルスクリーンの実装時(& DISCARD) のものを載せています。

ベンダー DX9+DX11 DXGI_SWAP_EFFECT_DISCARD
NVIDIA 0.2 ms 0 ms
Intel 3.5 ms 3 ms

これをみるとやはり若干の処理コストがかかっていることが確認できます。

まとめ

最早何がしたいか分からなくなってきた状況ですが、 DirectX11 を使いつつも、フルスクリーンで描画を処理させるということについて説明しました。共有サーフェースを使ってなんとか頑張ってみることは出来たものの、パフォーマンスについては次点となりました。フルスクリーンについては、仮想フルスクリーンの実装を行い、 DXGI_SWAP_EFFECT_DISCARD でスワップを作っておくのが一番パフォーマンスがよい結果となりました。

DirectX
すらりんをフォローする
すらりん日記

コメント

タイトルとURLをコピーしました