Windows 7 におけるULWの挙動 (2)

DWMでもなく、タイマーでもない。原因になる得るものがなく、困ってしまった。

Direct2Dによる高速描画の試行

ということで、とりあえず原因究明はあきらめ、 「人事を尽くす」方向でアプローチすることにした。Windows Vista/7からはGDIはレガシーであり、はっきり言って遅い。時代はGPUをフル活用したグラフィックス描画であり、Vista/7にはそのためのDirect2Dというグラフィックスレイヤーが存在する。

Direct2Dは名前が示すようにDirectXコンポーネントの一部で、ハードウェア(GPU)を利用して二次元描画を高速に行うサービスである。DirectSoundなどDirectXのほかのコンポーネントがゲーム向けであるのに対して、Direct2DはOSや一般アプリが利用することを想定されている点が特徴である。IE9が利用して大幅に高速化されたというのも、このDirect2Dである。

Direct2Dについては下記のリンクが詳しい。

DirectX関係はC++になるわバカでかいSDKをダウンロードしないといけないわ環境が汚れるわで敬遠しているんだけど、仕方ない、さっそく DirectX SDK (February 2010) を落としてインストール。サンプルのDirect2DHelloWorldを改造して、タイマーでアニメーションするようにした。

タイマーを設定して、

::SetTimer(hwnd, 0, 1000/100, NULL);



ウインドウプロシージャで受けて、

case WM_TIMER:
    ::InvalidateRect(hwnd, NULL, FALSE);
    break;


描画ルーチンでQPCの値基準で横方向に移動させるようにした。

m_pRenderTarget->DrawText(
    sc_helloWorld,
    ARRAYSIZE(sc_helloWorld) - 1,
    m_pTextFormat,
    D2D1::RectF((float)fmod(800 * (f+i/10.0f), 1600) - 800, (i-25)*40.0f, renderTargetSize.width, renderTargetSize.height),
    m_pBlackBrush
    );


DWM環境下で実行させてみるとびっくり、これなら滑らかに動いている!?


……と思ったけど、なんかおかしい。前よりは滑らかだけど、やっぱりカクカクしている。現代のコンピュータはこの程度の負荷では間違いなく処理落ちしない。なにか、意図しない出来事が中で起こっているのに違いない。


試しに60fpsになるようにタイマーのウェイトを調整してみたら、さらにコマ落ちが発生した。さらに、半透明ウインドウにしてみたらさらにコマ落ちがひどくなった。アルファブレンドでのレイヤードウインドウは面倒なのでサボった。


ここまでのまとめ


ここまでの実験結果から分かることは、


  • Windows 7では処理落ちしなくてもコマ落ちする。DWM環境に限らず、GDI環境でも落ちる。 レイヤードウインドウでなくてもダメ。
  • タイマーの割り込みはXP/Vistaと同じ程度には良い精度で受け取ることができる。しかし、タイマーが周期的に描画していても、画面上では周期的に更新されない場合がある。
  • Direct2Dを用いて超高速描画を行うと状況は改善する。


……ふむ、要は「アプリは描画したつもりなのに画面に反映されていない」ということらしい。となれば、やっぱりDWMが余計なことしてくれている可能性が高い。「余計なこと」の第一候補はアンチティアリングだろう。画面描画のために同期をとっているのだから、一般的に考えて何も起きないわけがない。