BufferedInput=ON時にタイミングよくキーを押しても判定がMISSになってしまう
取り急ぎ、「MISSになる」のではなく「判定がずれる」という前提で進めます。
どうもDTXMania派生のTJAP3でも似たような話が出ている模様。https://github.com/AioiLight/TJAPlayer3/issues/195
簡単にぐぐったところ、
ようです。
ですが、3番目のtimeBeginPeriod()での改善は、実はFDKのCTimer()で昔から実装済みです。(CTimerをマルチメディアタイマーで使えば、timeBeginPeriod(1ms)が実行される)
なので・・・この話とは別ということか。うーむ。わからん。ということは、これらの話が当てはまらない比較的新しい時代の話=Win10のバグか? (テキトー)
# 余談: SlimDXの最新コードでも未だにDirectInputのタイムスタンプ実装が入ってないことをgithubで確認(涙;;;
DirectInput のタイマが GetTickCount だというのは初耳でしたので、こちらでも調べてみました。
DIDEVICEOBJECTDATA Structure https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ee416611(v%3Dvs.85)
これの Remarks には「Win95のGetTickCountの精度は55ミリ秒だけどもDirectInputは1ミリ秒以内」とあります。
だから
var ヒット時刻ms = diDeviceObjectData.dwTimeStamp - GetTickCount();
は NG だ、というのが要旨ですね。
DTXManiaではご指摘の通り timeBeginPeriod() で精度を1ミリ秒に上げた timeGetTime() を使っているので、この点では問題ないかと思います。
# SlimDX はもう開発終了したとみなして諦めましょう…… SharpDXでは私のプルリクも取り入れてもらえましたよ。
コメントいただきありがとうございます。そこのページは私も見ていましたが、remarksまでは見ていませんでした・・・確かに書いてありますね。
となると、実際の挙動がどんなものか、せなさんに聞いてみるしかないかな・・・
叩いてもMissというバグは自分でも(今でも)結構生み出してますので、 ソースが公開されていれば実験もできるのですが……
あけましておめでとうございます。(転置法
今年もよろしくお願いします。もうすぐDTXMania 19周年ですね!(とか言ってみる)
叩いてMissって、本当になるのですね&AL固有現象?(まだALを試していないのがバレバレ)
# んー、slimdxに対してfromさんが修正を加えられたところ(timestamp対応)と私が修正したところ(POV/HATバグ対応)をdiffにして保存しておいたはずなのですが、見つからない・・・
# まあ、修正点の概要は開発メモにまとめてあるので、これを踏まえてosdnのリポジトリを見ろ、程度のまとめでいいかな・・・
# slimdxのfromさんの修正diffを発掘できました。他の私の修正箇所も含め、開発メモ から参照できるようにしておきます。
http://senamih.com/dtxal/ で、せなさんの調査結果が公開されていました。以下引用。
前提 ・BufferedInputを使用する場合は、SharpDXのGetBufferedData()を使用 前回取得から取得時までのキーボード情報が返るので走査してタイムスタンプを得る (SharpDXのGetBufferedData()はDirectInputの構造体を参照しているのみ つまりタイムスタンプはDI由来なはず) ・BufferedInputを使用しない場合は、SharpDXのGetCurrentState()を使用 FPSに応じて1フレーム毎(描画前)に入力の確認をし時刻を記録する つまり時刻記録は1フレームあたりのミリ秒(1000/FPS)区切りになる 検証(適当なのであまり真に受けないこと) ・BufferedInputでキー押下時のタイムスタンプをログに出力すると16ms区切りになる(キーボード、ジョイスティックで確認) →タイムスタンプは新しめの日本語MSDNドキュメントで1ms程度の誤差としているが、誤差とは?分解能は別なのでは?? (古いバージョン向けドキュメントなら英語版があって精度が1msみたいな表記がされているけど…精度=分解能なの?every 55って書いてあるのと精度はよく考えたら違うような?前の文章から繋げて考えると1ms毎ってことなの?なんなの??) →音ゲーをやる上で、16ms分解能は人によっては判定に違和感が生じるはず ・Taskを利用した別スレッドでGetCurrentState()をSleep0ループさせた時の分解能は8ms(タイマはFDKのCTimer(timeGetTime由来)) →自分が使用しているUSBキーボードのポーリングレートが125hzなのでは(つまり8msより下にはできないだろう) →同時に押しても8ms区切りになってしまい完全な同時押しは(自環境では)できない (USBとかキーボとかHIDの仕組みはわからないけどポーリングレート単位なので何となく理解はできる) まとめると BufferedInputがオンだとキー入力が16ms単位になる(環境によるかもしれないけど) BufferedInputがオフでVSyncWaitがオンだとキー入力が(1000/FPS)ms単位になる(FPS60なら16ms) BufferedInputがオフでVSyncWaitがオフでSleepTimePerFrameが1なら最大FPSが1000になり、キー入力が最小1ms単位になる (そのままだとGPU(とCPUも)負荷がやばくなるのでSleepTimePerFrame(1フレームあたりの待機時間)を必ず1~2に設定すること) ※BufferedInputがオンだとAL本体がガタついた時の入力保障がある(大事) ※VSyncWaitがオフだとFPSが1000合ってもスクロールが滑らかに見えない(人による) ※USBキーボードは仕様上、入力が8ms単位になることが多い 作者は144HzモニタなのでBIオフ VSyncオンにしてます 読んでないけどつまりどういうことや FPS60モニタならBufferedInput使えば良いと思うよ 19.2.3
うーん、やっぱバッファ入力ありの時の分解能は15~16msあたりになってしまっているようですね。たとえtimeBeginPeriod()を使っていたとしても。(念のため、せなさんには ClockRes で DTXMania 動作中の Current timer intervalが1msになっているかどうかご確認いただきたいところ。私の環境では確かに1msになっていましたが、ここが1msになっていたとしても、DirectInputのバッファ入力時のタイムスタンプの精度が15~16msということかなと。)
これが事実だとすると、問題回避のためには別スレッドでバッファ無し入力取得をぐるぐるぶん回すしかないか・・・。
うちでも試してみました。
timeBeginPeriod(1) を使うことで timeGetTime() は 1ms 単位で取得できますが、それでも DirectInput の Timestamp は 16ms の倍数でしか取得できませんでした。
300fps以上出てますのでだいたい 3~4ms ごとにGetBufferedData()を呼び出している計算なのですが、それでも 16ms の倍数でした。
なんかありそうですね。
Are gaming keyboards really faster than conventional keyboards?
2017年10月の記事ですが
Apple Wireless Magic Keyboard 2 の遅延が 15ms でゲーミングキーボードより速い!とか書かれてます。
そーいうもんなんでしょうか。
ゲーミングキーボードを買ってみれば、何か変わるのでしょうか。
興味深い実験結果ですね。そこからリンクされているDan Luuさんの元記事の方がより詳細に書かれていますが、要は分解能云々以前に、USB等の信号として出ていくまでの、キーボード内の諸々の処理による遅延の方がはるかに支配的でデカいじゃろということですね。
・・・それはそれ、これはこれだと思いますよ。こちらの話は音ゲー専用のHIDデバイスにも当てはまって、それらの内部遅延は相当小さいですから。(少なくともArduinoやREVIVE USBで作ったHID機器の内部遅延は1~2ms程度です) ここに、15~16msの半分の8ms程度が平均的に上乗せされるとなると、非60Hzなモニタのユーザーはがっかりするかと。
なお、appleのキーボードの遅延が小さいのは、単にキーストロークが短いからのようにも見えます。逆に、キーストロークの長さを考慮に入れると、他の上位陣のキーボードは十分善戦しているように感じます。(そして、音ゲー向けの利用であれば、キーストロークの長さの要素は無視できるようにも思えますしね)
DirectInput等々入力の初期化をした後でタイマーの初期化をしているようなので(timeBeginPeriod含む)、試しに逆順にして試してみようと思います。
DTXMania公式さんのツイートより
https://twitter.com/dtxmania_mania/status/1100676599597285376
【悲報】DirectInput はウィンドウメッセージで実装されていた DirectInputのバッファありなしに関係なくメッセージディスパッチひ頻度下げたらあかんてことですやん
へ!? 事実上マルチスレッドで使えないDirectX9版DTXManiaへの死亡通告デスカ(T_T)
# 元ネタはこれですね: https://docs.microsoft.com/en-us/windows/desktop/dxtecharts/taking-advantage-of-high-dpi-mouse-movement
事実上マルチスレッドで使えないDirectX9版DTXManiaへの死亡通告デスカ(T_T)
そんな感じですねー。
ゲームを4パターンに分類して最適な実装を紹介してるMicrosoftの記事でも、 「リズム/タイミングゲーム」のように「かなり厳密なイベント ウィンドウ」が必要な場合には、シナリオ4、すなわち マルチスレッドで描画と表示を行うよう推奨されていますね。
実際、重たい動画の再生に20~30ms/フレームもかかってた原因もメッセージディスパッチの頻度低下にあったようですし、 MFの文書ではワークキュー(別スレッド)を使うことになってても、実際にはメインスレッドが重くなるとワークキューも同時に重たくなるので、 「メインスレッド(メッセージディスパッチ)は止めるな」というのが今回得た教訓でした。(涙
ありがとうございます。とっととDX11に移行しなきゃですね。
ですが今はdtxmania.netからosdnへの各種説明お引越し作業を最優先にしていますので、DX11化はそれがおわってからですね。
まず日本語のコンテンツ(の文章部分)の最低限のところだけosdnに移しましたが、説明に使っている画像が古いバージョンのDTXManiaを使ったものばかりで、それの差し替えが面倒くさい感じです。
BufferedInput=ON時にタイミングよくキーを押しても判定がMISSになってしまう、らしいです。(DTXMania ALさん曰く: http://senamih.com/dtxal/)
おそらくこちらのDTXManiaでも同様と思われます。
ただ、当方、今までそのようなことを感じたことはないのですが・・・PerfectがGreatになるとかでしょうかね。