RenderingNG の主なデータ構造

Chris Harrelson
Chris Harrelson
Daniel Cheng
Daniel Cheng
Philip Rogers
Philip Rogers
Koji Ishi
Koji Ishi
Ian Kilpatrick
Ian Kilpatrick
Kyle Charbonneau
Kyle Charbonneau

レンダリング パイプラインへの入出力である、重要なデータ構造について見てみましょう。

これらのデータ構造は次のとおりです。

  • フレームツリーは、どのレンダリング プロセスとどの Blink レンダラにあるウェブドキュメントを表すローカルノードとリモートノードで構成されています。
  • 不変のフラグメント ツリーは、レイアウト制約アルゴリズム(およびその入力)の出力を表します。
  • プロパティ ツリーは、ウェブ ドキュメントの変換、クリップ、効果、スクロールの階層を表します。これらはパイプライン全体で使用されます。
  • ディスプレイ リストとペイント チャンクは、ラスター化アルゴリズムとレイヤ化アルゴリズムの入力です。
  • コンポジタ フレームは、GPU を使用して描画するために使用されるサーフェス、レンダリング サーフェス、GPU テクスチャ タイルをカプセル化します。

これらのデータ構造について説明する前に、次の例はアーキテクチャ レビューに基づいています。この例は、データ構造がどのように適用されるかを示すために、このドキュメント全体で使用されます。

<!-- Example code -->
<html>
  <div style="overflow: hidden; width: 100px; height: 100px;">
    <iframe style="filter: blur(3px);
      transform: rotateZ(1deg);
      width: 100px; height: 300px"
      id="one" src="foo.com/etc"></iframe>
  </div>
  <iframe style="top:200px;
    transform: scale(1.1) translateX(200px)"
    id="two" src="bar.com"></iframe>
</html>

フレームツリー

Chrome は、親フレームとは異なるレンダリング プロセスでクロスオリジン フレームのレンダリングを選択することがあります。

サンプルコードでは、合計 3 つのフレームがあります。

2 つの iframe を含む親フレーム foo.com。

サイト分離では、Chromium は 2 つのレンダリング プロセスを使用してこのウェブページをレンダリングします。各レンダリング プロセスには、そのウェブページのフレームツリーの独自の表現があります。

2 つのレンダリング プロセスを表す 2 つのフレームツリー。

別のプロセスでレンダリングされたフレームはリモート フレームとして表されます。リモート フレームには、レンダリングでプレースホルダとして機能するために必要な最小限の情報(サイズなど)が保持されます。そうでない場合、リモート フレームには実際のコンテンツのレンダリングに必要な情報は含まれません。

一方、ローカル フレームは、標準レンダリング パイプラインを通過するフレームを表します。ローカル フレームには、そのフレームのデータ(DOM ツリーやスタイルデータなど)をレンダリングおよび表示可能なものにするために必要なすべての情報が含まれています。

レンダリング パイプラインは、ローカル フレームツリー フラグメントの粒度で動作します。foo.com をメインフレームとする、より複雑な例について考えてみましょう。

<iframe src="bar.com"></iframe>

次の bar.com サブフレームも追加します。

<iframe src="foo.com/etc"></iframe>

レンダラは引き続き 2 つですが、ローカル フレームツリー フラグメントは 3 つあります。2 つは foo.com のレンダリング プロセスにあり、1 つは bar.com のレンダリング プロセスにあります。

2 つのレンダリングと 3 つのフレームツリー フラグメントの表現。

ウェブページの 1 つのコンポジタ フレームを生成するために、Viz は 3 つのローカル フレームツリーのルートフレームからコンポジタ フレームを同時にリクエストし、それらを集約します。コンポーザ フレーム セクションも参照してください。

foo.com メインフレームと foo.com/other-page サブフレームは同じフレームツリーの一部であり、同じプロセスでレンダリングされます。ただし、2 つのフレームは異なるローカル フレームツリー フラグメントの一部であるため、独立したドキュメント ライフサイクルを持ちます。このため、1 回の更新で両方のコンポジタ フレームを生成することはできません。レンダリング プロセスには、foo.com/other-page 用に生成されたコンポジタ フレームを foo.com メインフレームのコンポジタ フレームに直接合成するための十分な情報がありません。たとえば、プロセス外の bar.com 親フレームは、CSS で iframe を変換したり、DOM 内の他の要素で iframe の一部を隠したりすることで、foo.com/other-url iframe の表示に影響する可能性があります。

ビジュアル プロパティの更新ウォーターフォール

デバイスのスケール ファクタやビューポートのサイズなどの視覚的なプロパティは、レンダリングされた出力に影響するため、ローカル フレームツリー フラグメント間で同期する必要があります。各ローカル フレームツリー フラグメントのルートには、ウィジェット オブジェクトが関連付けられています。ビジュアル プロパティの更新は、メインフレームのウィジェットに送信された後、残りのウィジェットに上から下に伝播されます。

たとえば、ビューポートのサイズが変更された場合:

前述のプロセスを示す図。

このプロセスは瞬時に行われないため、複製されたビジュアル プロパティには同期トークンも含まれます。Viz コンポジタは、この同期トークンを使用して、すべてのローカル フレームツリー フラグメントが現在の同期トークンを使用してコンポジタ フレームを送信するのを待ちます。このプロセスにより、異なる視覚プロパティのコンポジット フレームが混在するのを回避できます。

イミュータブル フラグメント ツリー

不変のフラグメント ツリーは、レンダリング パイプラインのレイアウト ステージの出力です。ページ上のすべての要素の位置とサイズを表します(変換は適用されません)。

各ツリーのフラグメントの表現。1 つのフラグメントがレイアウトが必要とマークされています。

各フラグメントは DOM 要素の一部を表します。通常、要素ごとに 1 つのフラグメントのみが存在しますが、印刷時に異なるページに分割されている場合や、複数列のコンテキストで列に分割されている場合は、複数のフラグメントが存在することもあります。

レイアウト後、各フラグメントは不変になり、再度変更されることはありません。また、いくつかの追加制限も設けています。Google は以下のことは行いません。

  • ツリー内の「上」の参照を許可します。(子に親へのポインタを設定することはできません)。
  • データをツリーに沿って「バブルアップ」します(子は親からではなく、子からのみ情報を読み取ります)。

こうした制限により、後続のレイアウトでフラグメントを再利用できるようになります。これらの制限がないと、ツリー全体を頻繁に再生成する必要があり、費用がかかります。

ほとんどのレイアウトは通常、段階的な更新です。たとえば、ユーザーが要素をクリックしたときに UI のごく一部を更新するウェブアプリなどです。理想的には、レイアウトは画面上で実際に変更されたものに比例した作業のみを行う必要があります。これは、前のツリーをできるだけ多く再利用することで実現できます。つまり、通常はツリーのスパインを再ビルドするだけで済みます。

将来的には、この不変の設計により、必要に応じてスレッド境界を越えて不変のフラグメント ツリーを渡す(別のスレッドで後続のフェーズを実行するため)、スムーズなレイアウト アニメーションのために複数のツリーを生成する、並列推測レイアウトを実行するなど、興味深いことを実現できる可能性があります。また、レイアウト自体をマルチスレッド化することもできます。

インライン フラグメント アイテム

インライン コンテンツ(主にスタイル設定されたテキスト)では、表現が若干異なります。ボックスとポインタを含むツリー構造ではなく、ツリーを表すフラットなリストでインライン コンテンツを表します。主なメリットは、インラインのフラットリスト表現が高速で、インライン データ構造の検査やクエリに便利であり、メモリ効率が高いことです。テキストのレンダリングは非常に複雑であり、高度に最適化しないとパイプラインの最も遅い部分になりやすいため、これはウェブ レンダリングのパフォーマンスにとって非常に重要です。

フラットリストは、インライン レイアウト サブツリーの深さ優先検索の順序で、インライン フォーマット コンテキストごとに作成されます。リスト内の各エントリは、(オブジェクト、子孫の数)のタプルです。たとえば、次の DOM について考えてみましょう。

<div style="width: 0;">
  <span style="color: blue; position: relative;">Hi</span> <b>there</b>.
</div>

width プロパティが 0 に設定されているため、行は「Hi」と「there」の間で折り返します。

この状況のインライン フォーマット コンテキストをツリーとして表すと、次のようになります。

{
  "Line box": {
    "Box <span>": {
      "Text": "Hi"
    }
  },
  "Line box": {
    "Box <b>": {
      "Text": "There"
    }
  },
  {
    "Text": "."
  }
}

フラット リストは次のようになります。

  • (折れ線ボックス、2)
  • (Box <span>, 1)
  • (テキスト「Hi」、0)
  • (ラインボックス、3)
  • (Box <b>、1)
  • (テキスト「there」、0)
  • (テキスト「.」, 0)

このデータ構造を使用するコンシューマは、ユーザー補助 API、getClientRectscontenteditable などのジオメトリ API など、多数あります。それぞれ要件が異なります。これらのコンポーネントは、便利なカーソルを介してフラット データ構造にアクセスします。

カーソルには、MoveToNextMoveToNextLineCursorForChildren などの API があります。このカーソル表現は、テキスト コンテンツにおいて非常に効果的です。これには次のような理由があります。

  • 深さ優先探索順序で反復処理すると、非常に高速です。キャレットの動きに似ているため、よく使用されます。 フラットなリストであるため、深さ優先探索では配列オフセットをインクリメントするだけで、高速な反復処理とメモリ局所性が実現されます。
  • 幅優先検索を提供します。これは、線とインライン ボックスの背景をペイントする場合などに必要です。
  • 子孫の数がわかれば、次の兄弟に素早く移動できます(配列オフセットをその数だけインクリメントするだけです)。

プロパティ ツリー

DOM は要素(およびテキストノード)のツリーであり、CSS では要素にさまざまなスタイルを適用できます。

4 つの方法で表示されます。

  • レイアウト: レイアウト制約アルゴリズムの入力。
  • Paint: 要素(その子孫は除く)をペイントしてラスタ化する方法。
  • 視覚効果: 変換、フィルタ、クリッピングなど、DOM サブツリーに適用されるラスター/描画効果。
  • スクロール: 軸に沿った丸い角のクリッピングと、含まれるサブツリーのスクロール。

プロパティ ツリーは、視覚効果とスクロール効果が DOM 要素に適用される仕組みを説明するデータ構造です。たとえば、特定の DOM 要素が、所定のレイアウト サイズと位置で示されているのは、画面に対する相対位置で、また、ビジュアル エフェクトとスクロール エフェクトを適用するために、どのような順序で GPU オペレーションを使用すればよいですか?

ウェブ上の視覚効果とスクロール効果は、そのすべてを網羅すると非常に複雑です。プロパティ ツリーが行う最も重要なことは、その複雑さを、構造と意味を正確に表す単一のデータ構造に変換し、同時に DOM と CSS の複雑さを排除することです。これにより、コンポジットとスクロールのアルゴリズムをより確実に実装できるようになります。具体的には、次のとおりです。

  • エラーが発生する可能性のあるジオメトリやその他の計算を 1 か所に集約できます。
  • プロパティ ツリーの構築と更新の複雑さは、1 つのレンダリング パイプライン ステージに分離されます。
  • プロパティ ツリーをさまざまなスレッドやプロセスに送信するのは、完全な DOM 状態よりもはるかに簡単で高速です。これにより、多くのユースケースでプロパティ ツリーを使用できます。
  • ユースケースが多いほど、相互のキャッシュを再利用できる上、構築されたジオメトリ キャッシュから得られるメリットが大きくなります。

RenderingNG では、次のような多くの目的でプロパティ ツリーを使用します。

  • コンポジットをペイントから分離し、コンポジットをメインスレッドから分離。
  • 最適な合成 / 描画戦略の決定。
  • IntersectionObserver ジオメトリを測定する方法。
  • 画面外要素と GPU テクスチャ タイルの処理を回避。
  • ペイントとラスターを効率的かつ正確に無効化。
  • Core Web Vitals でレイアウト シフトLargest Contentful Paint を測定する。

すべてのウェブ ドキュメントには、transform、clip、effect、scroll という 4 つのプロパティ ツリーがあります(*)。変換ツリーは、CSS の変換とスクロールを表します。(スクロール変換は 2D 変換行列として表されます)。クリップツリーは、オーバーフロー クリップを表します。エフェクト ツリーは、他のすべての視覚効果(不透明度、フィルタ、マスク、ブレンドモード、clip-path などの他の種類のクリップ)を表します。スクロール ツリーは、スクロールが連鎖する方法など、スクロールに関する情報を表します。コンポジタ スレッドでスクロールを行うために必要です。プロパティ ツリーの各ノードは、DOM 要素によって適用されるスクロールまたは視覚効果を表します。複数の効果がある場合は、同じ要素の各ツリーに複数のプロパティ ツリーノードがある場合があります。

各ツリーのトポロジは、DOM のスパース表現に似ています。たとえば、オーバーフロー クリップを持つ DOM 要素が 3 つある場合、クリップツリー ノードは 3 つあり、クリップツリーの構造はオーバーフロー クリップ間の包含ブロックの関係に従います。ツリー間のリンクもあります。これらのリンクは、ノードの相対 DOM 階層、つまり適用順序を示しています。たとえば、ある DOM 要素の変換が、フィルタが設定された別の DOM 要素の下にある場合、その変換は当然フィルタの前に適用されます。

各 DOM 要素にはプロパティ ツリー状態があります。これは、その要素に適用される最も近い祖先のクリップ、変換、エフェクト ツリーノードを示す 4 タプル(変換、クリップ、エフェクト、スクロール)です。この情報があれば、その要素に適用されるクリップ、変換、エフェクトのリストと順序を正確に把握できるため、非常に便利です。これにより、画面上の位置と描画方法が決まります。

出典

<html>
  <div style="overflow: scroll; width: 100px; height: 100px;">
    <iframe style="filter: blur(3px);
      transform: rotateZ(1deg);
      width: 100px; height: 300px"
  id="one" srcdoc="iframe one"></iframe>
  </div>
  <iframe style="top:200px;
      transform: scale(1.1) translateX(200px)" id=two
      srcdoc="iframe two"></iframe>
</html>

上記の例(導入の例とは若干異なります)で生成されたプロパティ ツリーの主な要素は次のとおりです。

プロパティ ツリー内のさまざまな要素の例。

ディスプレイ リストとペイント チャンクを表示する

ディスプレイ アイテムには、Skia でラスタライズできる低レベルの描画コマンド(こちらを参照)が含まれています。ディスプレイ アイテムは通常、境界や背景の描画など、数個の描画コマンドのみを使用します。ペイント ツリー ウォークは、CSS ペイント順序に従ってレイアウト ツリーと関連するフラグメントを反復処理し、表示アイテムリストを生成します。

例:

青いボックスの中に緑色の長方形があり、「Hello world」という文字が含まれています。

<div id="green" style="background:green; width:80px;">
    Hello world
</div>
<div id="blue" style="width:100px;
  height:100px; background:blue;
  position:absolute;
  top:0; left:0; z-index:-1;">
</div>

この HTML と CSS は、次の表示リストを生成します。各セルは表示アイテムです。

ビューの背景 #blueのバックグラウンド #greenのバックグラウンド #green インライン テキスト
サイズが 800x600 で色が白の drawRect drawRect: サイズ 100x100、位置 0,0、色は青。 drawRect: サイズ 80x18、位置 8,8、色は緑。 drawTextBlob(位置 8,8、テキスト「Hello world」)。

ディスプレイ アイテムのリストは後ろから前に並べられます。上記の例では、DOM 順では緑の div が青の div より前に配置されていますが、CSS のペイント順序では、負の Z-Index の青い div が緑の div(ステップ 4.1)の前にペイントされる必要があります(ステップ 3)。ディスプレイ アイテムは、CSS ペイント順序仕様のアトミック ステップに対応しています。1 つの DOM 要素から複数の表示アイテムが作成されることがあります。たとえば、#green にインライン テキスト用のアイテムと、背景用のアイテムがあります。この粒度は、負のマージンによって作成されたインターリーブなど、CSS ペイント順序仕様の複雑さを完全に表すために重要です。

緑色の長方形に、グレーのボックスが部分的に重ねられ、「Hello world」と表示されています。

<div id="green" style="background:green; width:80px;">
    Hello world
</div>
<div id="gray" style="width:35px; height:20px;
  background:gray;margin-top:-10px;"></div>

これにより、次の表示リストが生成されます。各セルが表示アイテムです。

ビューの背景 #greenのバックグラウンド #grayのバックグラウンド #green インライン テキスト
drawRect(サイズ 800x600、色: White) drawRect: サイズ 80x18、位置 8,8、色は緑。 drawRect: サイズ 35x20、位置 8,16、色グレー。 drawTextBlob(位置 8,8、テキスト「Hello world」)。

ディスプレイ アイテム リストが保存され、後の更新で再利用されます。ペイント ツリー ウォーク中にレイアウト オブジェクトが変更されていない場合、そのディスプレイ アイテムは前のリストからコピーされます。追加の最適化は、CSS ペイント順序仕様のプロパティ(スタッキング コンテキストがアトミックにペイントされる)に依存しています。スタッキング コンテキスト内でレイアウト オブジェクトが変更されていない場合、ペイント ツリー ウォークはスタッキング コンテキストをスキップし、前のリストからディスプレイ アイテムのシーケンス全体をコピーします。

現在のプロパティ ツリー状態はペイント ツリー ウォーク中に維持され、ディスプレイ アイテム リストは、同じプロパティ ツリー状態を共有するディスプレイ アイテムの「チャンク」にグループ化されます。次の例で説明します。

傾いたオレンジ色の箱が入っているピンクの箱。

<div id="scroll" style="background:pink; width:100px;
   height:100px; overflow:scroll;
   position:absolute; top:0; left:0;">
    Hello world
    <div id="orange" style="width:75px; height:200px;
      background:orange; transform:rotateZ(25deg);">
        I'm falling
    </div>
</div>

これにより、次の表示リストが生成されます。各セルが表示アイテムです。

ビューの背景 #scrollのバックグラウンド #scroll インライン テキスト #orangeのバックグラウンド #orange インライン テキスト
サイズが 800x600 で色が白の drawRect drawRect: サイズ 100x100、位置 0,0、色ピンク。 drawTextBlob(位置 0,0、テキスト「Hello world」)。 drawRect(位置 0,0、サイズ 75×200、色: オレンジ色) drawTextBlob(位置 0,0、テキスト「I'm falling」)。

変換プロパティ ツリーとペイント チャンクは次のようになります(簡潔にするため簡略化しています)。

前の表の画像。チャンク 1 の最初の 2 つのセル、チャンク 2 の最初の 2 つのセル、チャンク 3 の最後の 2 つのセル。

ペイント チャンクの順序付きリスト(ディスプレイ アイテムとプロパティ ツリー状態のグループ)は、レンダリング パイプラインのレイヤ化ステップへの入力です。ペイント チャンクのリスト全体を 1 つの合成レイヤに統合して一緒にラスタライズすることもできますが、この場合、ユーザーがスクロールするたびに高負荷のラスタライズが必要になります。ペイント チャンクごとに合成レイヤを作成し、個別にラスタライズして、すべての再ラスタライズを回避することもできますが、GPU メモリがすぐに使い果たされます。レイヤ化のステップでは、GPU メモリと変更時の費用削減のトレードオフを行う必要があります。一般的なアプローチとしては、デフォルトでチャンクを統合し、コンポジタ スレッドで変更が予想されるプロパティ ツリー状態を持つペイント チャンクを統合しないことをおすすめします(コンポジタ スレッドのスクロールやコンポジタ スレッドの変換アニメーションなど)。

上記の例では、理想的には 2 つの合成レイヤが生成されます。

  • 描画コマンドを含む 800 x 600 の合成レイヤ:
    1. drawRect(サイズ 800x600、色: 白)
    2. drawRect: サイズ 100x100、位置 0,0、色ピンク
  • 描画コマンドを含む 144x224 の合成レイヤ:
    1. 位置 0,0 でテキスト「Hello world」の drawTextBlob
    2. 0.18 を翻訳
    3. rotateZ(25deg)
    4. drawRect(サイズ 75x200、位置 0,0、色オレンジ)
    5. drawTextBlob(位置 0,0、テキスト「I'm falling」)

ユーザーが #scroll をスクロールすると、2 番目の合成レイヤが移動されますが、ラスタライズは必要ありません。

として、プロパティ ツリーに関する前のセクションでは、ペイント チャンクが 6 つあります。プロパティ ツリー状態(変換、クリップ、エフェクト、スクロール)とともに、次のように分類されます。

  • ドキュメントの背景: ドキュメントのスクロール、ドキュメントのクリップ、ルート、ドキュメントのスクロール。
  • div の水平方向、垂直方向、スクロールの角(3 つの個別のペイント チャンク): ドキュメントのスクロール、ドキュメントのクリップ、#one ぼかし、ドキュメントのスクロール。
  • iframe #one: #one 回転、オーバーフロー スクロール クリップ、#one ぼかし、div スクロール。
  • iframe #two: #two 縮尺、ドキュメント クリップ、ルート、ドキュメントのスクロール。

コンポジタ フレーム: サーフェス、レンダリング サーフェス、GPU テクスチャ タイル

ブラウザ プロセスとレンダリング プロセスはコンテンツのラスタライズを管理し、コンポジタ フレームを Viz プロセスに送信して画面に表示します。コンポジター フレームは、ラスタライズされたコンテンツをどのようにつなぎ合わせて、GPU を使用して効率的に描画するかを表します。

タイル

理論上は、レンダリング プロセスまたはブラウザ プロセス コンポジタは、レンダラ ビューポートのフルサイズのピクセルを単一のテクスチャにラスタライズし、そのテクスチャを Viz に送信できます。ディスプレイ コンポジタは、その単一のテクスチャからフレーム バッファの適切な位置(画面など)にピクセルをコピーするだけで済みます。ただし、そのコンポーザが 1 ピクセルでも更新する場合は、ビューポート全体を再ラスタライズし、新しいテクスチャを Viz に送信する必要があります。

代わりに、ビューポートはタイルに分割されます。個別の GPU テクスチャ タイルが、ビューポートの一部のラスタ化されたピクセルで各タイルをバッキングします。レンダラは、個々のタイルを更新したり、既存のタイルの画面上の位置を変更したりできます。たとえば、ウェブサイトをスクロールすると既存のタイルの位置が上がるため、ページのより下にあるコンテンツ用に新しいタイルをラスタライズする必要があるのはまれです。

4 つのタイル。
この画像は、晴れた日の画像で、4 つのタイルがあります。 スクロールすると、5 つ目のタイルが表示されます。タイルの 1 つが 1 色(スカイブルー)のみで、その上に動画と iframe がある場合。

クアッドとサーフェス

GPU テクスチャ タイルは特別な種類の四角形です。これは、テクスチャのカテゴリを示すおしゃれな名前にすぎません。四角形は入力テクスチャを識別し、変換して視覚効果を適用する方法を指定します。たとえば、通常のコンテンツ タイルには、タイル グリッド内の x 座標と y 座標を示す変換があります。

GPU テクスチャ タイル。

これらのラスタライズされたタイルは、クワッドのリストであるレンダリング パスにラップされます。レンダリング パスにはピクセル情報は含まれません。代わりに、目的のピクセル出力を生成するために、各クワッドを描画する場所と方法に関する指示があります。GPU テクスチャタイルごとに描画クアッドがあります。ディスプレイ コンポーザは、指定された視覚効果で各四角形を描画し、レンダリング パスに必要なピクセル出力を生成するために、四角形のリストを反復処理するだけです。レンダリング パス用の描画クワッドの合成は、GPU で効率的に行うことができます。これは、GPU 機能に直接マッピングされる視覚効果が慎重に選択されているためです。

ラスター化されたタイル以外にも、描画四角形の種類があります。たとえば、テクスチャにまったく支えられていないソリッド カラー描画クワッドや、動画やキャンバス以外のテクスチャ用のテクスチャ描画クワッドがあります。

コンポジット フレームに別のコンポジット フレームを埋め込むこともできます。たとえば、ブラウザのコンポーザは、ブラウザ UI と、レンダリング コンポーザのコンテンツが埋め込まれる空の長方形を含むコンポーザ フレームを生成します。別の例として、サイト分離された iframe があります。このエンベディングは、サーフェスによって実現されます。

コンポーザがコンポーザ フレームを送信すると、サーフェス ID と呼ばれる識別子が付加され、他のコンポーザ フレームが参照によってそのフレームを埋め込むことができます。特定のサーフェス ID で送信された最新のコンポジタ フレームは、Viz によって保存されます。別のコンポジタ フレームは、後で Surface Draw クワッドを介してそれを参照できるため、Viz は描画対象を認識できます。(サーフェス描画四角形にはサーフェス ID のみが含まれ、テクスチャは含まれません)。

中間レンダリング パス

多くのフィルタや高度なブレンドモードなどの視覚効果では、2 つ以上の四角形を中間テクスチャに描画する必要があります。次に、中間テクスチャが GPU 上の宛先バッファ(または別の中間テクスチャ)に描画され、同時に視覚効果が適用されます。これを可能にするために、コンポジタ フレームにはレンダリング パスのリストが実際に含まれています。常にルート レンダリング パスがあり、これは最後に描画され、フレームバッファに対応する宛先があります。また、複数のパスがある場合もあります。

複数のレンダリング パスが存在する可能性があるため、このパスは「レンダリング パス」と呼ばれます。各パスは GPU で複数の「パス」で順番に実行する必要がありますが、単一のパスでは単一の超並列 GPU 計算で完了できます。

集計

複数のコンポジタ フレームが Viz に送信され、一緒に画面に描画する必要があります。これは、それらを単一の集約コンポジタ フレームに変換する集計フェーズによって実現されます。集計では、サーフェス描画クアッドに指定されたコンポジター フレームが置き換えられます。また、不要な中間テクスチャや画面外にあるコンテンツを最適化して削除することもできます。たとえば、多くの場合、サイトの分離された iframe のコンポジタ フレームは独自の中間テクスチャを必要とせず、適切な描画四角形を介してフレームバッファに直接描画できます。集約フェーズでは、このような最適化を特定し、個々のレンダラ コンポーザにアクセスできないグローバルな知識に基づいて適用します。

以下に、この記事の冒頭の例を表すコンポジタ フレームを示します。

  • foo.com/index.html サーフェス: id=0
    • レンダリング パス 0: 出力に描画します。
      • レンダリング パス描画四角形: 3 ピクセルのぼかしで描画し、レンダリング パス 0 にクリップします。
        • レンダリング パス 1:
          • #one iframe のタイル コンテンツの四角形を、それぞれ x 位置と y 位置を指定して描画します。
      • サーフェス描画クワッド: ID 2、スケールと平行移動変換で描画。
  • ブラウザ UI サーフェス: ID=1
    • レンダリング パス 0: 出力に描画します。
      • ブラウザ UI のクアッド(タイリングも)を描画する
  • bar.com/index.html サーフェス: ID=2
    • レンダリング パス 0: 出力に描画します。
      • #two iframe のコンテンツの四角形を、それぞれ x 位置と y 位置を指定して描画します。

イラスト: Una Kravets