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

DirectX11 を使ってマルチディスプレイをフルスクリーンモードで使いたい場合に、Windows10 では問題があるということを前回記載しました。結論としては、仮想的なフルスクリーンを実装する(=全画面を覆うウィンドウを作成&最前面)でしたが、これを今回はテストしてみたいと思います。

仮想フルスクリーンの実装

仮想フルスクリーンの実装について説明します。といっても全画面を覆うウィンドウを作成するだけですので、難しいことはありません。
コードの抜粋ですが、以下のような感じで用意します。

ComPtr adapter;
IDXGIOutput* output = nullptr;
for (UINT i = 0; adapter->EnumOutputs(i, &output) != DXGI_ERROR_NOT_FOUND && i < MonitorCount; ++i)
{
  DXGI_OUTPUT_DESC desc{};
  output->GetDesc(&desc);
	UINT num = 0;
	hr = output->GetDisplayModeList(format, 0, &num, nullptr);
	std::vector modes;
	modes.resize(num);
	output->GetDisplayModeList(format, 0, &num, modes.data());

  MONITORINFO monInfo; ZeroMemory(&monInfo,sizeof(monInfo));
  monInfo.cbSize = sizeof(monInfo);
  GetMonitorInfo(desc.Monitor, &monInfo);
  int width = monInfo.rcMonitor.right - monInfo.rcMonitor.left;
  int height = monInfo.rcMonitor.bottom - monInfo.rcMonitor.top;
  // ウィンドウを作成
  hwnds[i] = InitInstance(
     hInstance, 
     monInfo.rcMonitor.left, monInfo.rcMonitor.top,
     width, height);
}


HWND InitInstance11(HINSTANCE hInstance, int x, int y, int Width, int Height )
{
    DWORD dwStyle = WS_POPUP;
    DWORD dwExStyle = WS_EX_TOPMOST;
    HWND hWnd = CreateWindowExW(
        dwExStyle,
        szWindowClass, szTitle, dwStyle,
        x, y, 
        Width, Height, 
        nullptr, nullptr, hInstance, nullptr);

    ShowWindow(hWnd, SW_SHOWNORMAL);
    UpdateWindow(hWnd);
    return hWnd;
}

あとは作成したウィンドウごとにスワップチェインを CreateSwapChainForHwnd 関数を用いて作成します。

実験

スワップチェインのフラグに、従来のモードとフリップタイプのモードを設定してみてどのような差が出るかを確認してみたいと思います。

環境

今回環境としては以下のような2機種で試してみました。いずれも Windows10 CU (1703) x64 の環境です。

  • NVIDIA Geforce 650 Ti
  • Intel HD Graphics 5300

どちらの環境でもモニタの接続については、プライマリを 1920×1200, セカンダリを 1280×1024 という環境となっています。

テスト

バッファ使用数は DXGI_SWAP_CHAIN_DESC1.BufferCount = 3 で実験を開始しました。いわゆるトリプルバッファリングです。DXGI_SWAP_EFFECT_DISCARD や DXGI_SWAP_EFFECT_FLIP_DISCARD を設定して Vsync 同期しないで全力で描画を実行してみました。表に記載の描画にかかっている時間は、直近 300 フレームの平均値となっています。

ベンダー DXGI_SWAP_EFFECT_DISCARD DXGI_SWAP_EFFECT_FLIP_DISCARD
NVIDIA 0 ms 8 ms
Intel 3 ms 8 ms

この結果を見ると、 DXGI_SWAP_EFFECT_DISCARD のほうが全力で描画処理を回せているように見えます。一方で、 DXGI_SWAP_EFFECT_FLIP_DISCARD は両者で同じような値になったことから、何か待ちが発生していると考えられます。

参考までに各フレームでの描画の時間をグラフ描画してみたところ、以下のようになり、描画時間が一定では無いことが確認できました。定期的に一定時間を待っているような感じです。(グラフは描画にかかった時間を縦軸、画面下をゼロとしています)

続いてバッファの使用数を DXGI_SWAP_CHAIN_DESC1.BufferCount = 12 で実験を行いました。同じように SWAP_EFFECT を変更しつつ確認してみます。

同じようにグラフを確認してみると以下のようになっていました。先ほどよりは待ち時間が発生しているフレームが減っていることが分かります。

まとめ

ベンダー違いで差が出る結果がとなりました。
DXGI_SWAP_EFFECT_FLIP_DISCARD を設定したときに、描画の全力を計る際には DXGI の flip するバッファ数によって速度制限がかかるような動きをしていました。次の描画のための使用可能な DXGI バッファが無いために、待ちが発生したためだと思います。そのためバッファを増やすとその待ちが発生するタイミングを減らすことが出来たと考えられます。

Vsync同期を無効にして全力を計る際には、 DXGI_SWAP_EFFECT_FLIP_DISCARD が設定されていると待ちが発生してしまうため使えなさそうです。 Intel のほうでは多量のバッファがある場合には従来の設定よりも早く Present 完了するようで、効果を確認することができました。

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

コメント

ベンダー DXGI_SWAP_EFFECT_DISCARD DXGI_SWAP_EFFECT_FLIP_DISCARD
NVIDIA 0 ms 0.9 ms
Intel 3 ms 2.5 ms
2019年12月
« 11月    
1234567
891011121314
15161718192021
22232425262728
293031  
タイトルとURLをコピーしました