はじめに
VulkanにはVK_EXT_full_screen_exclusive拡張機能というものがあり、これを使うとコンポジタを迂回しての描画が可能となります。この拡張機能が提案されたのが 2019年くらいだったので、今更ではありますが、少し調べてみました。
Windows 環境では DWM というコンポジタが各ウィンドウの描画結果を合成してディスプレイに表示をします。この動作のため、処理時間分がレイテンシとしてのってしまうため、タイミングにシビアなアプリケーションからは嫌われています。そして、DWM登場の頃から今に至るまで、 Windows XP の頃、DirectX9世代にあった排他的なフルスクリーンの挙動を求める声をよく聞くように思います。
VK_EXT_full_screen_exclusive
Vulkanのスワップチェーンサーフェースに排他的なフルスクリーンモードを使えるようにする拡張機能です。プログラム上から明示的な指示もできるようですし、ドライバがフルスクリーン用の描画処理を自動で実行するというような設定にも出来るようです。
VkFullScreenExclusiveEXT
- VK_FULL_SCREEN_EXCLUSIVE_DEFAULT_EXT
- デフォルト。従来の挙動
- VK_FULL_SCREEN_EXCLUSIVE_ALLOWED_EXT
- 排他的な全画面を明示的に有効にします。ドライバーはDWMを迂回した処理が可能であれば使用してもよい。
- VK_FULL_SCREEN_EXCLUSIVE_DISALLOWED_EXT
- 排他的な全画面を無効
- VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT
- 全画面モードをプログラムから制御します。
このようにフラグが用意されています。サンプルなどを確認すると、通常はデフォルトを選んでおくものの、フルスクリーン有効化を選ばれた場合には、VK_FULL_SCREEN_EXCLUSIVE_ALLOWED_EXTやVK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXTを用いて、全画面モードへ突入するという処理をするようです。
VkSurfaceFullScreenExclusiveInfoEXT
この構造体は排他的フルスクリーンを使用するために使用します。先に挙げたVkFullScreenExclusiveEXT のフラグを設定する構造体です。
VkSurfaceFullScreenExclusiveWin32InfoEXT
WindowsのHMONITORハンドルを格納するための構造体です。ウィンドウハンドルから HMONITOR ハンドルを得るコード例が以下の通りです。
MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
フルスクリーンウィンドウ
DWMの合成を迂回してディスプレイに表示するためには、ディスプレイを覆うフルスクリーンのウィンドウが必要です。画面解像度と違うウィンドウサイズでフルスクリーン化することは出来ないようです。
いわゆるボーダーレスウィンドウでウィンドウスタイルを設定することが必要です。
- WS_BORDER, WS_DLGFRAME, WS_THICKFRAME フラグをオフ、WS_POPUP フラグをオン
- WS_EX_WINDOWEDGEフラグをオフ、 WS_EX_TOPMOST フラグをオン
APIの使用について
スワップチェインを生成するときに使用する VkSwapchainCreateInfoKHR 構造体の pNext メンバに、先に示した VkSurfaceFullScreenExclusiveInfoEXTやVkSurfaceFullScreenExclusiveWin32InfoEXTの構造体を連結します。
VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT を使う場合には、フルスクリーン化の実装が必要です。VK_FULL_SCREEN_EXCLUSIVE_ALLOWED_EXT の場合には、ボーダーレスウィンドウ化だけの準備を行い、後はランタイムやドライバにお任せするという感じになります。
Application Controlled の場合の実装
排他フルスクリーンを開始するときには、vkAcquireFullScreenExclusiveModeEXTを呼び出します。条件が整っていない場合には排他的フルスクリーン化は失敗して、この関数の戻り値が VK_ERROR_INITIALIZATION_FAILED となります。また、フルスクリーンを解除するときは、vkReleaseFullScreenExclusiveModeEXTを呼び出します。
実行について
Windows11 (22H2) の環境で試してみました。確かに排他的なフルスクリーン化ができているようです。このフルスクリーン化された状態で、他のアプリケーションに切り替えたり、スタートメニューを開いたりすると、プレゼンテーションに失敗するようです。 vkQueuePresentKHR の戻り値が、 VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT となり、ロスト状態が観測されました。 このあたりも以前の排他的フルスクリーンの挙動に似ている感じがします。
この排他的フルスクリーンで画面が実際に表示されるまでのレイテンシが短縮されるかどうかについては未検証です。
以下の図はフルスクリーン化が解除されたときのアプリケーションの状態です。全画面ウィンドウモードしていましたが、解除されてウィンドウ枠が表示されているものの、外側の領域は黒いままとなっていました。
コメント