VSYNC待ちをするには??


御酒肴  2006-05-11 20:58:48  No: 61764

DirectXを使ってVSYNC待ちできると聞いたのですがよくわかりません。どなたか教えていただけないでしょうか。
環境は WinXP  SP2 VC.Net2003  MFC  です。


愚暗  2006-05-12 07:12:46  No: 61765

IDirectDraw::WaitForVerticalBlank というのを
昔使ったことがありますが、割と取りこぼしというか
抜けが多く発生したような記憶があります。
そのときは、結局, WaitForVerticalBlank で何回か
垂直ブランキングを待って 1フレームの時間を割り出して、
タイマーでタイミングを取って解決したはず。


御酒肴  2006-05-12 20:22:16  No: 61766

解答ありがとうございます。それはDirectGraphicsでも使用できるのですか?


愚暗  2006-05-14 20:29:50  No: 61767

DirectGraphics は使ったことがないのでわかりませんが、
IDirectDraw::WaitForVerticalBlank でタイミングを取って
DirectGraphics の機能を使って描画、というやり方に
なるのではないかと想像します。
取り敢えず試してみてください。


御酒肴  2006-06-16 19:44:39  No: 61768

WaitForVerticalBlankでVSYNCがとれるようになったのですが
やはりとりこぼしが多く発生します。
  WaitForVerticalBlank で何回か
垂直ブランキングを待って 1フレームの時間を割り出して、
タイマーでタイミングを取って解決したはず。
っていう部分を具体的に教えてください。


愚暗  2006-06-19 09:59:06  No: 61769

過去のソースをサルベージしたら、とあるプロジェクトで
V待ちを行っていて、それは概略こんな感じになってました。

・時間を QueryPerformanceCounter で計測しながらVを3回待つ。
・VとVの間隔のうち、短いほうをV周期として採用。
  (短いほうが正しいV周期と思われるので)
・描画ループの中で、時間を QueryPerformanceCounter で計測して、
  V周期の間待ち、所定の時間に達したら描画する、というのを
  繰り返す。

描画ループ中のV待ちを単純に時間計測で行っているので、
長い間には誤差が蓄積してしまうでしょうが、このプロジェクトでの
描画は 2秒くらいで一区切りつくような構成になっていたので
問題ありませんでした。
また、描画ループ中、CPU使用率が100%になったままになりますが、
スムーズな描画のためと、割り切りました。

なお、最初に時間計測するときのV待ちには 
IDirectDraw::WaitForVerticalBlank ではなく
IDirectDraw::GetVerticalBlankStatus を使っていました。
どうも, IDirectDraw::WaitForVerticalBlank は
モニターパワーセーブに入ると帰ってこなくなってしまう、
という問題があって使うのをやめたようです。

IDirectDraw::GetVerticalBlankStatus によるV待ちは
次のようにしていました。

・まず現在時刻を計測。
・ループの中で時刻を計測して、設定したタイムアウトに
  達していないか確認。(タイムアウトは200msを設定していました)
・IDirectDraw::GetVerticalBlankStatus で現在垂直帰線期間内か
  確認すると同時に、その状態を保存。
・現在垂直帰線期間内で、前回は垂直帰線期間内ではなかったなら、
  新たに垂直帰線期間に入ったということなので、ループを抜ける。

ところで、このプロジェクトのもっと後のバージョンでは、
別の方法でのV待ちを行っていました。
どうも、上記の方法でもまれに抜けが発生していたようで、
もっと確実にV待ちを行うため、ライン番号を監視することに
したようです。
具体的には IDirentDraw::GetScanLine を使って、
次のようにしていました。

・まず現在時刻を計測。
・ループの中で時刻を計測して、設定したタイムアウトに
  達していないか確認。
  (ここまでは GetVerticalBlankStatus による方法と同じ)
・IDirentDraw::GetScanLine で現在のライン番号を取得。
  同時にこれを保存。
  なお, DDERR_VERTICALBLANKINPROGRESS が返ってきたなら
  ライン番号は 0 とする。
・前回のライン番号より今回のライン番号のほうが少なければ
  帰線したということなのでループを抜ける。

IDirentDraw::GetScanLine によるV待ちでは抜けがほとんど
なかったので、描画ループの中でダイレクトに GetScanLine による
V待ち処理を呼び出してしました。

ただし, IDirentDraw::GetScanLine は環境によっては
正常な値を返さない(1画面スキャンする間に何度も増減を繰り返す)
ことがありました。
よって、最初に GetScanLine で2回V待ちを行ってその間隔を計測し、
想定する最小間隔(600分の1秒という値を想定していました)より
小さかったら GetScanLine は採用せず, GetVerticalBlankStatus 
による待ちを行うようにしていました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加