次の方法で共有


アーキテクチャとコンポーネント

注意

Windows 10上のアプリの場合は、DirectComposition ではなく Windows.UI.Composition API を使用することをお勧めします。 詳細については、「 Visual レイヤーを使用してデスクトップ アプリをモダン化する」を参照してください。

このトピックでは、Microsoft DirectComposition を構成するコンポーネントについて説明します。 これは、次のセクションで構成されます。

ソフトウェア コンポーネント

DirectComposition は、次のメインソフトウェア コンポーネントで構成されます。

  • コンポーネント オブジェクト モデル (COM) ベースのパブリック API を実装するユーザー モード アプリケーション ライブラリ (dcomp.dll)。
  • デスクトップ ウィンドウ マネージャー (DWM) プロセス (dwm.exe) でホストされ、実際のデスクトップコンポジションを実行するユーザー モードコンポジション エンジン (dwmcore.dll)。
  • アプリケーションからコンポジション エンジンにコマンドをマーシャリングするカーネル モード オブジェクト データベース (win32k.sysの一部)。

コンポジション エンジンの 1 つのインスタンスが、すべてのアプリケーションの DirectComposition コンポジション ツリーと、デスクトップ全体を表す DWM コンポジション ツリーを処理します。 カーネル モード オブジェクト データベースとユーザー モードコンポジション エンジンの両方がセッションごとに 1 回インスタンス化されるため、複数のユーザーを持つターミナル サーバー マシンには、両方のコンポーネントの複数のインスタンスがあります。

次の図は、DirectComposition コンポーネントメインと、それらが相互にどのように関連しているかを示しています。

directcomposition の最上位アーキテクチャ

アプリケーション ライブラリ

DirectComposition アプリケーション ライブラリは、dcomp.dllからエクスポートされ、デバイス オブジェクトへのインターフェイス ポインターを返す単一のフラット エントリ ポイントを持つパブリック COM ベースの API です。 さらに、デバイス オブジェクトには、他のすべてのオブジェクトを作成するためのメソッドがあり、各オブジェクトはインターフェイス ポインターで表されます。 すべての DirectComposition インターフェイスは 、IUnknown インターフェイスから継承され、完全に実装されます。 DirectComposition インターフェイスを受け入れるすべてのメソッドは、インターフェイスが dcomp.dll 内で実装されているか、別のコンポーネントによって実装されているかをチェックします。 DirectComposition は拡張可能ではないので、インターフェイスをパラメーターとして受け取るメソッドは、インターフェイスが dcomp.dll に実装されていない場合はE_INVALIDARG返します。 API には特別な特権は必要ありません。これは、最も低いレベルのアクセスで実行されているプロセスによって呼び出すことができます。 ただし、API はセッション 0 では動作しないため、サービスには適していません。 これらの点で、DirectComposition API は他の Microsoft DirectX API (特に Direct2D、Microsoft Direct3D、Microsoft DirectWrite) と似ています。

コンポジション エンジンは非同期実行専用に設計されているため、DirectComposition API のオブジェクト プロパティは書き込み専用です。 すべてのプロパティにはセッター メソッドがありますが、getter メソッドはありません。 プロパティの読み取りはリソースを大量に消費するだけでなく、コンポジション エンジンが返す値がすぐに無効になる可能性があるため、不正確になる可能性もあります。 これは、たとえば、独立したアニメーションが読み取られるプロパティにバインドされている場合に発生する可能性があります。

API はスレッド セーフです。 アプリケーションは、任意のスレッドからいつでも任意のメソッドを呼び出すことができます。 ただし、多くの API メソッドは特定のシーケンスで呼び出す必要があるため、同期を行わないと、スレッドのインターリーブ方法によっては、アプリケーションで予期しない動作が発生する可能性があります。 たとえば、2 つのスレッドが同じオブジェクトの同じプロパティを同時に異なる値に変更した場合、2 つの値のうち、プロパティの最後の値になる値をアプリケーションで予測することはできません。 同様に、2 つのスレッドが同じデバイスで Commit を 呼び出した場合、1 つのスレッドで Commit を呼び出すと、 Commit を呼び出したコマンドだけでなく、両方のスレッドによって発行されたすべてのコマンドのバッチが送信されるため、どちらのスレッドも真のトランザクション動作を取得しません。

システムは、デバイス オブジェクトごとにすべての内部状態を維持します。 アプリケーションが 2 つ以上の DirectComposition デバイス オブジェクトを作成する場合、アプリケーションは 2 つの間で独立したバッチとその他の状態を維持できます。

すべての DirectComposition オブジェクトには、デバイス オブジェクト アフィニティがあります。特定のデバイス オブジェクトによって作成されたオブジェクトは、そのデバイス オブジェクトでのみ使用でき、同じデバイス オブジェクトによって作成された他のオブジェクトにのみ関連付けることができます。 言い換えると、各デバイス オブジェクトは、機能の個別の不整合な島です。 1 つの例外は、ビジュアル クラスです。これにより、ビジュアルが親とは異なるデバイス オブジェクトに属できるビジュアル ツリーを構築できます。 これにより、アプリケーションとコントロールが 1 つの合成ツリーを管理でき、1 つの DirectComposition デバイス オブジェクトも共有する必要がないシナリオが可能になります。

コンポジション エンジン

DirectComposition 合成エンジンは、アプリケーション プロセスとは別に、専用のプロセスで実行されます。 1 つのコンポジション プロセス (dwm.exe) は、セッション内のすべてのアプリケーションをサポートします。 各アプリケーションは、所有するウィンドウごとに 2 つのビジュアル ツリーを作成できます。 すべてのツリーは、DWM のコンポジション構造も含む、より大きなビジュアル ツリーのサブツリーとして実際に実装されます。 DWM は、セッション内のデスクトップごとに 1 つの大きなビジュアル ツリーを構築します。 このアーキテクチャの主な利点を次に示します。

  • コンポジション エンジンは、すべてのアプリケーション ビットマップとビジュアル ツリーにアクセスできます。これにより、クロスプロセス ウィンドウの相互運用性とコンポジションが可能になります。
  • コンポジション エンジンは、任意のアプリケーション プロセスとは別の信頼されたシステム プロセスで実行されるため、アクセス権が低いアプリケーションは保護されたコンテンツを安全に作成できます。
  • コンポジション エンジンは、特定のウィンドウが完全に隠されていることを検出し、ウィンドウ用に作成される CPU およびグラフィックス処理装置 (GPU) リソースの無駄を回避できます。
  • コンポジション エンジンは画面バック バッファーに直接作成できるため、プロセスごとのコンポジション エンジンに必要な追加のコピーが不要になります。
  • すべてのアプリケーションで合成用に 1 つの Direct3D デバイスを共有します。これにより、メモリを大幅に節約できます

ビジュアル ツリーは保持構造です。 DirectComposition API は、アトミックに処理される変更のバッチで構造を編集するメソッドを公開します。 DirectComposition API のルート オブジェクトはデバイス オブジェクトであり、他のすべての DirectComposition オブジェクトのファクトリとして機能し、 Commit というメソッドが含まれています。 コンポジション エンジンは、アプリケーションが Commit を呼び出すまで、アプリケーションがビジュアル ツリーに加えた変更を反映しません。この時点で、最後の コミット 以降のすべての変更は 1 つのトランザクションとして処理されます。

Commit を呼び出す要件は"フレーム" の概念に似ていますが、コンポジション エンジンは非同期的に実行されるため、Commit の呼び出しの間に複数の異なるフレームを提示できる点が異なります。 DirectComposition では、 フレーム はコンポジション エンジンの 1 回の反復であり、 Commit の 2 回の呼び出しの間にアプリケーションによって費やされる間隔は バッチと呼ばれます。

DirectComposition は、DirectComposition API に対するすべてのアプリケーション呼び出しをバッチ処理します。 win32k.sys セッション ドライバーに実装されているカーネル オブジェクト データベースには、API 呼び出しに関連付けられているすべての状態情報が格納されます。

コンポジション エンジンは、ディスプレイ内の垂直ブランクごとに 1 つのフレームを生成します。 フレームは垂直ブランクで開始され、後続の垂直ブランクをターゲットとします。 フレームが起動すると、コンポジション エンジンはすべての保留中のバッチを取得し、そのフレームにコマンドを含めます。 アプリケーションが Commit を呼び出すと、バッチは保留中のキューに配置され、保留中のキューはフレームの先頭でアトミックにフラッシュされます。 したがって、フレームの先頭をマークする 1 つの時点があります。 このポイントの前に送信されたバッチはフレームに含まれますが、 の後に送信されたバッチは、次のフレームが処理されるまで待機する必要があります。 完全なコンポジション ループは次のとおりです。

  1. 次の垂直ブランクの時刻を見積もる。
  2. 保留中のすべてのバッチを取得します。
  3. 取得したバッチを処理します。
  4. 手順 1 で推定された時間を使用して、すべてのアニメーションを更新します。
  5. 再構成する必要がある画面の領域を決定します。
  6. ダーティリージョンを再作成します。
  7. 各画面の背面バッファーと前面バッファーを反転してフレームを表示します。
  8. 何も構成されておらず、手順 6 と 7 で示されていない場合は、バッチがコミットされるのを待ちます。
  9. 次の垂直空白を待ちます。

1 つのビデオ アダプターに複数のモニターが接続されている場合、コンポジション エンジンはプライマリ モニターの垂直ブランクを使用してコンポジション ループを駆動し、アニメーションのサンプリング時間を設定します。 各モニターは、個別の全画面表示のフリップ チェーンで表されます。コンポジション エンジンは、1 つの Direct3D デバイスを使用して、ラウンドロビン方式でモニターごとに手順 6 と 7 を繰り返します。 複数のビデオ アダプターがある場合、コンポジション エンジンは、手順 6 と 7 でビデオ アダプターごとに個別の Direct3D デバイスを使用します。

次の図に示すように、コンポジション フレームは常に垂直ブランクから開始するようにスケジュールされています。

コンポジション フレームのスケジュール設定

コンポジション ツリーが変更されていないためにコンポジション エンジンに作業がない場合、コンポジション スレッドは新しいバッチの待機中にスリープ状態になります。 新しいバッチが送信されると、コンポジション スレッドはウェイクアップしますが、すぐに次の垂直空白までスリープ状態に戻ります。 この動作により、アプリケーションとコンポジション エンジンの予測可能なフレームの開始時刻と終了時刻が保証されます。

コンポジション エンジンは、フレームの表示時間と現在のフレーム レートを公開します。 この情報を公開すると、アプリケーションは独自のバッチのプレゼンテーション時間を見積もり、アニメーションを同期できるようになります。 特に、アプリケーションでは、コンポジション エンジンからのフレーム統計と、UI スレッドがバッチを生成するのにかかる時間の履歴モデルを組み合わせて使用して、独自のアニメーションのサンプリング時間を決定できます。

たとえば、前の図に示したアプリケーション バッチの先頭で、アプリケーションはコンポジション エンジンに対してクエリを実行して、次のフレームの正確な表示時間を判断できます。 その後、アプリケーションは、現在の時刻と、生成された以前のバッチに関する情報を使用して、アプリケーションが次の垂直ブランクの前に現在のバッチを完了できるかどうかを判断できます。 したがって、アプリケーションでは、フレームプレゼンテーション時間を独自のアニメーションのサンプリング時間として使用します。 アプリケーションが現在の垂直ブランクで作業を完了する可能性が低いと判断した場合、アプリケーションはその時間を計算するためにコンポジション・エンジンから返されたフレーム・レート情報を使用して、代わりに後続のフレーム時間をサンプリング時間として使用できます。

DirectComposition の概念