DWM による描画の現場を押さえる

これまで何度か Windows Vista で大規模に導入される DWM によるデスクトップ描画の仕組みについて取り上げてきました.その中で,従来の GDI アプリケーションを,どのように Direct3D による Desktop Composition に参加させるかについても紹介を行いました.
それは,トップレベルウィンドウの内容をいったんシステムメモリ上のサーフェイスに GDI 描画し,そのサーフェイスの更新を検出したDWM が適時 Direct3D 上のサーフェイスに転送するという,2 段構えの仕組みです.今回は,その「システムメモリ上のサーフェイス」を直接覗き見ることに挑戦してみます.

共有ワーキングセット

まず,いくつかの状況証拠が,このサーフェイスがメモリマップされた共有メモリであることを示唆しています.
例えば,Process Explorer で dwm.exe のメモリ使用量を見ていると,ウィンドウを開いたり,広げたりするごとに,共有ワーキングセットのサイズが増加するのを確認することができます.

上図は大きさ 1024×1024 のウィンドウを 50 枚程度開いたときの dwm.exe のメモリ使用量です.Windows Vista のタスクマネージャのデフォルト設定では「メモリ (プライベート ワーキングセット) 201 MB」と表示されているはずです.ちなみに Windows XP までのタスクマネージャのデフォルト設定では,「メモリ使用量 440 MB」となります.数字の比較をするときは定義に注意.
同様に,各アプリケーションの共有ワーキングセットのサイズに注目しても,ウィンドウサイズに連動して増減することが分かります.これらの実験から,各アプリケーションと DWM は共有メモリでサーフェイスを共有している可能性が示唆されます.

共有メモリ

また,各アプリケーションのメモリ空間内に共有サーフェイスが存在することを明言している資料もあります.『Windows Vista デベロッパ ストーリー: アプリケーション互換性解説書』は,Windows Vista 移行に伴う影響として次のようなものを挙げています.

アプリケーションのアドレス空間が狭くなりましたか。
最上位ウィンドウのビットマップは、アプリケーションのアドレス空間に格納される (描画の説明を参照) ため、使用可能なアドレス空間が数 MB 減る可能性があります。

どうやらアプリケーションのメモリ空間内に,トップレベルウィンドウの表示イメージがあるのは間違いないようです.再び Process Explorer に戻り,下部ペインにプロセスに読み込まれた DLL 一覧を表示させます.さらに,メニューから「View」→「Show Unnamed Handles and Mappings」をチェックし,ページファイルに対するメモリマッピングも表示されるようにしましょう.後は,マッピングのアドレスとサイズが分かるように表示を調整しておきます.
この状態で,ウィンドウのピクセル数×4 byteに近いサイズを持つ のメモリマッピングを探します.見つかったら,ウィンドウのサイズをマウスで変化させてみましょう.新しいサイズに合わせてメモリマッピングの削除と生成が行われるところを見ることができるはずです.

実験と結果

次のようなウィンドウで実験してみました.

このウィンドウのサイズは 347×383 で,ARGB 合わせて 531,604 byte 以上のサーフェイスが存在すると予想されます.Process Explorer の方も見てみましょう.

ちょうど 0x4750000 番地から 532,480 byte のメモリマッピングが存在します.メモリマッピングは少なくとも 4 KB 単位なので,ウィンドウのイメージがそのまま格納されていると考えて矛盾がない数字です.
そこで実際に,0x4750000 番地から 531,604 byte 読み取って,素直にピクセル配列と思って出力してみたのが次の図です.ピクセルフォーマットは,0xAARRGGBB *1 を仮定しました.

結果は予想通りトップレベルウィンドウのイメージがそのまま格納されていました.何度かの実験から,スキャンラインごとのアライメントなどは一切存在せず,単純にピクセルデータが並んでいるだけらしいことも分かりました.

まとめ

最後に,今回の実験から分かったことをまとめておきます.

  1. DWM 環境下では,GDI 描画アプリケーションと DWM がメモリマッピングを通してトップレベルウィンドウのイメージを共有する.
  2. 共有サーフェイスのサイズは,クライアント領域のサイズではなく,ウィンドウフレームを含めたサイズに等しく,単純にピクセル数だけデータを並べたものである.
  3. 共有サーフェイスは,ウィンドウサイズが変更されるたびに作りなおされる.
  4. 共有サーフェイスの時点で,COLORREF 形式 (0xXXBBGGRR) から Direct3D 形式 (0xAARRGGBB) への変換が終了している.

*1:32-bit DIB や Direct3D で標準的なフォーマット