DirectXで、フルスクリーン描画をする際のディスプレイのリフレッシュレートについてです。
最近のPC向けディスプレイ
近年のPC向けディスプレイは、さまざまな垂直同期周波数を持っているケースがあります。具体的には、60Hzのほかに、120Hzや、144Hzなどです。
これ等のリフレッシュレートは、垂直同期を有効にした場合でも、60Hzのディスプレイに比べ、高頻度に画面を書き換える機会を有しています。また、垂直同期を無効にした場合でも、同様に、高頻度に画面を書き換える機会を有しているため、ティアリングによる不快感を軽減(分断された絵の差分を最小限に)できる可能性があります。
ゲーム製作者側の留意点
ゲーム製作者側が留意しなくてはならないのは、当然ながら、垂直同期:有効=60Hzという前提でゲームを製作しないということです。これに関しては、殆どのPC向けのゲームでは、フレーム間の時間間隔は可変となっているので、問題になることは無いと思います。また、垂直同期を無効にしたケースではプログラム側は特に留意することは無いように思えます。
ただし一点だけ気をつけたほうが良いことがあります。それは、フルスクリーン描画を行う際の、RefreshRateの設定値です。デバイス作成時に設定するRefreshRateは、そのままディスプレイの垂直同期周波数として設定され、D3DPRESENT_INTERVALがどのように設定されても、その値が使用されます。
つまり、120Hzの垂直同期周波数をサポートするディスプレイでは、60Hz/120Hzいずれにも設定して、垂直同期を無効にしてフルスクリーン描画を行うことができます。その際に観測されるFPSは、基本的には全く差が無い状態となりますが、ディスプレイの駆動周波数は異なるため、プレイヤーの体験としては違うものになってしまいます。
では、どうすれば良いかですが、現在のディスプレイのRefreshRateを取得し、同一のRefreshRateで使用可能なスクリーン解像度を使用すると良いと思います。また、ゲーム内のメニューから明示的に設定できるようにしても良いと思います。
初期化の例
以下の例では、現在設定されているRefreshRateを尊重しつつ、19×10解像度のフルスクリーン描画の初期化を行うコードです。解像度が存在しない場合の処理などは省略されています。
if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) ) return E_FAIL; D3DDISPLAYMODE curDM; g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &curDM); D3DDISPLAYMODE targetDM; UINT targetRes[2] = {1920, 1080}; ZeroMemory(&targetDM, sizeof(targetDM)); // check if there is 19x10 resolution with current refresh rate and color depth. UINT cnt = g_pD3D->GetAdapterModeCount(D3DADAPTER_DEFAULT, curDM.Format); for (UINT i=0; iEnumAdapterModes(D3DADAPTER_DEFAULT, curDM.Format, i, &dm); if (curDM.Format == dm.Format && curDM.RefreshRate == dm.RefreshRate && targetRes[0] == dm.Width && targetRes[1] == dm.Height) { targetDM = dm; break; } } // you'll need proper handler... if (targetDM.Width != targetRes[0]) return E_FAIL; static D3DPRESENT_PARAMETERS d3dpp = { targetDM.Width, targetDM.Height, targetDM.Format, 2, D3DMULTISAMPLE_NONE, 0, D3DSWAPEFFECT_DISCARD, hWnd, 0, //Full screen 0, D3DFMT_UNKNOWN, 0, targetDM.RefreshRate, // set the refresh rate that have been set. //D3DPRESENT_INTERVAL_ONE // enable v-sync D3DPRESENT_INTERVAL_IMMEDIATE // disable v-sync }; // create a device. if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice ) ) )