みかづきブログ・カスタム

基本的にはちょちょいのほいです。

多くの場合、requestAnimationFrameのFPSはディスプレイのリフレッシュレートに依存する 💻

結論

多くの場合、requestAnimationFrameのFPSはディスプレイのリフレッシュレートに依存します。

developer.mozilla.org

もしも、ディスプレイに依存せずにFPSの最大値を設定したい場合、

const fps = 60;
let lastRenderTime = 0;

function render(now) {
  const delta = now - lastRenderTime;

  if (1000 / fps < delta) {
    lastRenderTime = now;
    // 描画の処理
  }

  requestAnimationFrame(render);
}

とかで、フレームで行う処理を間引くなどが必要になります。

ことの発端

WebGLのWebコンテンツを制作していた際、

M1 MaxのMacBook Pro 👉 10秒に一回ぐらいフレームが飛ぶ
Core i7のMacBook Pro 👉 安定して動作する

という事象に悩んでいました。
なんでパフォーマンスが高いであろうM1 MaxがCore i7よりも安定しないのか。
そんなにGPUが貧弱なのだろうか。外部ディスプレイの枚数に制限が掛かってるし。
などと、M1の性能を疑っていたのですが、

調査の結果、requestAnimationFrameが、

M1 MaxのMacBook Pro 👉 120FPS
Core i7のMacBook Pro 👉 60FPS

を目指して動作していることが判明し、requestAnimationFrameのFPSはディスプレイのリフレッシュレートに依存するということに気づいた次第です。
これまで、60FPSを目指して動作するものと思い込んでいましたが、それは60FPSのディスプレイで動かしていたからだったようです。

Macは設定からディスプレイのリフレッシュレートを設定できますが、M1 MaxのMacBook Proは初期値がProMotionになっています。

ProMotionのままだとrequestAnimationFrameは120FPSを目指して動作するのですが、60ヘルツに変更すると60FPSを目指して動作するようになります。

ちなみに、リフレッシュレート240Hzのゲーミングモニタを拡張ディスプレイとして繋いだ時の挙動は、

M1 MaxのMacBook Pro + ゲーミングモニタ
  • MacBookのディスプレイ上で動かした場合 👉 120FPS
  • ゲーミングモニタ上で動かした場合 👉 240FPS
Core i7のMacBook Pro + ゲーミングモニタ
  • MacBookのディスプレイ上で動かした場合 👉 60FPS
  • ゲーミングモニタ上で動かした場合 👉 60FPS

となりました。

また、M1 MaxのMacBook Pro(120Hz) + ゲーミングモニタ(240Hz)の構成でミラーリングを行った場合は120FPSで動作したので、ミラーリング時はリフレッシュレートが低い方に合わせて動作する模様です。

ことの発端で作成していたWebGLのアプリケーションは、1フレームの中で実行する処理が重すぎて、120FPSに耐えきれなかったことが原因でフレームが飛んでいたようだったので、冒頭で記載した60を超えるFPSで実行されないようなロジックを追加したところ、安定して動作するようになりました。

FPS計測ページ

jsfiddle.net