精度が足りない!
さて、ロガーも使えるようになったし、FPSの問題解決に挑む。現象は、「FPSが60になるよう調整したが、大した処理してないのに、30fps前後まで落ちてしまう」である。我がPCは中堅どころのグラボを搭載しており、そこらの3Dゲームなど苦もなく動く。デバイス初期化時も容赦なくハードウェア頼りにしてある。スペック不足は考えられない。あ、C#とManaged DirectXでゲーム開発やってるんで、それ関係のトラブル。読者置いてけぼりの覚え書きである。
ログを取って解析してみる。
2005-12-14 03:40:21,984 [5672] DEBUG DirectXTest.MainForm - 0 2005-12-14 03:40:21,984 [5672] DEBUG DirectXTest.MainForm - 0 2005-12-14 03:40:21,984 [5672] DEBUG DirectXTest.MainForm - 0 2005-12-14 03:40:21,984 [5672] DEBUG DirectXTest.MainForm - 0 2005-12-14 03:40:21,984 [5672] DEBUG DirectXTest.MainForm - 0 2005-12-14 03:40:21,984 [5672] DEBUG DirectXTest.MainForm - 0 2005-12-14 03:40:21,984 [5672] DEBUG DirectXTest.MainForm - 0 2005-12-14 03:40:21,984 [5672] DEBUG DirectXTest.MainForm - 0 2005-12-14 03:40:22,000 [5672] DEBUG DirectXTest.MainForm - 15.625 2005-12-14 03:40:22,000 [5672] DEBUG DirectXTest.MainForm - 15.625 2005-12-14 03:40:22,000 [5672] DEBUG DirectXTest.MainForm - 15.625 2005-12-14 03:40:22,000 [5672] DEBUG DirectXTest.MainForm - 15.625 2005-12-14 03:40:22,000 [5672] DEBUG DirectXTest.MainForm - 15.625 2005-12-14 03:40:22,000 [5672] DEBUG DirectXTest.MainForm - 15.625 2005-12-14 03:40:22,000 [5672] DEBUG DirectXTest.MainForm - 15.625 2005-12-14 03:40:22,000 [5672] DEBUG DirectXTest.MainForm - 15.625 2005-12-14 03:40:22,015 [5672] DEBUG DirectXTest.MainForm - 31.25 2005-12-14 03:40:22,015 [5672] DEBUG DirectXTest.MainForm - RENDER!!
ループのたびに経過時間をミリ秒単位で出力してみたのだが、なるほど、15.625msが分解能ギリギリなのか。FPSを60に固定する場合、16.666msごとに画面を更新することになるわけだが、これではギリギリ不足して、31ms経過してからでないと更新されない。だいたい半分のペースになるから、FPSは30ぐらいに落ち込む・・・計算合うね。ちなみに、経過時間の測定にSystem.DateTimeを使った。System.Environment.TickCountも試したが、同様の結果に。
さて、どうしたものか。フレームレートなんてゲーム作成していれば必ず出てくる問題なので、DirectXにそういうAPIがあっても不思議じゃない、と思っているのだが、見つからない。僅かにあるManaged DirectXを扱ったサイトでFPSについての記事を見ていると、System.Environment.TickCountで凌げているようだ。ハードによるのだろう。
WIN32APIのtimeGetTime()を直接呼ぶしかねーのかなぁ。Timerは精度が怪しいし・・・。というわけで、なにかすっきりしないが、timeGetTime()を使用。
2005-12-14 04:49:19,703 [5936] DEBUG DirectXTest.MainForm - 3 2005-12-14 04:49:19,703 [5936] DEBUG DirectXTest.MainForm - 6 2005-12-14 04:49:19,703 [5936] DEBUG DirectXTest.MainForm - 8 2005-12-14 04:49:19,703 [5936] DEBUG DirectXTest.MainForm - 10 2005-12-14 04:49:19,703 [5936] DEBUG DirectXTest.MainForm - 12 2005-12-14 04:49:19,718 [5936] DEBUG DirectXTest.MainForm - 14 2005-12-14 04:49:19,718 [5936] DEBUG DirectXTest.MainForm - 17 2005-12-14 04:49:19,718 [5936] DEBUG DirectXTest.MainForm - RENDER!! 2005-12-14 04:49:19,718 [5936] DEBUG DirectXTest.MainForm - 3 2005-12-14 04:49:19,718 [5936] DEBUG DirectXTest.MainForm - 5 2005-12-14 04:49:19,718 [5936] DEBUG DirectXTest.MainForm - 7 2005-12-14 04:49:19,718 [5936] DEBUG DirectXTest.MainForm - 9 2005-12-14 04:49:19,718 [5936] DEBUG DirectXTest.MainForm - 10 2005-12-14 04:49:19,734 [5936] DEBUG DirectXTest.MainForm - 16 2005-12-14 04:49:19,734 [5936] DEBUG DirectXTest.MainForm - 18 2005-12-14 04:49:19,734 [5936] DEBUG DirectXTest.MainForm - RENDER!!
おおっ、分解能が2から3ms程度に。これで55fpsぐらい。いまはThread.Sleep(1)でウェイトかけているから、これをとっぱらってみると・・・59fpsで安定。おおむね予定していた数値になった。でも、sleep取ってしまうと無駄なループが多発するのがなんとも気持ち悪い。うまい解決案が浮かぶまで55fpsに止めておくか。この程度の差はソフトの質に影響しない。たぶん。