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 有時可能會選擇顯示跨來源頁框 和父項頁框不同的轉譯程序

範例程式碼中有三個影格:

上層頁框 foo.com,包含兩個 iframe。

開啟網站隔離功能後,Chromium 會使用兩種轉譯程序轉譯這個網頁。 每個轉譯程序都會以個別方式呈現該網頁的頁框樹狀結構:

兩個影格樹狀結構,代表兩個轉譯程序。

其他程序轉譯的影格會顯示為遠端影格。 遠端影格擁有轉譯時做為預留位置所需的最低資訊。 例如維度 否則,遠端頁框就不會包含轉譯實際內容所需的任何資訊。

相對地,本機影格則代表通過標準的影格 轉譯管線本機頁框包含轉彎所需的所有資訊 您需要查看該頁框的資料 (例如 DOM 樹狀結構和樣式資料) 可以顯示及顯示的

轉譯管道會以 本機框架樹狀結構片段。 假設有一個較複雜的範例,以 foo.com 做為主要影格:

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

以及以下 bar.com 子頁框:

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

雖然現在只有一個轉譯器,但現在有三個本機影格 樹狀片段,兩個在轉譯程序中有兩個片段,分別為 foo.combar.com 的轉譯程序:

兩個轉譯結果和三個影格樹狀結構片段的表示法。

如要為網頁產生一個合成器頁框 Viz 同時向每個應用程式的根框架要求一個合成器影格 本機的三個頁框樹狀結構 匯總這些事件。 另請參閱合成器框架一節。

foo.com 主頁框和 foo.com/other-page 子頁框 屬於同一影格樹狀結構,並在同一程序中轉譯。 不過,這兩個影格仍各自獨立 文件生命週期 因為是本機框架樹狀結構中不同的部分 因此,在一次更新中無法同時產生兩個合成器框架。 轉譯程序提供的資訊不足 組合為 foo.com/other-page 產生的合成器框架 直接加入 foo.com 主影格的合成器影格中。 舉例來說,獨立程序 bar.com 上層頁框可能會影響 foo.com/other-url iframe 的顯示方式, 使用 CSS 來轉換 iframe,或是將 iframe 中的部分與 DOM 中的其他元素遮蔽。

視覺化屬性更新刊登序列

裝置縮放係數和可視區域大小等視覺屬性會影響轉譯後的輸出內容 且必須在本機框架樹狀結構之間同步。 每個本機框架樹狀結構片段的根都有一個相關聯的小工具物件。 視覺屬性更新會移至主要頁框的小工具,再正式生效 其他小工具

舉例來說,當可視區域大小改變時:

上文說明的程序圖表。

這項程序不會立即執行, 因此複製的視覺屬性也會包含同步權杖。 Viz 合成器會使用這個同步權杖等待所有本機影格樹狀結構片段 以目前同步權杖提交合成器框架。 這個程序可避免混合具有不同視覺屬性的合成器框架。

不可變更的片段樹狀結構

不可變更的片段樹狀結構是轉譯版面配置階段的輸出內容 這種模型通常已開放原始碼 可以透過自訂筆記本或管線微調代表頁面上所有元素的位置和大小 (未套用轉換)。

代表每個樹狀結構中的片段,一個片段標示為需要版面配置。

每個片段都代表一部分的 DOM 元素。 通常每個元素只會有一個片段 但列印時如果分割成多個頁面 或資料欄中的內容

版面配置後,每個片段都會變成不可變更,且永遠不會再變更。 重要的是,我們也設有一些額外的限制。我們不會採取以下做法:

  • 允許任何「向上」樹狀結構中的參照 (子項不能有指向父項的指標)。
  • 「泡泡」樹狀圖 (子項只會讀取其子項的資訊,而非從父項讀取資訊)。

這些限制讓我們可以將片段重複用於後續的版面配置。 少了這些限制,我們就得經常重新產生整個樹狀結構,這種方式所費不貲。

大多數版面配置通常是漸進式更新,例如: 網頁應用程式會隨著使用者點擊元素而更新一小部分的 UI。 在理想情況下,版面配置應該只根據畫面上實際變更的內容按比例運作。 我們可以盡量重複使用前一個樹狀結構的更多部分,實現此目標。 這表示 (通常) 我們只需要重新構建樹木的脊椎。

日後這種不可變動的設計 例如視需要跨執行緒邊界傳遞不可變的片段樹狀結構 (在不同的執行緒上執行後續階段)、 來產生多個樹狀結構,以便呈現順暢的版面配置動畫 或執行平行推測版面配置 這也讓我們能利用多執行緒版面配置本身。

內嵌片段項目

內嵌內容 (樣式文字主要) 採用的呈現方式略有不同。 與其使用含有方塊和指標的樹狀結構 我們都會以代表樹狀結構的平面清單呈現內嵌內容。 主要優點是內嵌清單表示快速且快速 且可用於檢查或查詢內嵌資料結構 並提高記憶體的效率 這對於網頁轉譯效能至關重要 因為文字顯示程序非常複雜 並輕易成為管道最慢的部分。

系統會為每個 內嵌格式設定結構定義 按照其內嵌版面配置子樹狀結構的深度優先搜尋順序排序。 清單中的每個項目都是元組 (物件、子系數量)。 以這個 DOM 為例:

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

width 屬性設為 0,讓該行在「Hi」之間換行和「該位置」

如果這種情況的內嵌格式設定內容以樹狀結構表示, 如下所示:

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

扁平清單看起來像這樣:

  • (線條方塊, 2)
  • (方塊 <span>、1)
  • (傳送文字「Hi」的 0)
  • (線條方塊, 3)
  • (方塊 <b>、1)
  • (傳送文字「the」,0)
  • (文字「.」,0)

這類資料結構有許多取用者,例如無障礙功能 API、 和幾何圖形 API getClientRects、 和 contenteditable。 每種方式的規定各有不同。 這些元件可透過便利遊標存取平面資料結構。

遊標 含有 MoveToNextMoveToNextLineCursorForChildren 等 API。 這種遊標表示法非常適合用於文字內容,原因如下:

  • 依深度優先搜尋順序疊代處理速度非常快。 這與插入點動作類似,因此經常使用。 由於這是平面清單,因此深度優先搜尋只會增加陣列的偏移量。 可提供快速的疊代和記憶體本地性
  • 這項服務提供廣泛優先的搜尋, 例如, 繪製線條和內嵌方塊的背景
  • 知道子系的數量後,就能快速移動到下一手 (只要以該數字遞增陣列偏移即可)。

物業樹狀結構

DOM 是元素 (加上文字節點) 的樹狀結構,CSS 可以套用多種 為每個元素設定樣式

這有四種顯示方式:

  • 版面配置:版面配置限制演算法的輸入內容。
  • 繪製:如何繪製及光柵元素 (但不適用於子系)
  • 視覺效果:套用至 DOM 子樹狀結構的光柵/繪圖效果。 例如轉換、篩選器和裁剪
  • 捲動:以軸對齊和圓角 裁剪及捲動內含的子樹狀結構。

屬性樹狀結構是資料結構,用於說明視覺效果和捲動效果如何套用至 DOM 元素。 能引導你回答下列問題:地點、地點、 是給定 DOM 元素 版面配置大小和位置? 以及:如要套用視覺效果和捲動效果,應使用哪一系列 GPU 作業?

網路上的視覺效果和捲動效果非常複雜, 屬性樹狀結構最重要的是 整合為單一資料結構,能精確反映資料的結構和意義 同時消除 DOM 和 CSS 的其他複雜度 如此一來,我們就能實作演算法,更安心地進行合成和捲動。請特別注意以下幾點:

  • 可能容易出錯的幾何圖形和其他計算結果 都能集中管理
  • 建立及更新屬性樹狀結構的複雜度 都隔離到一個轉譯管道階段
  • 相較於完整的 DOM 狀態,將屬性樹狀結構傳送至不同的執行緒和程序,會更加簡單快速。 因此,您可以將其用於各種用途。
  • 應用實例越多 若能從建構基礎的幾何圖形快取中 獲得越多好處 因為使用者可以重複使用快取。

RenderingNG 會將屬性樹狀結構用於許多用途,包括:

  • 將顏料與顏料分開,並從主要執行緒進行合成。
  • 決定最佳的組合 / 繪圖策略。
  • 測量中 IntersectionObserver 幾何圖形
  • 避免處理螢幕外元素和 GPU 紋理圖塊。
  • 有效且精準地撤銷顏料和光柵。
  • 測量中 版面配置位移及 Core Web Vitals 中的 largest Contentful Paint

每個網頁文件都有四個不同的屬性樹狀結構:轉換、剪輯、效果和捲動(*)。 轉換樹狀結構代表 CSS 轉換和捲動。 (捲動轉換會以 2D 轉換矩陣表示)。 裁剪樹 溢位短片。 特效樹代表了透明度、濾鏡、遮罩、 混合模式,以及夾扣路徑等其他片段 捲動樹狀結構,代表捲動相關資訊 例如捲動網頁 鏈結; 必須在合成器執行緒上執行捲動作業。 屬性樹狀結構中的每個節點,都代表由 DOM 元素套用的捲動或視覺效果。 如果是多個效果 同一元素的每個樹狀結構中可以有多個屬性樹狀結構節點。

每個樹狀圖的拓撲就像是 DOM 的稀疏表示法。 舉例來說,假設有三個 DOM 元素含有溢位片段 就會有三個夾木節點 裁剪樹的結構會位於 溢位片段之間的包含區塊關係 樹狀圖之間也有連結。 這些連結會指出相關的 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 內嵌文字
drawRect,尺寸為 800x600,顏色為白色。 drawRect 大小為 100x100 (位置 0,0),顏色為藍色。 drawRect 大小為 80x18 的位置 8,8,顏色為綠色。 drawTextBlob 取代為位置 8,8,並且顯示「Hello World」文字。

這個顯示項目清單是以後方排序。 在上述範例中,綠色 div 之前在 DOM 順序出現藍色 div 之前。 但 CSS 繪製順序要求負的 Z-index 藍 div 繪製順序 before (步驟 3) 綠色 div (步驟 4.1)。 顯示項目大致相當於 CSS 繪製順序規格中的不可分割步驟。 單一 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,顏色為白色。 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 內嵌文字
drawRect,尺寸為 800x600,顏色為白色。 drawRect 大小為 100x100,位置為 0,0,顏色為粉紅色。 drawTextBlob 以位置 0,0 表示,並且顯示「Hello World」文字。 drawRect 的大小為 75x200,位置為 0,0,顏色為橘色。 drawTextBlob 位置為 0,0,且文字「I'm Falling」。

轉換屬性樹狀結構和繪製區塊就會 (為求簡潔而簡化):

上表圖片,區塊 1 中的前兩個儲存格,區塊 2 中的第三個儲存格,是區塊 3 中的最後一個兩個儲存格。

顏料塊的順序清單 也就是顯示項目群組及屬性樹狀結構狀態 是轉譯管道分層步驟的輸入內容 整份油漆區塊清單可以合併成單一合成圖層,然後光柵化, 但這需要在每次使用者捲動畫面時耗用大量光柵化作業。 可以為每個顏料區塊建立複合圖層 光柵化和光柵化,以避免所有重新光柵化,但這樣會快速耗盡 GPU 記憶體。 分層步驟必須在 GPU 記憶體之間取得平衡,並降低情況發生變化時的費用。 常見的做法是預設合併區塊 而不是合併具有預期在合成器執行緒上變更屬性樹狀結構狀態的繪製區塊。 例如 Compositor-thread 捲動,或 Compositor-thread 轉換動畫。

上述範例在理想情況下應產生兩個複合層:

  • 包含繪圖指令的 800x600 合成圖層:
    1. drawRect,尺寸為 800x600,顏色為白色
    2. drawRect,大小為 100x100 (位置為 0,0),顏色粉紅色
  • 144x224 包含繪圖指令的合成圖層:
    1. drawTextBlob 位置為 0,0,文字「Hello world」
    2. 翻譯 0,18
    3. rotateZ(25deg)
    4. drawRect 大小為 75x200,位置為 0,0,顏色為橘色
    5. drawTextBlob 位置為 0,0,搭配「I'm Falling」文字

如果使用者捲動 #scroll 則會移動第二個合成圖層,但不需要光柵化。

例如 如先前章節所述 有六個顏料塊 結合它們 (轉換、片段、效果、捲動) 的屬性樹狀結構狀態,如下所示:

  • 文件背景:文件捲動、文件片段、根層級、文件捲動
  • div 的水平、垂直和捲動角落 (三個不同的繪製區塊): 文件捲動畫面,文件片段,#one 模糊處理,文件捲動。
  • iframe #one#one 旋轉、溢位捲動短片、#one 模糊、div 捲動。
  • iframe #two:縮放 #two、文件片段、根層級、文件捲動。

合成器頁框:表面、算繪表面和 GPU 紋理圖塊

瀏覽器和算繪程序可管理內容的光柵化作業, 然後將合成器影格提交至 Viz 處理過程,以呈現在畫面上。 合成框架可表示如何將光柵化內容拼接在一起 並以 GPU 有效率地繪製圖片

資訊方塊

理論上 轉譯程序或瀏覽器程序合成器可以光柵化像素 將紋理上傳至單一紋理,並與轉譯器可視區域的原尺寸合併,再將該紋理提交至 Viz。 如要顯示這組版面配置,只需複製像素 從該單一紋理轉移至影格緩衝區中的適當位置 (例如螢幕)。不過,如果該合成器想要更新 一個像素,就需要重新將整個可視區域的光柵化,然後提交新的紋理給 Viz。

而是將可視區域分割成多個圖塊。 獨立的 GPU 紋理圖塊會傳回每個圖塊,可視區域的部分採用光柵化像素。 接著,轉譯器可以更新個別圖塊,甚至還能 只需變更現有動態磚在螢幕上的位置即可。 舉例來說,捲動瀏覽網站時 現有圖塊的位置會上移,但有時只有 新的圖塊需要經過光柵化,才會出現在頁面更下方的內容。

四個圖塊。
這張圖片顯示陽光日的圖片,並有四個圖塊。 當捲動發生時,第五個資訊方塊就會開始顯示。 其中一個圖塊只剩下一種顏色 (天空藍), 上方有一個影片和 iframe。

四區和表面

GPU 紋理圖塊是一種特殊的「四」、 這只是某種紋理或另一種類別的紋理名稱。 四捨五入會識別輸入紋理,並指出如何轉換及套用視覺效果。 例如,一般內容圖塊會有轉換,在圖塊格線中指出其 x, y 位置。

GPU 紋理圖塊。

這些光柵化圖塊會包裝在「算繪通道」中,也就是四捨五入清單。 算繪通道不含任何像素資訊 而是提供指示,說明如何繪製每個四邊形,以產生所需的像素輸出。 每個 GPU 紋理圖塊都有繪圖四分之一。 顯示合成器只需要反覆執行四邊數清單 套用特定視覺特效 為算繪通道產生所需的像素輸出內容 您可在 GPU 上有效率地編寫算繪通道的繪製方程式 因為我們精心挑選能直接對應至 GPU 功能的視覺特效。

除了光柵化圖塊之外,還有其他類型的繪製四邊形。 舉例來說,有些單色繪製序列完全不受紋理支援, 或使用紋理繪製四邊形 (適用於影片或畫布等非圖塊紋理)。

合成器框架也可以嵌入另一個合成器框架。 舉例來說,瀏覽器合成器會使用瀏覽器 UI 產生合成器框架。 以及要嵌入算繪合成器內容的空白矩形。 另一個例子是網站隔離的 iframe。這個嵌入是透過「介面」完成。

合成器提交合成器畫面時,會隨附 ID、 稱為介面 ID,可讓其他合成器頁框透過參照方式嵌入這個 ID。 使用特定表面 ID 提交的最新合成器畫面是由 Viz 儲存。 隨後,另一個合成器框架即可透過表面繪製四邊形參照。 這樣 Viz 就知道該繪製什麼內容。 (請注意,表面繪製四邊形僅包含表面 ID,不含紋理)。

中間算繪傳遞

例如多種濾鏡或進階混合模式 需要將兩個以上的四邊序列繪製到中繼紋理。 接著,中繼紋理會繪製到 GPU 上的目的地緩衝區 (或可能是其他中繼紋理)。 同時套用視覺效果 為此,合成器框架實際上包含算繪通道清單。 通常都會有根轉譯通道 是最後繪製的,其目的地與影格緩衝區對應 您或許還能

可能會有多個算繪通道 「算繪通道」每個票證都必須在 GPU 上依序執行,並於多個「傳遞」中 單次傳遞則能透過單一大量平行的 GPU 運算完成。

匯總

系統會將多個合成器影格提交至 Viz。 而需要把它們和畫面一起繪製在螢幕上 方法是透過匯總階段將其轉換為單一 匯總 LLM 回應程序 匯總會依照自身指定的合成器框架取代表面繪製四邊形。 您也能藉此機會改善非必要的中繼紋理或畫面外的內容。 舉例來說,在許多情況下,網站獨立 iframe 的合成器頁框 不需要自己的中繼紋理 並透過適當的繪製四邊形直接繪製到影格緩衝區。 匯總階段會設法找出這類最佳化作業 並依據個別轉譯合成器無法存取的全球知識套用這些知識。

範例

以下是合成器影格,代表從 這篇文章。

  • foo.com/index.html 途徑:id=0
    • 算繪傳遞 0:繪製至輸出內容。
      • 算繪通道繪製四邊形:使用 3 像素的模糊效果繪圖,並將片段剪輯至算繪通道 0。
        • 顯示通行證 1:
          • 針對 #one iframe 的圖塊內容繪製序列,每個方塊都有 x 和 y 位置。
      • 表面繪製四分之一:以 ID 2 繪製,以縮放和平移轉換功能繪製。
  • 瀏覽器使用者介面介面:ID=1
    • 算繪通道 0:繪製到輸出內容。
      • 繪製瀏覽器使用者介面的四邊形 (同時並排)
  • bar.com/index.html 途徑:ID=2
    • 算繪傳遞 0:繪製至輸出內容。
      • 針對 #two iframe 的內容繪製序列,每個物件都有 x 和 y 位置。

插圖:Una Kravets。