次の方法で共有


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

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

リソースの使用状況

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

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

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

  • EndDraw が発生しました。 EndDraw が呼び出されると、バッチ描画操作が完了し、操作の状態が返されます。
  • 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();

ジオメトリレンダリング

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

DrawRectangle などのより具体的な描画プリミティブ呼び出しは、一般的な DrawGeometry 呼び出しよりも使用します。 これは 、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 ではなく DrawTextLayout を使用します。DrawText は呼び出されるたびにレイアウトを作成するためです。

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

テキスト アンチエイリアス モードを明示的に 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 ページの短い印刷ジョブでは、direct2D 印刷コントロールが各ページにフォント リソースをサブセット化して埋め込むD2D1_PRINT_FONT_SUBSET_MODE_EACHPAGEし、ページの印刷後にそのフォント サブセットを破棄することをお勧めします。 このオプションを使用すると、各ページを生成した直後に印刷できますが、印刷に必要なページ リソースのサイズが若干大きくなります (通常はフォントサブセットが大きくなります)。
    • テキストのページが多く、フォント サイズが小さい印刷ジョブ (1 つのフォントを使用するテキストの 100 ページなど) の場合は、Direct2D 印刷コントロールでフォント リソースがまったくサブセット化されないD2D1_PRINT_FONT_SUBSET_MODE_NONEすることをお勧めします。代わりに、最初にフォントを使用するページと共に元のフォント リソースを送信し、後のページのフォント リソースを再送信せずに再利用します。
  • ラスター化 DPI: Direct2D 印刷コントロールで、Direct2D-XPS 変換中に Direct2D コマンドをラスター化する必要がある場合は、この DPI を使用してラスター化します。 つまり、ページにラスター化されたコンテンツがない場合、DPI を設定してもパフォーマンスと品質は変わりません。 ページ上のラスター化の使用法に応じて、再現性とパフォーマンスのバランスを最大限に高めるさまざまなラスター化 DPI を選択できます。
    • Direct2D 印刷コントロールの作成時に値を指定しない場合は 150 が既定値です。これは、ほとんどの場合、印刷品質と印刷パフォーマンスの最適なバランスです。
    • DPI 値を大きくすると、通常、印刷品質が向上します (詳細が保持される場合と同様)。ただし、生成されるビットマップが大きくなるほど、パフォーマンスが低下します。 300 を超える DPI 値は推奨されません。これは、人間の目で視覚的に知覚できる追加情報を導入しないためです。
    • DPI が低いほどパフォーマンスが向上する可能性がありますが、品質が低下する可能性もあります。

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

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

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

  • D2D1_PRIMITIVE_BLEND_SOURCEOVER以外のプリミティブ ブレンド モード 使用しないでください。
  • D2D1_COMPOSITE_MODE_SOURCE_OVERおよびD2D1_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 ビットマップをディスク ファイルまたはメモリ内ストリームから作成し、その WIC ビットマップから ID2D1DeviceContext::CreateBitmapFromWicBitmap を使用して Direct2D ビットマップを作成し、さらに操作せずに Direct2D ビットマップを Direct2D 印刷コントロールに直接渡すことができます。 これにより、Direct2D 印刷コントロールはビットマップ ストリームを再利用でき、通常は印刷パフォーマンスが向上し (冗長なビットマップ エンコードとデコードをスキップすることで)、印刷品質が向上します (カラー プロファイルなどのメタデータがビットマップに保持される場合)。

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

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

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

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

結論

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