Siv3D / OpenSiv3D

C++20 framework for creative coding 🎮🎨🎹 / Cross-platform support (Windows, macOS, Linux, and the Web)
https://siv3d.github.io/
MIT License
1k stars 138 forks source link

VSync無効時にフレームレートを制限する機能の提案 #1180

Open m4saka opened 8 months ago

m4saka commented 8 months ago

追加する機能の内容 | Describe the solution you'd like

過去バージョンに存在していた、下記の関数を別の実装で復活させたいと思っています。

下記の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点ご相談したいです。

  1. ユーザー側で呼び出すインタフェースは旧バージョンにあったGraphics::SetTargetFrameRateHzと同じにすべきでしょうか?それとも、より適切な名前があれば名前空間や関数名を別のものに変更しても問題ないでしょうか?
  2. フレームレート制限は旧バージョンと同様、VSyncを無効化した場合のみ効くようにした方が良いでしょうか?それとも、VSync有効のままで120Hzモニタや144Hzモニタでも60fpsに固定したいユーザーなどを想定して、VSyncが有効な場合も効くようにした方が良いでしょうか?
  3. プラットフォーム間で同一実装になる見込みです。そこで、時間待ちは旧バージョンで実装していたD3DSwapChain.cpp等ではなく、ISiv3DFrameRateLimitインタフェース、CFrameRateLimitクラスを新たに作成して実装し、System::Update内のAddonのpostPresentの直前か直後のタイミングにSIV3D_ENGINE(FrameRateLimit)->update();を入れて実行する形が良さそうですが、方針について問題なさそうでしょうか?
Reputeless commented 8 months ago

ご提案ありがとうございます。#1179 の調査完了後に検討します。

Reputeless commented 8 months ago

1179 をマージしたので、こちら進めます。

  1. Hz を外して void Graphics::SetTargetFrameRate(const Optional<double>& fps) / Optional<double> Graphics::GetTargetFrameRate() にしましょう。
  2. 既存のコードへの影響を小さくするため、VSync が無効な場合のみ有効としたいです。
  3. 新しいエンジンインタフェース FrameRateLimit の追加 OK です。その実装方針で良さそうです。
m4saka commented 8 months ago

ご確認ありがとうございます。1〜3について承知しました! 実装に進展がありましたらお知らせいたします!

m4saka commented 7 months ago

@Reputeless 下記で仮実装しました。実装内容に問題ないかご確認いただけますと幸いです! https://github.com/m4saka/OpenSiv3D/commit/da52430ef41c7aec1b624512a2f0873ee4e12602

実装にあたって気になっている点は下記2点です。

  1. 目標フレームレート(fps引数)にゼロや負の値を指定した時に例外を投げているのは問題ないか?
  2. 目標フレームレート(fps引数)にNaNや+inf、-infを指定した場合も例外を投げるべきか?

補足事項として、Qiita記事での実装ではMaxDrift(=10ミリ秒)という定数値を導入していましたが、now < sleepUntilの場合のみsleepを実行することで不要になったので、今回の実装には入っていません。

手元では現状Windows版のみで動作確認しているので、macOS版、Linux版、Web版でも正常動作するかどうかは今後確認予定です。 (Xcodeプロジェクトへのソースファイル追加についても現状は未対応です)

Reputeless commented 7 months ago

ありがとうございます。確認します、

m4saka commented 7 months ago

レビューコメントが記載できるように一旦Draft PRにいたしました。 https://github.com/Siv3D/OpenSiv3D/pull/1205

Reputeless commented 6 months ago

目標フレームレート(fps引数)にゼロや負の値を指定した時に例外を投げているのは問題ないか? 目標フレームレート(fps引数)にNaNや+inf、-infを指定した場合も例外を投げるべきか?