精度が足りない!

さて、ロガーも使えるようになったし、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に止めておくか。この程度の差はソフトの質に影響しない。たぶん。