OpenSiv3D
OpenSiv3D copied to clipboard
VSync無効時にフレームレートを制限する機能の提案
追加する機能の内容 | Describe the solution you'd like
過去バージョンに存在していた、下記の関数を別の実装で復活させたいと思っています。
-
Graphics::SetTargetFrameRateHz
-
Graphics::GetTargetFrameRateHz
下記のQiita記事に記載したstd::this_thread::sleep_until
を使う方法で、Windows版・macOS版の2通りで安定して300fpsに固定できることを確認できました。
OpenSiv3Dでフレームレートを60fps以外に固定する方法(FrameRateLimitアドオン) | Qiita
そこで、上記と同じような内容の実装をSiv3D内に組み込んで、VSync無効時のフレームレートを指定できるようにしたいと思っています。
その機能の追加によって解決する問題 | Is your feature request related to a problem? Please describe.
60fps以外のフレームレートで安定動作させられる。 ソフトウェア作成者が適切なウェイトを入れないままVSyncを無効化してしまい、ソフトウェア利用者の環境にて過剰な負荷が発生するのを防げる。
備考 | Additional context
もしよろしければ、実装についてぜひ私の方で挑戦してみたいです。 そこで、まずは実装方針について3点ご相談したいです。
- ユーザー側で呼び出すインタフェースは旧バージョンにあった
Graphics::SetTargetFrameRateHz
と同じにすべきでしょうか?それとも、より適切な名前があれば名前空間や関数名を別のものに変更しても問題ないでしょうか? - フレームレート制限は旧バージョンと同様、VSyncを無効化した場合のみ効くようにした方が良いでしょうか?それとも、VSync有効のままで120Hzモニタや144Hzモニタでも60fpsに固定したいユーザーなどを想定して、VSyncが有効な場合も効くようにした方が良いでしょうか?
- プラットフォーム間で同一実装になる見込みです。そこで、時間待ちは旧バージョンで実装していたD3DSwapChain.cpp等ではなく、
ISiv3DFrameRateLimit
インタフェース、CFrameRateLimit
クラスを新たに作成して実装し、System::Update
内のAddonのpostPresentの直前か直後のタイミングにSIV3D_ENGINE(FrameRateLimit)->update();
を入れて実行する形が良さそうですが、方針について問題なさそうでしょうか?
ご提案ありがとうございます。#1179 の調査完了後に検討します。
#1179 をマージしたので、こちら進めます。
- Hz を外して
void Graphics::SetTargetFrameRate(const Optional<double>& fps)
/Optional<double> Graphics::GetTargetFrameRate()
にしましょう。 - 既存のコードへの影響を小さくするため、VSync が無効な場合のみ有効としたいです。
- 新しいエンジンインタフェース
FrameRateLimit
の追加 OK です。その実装方針で良さそうです。
ご確認ありがとうございます。1〜3について承知しました! 実装に進展がありましたらお知らせいたします!
@Reputeless 下記で仮実装しました。実装内容に問題ないかご確認いただけますと幸いです! https://github.com/m4saka/OpenSiv3D/commit/da52430ef41c7aec1b624512a2f0873ee4e12602
実装にあたって気になっている点は下記2点です。
- 目標フレームレート(
fps
引数)にゼロや負の値を指定した時に例外を投げているのは問題ないか? - 目標フレームレート(
fps
引数)にNaNや+inf、-infを指定した場合も例外を投げるべきか?
補足事項として、Qiita記事での実装ではMaxDrift
(=10ミリ秒)という定数値を導入していましたが、now < sleepUntil
の場合のみsleepを実行することで不要になったので、今回の実装には入っていません。
手元では現状Windows版のみで動作確認しているので、macOS版、Linux版、Web版でも正常動作するかどうかは今後確認予定です。 (Xcodeプロジェクトへのソースファイル追加についても現状は未対応です)
ありがとうございます。確認します、
レビューコメントが記載できるように一旦Draft PRにいたしました。 https://github.com/Siv3D/OpenSiv3D/pull/1205
目標フレームレート(fps引数)にゼロや負の値を指定した時に例外を投げているのは問題ないか? 目標フレームレート(fps引数)にNaNや+inf、-infを指定した場合も例外を投げるべきか?
- ほかの関数のほとんどがそうなので、NaN の挙動は未定義(対策なし)で問題ありませんが、例外で知らせても良いです。
- 「スリープ無し / 目標フレームレート ∞」である状態を、+inf で表現するのはどうでしょうか。
- あまりにも低すぎるフレームレートは他の機能(入力関連など)に悪影響を及ぼす可能性があるため、目標フレームレートの下限を 1.0 fps にしたいです。
- 目標フレームレートの有効範囲を関数内部で自動的に 1.0 以上 +inf 以下にクランプすると良さそうな気がします。