VSync(垂直同期)は、GPUの各新フレームの出力をディスプレイのリフレッシュレートに同期させ、画面のティアリングを解消する技術です。Apple Metalドキュメントによると、モバイルデバイスでのスムーズなレンダリングにはVBlankとの同期が必須です。画面ティアリングは、垂直リフレッシュ中にフレームが更新されると発生し、VSyncはこの混在を防ぎます。
重要なポイント
VSync(垂直同期)は、新しいフレームを出力する前にGPUに垂直ブランキング信号(VBlank)を待機させるハードウェア・ソフトウェア機構です。VSyncがない場合、GPUはディスプレイが現在のフレームを描画中でもいつでもフレームを送信でき、水平ラインに沿って画像のティアリングが発生します。
モバイルデバイスでは、VSyncはグラフィックドライバとOSレベルで実装されています。iOSはMetalを介してVBlank同期を使用し、AndroidはSurfaceFlingerとBufferQueueを介して使用します。垂直同期が有効な場合、アプリケーションのFPSはディスプレイのリフレッシュレート(デバイスモデルに応じて60、90、120Hz)を超えることはできません。
垂直同期という用語は、電子ビームが上から下へラインごとに画像を描画するCRTモニターの動作原理に由来します。フレーム完了後、ビームは左上隅に戻ります — この瞬間を垂直ブランキングと呼びました。現代のLCDおよびOLEDディスプレイはこの用語を保持していますが、物理的には異なる動作をします。
GPUはバックバッファにフレームをレンダリングし、ディスプレイはフロントバッファから読み取ります。VSyncは、ディスプレイが現在のフレームの表示を終了して次のフレームの準備ができたとき(VBlankの瞬間)にのみバッファスワップが発生することを保証します。この仕組みはVBlank同期によるダブルバッファリングと呼ばれます。
ダブルバッファリングは2つのバッファを使用します:画面に表示されるフロントバッファと、GPUが現在のフレームを書き込むバックバッファです。フレームの準備ができると、バッファが交換されます。VSyncが有効な場合、このスワップは直近のVBlankまで延期されます。フレームがVBlankより前に準備できた場合、GPUはアイドル状態になり、パフォーマンスは低下しますがティアリングは解消されます。
// OpenGL — WGL_EXT_swap_controlによるVSync有効化
HDC hdc = wglGetCurrentDC();
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT =
reinterpret_cast<PFNWGLSWAPINTERVALEXTPROC>(
wglGetProcAddress("wglSwapIntervalEXT"));
wglSwapIntervalEXT(1); // 1 = VSync有効、0 = 無効
VBlankは、現在のフレームの最終ラインと次のフレームの最初のラインの間の短い間隔です。この間、ディスプレイはピクセルを更新せず、バッファスワップはアーティファクトなしで行われます。VBlankの持続時間はリフレッシュレートに依存します:1080pディスプレイの60Hzでは、VBlankは約1.4ms続きます。GPUがVBlank前にレンダリングを完了できない場合、フレームはスキップされ、ディスプレイは前のフレームをさらに1サイクル表示します — これはスタッターとして認識されます。
トリプルバッファリングは3つ目のバッファを追加することでGPUのアイドル問題を解決します。GPUはバックバッファの1つがVBlankを待機している場合でも、直ちに次のフレームのレンダリングを開始できます。これによりVSync使用時のFPSが向上しますが、余分なフレームの遅延が追加されます。モバイルデバイスでは、トリプルバッファリングは一部のゲームエンジンや、Mailboxモードを介してVulkanで使用されています。
VSyncを無効にすると最大FPSと最小入力遅延が得られますが、視覚的アーティファクトを代償とします。モバイルゲームやスムーズなアニメーションを伴うアプリケーションでは、VSyncとその無効化の選択は、画像の明瞭さと操作の応答性のトレードオフです。
画面ティアリングは、画面の上部が前のフレームを表示し、下部がすでに次のフレームを表示する水平方向の分割です。これはGPUがスキャンアウト中にバッファを交換するときに発生します。モバイルデバイスでは、高速スクロール時や高フレームレートの動的シーンで特に目立ちます。OLEDディスプレイは応答が瞬時であるため、LCDと比較してティアリングがより際立ちます。
ティアリングの強度はFPSとリフレッシュレートの比率に依存します。60Hzディスプレイで60FPSの場合、ティアリングは1本の静的な線として現れますが、60Hzで300FPSの場合は、上から下へ移動する複数の波状のティアリングとして現れます。FPSがリフレッシュレートに対して高いほど、ティアリングが増え、より目立つようになります。
入力遅延は、VSync使用時にボタンを押してから画面に結果が表示されるまでの遅延です。垂直同期は平均で1フレーム(60Hzで16.7ms)の遅延を追加し、トリプルバッファリングでは最大2フレーム追加します。カジュアルなアプリケーションではこの遅延は知覚できませんが、シューティング、格闘、リズムゲームでは致命的です:プロフェッショナルは8msの遅延でも認識します。
NVIDIA(2024)の調査によると、CS:GOにおけるVSyncなしの60FPSでの平均入力遅延は22ms、VSyncありでは39msです。144FPSでは、差はそれぞれ14ms対18msに縮まります。モバイルプラットフォームでは、タッチ入力のハードウェア遅延(10~30ms)が同期の追加遅延を隠蔽するため、VSyncの入力遅延はそれほど重要ではありません。
モバイル開発では、VSyncはグラフィックAPI、ゲームエンジン、OSのシステム設定を介して制御されます。iOSは制御が少なく、AndroidはVulkanとOpenGL ESを介してより多くの制御を提供します。モードの選択はアプリケーションの種類(ゲーム、UI、ビデオ)によって異なります。
UnityはQualitySettings.vSyncCount設定を使用します:0 — 無効、1 — 毎VBlankでVSync、2 — 2回目のVBlankごと(FPS半減)。Unreal Engineでは、VSyncはr.VSyncコンソールコマンドとDefaultEngine.iniを介して制御されます。モバイルビルドでは、UnityでVSyncを無効にし、カスタムFPSリミッターを使用することを推奨します。Android SurfaceFlingerの組み込みVSyncは予測不能な遅延を生じる可能性があるためです。
// Unity — VSyncとFPSの制御
void Awake()
{
// 0 = VSync無効、1 = VSync有効
QualitySettings.vSyncCount = 0;
// VSyncの代わりにカスタムFPSリミッター
Application.targetFrameRate = 60;
}
VulkanはVkSwapchainPresentInfoとpresentModeを介して完全な制御を提供します:VK_PRESENT_MODE_FIFO_KHR — クラシックVSync、VK_PRESENT_MODE_MAILBOX_KHR — 待機なしのトリプルバッファリング、VK_PRESENT_MODE_IMMEDIATE_KHR — 同期なし。MetalはiOSでCAMetalLayer.displaySyncEnabledを介してVSyncを制御します。iOS 14以降、Appleはアーケードスタイルのゲームを除くすべてのアプリケーションでデフォルトでdisplaySyncEnabled = trueを使用することを推奨しています。
| モード | 説明 | 遅延 |
|---|---|---|
| FIFO | VBlank待機ありのクラシックVSync | 1フレーム |
| Mailbox | トリプルバッファリング、古いフレームを破棄 | 1~2フレーム |
| Immediate | 同期なし、最大FPS | 0フレーム |
FPSリミッターは、VBlankを待たずにアプリケーションがプログラムでフレームレートを制限するVSyncの代替手段です。このアプローチは予測可能な遅延を提供し、ディスプレイのリフレッシュレートに依存しません。AndroidではFPS制限はChoreographerを介して実装され、iOSではCADisplayLinkを介して手動出力タイミング制御で実装されます。
従来のVSyncには根本的な欠点があります:ディスプレイの固定リフレッシュレートに拘束されることです。GPUが60Hzディスプレイで45FPSを出力する場合、VSyncは45フレームを表示できません — 30フレーム(2回目のVBlankごとにスキップ)を表示するか、不均等な間隔で60と30を交互に表示します。これによりスタッターが発生し、ティアリング以上にゲーム体験を損なうことになります。
アダプティブシンク(FreeSync、G-Sync、Apple ProMotion)は、アプリケーションのFPSに応じてディスプレイのリフレッシュレートを動的に変更することでこの問題を解決します。アプリケーションが47FPSを出力する場合、ディスプレイは47Hzに切り替わり — 各フレームはティアリングやスタッターなしで正確に1回表示されます。iOSのProMotionは24〜120Hzの周波数を自動的に選択し、滑らかさと消費電力のバランスを取ります。
モバイルデバイスでは、アダプティブシンクが標準になりつつあります:ProMotion搭載のiPad Pro(2017+)、LTPOディスプレイ搭載のAndroidフラッグシップ(Samsung Galaxy S23 Ultra、Google Pixel 8 Pro)は1〜120Hzの動的リフレッシュレートをサポートしています。開発者にとっては、従来の意味でのVSyncがシステム管理に置き換えられることを意味します — targetFrameRateを設定するだけで、OS自体が滑らかさとバッテリー持続時間の最適なバランスのためにリフレッシュレートを調整します。
よくある質問
いいえ。ダイナミックなゲーム(シューティング、格闘)では、VSyncは有意な利益なく入力遅延を増加させます — モバイルOLED画面ではディスプレイサイズが小さいためティアリングはあまり目立ちません。カジュアルゲームやUIでは、VSyncは滑らかさの知覚を向上させます。
VSyncは消費電力を削減します。GPUが不要なフレームをレンダリングしないためです。VSyncを無効にすると、GPUは最大周波数で動作し、表示されない各フレームがエネルギーを浪費し、ユーザーに利益なくデバイスを加熱します。
VSyncはフレーム出力をディスプレイのVBlankに同期しますが、FPSリミッターはアプリケーションコード内でレンダリング周波数を制限するだけです。FPSリミッターはティアリングを解消しませんが、画面のリフレッシュレートに拘束されずに予測可能な遅延を提供します。
GPUがVBlank前にフレームを完了できない場合、VBlankがスキップされ、フレームは2回のリフレッシュサイクル表示されます。60Hzでは、これにより30FPSになります。トリプルバッファリングは、GPUが待機せずに次のフレームを開始できるようにすることでこの影響を軽減します。
はい。iOS ProMotion(iPad Pro、iPhone 13 Pro+)は24〜120Hzの動的周波数をサポートしています。AndroidはLTPOパネルを介して1〜120Hzをサポートしています。開発者はこれを手動で管理する必要はありません — システムが最適な周波数を自動的に選択します。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。