Share via


Direct2D アプリのパフォーマンスの向上

Direct2D はハードウェア アクセラレータであり、高パフォーマンスを目的としていますが、スループットを最大化するには、機能を正しく使用する必要があります。 ここで示す手法は、一般的なシナリオの調査から派生しており、すべてのアプリ シナリオには適用されない場合があります。 そのため、アプリの動作とパフォーマンスの目標を慎重に理解することは、必要な結果を達成するのに役立ちます。

リソースの使用状況

リソースは、ビデオまたはシステム メモリ内の何らかの種類の割り当てです。 ビットマップとブラシは、リソースの例です。

Direct2D では、ソフトウェアとハードウェアの両方でリソースを作成できます。 ハードウェアでのリソースの作成と削除は、ビデオ カードとの通信に多くのオーバーヘッドが必要になるため、コストの高い操作です。 Direct2D がコンテンツをターゲットにレンダリングする方法を見てみましょう。

Direct2D では、すべてのレンダリング コマンドが BeginDraw の呼び出しと EndDraw の呼び出しの間で囲まれます。 これらの呼び出しは、レンダー ターゲットに対して行われます。 レンダリング操作 を呼び出す前に、 BeginDraw メソッドを呼び出す必要があります。 BeginDraw を呼び出した後、コンテキストは通常、レンダリング コマンドのバッチを構築しますが、これらのステートメントのいずれかが true になるまで、これらのコマンドの処理を遅延させます。

  • EndDraw が発生しました。 EndDraw が呼び出されると、バッチ描画操作が完了し、操作の状態が返されます。
  • Flush: Flush メソッドを明示的に呼び出すと、バッチが処理され、保留中のすべてのコマンドが発行されます。
  • レンダリング コマンドを保持しているバッファーがいっぱいです。 前の 2 つの条件が満たされる前にこのバッファーがいっぱいになると、レンダリング コマンドがフラッシュされます。

プリミティブがフラッシュされるまで、Direct2D はビットマップやブラシなどの対応するリソースへの内部参照を保持します。

リソースの再利用

既に説明したように、リソースの作成と削除はハードウェア上でコストがかかります。 そのため、可能な場合はリソースを再利用します。 ゲーム開発でのビットマップ作成の例を見てみましょう。 通常、ゲーム内のシーンを構成するビットマップはすべて同時に作成され、後でフレーム間レンダリングに必要なすべてのバリエーションが必要になります。 実際のシーン レンダリングと再レンダリングの時点で、これらのビットマップは再作成される代わりに再利用されます。

注意

ウィンドウサイズ変更操作のリソースを再利用することはできません。 ウィンドウのサイズを変更すると、互換性のあるレンダー ターゲットや場合によっては、ウィンドウのコンテンツを再描画する必要があるため、一部のレイヤー リソースなどのスケールに依存するリソースを再作成する必要があります。 これは、レンダリングされたシーンの全体的な品質を維持するために重要な場合があります。

 

フラッシュの使用を制限する

Flush メソッドを使用すると、バッチ レンダリング コマンドが処理されるため、使用しないことをお勧めします。 最も一般的なシナリオでは、リソース管理は Direct2D のままにします。

ビットマップ

前述のように、リソースの作成と削除は、ハードウェアでの非常にコストの高い操作です。 ビットマップは、頻繁に使用されるリソースの一種です。 ビデオ カードでビットマップを作成するのはコストがかかります。 これらを再利用すると、アプリケーションの高速化に役立ちます。

大きなビットマップを作成する

通常、ビデオ カードには最小メモリ割り当てサイズがあります。 これより小さい割り当てが要求された場合、この最小サイズのリソースが割り当てられ、余分なメモリが無駄になり、他のものでは使用できなくなります。 多くの小さなビットマップが必要な場合は、1 つの大きなビットマップを割り当てて、小さなビットマップの内容をすべてこの大きなビットマップに格納することをお勧めします。 次に、小さいビットマップが必要な場所で、大きなビットマップのサブエリアを読み取ることができます。 多くの場合、操作中に小さいイメージ間の相互作用を回避するために、小さなビットマップの間にパディング (透明な黒ピクセル) を含める必要があります。 これは アトラスとも呼ばれ、ビットマップ作成のオーバーヘッドを減らし、小さなビットマップ割り当てのメモリ無駄を減らすという利点があります。 ほとんどのビットマップは少なくとも 64 KB に保ち、4 KB 未満のビットマップの数を制限することをお勧めします。

ビットマップのアトラスを作成する

ビットマップ アトラスが非常に適切に機能する一般的なシナリオがいくつかあります。 小さなビットマップは、大きなビットマップ内に格納できます。 これらの小さなビットマップは、目的の四角形を指定することで、必要に応じて大きなビットマップから引き出すことができます。 たとえば、アプリケーションでは複数のアイコンを描画する必要があります。 アイコンに関連付けられているすべてのビットマップは、大きなビットマップに前面に読み込むことができます。 また、レンダリング時に、大きなビットマップから取得できます。

注意

ビデオ メモリで作成された Direct2D ビットマップは、それが格納されているアダプターでサポートされている最大ビットマップ サイズに制限されます。 より大きいビットマップを作成すると、エラーが発生する可能性があります。

 

注意

Windows 8以降、Direct2D には、このプロセスを容易にする Atlas 効果が含まれています。

 

共有ビットマップを作成する

共有ビットマップを作成すると、高度な呼び出し元は、レンダー ターゲットと互換性のある既存のオブジェクトによって直接サポートされる Direct2D ビットマップ オブジェクトを作成できます。 これにより、複数のサーフェスを作成する必要がなくなり、パフォーマンスのオーバーヘッドを軽減できます。

注意

共有ビットマップは通常、ソフトウェア ターゲットまたは DXGI と相互運用可能なターゲットに制限されます。 共有ビットマップを作成するには、 CreateBitmapFromDxgiSurfaceCreateBitmapFromWicBitmap、および CreateSharedBitmap メソッドを使用します。

 

ビットマップのコピー

DXGI サーフェスの作成はコストの高い操作であるため、可能な場合は既存のサーフェスを再利用します。 ソフトウェアでも、ビットマップが主に小さな部分を除いて必要な形式である場合は、ビットマップ全体を投げ捨ててすべてを再作成するよりも、その部分を更新することをお勧めします。 CreateCompatibleRenderTarget を使用して同じ結果を得ることができますが、通常、レンダリングはコピーよりもはるかにコストの高い操作です。 これは、キャッシュの局所性を向上させるために、ハードウェアはビットマップがアドレス指定されたのと同じメモリ順序でビットマップを実際に格納しないためです。 代わりに、ビットマップがスウィズルされる可能性があります。 スウィズルは、ドライバー (低速で下端部分でのみ使用される) または GPU 上のメモリ マネージャーによって、CPU から非表示になります。 レンダリング時にデータをレンダー ターゲットに書き込む方法に制約があるため、通常、レンダー ターゲットはスウィズルされないか、サーフェスにレンダリングする必要がないことがわかっている場合よりも最適ではない方法でスウィズルされます。 したがって、 CopyFrom* メソッドは、ソースから Direct2D ビットマップに四角形をコピーするために提供されます。

CopyFrom は、次の 3 つの形式のいずれかで使用できます。

ダッシュの上にタイルビットマップを使用する

破線のレンダリングは、基になるアルゴリズムの品質と精度が高いため、非常に高価な操作です。 直線ジオメトリを含まないほとんどの場合、タイルビットマップを使用すると、同じ効果をより速く生成できます。

複雑な静的コンテンツをレンダリングするための一般的なガイドライン

フレーム上に同じコンテンツ フレームをレンダリングする場合 (特にシーンが複雑な場合)、コンテンツをキャッシュします。

次の 3 つのキャッシュ手法を使用できます。

  • カラー ビットマップを使用した完全なシーン キャッシュ。
  • A8 ビットマップと FillOpacityMask メソッドを使用したプリミティブ キャッシュごと。
  • ジオメトリの実現を使用したプリミティブごとのキャッシュ。

これらのそれぞれについて詳しく見てみましょう。

カラー ビットマップを使用した完全なシーン キャッシュ

静的コンテンツをレンダリングする場合、アニメーションなどのシナリオでは、画面ビットマップに直接書き込むのではなく、別のフル カラー ビットマップを作成します。 現在のターゲットを保存し、ターゲットを中間ビットマップに設定し、静的コンテンツをレンダリングします。 次に、元の画面ビットマップに戻り、中間ビットマップを描画します。

次に例を示します。

// Create a bitmap.
m_d2dContext->CreateBitmap(size, nullptr, 0,
    D2D1::BitmapProperties(
        D2D1_BITMAP_OPTIONS_TARGET,
        D2D1::PixelFormat(
            DXGI_FORMAT_B8G8R8A8_UNORM,
            D2D1_ALPHA_MODE_PREMULTIPLIED),
        dpiX, dpiY),
    &sceneBitmap);

// Preserve the pre-existing target.
ComPtr<ID2D1Image> oldTarget;
m_d2dContext->GetTarget(&oldTarget);

// Render static content to the sceneBitmap.
m_d2dContext->SetTarget(sceneBitmap.Get());
m_d2dContext->BeginDraw();
…
m_d2dContext->EndDraw();

// Render sceneBitmap to oldTarget.
m_d2dContext->SetTarget(oldTarget.Get());
m_d2dContext->DrawBitmap(sceneBitmap.Get());

この例では、中間ビットマップをキャッシュに使用し、レンダリング時にデバイス コンテキストが指すビットマップを切り替えます。 これにより、同じ目的で互換性のあるレンダー ターゲットを作成する必要がなくなります。

A8 ビットマップと FillOpacityMask メソッドを使用したプリミティブ キャッシュごと

シーン全体が静的ではなく、ジオメトリや静的なテキストなどの要素で構成されている場合は、プリミティブごとのキャッシュ手法を使用できます。 この手法は、キャッシュされるプリミティブのアンチエイリアシング特性を保持し、ブラシの種類の変更に対応します。 A8 は、8 ビットのアルファ チャネルを表すピクセル形式の一種である A8 ビットマップを使用します。 A8 ビットマップは、ジオメトリ/テキストをマスクとして描画する場合に便利です。 コンテンツ自体を操作する代わりに、静的コンテンツの不透明度を操作する必要がある場合は、マスクの不透明度を翻訳、回転、傾斜、またはスケーリングできます。

次に例を示します。

// Create an opacity bitmap.
m_d2dContext->CreateBitmap(size, nullptr, 0,
    D2D1::BitmapProperties(
        D2D1_BITMAP_OPTIONS_TARGET,
        D2D1::PixelFormat(
            DXGI_FORMAT_A8_UNORM,
            D2D1_ALPHA_MODE_PREMULTIPLIED),
        dpiX, dpiY),
    &opacityBitmap);

// Preserve the pre-existing target.
ComPtr<ID2D1Image> oldTarget;
m_d2dContext->GetTarget(&oldTarget);

// Render to the opacityBitmap.
m_d2dContext->SetTarget(opacityBitmap.Get());
m_d2dContext->BeginDraw();
…
m_d2dContext->EndDraw();

// Call the FillOpacityMask method
// Note: for this call to work correctly the anti alias mode must be D2D1_ANTIALIAS_MODE_ALIASED. 
m_d2dContext->SetTarget(oldTarget.Get());
m_d2dContext->FillOpacityMask(
    opacityBitmap.Get(),
    m_contentBrush().Get(),
    D2D1_OPACITY_MASK_CONTENT_GRAPHICS);

ジオメトリの実現を使用したプリミティブごとのキャッシュ

もう 1 つのプリミティブごとのキャッシュ手法は、ジオメトリの実現と呼ばれ、ジオメトリを処理する際の柔軟性を高めます。 エイリアス化またはアンチエイリアシングされたジオメトリを繰り返し描画する場合は、ジオメトリ自体を繰り返し描画するよりも、ジオメトリの実現に変換し、実現を繰り返し描画する方が高速です。 また、ジオメトリの実現では、通常、不透明度マスク (特に大きなジオメトリの場合) よりもメモリ消費量が少なく、スケールの変更に対する影響も少なくなります。 詳細については、「 ジオメトリの実現の概要」を参照してください。

次に例を示します。

    // Compute a flattening tolerance based on the scales at which the realization will be used.
    float flatteningTolerance = D2D1::ComputeFlatteningTolerance(...);

    ComPtr<ID2D1GeometryRealization> geometryRealization;

    // Create realization of the filled interior of the geometry.
    m_d2dDeviceContext1->CreateFilledGeometryRealization(
        geometry.Get(),
        flatteningTolerance,
        &geometryRealization
        );

    // In your app's rendering code, draw the geometry realization with a brush.
    m_d2dDeviceContext1->BeginDraw();
    m_d2dDeviceContext1->DrawGeometryRealization(
        geometryRealization.Get(),
        m_brush.Get()
        );
    m_d2dDeviceContext1->EndDraw();

Geometry レンダリング

描画ジオメトリに対して特定の描画プリミティブを使用する

DrawGeometry の汎用呼び出しに対して DrawRectangle などのより具体的な描画プリミティブ呼び出しを使用します。 これは、 DrawRectangle ではジオメトリが既に認識されているため、レンダリングが高速になるためです。

静的ジオメトリのレンダリング

ジオメトリが静的なシナリオでは、上記で説明したプリミティブごとのキャッシュ手法を使用します。 不透明度マスクとジオメトリの実現により、静的ジオメトリを含むシーンのレンダリング速度が大幅に向上します。

マルチスレッド デバイス コンテキストを使用する

大量の複雑な幾何学的コンテンツをレンダリングすることを想定しているアプリケーションでは、Direct2D デバイス コンテキストを作成するときにD2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTI_THREADED_OPTIMIZATIONS フラグを指定することを検討する必要があります。 このフラグを指定すると、Direct2D はシステム上にあるすべての論理コアにレンダリングを分散させます。これにより、レンダリング時間全体が大幅に短縮される可能性があります。

メモ:

  • Windows 8.1の時点では、このフラグはパス ジオメトリのレンダリングにのみ影響します。 他のプリミティブ型 (テキスト、ビットマップ、ジオメトリの実現など) のみを含むシーンには影響しません。
  • このフラグは、ソフトウェアでレンダリングする場合 (つまり、WARP Direct3D デバイスを使用してレンダリングする場合) にも影響しません。 ソフトウェア マルチスレッドを制御するには、WARP Direct3D デバイスを作成するときに、呼び出し元が D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS フラグを使用する必要があります。
  • このフラグを指定すると、レンダリング中にピークワーキングセットが増加し、マルチスレッド処理を既に利用しているアプリケーションのスレッド競合が増加する可能性があります。

Direct2D を使用したテキストの描画

Direct2D テキスト レンダリング機能は、2 つの部分で提供されます。 ID2D1RenderTarget::D rawText メソッドおよび ID2D1RenderTarget::D rawTextLayout メソッドとして公開される最初の部分では、呼び出し元が文字列および書式設定パラメーターまたは DWrite テキスト レイアウト オブジェクトを複数の形式に渡すことができます。 これは、ほとんどの呼び出し元に適している必要があります。 ID2D1RenderTarget::D rawGlyphRun メソッドとして公開されるテキストをレンダリングする 2 つ目の方法は、レンダリングするグリフの位置を既に把握しているユーザーにラスタライズを提供します。 次の 2 つの一般的なルールは、Direct2D で描画するときのテキストのパフォーマンスを向上させるのに役立ちます。

DrawTextLayout と DrawText

DrawTextDrawTextLayout の両方を使用すると、DirectWrite API によって書式設定されたテキストをアプリケーションで簡単にレンダリングできます。 DrawTextLayout は既存の DWriteTextLayout オブジェクトを RenderTarget に描画し、DrawText は、渡されるパラメーターに基づいて呼び出し元のDirectWrite レイアウトを構築します。 同じテキストを複数回レンダリングする必要がある場合は、DrawText が呼び出されるたびにレイアウトが作成されるため、DrawText の代わりに DrawTextLayout を使用します。

適切なテキスト レンダリング モードの選択

テキストアンチエイリアス モードを明示的に D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE に設定します。 グレースケール テキストのレンダリングの品質は ClearType に匹敵しますが、はるかに高速です。

キャッシュ

他のプリミティブを描画する場合と同様に、完全なシーンまたはプリミティブごとのビットマップ キャッシュを使用します。

任意の図形をクリッピングする

次の図は、画像にクリップを適用した結果を示しています。

クリップの前後の画像の例を示す画像。

この結果を得るには、ジオメトリ マスクを含むレイヤー、または不透明度ブラシを使用した FillGeometry メソッドを使用します。

レイヤーを使用する例を次に示します。

// Call PushLayer() and pass in the clipping geometry.
m_d2dContext->PushLayer(
    D2D1::LayerParameters(
        boundsRect,
        geometricMask));

FillGeometry メソッドを使用する例を次に示します。

// Create an opacity bitmap and render content.
m_d2dContext->CreateBitmap(size, nullptr, 0,
    D2D1::BitmapProperties(
        D2D1_BITMAP_OPTIONS_TARGET,
        D2D1::PixelFormat(
            DXGI_FORMAT_A8_UNORM,
            D2D1_ALPHA_MODE_PREMULTIPLIED),
        dpiX, dpiY),
    &opacityBitmap);

m_d2dContext->SetTarget(opacityBitmap.Get());
m_d2dContext->BeginDraw();
…
m_d2dContext->EndDraw();

// Create an opacity brush from the opacity bitmap.
m_d2dContext->CreateBitmapBrush(opacityBitmap.Get(),
    D2D1::BitmapBrushProperties(),
    D2D1::BrushProperties(),
    &bitmapBrush);

// Call the FillGeometry method and pass in the clip geometry and the opacity brush
m_d2dContext->FillGeometry( 
    clipGeometry.Get(),
    brush.Get(),
    opacityBrush.Get()); 

このコード例では、PushLayer メソッドを呼び出すときに、アプリで作成されたレイヤーを渡しません。 Direct2D によってレイヤーが自動的に作成されます。 Direct2D は、アプリからの関与なしに、このリソースの割り当てと破棄を管理できます。 これにより、Direct2D は内部的にレイヤーを再利用し、リソース管理の最適化を適用できます。

Windows 8では、レイヤーの使用に対して多くの最適化が行われています。可能な限り FillGeometry ではなくレイヤー API を使用することをお勧めします。

Windows 8の PushLayer

ID2D1DeviceContext インターフェイスは ID2D1RenderTarget インターフェイスから派生し、Windows 8で Direct2D コンテンツを表示するための重要な要素です。このインターフェイスの詳細については、「デバイスとデバイス コンテキスト」を参照してください。 デバイス コンテキスト インターフェイスを使用すると、 CreateLayer メソッドの呼び出しをスキップし、 ID2D1DeviceContext::P ushLayer メソッドに NULL を 渡すことができます。 Direct2D はレイヤー リソースを自動的に管理し、レイヤーとエフェクト グラフ間でリソースを共有できます。

軸揃えクリップ

クリップする領域が任意ではなく、描画サーフェスの軸に揃えられる場合。 この場合は、レイヤーの代わりにクリップ四角形を使用する場合に適しています。 パフォーマンスの向上は、アンチエイリアシングされたジオメトリよりもエイリアス化されたジオメトリの方が高くなります。 軸揃えクリップの詳細については、「 PushAxisAlignedClip 」トピックを参照してください。

DXGI 相互運用性: 頻繁なスイッチを避ける

Direct2D は、Direct3D サーフェスとシームレスに相互運用できます。 これは、2D コンテンツと 3D コンテンツの組み合わせをレンダリングするアプリケーションを作成する場合に非常に便利です。 ただし、Direct2D コンテンツと Direct3D コンテンツの描画を切り替えるたびに、パフォーマンスが低下します。

DXGI サーフェスにレンダリングする場合、Direct2D はレンダリング中に Direct3D デバイスの状態を保存し、レンダリングの完了時に復元します。 Direct2D レンダリングのバッチが完了するたびに、この保存と復元のコストと、すべての 2D 操作をフラッシュするコストが支払われますが、Direct3D デバイスはフラッシュされません。 そのため、パフォーマンスを向上させるには、Direct2D と Direct3D の間のレンダリング スイッチの数を制限します。

ピクセル形式を把握する

レンダー ターゲットを作成するときに、レンダー ターゲットで使用されるピクセル形式とアルファ モードを指定する D2D1_PIXEL_FORMAT 構造を使用できます。 アルファ チャネルは、カバレッジ値または不透明度情報を指定するピクセル形式の一部です。 レンダー ターゲットがアルファ チャネルを使用しない場合は、 D2D1_ALPHA_MODE_IGNORE アルファ モードを使用して作成する必要があります。 これにより、不要なアルファ チャネルのレンダリングに費やされる時間が不要になります。

ピクセル形式とアルファ モードの詳細については、「 サポートされているピクセル形式とアルファ モード」を参照してください。

シーンの複雑さ

レンダリングされるシーンのパフォーマンス ホット スポットを分析する場合、シーンがフィル レート バインドか頂点バインドかを把握すると、役立つ情報が得られます。

  • 塗りつぶし速度: 塗りつぶし率とは、グラフィックス カードが 1 秒あたりのビデオ メモリにレンダリングおよび書き込みできるピクセル数を指します。
  • 頂点バインド: シーンは、複雑なジオメトリが多数含まれている場合に頂点バインドされます。

シーンの複雑さを理解する

シーンの複雑さを分析するには、レンダー ターゲットのサイズを変更します。 レンダリング ターゲットのサイズを比例的に縮小するためにパフォーマンスの向上が表示される場合、アプリケーションはフィル レート バインドされます。 そうしないと、シーンの複雑さがパフォーマンスのボトルネックになります。

シーンがフィル レート バインドされている場合、レンダー ターゲットのサイズを小さくすると、パフォーマンスが向上する可能性があります。 これは、レンダリングするピクセル数がレンダー ターゲットのサイズに比例して減少するためです。

シーンが頂点バインドされている場合は、ジオメトリの複雑さを軽減します。 しかし、これは画質を犠牲にして行われることに注意してください。 したがって、必要な品質と必要なパフォーマンスの間で慎重なトレードオフの決定を行う必要があります。

Direct2D 印刷アプリのパフォーマンスの向上

Direct2D は 印刷との互換性を提供します。 同じ Direct2D 描画コマンド (Direct2D コマンド リストの形式) を印刷用の Direct2D 印刷コントロールに送信できます。描画先のデバイスがわからない場合や、図面を印刷に変換する方法がわからない場合は、

Direct2D 印刷コントロールと Direct2D 描画コマンドの使用方法をさらに微調整して、より優れたパフォーマンスで印刷結果を提供できます。

Direct2D 印刷コントロールは、出力品質やパフォーマンスを低下させる Direct2D コード パターン (このトピックで後述するコード パターンなど) が表示されると、デバッグ メッセージを出力して、パフォーマンスの問題を回避できる場所を通知します。 これらのデバッグ メッセージを表示するには、コードで Direct2D デバッグ レイヤー を有効にする必要があります。 デバッグ メッセージ出力を有効にする手順については、「メッセージのデバッグ」を参照してください。

D2D 印刷コントロールを作成するときに適切なプロパティ値を設定する

Direct2D 印刷コントロールを作成するときに設定できるプロパティは 3 つあります。 これらの 2 つのプロパティは、Direct2D 印刷コントロールが特定の Direct2D コマンドを処理する方法に影響し、その結果、全体的なパフォーマンスに影響します。

  • フォント サブセット モード: Direct2D 印刷コントロールは、印刷するページを送信する前に、各ページで使用されるフォント リソースをサブセット化します。 このモードでは、印刷に必要なページ リソースのサイズが小さくなります。 ページ上のフォントの使用状況に応じて、最適なパフォーマンスを得るためのさまざまなフォント サブセット モードを選択できます。
    • D2D1_PRINT_FONT_SUBSET_MODE_DEFAULT は、ほとんどの場合、最高の印刷パフォーマンスを提供します。 このモードに設定すると、 Direct2D 印刷コントロールはヒューリスティック戦略を使用して、フォントをサブセット化するタイミングを決定します。
    • 1 ページまたは 2 ページの短い印刷ジョブの場合は、 をD2D1_PRINT_FONT_SUBSET_MODE_EACHPAGE することをお勧めします。この場合、 Direct2D 印刷コントロールは各ページにフォント リソースをサブセット化して埋め込み、ページの印刷後にそのフォント サブセットを破棄します。 このオプションを使用すると、各ページを生成した直後に印刷できますが、印刷に必要なページ リソースのサイズが少し大きくなります (通常はフォント サブセットが大きくなります)。
    • 多数のページのテキストと小さなフォント サイズ (1 つのフォントを使用する 100 ページのテキストなど) を含む印刷ジョブの場合は、Direct2D 印刷コントロールでフォント リソースがまったくサブセット化されないD2D1_PRINT_FONT_SUBSET_MODE_NONEすることをお勧めします。代わりに、最初にフォントを使用するページと共に元のフォント リソースを送信し、後のページのフォント リソースを再送信せずに再利用します。
  • ラスター化 DPI: Direct2D-XPS 変換中に Direct2D 印刷コントロールで Direct2D コマンドをラスター化する必要がある場合は、この DPI をラスター化に使用します。 つまり、ページにラスター化されたコンテンツがない場合、DPI を設定してもパフォーマンスと品質は変わりません。 ページ上のラスター化の使用に応じて、忠実性とパフォーマンスのバランスを最適にするために、異なるラスター化 DPI を選択できます。
    • Direct2D 印刷コントロールを作成するときに値を指定しない場合は 150 が既定値です。これは、ほとんどの場合、印刷品質と印刷パフォーマンスの最適なバランスです。
    • 通常、DPI 値が大きいほど印刷品質は向上しますが (詳細は保持されます)、生成されるビットマップが大きくなるほどパフォーマンスは低下します。 300 を超える DPI 値は、人間の目で視覚的に認識できる追加情報を導入しないため、お勧めしません。
    • DPI が低いほど、パフォーマンスが向上する可能性がありますが、品質が低下する可能性もあります。

特定の Direct2D 描画パターンを使用しないようにする

Direct2D が視覚的に表すことができるものと、印刷サブシステムが印刷パイプライン全体に沿って保守および転送できる内容には違いがあります。 Direct2D 印刷コントロールは、印刷サブシステムがネイティブにサポートしていない Direct2D プリミティブを近似またはラスター化することによって、これらのギャップを埋めます。 このような近似では、通常、印刷の忠実度が低くなり、印刷パフォーマンスが低下するか、またはその両方が得られます。 したがって、お客様が画面レンダリングと印刷レンダリングの両方に同じ描画パターンを使用できる場合でも、すべての場合に理想的ではありません。 このような Direct2D プリミティブとパターンは、印刷パスにできるだけ使用しないか、ラスター化された画像の品質とサイズを完全に制御できる独自のラスター化を行うことをお勧めします。

次に示すのは、印刷のパフォーマンスと品質が理想的でない場合と、最適な印刷パフォーマンスを得るためにコード パスを変更することを検討する必要があるケースの一覧です。

  • D2D1_PRIMITIVE_BLEND_SOURCEOVER以外のプリミティブ ブレンド モードは使用しないでください。
  • D2D1_COMPOSITE_MODE_SOURCE_OVERD2D1_COMPOSITE_MODE_DESTINATION_OVER以外のイメージを描画する場合は、コンポジション モードを使用しないでください。
  • GDI メタ ファイルの描画は避けてください。
  • ソースの背景をコピーするレイヤー リソースをプッシュしないようにします (D2D1_LAYER_PARAMETERS1 構造体にD2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUNDを渡して PushLayer を呼び出します)。
  • D2D1_EXTEND_MODE_CLAMPを使用してビットマップ ブラシまたはイメージ ブラシを作成しないでください。 バインドされたイメージの外側のピクセルを気にしない場合は、D2D1_EXTEND_MODE_MIRRORを使用することをお勧めします (たとえば、ブラシにアタッチされているイメージは、塗りつぶされたターゲット領域よりも大きいことがわかっています)。
  • パースペクティブ変換を使用してビットマップを描画しないようにします。

テキストを直接プレーンな方法で描画する

Direct2D には、パフォーマンスやビジュアル品質を向上させるために表示するテキストをレンダリングするときの最適化がいくつか用意されています。 ただし、通常、用紙への印刷ははるかに高い DPI で、印刷ではアニメーションなどのシナリオに対応する必要がないため、すべての最適化によって印刷のパフォーマンスと品質が向上するわけではありません。 そのため、元のテキストまたはグリフを直接描画し、印刷用のコマンド リストを作成するときに、次の最適化を避けるようにすることをお勧めします。

  • FillOpacityMask メソッドを使用してテキストを描画しないようにします。
  • エイリアスモードでテキストを描画しないようにします。

可能な場合は元のビットマップを描画します

ターゲット ビットマップが JPEG、PNG、TIFF、または JPEG-XR の場合は、WIC ビットマップをディスク ファイルまたはメモリ内ストリームから作成し、ID2D1DeviceContext::CreateBitmapFromWicBitmap を使用してその WIC ビットマップから Direct2D ビットマップを作成し、最後に Direct2D ビットマップを Direct2D 印刷コントロールに直接渡すことができます。 これにより、Direct2D 印刷コントロールはビットマップ ストリームを再利用できます。通常、印刷パフォーマンスが向上し (冗長なビットマップ エンコードとデコードをスキップして)、印刷品質が向上します (ビットマップ内のメタデータ (カラー プロファイルなど) が保持される場合)。

元のビットマップを描画すると、アプリケーションに次の利点があります。

  • 一般に、 Direct2D 印刷は、特にアプリが印刷パイプラインの詳細 (印刷先のプリンター、ターゲット プリンターの DPI など) を知らない (または知りたくない) 場合に、パイプラインの後半まで元の情報 (損失やノイズなし) を保持します。
  • 多くの場合、ビットマップのラスター化を遅延させると、パフォーマンスが向上します (96dpi 写真を 600dpi プリンターに印刷する場合など)。
  • 場合によっては、元のイメージを渡すことが、(埋め込みカラー プロファイルなど) 高忠実度を尊重する唯一の方法です。

ただし、 では、次の理由でこのような最適化を選択することはできません。

  • プリンター情報を照会し、初期のラスター化を行うことで、紙の最終的な外観を完全に制御してコンテンツ自体をラスター化できます。
  • 場合によっては、初期のラスター化によって、アプリのエンド ツー エンドのパフォーマンス (ウォレットサイズの写真の印刷など) が実際に向上する可能性があります。
  • 場合によっては、元のビットマップを渡す場合、既存のコード アーキテクチャを大幅に変更する必要があります (イメージの遅延読み込み、特定のアプリケーションで見つかったリソース更新パスなど)。

まとめ

Direct2D はハードウェア アクセラレータであり、高パフォーマンスを目的としていますが、スループットを最大化するには、機能を正しく使用する必要があります。 ここで説明した手法は、一般的なシナリオの調査から派生しており、すべてのアプリケーション シナリオには適用されない場合があります。