Direct2D - BeginDraw()とEndDraw()

公開:2010-11-19 21:09
更新:2020-02-15 04:36
カテゴリ:windows,direct2d,c++

レンダーターゲットに対して描画を行う場合描画前にBeginDraw()・描画後にEndDraw()を呼び出さなくてはならない。これは描画がバッチ処理で行なわれるためである。 BeginDraw()でレンダーターゲットに描画開始を伝えると描画メソッドをレンダーターゲットに送ることが出来る。

描画メソッドは内部バッファに蓄えられ、EndDraw()で描画が行なわれる。処理結果はHRESULTで返る。ただし、内部バッファがいっぱいになった時・Flush()が呼ばれた時はその時点で描画が行なわれる。 EndDraw()の戻り値で重要なのはD2DERR_RECREATE_TARGETで、このエラーを受け取った場合デバイス依存リソースを再作成しなくてはならない。

BeginDraw()を呼んだらEndDraw()を必ず呼ばなければいけないので、描画中に例外が発生した時でも必ずEndDraw()を呼び出すために1年くらい前に下記クラスを作った。


template <typename T>
struct begin_draw
{
begin_draw(T& render_target)
: render_target_(render_target) ,is_end_(false)
{render_target->BeginDraw();}
HRESULT end_draw()
{
HRESULT hr = S_OK;
if(!is_end_) {
hr = render_target_->EndDraw();
is_end_ = true;
}
return hr;
};
~begin_draw(){ if(!is_end_) { render_target_->EndDraw();}}
private:
T& render_target_;
bool is_end_;
};

通常はend_draw()を呼び出してエラーチェックする。何らかの例外が発生してもデストラクタでEndDraw()を呼び出す。その際はエラーチェックは行なわれない。 というわけで今になってSTed2をDirect2D化するために使い始めたのだが、end_draw()を通常呼び出すということをすっかり忘れていて、スコープが外れデストラクタでEndDraw()を自動的に呼び出すのが通常というような使い方をしてしまっていた。EndDraw()はリソースの解放ではなく、描画を実行するというメソッドなのだから、通常処理はデストラクタでEndDraw()を呼び出してはならない。エラー処理もできないしね。

話は変わるけどEndDraw()は引数が2つあることをヘルプで発見してしまった。サンプルとかでは全然出てこなかったので知らなかったのだ。


virtual HRESULT EndDraw(
[out, optional]  D2D1_TAG *tag1 = NULL,
[out, optional]  D2D1_TAG *tag2 = NULL
) = 0;

この2つの引数にはエラーの原因となった描画操作のタグが格納されるらしい。タグ(D2D1_TAG)は64bitの符合なし整数である。しかしこのタグの中身の説明がどこにもない。。これに関連するメソッドとしてSetTags()・GetTags()があるのだけれど、ヘルプを読んでも使い方がよく解らない。なんだこれ。。