マルチメディアタイマー制御は危険なのか?

ついに今年初めての黒い悪魔登場。
しかし、何故か浴槽の中で瀕死状態。一体何があった?
とはいえ、そんな状態でもキモイものはキモイ。
排水口から流して終了ですがね。そのあと、パイプユニッシュを流しておいたけどね。
やはりやつらを完全にシャットアウトするのは難しいようだ。
っていうか、一体どこから入ったんだ?

昨日は一日中自宅でプログラミング。
弾幕ツールを.NET Frameworkに移植中なのですが、これが色々面倒。
C#でカスタムコントロールを作るのは簡単ですが、マネージとアンマネージを混合させると色々制約が多くなってわかりづらい。
とはいえ、ゲーム製作にC#はちょっと…なので、描画エンジンを共有させようと思ったらC++を使うことになるわけで。
そうなると当然混合させる必要があるわけで。これが結構重いっぽいんですがねぇ…。

そんな状態でまず躓いたのがタイマー処理。
ツール上で60フレーム描画をする場合、私は今までタイマーを使用してきました。
タイマーで1/60秒(約17ms)ごとに描画イベントをキックするって感じ。
しかし、Forms.Timer は精度が非常に悪い。確か 55ms が限界のはず。
そこで調べてみたところ、.NET Framework にはタイマーが3つあることが判明。
1つは前述したフォームコントロールのForms.Timer、1つはスレッドのタイマー、1つはサーバ用のタイマー。
この中で最も精度が高いのはサーバ用のタイマーだということで、どの程度の精度があるか調べてみると、これがまた酷い。
17ms に設定してみたら、30ms 前後で動いてた。10ms だと 11?13ms が基本で、3?4回に1回は 23ms 前後の数値が出てくる。
これでは使い物にならないので、やっぱりいつも通りにマルチメディアタイマーを使うことに。

ここでまた躓いた。マネージコードではコールバックが使えないから。
まあ、これも仕方のないこと。
マネージコードではガベージコレクタによってメモリの再配置が行われる可能性がある。
コールバック関数のように関数ポインタを用いるもの場合、そのポインタがガベージコレクタによって無効にされる恐れがある。
もちろん、やりかた次第で出来ないことはないし、マネージコードでも関数ポインタを使用する仕組みがある。
ただ、出来ればカスタムコンポーネントとして作成したいので、Google先生に聞きまくった結果、マルチメディアタイマーをコンポーネントにしてるプログラムを発見。
ここまででかなり時間はかかってるのですが、先人が作っているなら使わせてもらおう。
実際、これは全く問題なく動いてバンバンザイだったのですが、ここで再び問題発生。

マルチメディアタイマーで描画命令をしてたら、ちょっと負荷がかかっただけでアプリが応答しなくなった。
タイマーとメインフォームを同期させていたため、描画命令が遅れてキューが溜まりまくったからっぽい。
ちょっと負荷って言っても、そんなに重いはずもないような描画なんですが。
スプライトの描画をスプライトエディタと共通させたのが間違いだったかなぁ?
それでも、負荷がかかると応答がなくなるのは困りもの。
タイマーとメインフォームを非同期にしてみたのですが、若干改善されたくらいでやっぱり応答がなくなることがしばしば。
結局、いろいろ考えて、別の非同期スレッドを作成してそこで描画を行うように変更。
VSync待ちはDirectXに任せることにした。多分大丈夫でしょう。うちでは大丈夫だし。

マルチメディアタイマーは結構危険という話は聞いたことがあるのですが、こういうことになるとはねぇ。
今まではなったことないんですがね、こんなこと。
まあ、1つ勉強になったから良しとしますか。