蓬莱の備忘録

VRとか画像処理とか

【Direct2D】規定値でパラメータを初期化したら垂直同期に合わせられて困った話

はじめに

OpenCVで画像処理をした結果をDirect2Dで描画しようとプログラムを作ってみたら予想以上にフレームレートが落ちていたので,それについて記事にしてみました.

実装と計測

HWNDを対象とするレンダーターゲットであるID2D1HwndRenderTargetインターフェースに関しては,以下の通りに生成しました.

D2D1_SIZE_U PixelSize = { rect.Width(), rect.Height() };
D2D1_RENDER_TARGET_PROPERTIES RenderTargetProperties = D2D1::RenderTargetProperties();
D2D1_HWND_RENDER_TARGET_PROPERTIES HwndRenderTargetProperties = D2D1::HwndRenderTargetProperties(m_hWindow, PixelSize);
HRESULT hr= m_pD2d1Factory->CreateHwndRenderTarget(
		RenderTargetProperties,
		HwndRenderTargetProperties,
		&m_pRenderTarget);

また,今回は処理が無事に実行されることを確認するだけだったので,ウィンドウの背景をクリアするのみとなっています.

/* 開始 */
m_pRenderTarget->BeginDraw();
/* 背景のクリア */
m_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::Blue));
/* 終了 */
m_pRenderTarget->EndDraw();

処理自体は非常にシンプルであり,レンダリングの開始・背景のクリア・終了しかしていません.
しかし,このコードで処理を実行した結果,約60fpsしか出ませんでした...

フレームレートが重くなった原因

ID2D1HwndRenderTarget インターフェイスインスタンスを生成する上で,CreateHwndRenderTarget() 関数を使っていました.
このメソッドの第1・第2パラメータには,それぞれ適切に初期化されたD2D1_RENDER_TARGET_PROPERTIES 構造体,D2D1_HWND_RENDER_TARGET_PROPERTIES 構造体が必要となります.
しかし,先のプログラムでは初期化を簡単にするため,以下の関数を使用していました.

RenderTargetProperties(
        D2D1_RENDER_TARGET_TYPE type =  D2D1_RENDER_TARGET_TYPE_DEFAULT,
        _In_ CONST D2D1_PIXEL_FORMAT &pixelFormat = D2D1::PixelFormat(),
        FLOAT dpiX = 0.0,
        FLOAT dpiY = 0.0,
        D2D1_RENDER_TARGET_USAGE usage = D2D1_RENDER_TARGET_USAGE_NONE,
        D2D1_FEATURE_LEVEL  minLevel = D2D1_FEATURE_LEVEL_DEFAULT
        )
HwndRenderTargetProperties(
        _In_ HWND hwnd,
        _In_ D2D1_SIZE_U pixelSize = D2D1::Size(static_cast<UINT32>(0), static_cast<UINT32>(0)),
        _In_ D2D1_PRESENT_OPTIONS presentOptions = D2D1_PRESENT_OPTIONS_NONE
        )

このうち,HwndRenderTargetProperties() 関数の第3パラメータに指定するD2D1_PRESENT_OPTIONSがフレームレートを下げていた原因でした.このパラメータは規定値だと,レンダリングをディスプレイのリフレッシュレートに合わせる(垂直同期)ようです.
...うん,綺麗に60fpsなんて数字になったのでなんかおかしいとは思ったんですけど,パラメータの指定をさぼった自分のミスでしたね(-_-;)
このパラメータをD2D1_PRESENT_OPTIONS_IMMEDIATELY メンバに設定すれば垂直同期をしなくなるようなので,処理の実行速度なんかを計測したい場合はこのパラメータを設定するといいでしょう.

おわりに

元々は,OpenCVで画像処理をした結果をリアルタイムで表示するプログラムを作っていたんですが,OpenCVの機能でウィンドウに表示しようとしたらフレームレートがかなり落ちてしまったので,描画部分の処理をDirectXで実装しようとしていました.
その辺りについては,今作っているプログラムがひと段落したらまた記事にしたいと思います.