Direct3D12でG-SYNC Compatibleを試す
前回までに、フルスクリーンモードで自由にリフレッシュレートを変更できるようになりましたので、 今回は、可変リフレッシュレートの動作を確認したいと思います。
私が使っているディスプレイは2台ありまして、1台は最近買ったこのディスプレイです。
Dell AW2724DM 27インチ Alienware ゲーミングモニター
- NVIDIA G-SYNC Compatible
- AMD FreeSync Premium Pro
- VESA AdaptiveSync
に対応していると書いています。
もう一台は、iiyamaの28インチディスプレイです。 こちらは古いものなので、可変リフレッシュレートには対応していません。
まず、ディスプレイのリフレッシュレートとは何かといいますと、60Hzと書かれていたら、1秒間に60回画像を表示することを意味します。 どうやって画像を表示しているかというと、左上から1ラインずつ画像データを走査して、液晶や有機ELなどの画素を光らせています。 その1枚の画像を表示することを1/60秒に1回の間隔で繰り返しています。
では、可変リフレッシュレートは何かというと、この1/60秒の間隔をずらして、例えば、1/30秒から1/60秒の可変の間隔で 画面を表示する機能になります。
何のためにあるのかというと、例えば、60fpsのゲームの場合、1フレームの処理が重たい場合に、1/60秒で処理が終わらないことがあります(処理落ちといいます)。 60HzのリフレッシュレートでVSync待ちが有効なダブルバッファの場合、1ms処理がオーバーするだけで次のVSyncのタイミングまで待たされることで、半分の30fpsに フレームレートが落ちてしまいます。
可変リフレッシュレートは、このような処理落ちのときに、画面を表示するタイミングをずらすことで、フレームレートの低下を軽減することができます。 例えば、先ほどの1msオーバーしただけなら、画面の表示が、60fps(16.6ms)から56fps(17.6ms)に変わるだけで済むことになります。
処理落ちしないゲームには効果はありませんが、処理落ちに悩まされているゲームプログラマーから見るととても魅力的な機能だと思います。
では、Direct3D12での確認方法です。
特に何も設定しなくても可変リフレッシュレートの機能は動いているようですので、最近動かしている三角形を1つだけ表示するアプリを処理落ちさせて確認したいと思います。
まず、処理落ちさせるために、三角形の描画にforループを追加します。
for (int i = 0; i < mTestLoop ; ++i)
{
commandList->DrawInstanced(3, 1, 0, 0);
}
これを、imguiのUIでループの回数を変更できるようにします。
static int loop_index = -1;
const char* loop_data[] = {"1", "100", "1000", "2000", "3000", "4000", "5000", "6000", "7000", "8000", "9000","10000", "50000"};
if (ImGui::Combo("LoopMode", &loop_index, loop_data, _countof(loop_data)))
{
if (loop_index > 0) {
mTestLoop = atoi(loop_data[loop_index]);
}
}
これでアプリを以下の条件で動かします。
- ダブルバッファ、VSync待ち有効
- フルスクリーン
ループ回数を変えて処理負荷を高くしながら、fpsを確認しました。結果は以下の通り。
- 可変リフレッシュレート対応のディスプレイ
- fpsの変化 : 60fps → 50fps → 40fps → 30fps
- 可変リフレッシュレート非対応のディスプレイ
- fpsの変化 : 60fps → 30fps → 30fps → 30fps
可変リフレッシュレートが動いていることが確認できました。
最後に、可変リフレッシュレートの仕組みを書いておくと、表示する画像に変化がない場合に、画面を表示する走査の処理が開始待ちとなります。 例えば、60Hzの場合、画像が更新されている場合には、1/60秒間隔で走査が開始されるのですが、 画面が更新されていない場合には、1/30秒後まで画像が更新されるのを待っています。 画像が更新されると、その直後から走査が開始されます。画像の更新がない場合にも、1/30秒後には走査が開始されます。 そのようにすることで、30-60Hzの可変リフレッシュレートで画像を表示することができます。