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

このシリーズの以前の投稿では、RenderingNG アーキテクチャの目標、主なプロパティコンポーネントの概要の概要について説明しました。それでは、レンダリング パイプラインへの入力と出力となる主要なデータ構造を詳しく見ていきましょう。

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

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

これらのデータ構造を説明する前に、以前の投稿のデータ構造を基に構築される次の簡単な例を紹介します。データ構造がどのように適用されるかを示す この投稿ではこの例を数回使用します

<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 つになりました。このフラグメントは、foo.com のレンダリング プロセスで 2 つ、bar.com のレンダリング プロセスに 1 つあります。

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

ウェブページ用の 1 つのコンポジタ フレームを生成するために、Viz は 3 つのローカル フレームツリーそれぞれのルートフレームからコンポジタ フレームを同時にリクエストし、それらを集計します。(後述のコンポジタ フレームのセクションもご覧ください)。

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

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

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

前のテキストで説明したプロセスの図。

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

不変フラグメント ツリー

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

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

各フラグメントは DOM 要素の一部を表します。通常、要素ごとにフラグメントは 1 つだけですが、出力時に複数のページに分割する場合や、複数列のコンテキストの場合は列に分割する場合は、複数存在する可能性があります。

レイアウトの後、各フラグメントは不変になり、変更されることはありません。重要な点として、さらにいくつかの制限も適用されます。Google がしないこと:

  • ツリー内の「上」参照をすべて許可します。 (子は、その親へのポインタを持つことはできません)。
  • データをツリーの下側に「バブル」させます(子は、親からではなく、子からのみ情報を読み取ります)。

この制限により、後続のレイアウトでフラグメントを再利用できます。 このような制限がなければ、多くの場合、ツリー全体を再生成する必要があり、コストがかかります。

通常、ほとんどのレイアウトは増分アップデートです。たとえば、ウェブアプリの場合は、ユーザーによる要素のクリックに応じて UI の一部を更新します。理想的には、レイアウトは画面上で実際に変更された内容に比例して機能するようにします。これは、前のツリーをできるだけ多く再利用することで実現できます。つまり、通常は木の背骨を再構築するだけで済みます。

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

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

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

興味深い歴史的メモです。これは、当初はテキスト エディタと同様の方法で構築されていた Internet Explorer が以前 DOM を表現していた方法と非常によく似ています。

フラットリストは、インライン レイアウト サブツリーの深度優先検索順に、インライン書式設定コンテキストごとに作成されます。リスト内の各エントリは (object, number 子孫) のタプルです。たとえば、次の 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)
  • (ボックス <span>、1)
  • (「こんにちは」とテキスト 0 で送信)
  • (ラインボックス、3)
  • (ボックス <b>、1)
  • (テキスト「そこ」、0)
  • (テキスト "."、0)

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

カーソルには、MoveToNextMoveToNextLineCursorForChildren などの API があります。このカーソル表現はテキスト コンテンツに対して非常に強力で、次のような複数の理由があります。

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

プロパティ ツリー

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

効果には、主に 4 種類あります。

  • Layout: レイアウト制約アルゴリズムへの入力。
  • ペイント: 要素(子孫ではない)をペイントしてラスターする方法。
  • ビジュアル: DOM サブツリーに適用されるラスター/描画効果(変換、フィルタ、クリッピングなど)。
  • スクロール: 含まれているサブツリーの、軸に揃えられた角の丸みのクリップとスクロール。

プロパティ ツリーは、視覚効果とスクロール効果が DOM 要素にどのように適用されるかを説明するデータ構造です。特定の DOM 要素は、そのレイアウト サイズと位置が画面に対してどこにあるか、といった疑問に答える手段を提供します。また、視覚効果やスクロール効果を適用するには、GPU 操作のシーケンスをどのように行うべきでしょうか。

ウェブにおける視覚効果とスクロール効果は、その本来の美しさは非常に複雑です。プロパティ ツリーが行う最も重要なことは、その複雑さを、構造と意味を正確に表す単一のデータ構造に変換すると同時に、DOM と CSS のその他の複雑さを取り除くことです。これにより、より信頼性の高い合成とスクロールのアルゴリズムを実装できます。具体的には、次のとおりです。

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

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

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

すべてのウェブ ドキュメントには、transform、clip、作用、スクロールという 4 つの個別のプロパティ ツリーがあります(*)。変換ツリーは CSS 変換とスクロールを表します。(スクロール変換は 2D 変換行列として表されます)。クリップツリーはオーバーフロー クリップを表します。エフェクト ツリーは、他のすべての視覚効果(不透明度、フィルタ、マスク、ブレンド モード、クリップパスなどのクリップ)を表します。スクロールツリーは、スクロールがどのようにチェーンしているかなど、スクロールに関する情報を表します。コンポジタ スレッドでスクロールを実行する必要があります。プロパティ ツリー内の各ノードは、DOM 要素によって適用されたスクロールまたは視覚効果を表します。複数の効果が発生する場合は、同じ要素の各ツリーに複数のプロパティ ツリー ノードが存在する可能性があります。

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

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

出典

<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 インライン テキスト
drawRect(サイズ: 800x600、色: 白)。 位置 0,0 にサイズが 100x100、色が青の drawRect 位置 8,8 のサイズが 80x18、色が緑色である drawRect 位置が 8、8、テキスト「Hello world」の drawTextBlob

表示アイテムリストは前から並べられます。 上記の例では、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、色: 白)。 位置 8,8 のサイズが 80x18、色が緑色である drawRect drawRect(サイズが 35x20、位置が 8、16、色がグレー)。 位置が 8、8、テキスト「Hello world」の drawTextBlob

表示アイテムリストは保存され、その後の更新で再利用されます。ペイント ツリー ウォーク中にレイアウト オブジェクトが変更されていない場合、そのディスプレイ アイテムは前のリストからコピーされます。さらに最適化を行うには、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 インライン テキスト
drawRect(サイズ: 800x600、色: 白)。 位置 0,0 にサイズが 100x100、色がピンクの drawRect 位置が 0,0 でテキスト「Hello world」の drawTextBlob 位置 0,0 にサイズが 75x200、色がオレンジ色の drawRect 位置が 0,0 で「I'mfalling」というテキストが設定された drawTextBlob

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

前の表の画像。最初の 2 つのセルはチャンク 1、3 番目はチャンク 2、最後の 2 つのセルはチャンク 3 にあります。

ペイント チャンクの順序付きリストは、表示アイテムのグループとプロパティ ツリー状態であり、レンダリング パイプラインのレイヤ化ステップへの入力です。ペイント チャンクのリスト全体を 1 つの合成レイヤに統合して一緒にラスタライズすることもできますが、この場合、ユーザーがスクロールするたびにラスタライズのコストが高くなります。ペイント チャンクごとに合成レイヤを作成し、すべての再ラスタライズを回避するために個別にラスタライズすることもできますが、この場合、GPU メモリが急速に枯渇します。階層化のステップでは、GPU メモリと物事の変化時のコスト削減との間でトレードオフを考慮する必要があります。一般的に推奨されるアプローチは、デフォルトでチャンクをマージし、コンポジタ スレッドのスクロールやコンポジタ スレッドの変換アニメーションなど、コンポジタ スレッドで変化すると想定されるプロパティ ツリー状態を持つペイント チャンクをマージしないことです。

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

  • 描画コマンドを含む 800x600 の合成レイヤ:
    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. 位置が 0,0 で「転倒」というテキストが設定された drawTextBlob

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

こちらの例では、前のセクションのプロパティ ツリーでは、6 つのペイント チャンクがあります。(変形、クリップ、効果、スクロール)プロパティ ツリーの状態と合わせて、次のようになります。

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

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

以前の投稿(実際の例はこちら)で説明したように、ブラウザ プロセスとレンダリング プロセスはコンテンツのラスタライズを管理し、画面に表示するためにコンポジタ フレームを Viz プロセスに送信します。コンポジタ フレームは、RenderingNG がラスタライズされたコンテンツをつなぎ合わせ、GPU を使用して効率的に描画する方法を表します。

タイル

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

代わりに、ビューポートはタイルに分割されます。個別の GPU テクスチャ タイルが、ビューポートの一部分のラスタライズされたピクセルとともに各タイルの背後に配置されます。レンダラは、個々のタイルを更新するか、既存のタイルの画面上の位置を変更するだけで済みます。たとえば、ウェブサイトをスクロールすると、既存のタイルの位置が上に移動しますが、ページの下の方のコンテンツのために新しいタイルのラスタライズが必要になることはまれです。

4 つのタイル。

上の画像は、晴れた日の画像を 4 つのタイルで示したものです。 スクロールが発生すると、5 番目のタイルが表示され始めます。タイルの 1 つに単色(スカイブルー)のみが表示され、上部に動画と iframe が配置されています。それが次のトピックにつながります。

クワッドとサーフェス

GPU テクスチャ タイルは特別な種類のクワッドです。クワッドとは、あるテクスチャのカテゴリを表す華やかな名前です。クワッドは入力テクスチャを識別し、そのテクスチャを変換して視覚効果を適用する方法を示します。たとえば、通常のコンテンツ タイルには、タイルグリッド内の x 位置と y 位置を示す変換があります。

GPU テクスチャ タイル。

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

ドロークワッドには、ラスタライズド タイル以外にもタイプがあります。たとえば、テクスチャをまったくベースにしない単色の描画クワッドや、動画やキャンバスなどのタイル以外のテクスチャ用のテクスチャ描画クワッドがあります。

また、コンポジタ フレームに別のコンポジタ フレームを埋め込むこともできます。 たとえば、ブラウザ コンポジタはブラウザ UI を含むコンポジタ フレームと、レンダリング コンポジタ コンテンツが埋め込まれる空の長方形を生成します。別の例として、サイト分離 iframe があります。この埋め込みは、サーフェスを使用して行われます。

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

中間レンダリング パス

多くのフィルタや高度なブレンドモードなど、一部の視覚効果では、2 つ以上のクワッドを中間テクスチャに描画する必要があります。次に、中間テクスチャが GPU(または別の中間テクスチャ)のデスティネーション バッファに描画され、視覚効果が同時に適用されます。そのために、コンポジタ フレームには実際にレンダリング パスのリストが含まれています。ルート レンダリング パスは常に存在し、最後に描画され、そのデスティネーションがフレーム バッファに対応します(他にもルート レンダリング パスが存在する場合があります)。

「レンダリング パス」は、複数のレンダリング パスが存在する可能性があることから始まります。各パスは GPU 上で複数の「パス」で順次実行する必要がありますが、1 つのパスは単一の超並列 GPU 計算で完了できます。

集計

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

以下は、この投稿の冒頭で取り上げた例を表す実際のコンポジタ フレームです。

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

おわりに

ご精読ありがとうございました。 前の 2 回の投稿とあわせて RenderingNG の概要は終了です次は、レンダリング パイプラインの多くのサブコンポーネントにおける課題とテクノロジーを、最初から最後まで深く掘り下げます。近日中に対応する予定です。

イラスト: Una Kravets 氏