Direct3D10+Direct2DのVSync待ち

Direct3D10上にDirect2Dで画像をスクロールさせるだけの
処理を作ってるときに、VSync周りで地味にハマった。

縁無しのウィンドウモードで動かしていると、

pRenderTarget->EndDraw();		// 描画終了
pSwapChain->Present(1, 0);		// 表示

としているにも関わらず、
実機で実行するとモニタの上部で常にティアリングが・・・。
開発してるマシンでは起こらないんだけどー
ディスプレイの周波数は、ちゃんと60Hz。

どう考えてもVSync待ちに失敗してるっぽいので、
自力でVSyncを待つ方法を調べてみる。

IDXGIOutputクラスのWaitForVBlank()メソッドが正解っぽい。
ただ情報が全然ない・・・

仕方なく「描画→VSync待ち→表示」の流れが正解だろうと、
単純に

pRenderTarget->EndDraw();		// 描画終了
pDxgiOutput->WaitForVBlank();	// VSync待ち
pSwapChain->Present(0, 0);		// 表示

としてみると・・・
今度はコマ落ちしまくり・・・!

更に調べてみると、ID3D10DeviceクラスのFlush()メソッドの解説に、
アプリケーションが共有リソースを扱う場合、または CPU に任意の待機時間を設定する場合 (http://msdn2.microsoft.com/en-us/library/ms686298.aspx、ID3DX10ThreadPump::WaitForAllItems、または IDXGIOutput::WaitForVBlank の呼び出し時など) は、Flush を使用する必要があります。って書いてある!
EndDraw→WaitForVBlank→Presentだと、VSyncを待った後に
GPUへコマンド送信する余計な時間が掛かってしまいコマ落ちしてたのかな?

ってことで、

pRenderTarget->EndDraw();		// 描画終了
pD3DDevice->Flush();				// コマンド送信
pDxgiOutput->WaitForVBlank();	// VSync待ち
pSwapChain->Present(0, 0);		// 表示

と書き換えてみる。
するとティアリングがなくなって、
コマ落ちも滅多に起こらなくなった!
逆に言うと、稀にカクッとコマ落ちが・・・

作り始めた頃にも、盛大にコマ落ちしまくるの現象が起きて、
そのときは単純にtimeBeginPeriod関数と
timeEndPeriod関数を呼ぶだけで収まったから、
タイマの精度もかなり影響してるのかも?

でもフルスクリーンで作ってる別ソフトは、
全然コマ落ちも気にならないし、
単純に後ろで動いてる別プロセスの問題って気も。

どちらにせよ、発生頻度も極めて低くて気にならないし、
これ以上突き詰めても泥沼化しそうなので、ここらで妥協^^;
PresentのVSync待ちを使わずに
同期する方法が分かっただけでも良かったー

じゃ、ゲームして寝るー
バイニー☆

test?

コメントを残す