ID2D1CommandList
COM公式ドキュメント
記録して再生できる一連のコマンドを表します。
解説(Remarks)
コマンドリストには、記録されたコマンド群とともにリソースの静的なコピーが含まれることはありません。すべてのビットマップ、エフェクト、ジオメトリは実際のリソースへの参照として格納され、すべてのブラシは値として格納されます。リソースの作成と破棄はすべてコマンドリストの外部で行われます。次の表は、リソースがコマンドリスト内でどのように扱われるかを示しています。
| リソース | コマンドリストでの扱い |
|---|---|
| 単色ブラシ | 値渡しされます。 |
| ビットマップブラシ | ブラシは値渡しされますが、ブラシの作成に使用されるビットマップは実際には参照されます。 |
| グラデーションブラシ – 線形グラデーションと放射グラデーションの両方 | ブラシは値渡しされますが、グラデーションストップコレクション自体は参照されます。グラデーションストップコレクションオブジェクトは不変です。 |
| ビットマップ | 参照渡しされます。 |
| 描画状態ブロック | デバイスコンテキスト上の実際の状態は、変換の設定などの set 関数に変換され、値渡しされます。 |
| ジオメトリ | 値渡しされる不変オブジェクト。 |
| ストロークスタイル | 値渡しされる不変オブジェクト。 |
| メッシュ | 値渡しされる不変オブジェクト。 |
ターゲットとしてのコマンドリストの使用
次の擬似コードは、ターゲットがコマンドリストまたはビットマップのいずれかとして設定されるさまざまなケースを示しています。//create a D2D device from an already created DXGI device
ID2D1Device *pD2D1Device;
pD2D1Factory->CreateDevice(pDxgiDevice, &pD2D1Device);
//create a D2D device context from the D2D device
ID2D1DeviceContext *pD2D1DeviceContext;
pD2D1Device->CreateD2D1DeviceContext(&pD2D1DeviceContext);
//create command list
ID2D1CommandList *pCommandList1;
pD2D1DeviceContext->CreateCommandList(&pCommandList1);
//CreateBitmap
ID2D1Bitmap *pBitmap1;
ID2D1Bitmap *pBitmap2;
pD2D1DeviceContext->CreateBitmap(…, &pBitmap1);
pD2D1DeviceContext->CreateBitmap(…, &pBitmap2);
//Set the bitmap as the target
pD2D1DeviceContext->SetTarget(pBitmap1);
pD2D1DeviceContext->BeginDraw();
RenderMyVectorContent(pD2D1DeviceContext);
pD2D1DeviceContext->EndDraw();
//Set the command list as the target
pD2D1DeviceContext->SetTarget(pCommandList1);
pD2D1DeviceContext->BeginDraw();
RenderMyVectorContent(pD2D1DeviceContext);
pD2D1DeviceContext->EndDraw();
//Drawing a command list to a bitmap target
pD2D1DeviceContext->SetTarget(pBitmap2);
pD2D1DeviceContext->BeginDraw();
pD2D1DeviceContext->DrawImage(pCommandList1);
pD2D1DeviceContext->EndDraw();
- ビットマップをターゲットとして設定する:この場合、ビットマップにレンダリングされたすべての内容はラスタライズされます。このビットマップが他の場所で使用される場合、解像度非依存にはならず、High Quality Scale のような変換が使用されると、忠実度は維持されません。
- コマンドリストをターゲットとして設定する:この場合、シーンがラスタライズされる代わりに、すべてのコマンドが記録されます。後でコマンドリストが ID2D1DeviceContext::DrawImage を使用した画面描画に使用されたり、XPS 印刷コントロールに渡されたりすると、ベクターコンテンツは忠実度を損なうことなく再生されます。
- コマンドリストをビットマップターゲットに描画する:この場合、ターゲットがビットマップであるため、コマンドリストはビットマップに描画され、解像度非依存ではなくなります。
ブラシを作成するためのコマンドリストの使用
コマンドリストは再生時に忠実度を保持できるため、パターンブラシをサポートするのに適した方法です。目的のパターンをコマンドリストとして格納し、それを使用してイメージブラシを作成できます。このブラシを使ってパスを塗りつぶすことができます。コマンドリストでパスを塗りつぶすことをサポートするブラシの種類は、イメージブラシと呼ばれます。
次の擬似コードは、イメージブラシでコマンドリストを使用するプロセスを示しています。
//Draw the pattern to the command list
ID2D1CommandList *pCommandList;
pD2D1DeviceContext->SetTarget(pCommandList);
pD2D1DeviceContext->BeginDraw();
DrawMyPattern(pD2D1DeviceContext);
pD2D1DeviceContext->EndDraw();
//Create the image brush from the command list
ID2D1ImageBrush *pImageBrush;
pD2D1DeviceContext->CreateImageBrush(
pCommandList,
pImageBrushProperties,
pBrushProperties,
&pImageBrush);
//Fill the ellipse with the pattern brush
pD2D1DeviceContext->SetTarget(pTargetBitmap);
pD2D1DeviceContext->BeginDraw();
pD2D1DeviceContext->FillEllipse(pEllipse, pImageBrush);
pD2D1DeviceContext->EndDraw();
ブラシはイメージを受け入れるため、次のようなその他の利点もあります。
- エフェクトグラフの出力はイメージであるため、このイメージを使用してイメージブラシを作成でき、実質的にエフェクトを塗りつぶしとして使用する機能を提供します。
- コマンドリストはイメージの一種であるため、ベクターコンテンツをエフェクトグラフに挿入したり、タイル状に並べたり、操作したりできます。たとえば、大きな著作権表示を、仮想化されたイメージを含むグラフの上に挿入してからエンコードできます。
互換レンダーターゲットの代替としてのコマンドリストの使用
互換レンダーターゲットは、後で実際のシーンと合成される中間ビットマップへのオフスクリーンレンダリングに非常によく使用されます。特に印刷の場合、実際のプリミティブを保持する代わりにすべてがラスタライズされて XPS に送られるため、互換レンダーターゲットを使用するとメモリ使用量が増加します。このシナリオでは、開発者は互換レンダーターゲットを中間コマンドリストに置き換える方がよいでしょう。 次の擬似コードはこの点を示しています。pD2D1Device->CreateDeviceContext(&pD2D1DeviceContext);
pRenderTarget->CreateCompatibleRenderTarget(…, &pCompatibleRenderTarget);
//render to the compatible render target
pCompatibleRenderTarget->BeginDraw();
RenderMyScene1(pCompatibleRenderTarget);
pCompatibleRenderTarget->EndDraw();
//get the bitmap from the compatible render target
pCompatibleRenderTarget->GetBitmap(pCompatBitmap);
//draw this bitmap on the device context
pD2D1DeviceContext->SetTarget(pTargetBitmap)
pD2D1DeviceContext->BeginDraw();
pD2D1DeviceContext->DrawBitmap(pCompatBitmap);
pD2D1DeviceContext->EndDraw();
//draw something else on the compatible render target
pCompatibleRenderTarget->BeginDraw();
pCompatibleRenderTarget->Clear();
pCompatibleRenderTarget->RenderScene2();
pCompatibleRenderTarget->EndDraw();
//get the bitmap from the compatible render target
pCompatibleRenderTarget->GetBitmap(pCompatBitmap);
//draw this bitmap on the device context
pD2D1DeviceContext->SetTarget(pTargetBitmap)
pD2D1DeviceContext->BeginDraw();
pD2D1DeviceContext->DrawBitmap(pCompatBitmap);
pD2D1DeviceContext->EndDraw();
//Use a command list instead for better quality and performance
//store the original target
pOriginalTarget = pD2D1DeviceContext->GetTarget();
pD2D1DeviceContext->CreateCommandList(pCommandList1);
//draw to command list 1
pD2D1DeviceContext->SetTarget(pCommandList1);
pD2D1DeviceContext->BeginDraw();
RenderMyScene1(pD2D1DeviceContext);
pD2D1DeviceContext->EndDraw();
//draw the command list to the original target
pD2D1DeviceContext->SetTarget(pOriginalTarget);
pD2D1DeviceContext->BeginDraw();
pD2D1DeviceContext->DrawImage(pCommandList1);
pD2D1DeviceContext->EndDraw();
pD2D1DeviceContext->CreateCommandList(pCommandList2);
//draw something else to a new command list
pD2D1DeviceContext->SetTarget(pCommandList2);
pD2D1DeviceContext->BeginDraw();
pD2D1DeviceContext->RenderScene2();
pD2D1DeviceContext->EndDraw();
//draw the new command list on the old command list
pD2D1DeviceContext->SetTarget(pCommandList1);
pD2D1DeviceContext->BeginDraw();
pD2D1DeviceContext->DrawImage(pCommandList2);
pD2D1DeviceContext->EndDraw();
他の API との連携
Direct2D は、GDI および Direct3D/DXGI API と相互運用する際にシンプルなモデルを採用しています。コマンドリストはこれらのコマンドを記録しません。その代わりに、その場で内容をラスタライズし、ID2D1Bitmap として格納します。内容がラスタライズされるため、これらの相互運用ポイントは高い忠実度を維持しません。GDI: コマンドシンクインターフェイスは Get/ReleaseDC() の呼び出しをサポートしません。ID2D1GdiInteropRenderTarget::ReleaseDC の呼び出しが行われると、Direct2D は更新された領域の内容を D2D1Bitmap にレンダリングします。これは、コピー合成モードでのエイリアス化された DrawBitmap の呼び出しとして再生されます。 コマンドの再生時にビットマップを正しい DPI でラスタライズするために、その時点で SetDPI() 関数を使用して設定されている DPI 値が使用されます。これは、シンクが SetDPI() の呼び出しを尊重する唯一のケースです。
DX: Direct3D はコマンドリストに直接レンダリングできません。この場合に Direct3D コンテンツをレンダリングするには、アプリケーションは Direct3D サーフェスに基づく ID2D1Bitmap を指定して DrawBitmap を呼び出すことができます。
メソッド 2
vtbl = vtable インデックス(0始まり)。HSP等からCOMメソッドをインデックス指定で呼ぶ際に使用します。0〜2 は IUnknown。
コマンドリストの内容を、指定されたコマンドシンクにストリーミングします。
| sink | ID2D1CommandSink* | in | コマンドリストのストリーミング先となるシンク。 |
戻り値
型: HRESULT
メソッドが成功した場合は S_OK を返します。失敗した場合は HRESULT エラーコードを返します。
戻り値は、コマンドシンクの実装がその EndDraw メソッドを通じて返すあらゆる失敗を示します。
解説(Remarks)
コマンドシンクは、API の任意の呼び出し元によって実装できます。
コマンドリストがターゲットとして選択されている間に、呼び出し元がデザイン時に失敗する呼び出しを行うと、コマンドリストはエラー状態になります。stream の呼び出しは、渡されたシンクを一切呼び出すことなく失敗します。
使用例:
Class MyCommandSink : public ID2D1CommandSink
{
public:
// All of the ID2D1CommandSink methods implemented here.
};
HRESULT
StreamToMyCommandSink(
__in ID2D1CommandList *pCommandList
)
{
HRESULT hr = S_OK;
MyCommandSink *pCommandSink = new MyCommandSink();
hr = pCommandSink ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
// Receive the contents of the command sink streamed to the sink.
hr = pCommandList->Stream(pCommandSink);
}
SafeRelease(&pCommandSink);
return hr;
}
コマンドリストにコマンドの受け付けを停止するよう指示します。これにより、コマンドリストをエフェクトへの入力として、または ID2D1DeviceContext::DrawImage の呼び出しで使用できるようになります。
戻り値
型: HRESULT
このメソッドは HRESULT を返します。取り得る値には、次の表に示すものが含まれますが、これらに限定されません。
| HRESULT | 説明 |
|---|---|
| S_OK | エラーは発生しませんでした。 |
| D2DERR_WRONG_STATE | コマンドリストで Close が既に呼び出されています。 |
解説(Remarks)
このメソッドは、コマンドリストで既に呼び出されている場合は D2DERR_WRONG_STATE を返します。設定中にデバイスコンテキストでエラーが発生した場合は、そのエラーを返します。それ以外の場合は S_OK を返します。
Close メソッドがエラーを返した場合、それ以降のコマンドリストの使用はすべて同じエラーになります。
Microsoft 公式リファレンス: 英語 (en-us) · 日本語 (ja-jp) · 原文ソース (GitHub)
HSP用 COM定義
#usecom / #comfunc によるHSPのCOM呼び出し定義。数字は vtbl インデックス(0始まり)。クラスIDが無い場合 #usecom の末尾は "{}"、ある場合は "{CLSID}"。
#define global IID_ID2D1CommandList "{B4F34A19-2383-4D76-94F6-EC343657C3DC}"
#usecom global ID2D1CommandList IID_ID2D1CommandList "{}"
#comfunc global ID2D1CommandList_Stream 4 sptr
#comfunc global ID2D1CommandList_Close 5
; ※数字は vtbl インデックス(0始まり)。0/1/2 は IUnknown(QueryInterface/AddRef/Release)。
; ※このインターフェースは直接 CoCreateInstance するクラスIDが無いため "{}"(他メソッド/アクティベーションで取得)。
; ※ハンドル/void*等の不透明ポインタは IronHSP では intptr 指定が可能。