DirectX12 でフルスクリーン描画を行おうとしたときに、予想外に色々と苦戦しました。
DirectX12 というよりは、フルスクリーンは DXGI の機能・制御管轄なので、もしかすると今回の話は DirectX11 でも症状が出るのかもしれません。もしかすると環境要因もあるのかもしれませんが、何かの参考になれば幸いです。
出遭ったこと
「ALT+ENTER でフルスクリーンとウィンドウモードを行き来(切り替え)をしたい。」
これを実現するのに苦戦しています。
ディスプレイの解像度に対してのフルスクリーンとウィンドウモードの切り替えは、標準 DXGI の機能で問題なく出来ました。
ですが、描画の内容によっては指定された解像度でフルスクリーンとしたいことがあり、描画ターゲットの解像度を変えるのでは無く、ディスプレイの解像度設定のほうを変更したいという条件になります。
これには初期化時に DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH フラグを設定しますが、これがあると色々と問題に出遭いました。
ケース1
WM_SIZE メッセージが飛んできたときに解像度変更するような処理を作っていたのですが、ALT+ENTER の押下時にフルスクリーンとなるタイミングで WM_SIZE メッセージが通知されませんでした。見た目としてはフルスクリーンになって、前回の描画結果が表示されたまま、更新されないという症状でした。
DXGI のエラーメッセージは、次の通りでした。WM_SIZE メッセージが来たときに ResizeBuffers していたのでメッセージが来ない以上仕方なく・・・。
DXGI ERROR: IDXGISwapChain::Present: The application has not called ResizeBuffers or re-created the SwapChain after a fullscreen or windowed transition. Flip model swapchains (DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL and DXGI_SWAP_EFFECT_FLIP_DISCARD) are required to do so. [ MISCELLANEOUS ERROR #117: ]
ケース2
起動時からフルスクリーンの設定にしたいこともあるので、 DXGI_SWAP_CHAIN_FULLSCREEN_DESC 構造体に値をセットして初期化するようにしました。このときに、描画ループの組み方によっては次の症状が出るようです。
- フルスクリーン ⇒ ウィンドウに切り替えたとき、ウィンドウ化されたときに描画が止まる。
- 初回のフルスクリーン設定が強制的に解除され、ウィンドウ状態になる。しかし、ウィンドウ内は真っ黒状態になる。
環境情報
- Windows10 1809
- NVIDIA Geforce 1060
- ドライバは 425.31
まとめ
可能ならば DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH を使わずに、モニター解像度に対してのフルスクリーン対応にしておきたいところですね。しかし、そうも出来ないこともあるので、何かしらの対策案を見つけておきたいとは思っています。
(対処法が見つかったら、2019年秋の技術書典の冊子に載せたいと考えています。)