DirectX12 のサンプルはなぜ WM_PAINT で更新と描画をしているのか?

DirectX12 のサンプルを読んでいて不思議に思うのは、Update 関数と Render 関数が、メッセージループでは無くてウインドウプロシージャで処理されていることです。

DirectX9, 10, 11 のサンプルだと、更新と描画関数はメッセージループで処理されていたため、そのやり方が DirectX のお作法だと思っていたのですが、DirectX12 のサンプルからは突如として WndProc の WM_PAINT で処理されるように変更されました。

特に調べてもこれと言った理由にはたどり着けなかったのですが、推測も含めて自分なりの答えをメモとして残します。

なぜ、 WM_PAINT で更新と描画を行なっているのか?

恐らく UWP とコードの共通化を行いたかったためと思われます。DirectX12 のサンプルから、UWP と Desktop (WindowsAPI) のそれぞれに対応したサンプルが提供されています。

UWP の場合は Windows API のような、低レベルのメッセージループ処理を書く必要はありませんが、イベントに対応する関数をシステムに登録して、必要に応じてイベントドリブンで処理されます。この部分が、Windows API のウインドウプロシージャと同じなため、アプリケーション側はイベントハンドラー内で呼び出される関数のみを用意すれば良く、それが OnUpdate と OnRender として定義されており、Windows API からはウインドプロシージャで処理するようになったと推測します。

だがしかし、UWP 側は View::Run() の中で、ループを回して処理しているので、Windows API 側も似たようにメッセージループ内に書けば良かった気もし無いでも無いです。

なぜ、WM_PAINT が毎フレーム発行され続けるのか?

この挙動が不思議でした。Windows API の DirectX のサンプルの挙動を見ていると、WM_PAINT メッセージが毎フレーム呼び出されています。

通常、WM_PAINT は UpdateWindow() や InvalidateRect() が呼び出されて、再描画が必要な時に発行されるはずです。これらの関数呼び出しを行なっている箇所も見当たらないため、なぜ、毎フレームWM_PAINT に来るのか疑問でした。

少しテストしてみたら、WM_PAINT が発行された後に BeginPaint() などで描画処理を行わないと、WM_PAINT が発行され続ける挙動があるみたいです。DirectX ではウィンドウの更新は全て DirectX API が行うため、Windows API の描画命令が呼び出されることはありません。そのため、Windows は、再描画の依頼を出し続ける事により、連続的に WM_PAINT が呼び出される事で、毎フレームの更新が実現されています。

コメントを残す

メールアドレスが公開されることはありません。