轉譯 NG 架構

Chris Harrelson
Chris Harrelson

您可以在這裡瞭解 RenderingNG 元件的設定方式,以及轉譯管道的流程。

從最高層級開始,轉譯工作如下:

  1. 將內容轉譯為螢幕上的像素。
  2. 為內容加入動畫效果
  3. 捲動以回應輸入。
  4. 有效率地將路徑輸入內容轉送至正確的位置,讓開發人員指令碼和其他子系統能做出回應。

要轉譯的內容是每個瀏覽器分頁的頁框樹狀結構,以及瀏覽器介面。以及來自觸控螢幕、滑鼠、鍵盤和其他硬體裝置的原始輸入事件。

每個畫面都包含:

  • DOM 狀態
  • CSS
  • 面板
  • 外部資源,例如圖片、影片、字型和 SVG

頁框是指 HTML 文件及其網址。 透過瀏覽器分頁載入的網頁具有頂層頁框、頂層文件的每個 iframe 的子頁框,以及遞迴 iframe 子系。

視覺效果是指套用至點陣圖的圖形運算,例如捲動、轉換、剪輯、濾鏡、不透明度或混合。

架構元件

在 RenderingNG 中,這些工作會按照邏輯分割為多個階段與程式碼元件。這些元件會歸入這些執行緒中的各種 CPU 程序、執行緒和子元件。在網路內容的可靠性可擴充效能擴充性方面,每種類型都發揮了重要作用。

轉譯管道結構

轉譯管道圖表。
箭頭表示各階段的輸入和輸出內容。階段會以顏色標示,展示這些階段執行的執行緒或程序。在某些情況下,視實際情況而定,階段可能會在多個位置執行,這也是為何某些採用兩種顏色的原因。綠色階段轉譯程序主要執行緒;黃色代表轉譯程序合成器;橘色階段是指視覺程序。

轉譯作業在管道中繼續進行,過程中會有多個階段與構件。每個階段都代表程式碼,在轉譯作業中執行一項定義明確的工作。構件是階段的輸入或輸出內容「資料結構」

階段如下:

  1. Animate:根據宣告式時間軸變更計算樣式,並隨著時間修改屬性樹狀結構
  2. 樣式:將 CSS 套用至 DOM,並建立運算樣式
  3. 版面配置:決定畫面上的 DOM 元素大小和位置,並建立不可變動的片段樹狀結構
  4. 預先繪製:運算屬性樹狀結構,並視情況撤銷任何現有的顯示清單和 GPU 紋理圖塊
  5. 捲動:變更屬性樹狀結構,藉此更新文件和可捲動 DOM 元素的捲動偏移。
  6. 繪製:計算顯示清單,說明如何從 DOM 光柵 GPU 紋理圖塊。
  7. 「Commit」:將屬性樹狀結構和顯示清單複製到合成器執行緒。
  8. 「Layerize」:將顯示清單拆分為複合圖層清單,以便執行獨立的光柵化和動畫。
  9. 光柵、解碼和繪製工作程式:將顯示清單、已編碼的圖片和油漆工組程式碼分別轉換成 GPU 紋理圖塊
  10. 「Activate」(啟動):建立合成器框架,代表如何在畫面上繪製 GPU 圖塊並加上任何視覺效果。
  11. 「Aggregate」(匯總):將所有可見的合成器影格中的合成器影格合併,成為單一全域合成器框架。
  12. 繪製:在 GPU 上執行匯總合成器影格,在畫面上建立像素。

如不需要,可以略過轉譯管道階段。舉例來說,視覺效果和捲動的動畫可以略過版面配置、預先繪製和繪製動作。因此在圖表中,動畫和捲動會標上黃色和綠色的點。如果版面配置、預先繪製和繪畫作業可以略過,則可以在合成器執行緒上完全執行,並略過主執行緒。

此處不會直接描述瀏覽器 UI 轉譯,但可以想成是同一個管道的簡化版本 (事實上,它的實作會共用大部分的程式碼)。影片 (也未直接描述) 一般會使用獨立的程式碼進行轉譯,將影格解碼為 GPU 紋理圖塊,然後插入合成器影格和繪圖步驟。

程序和執行緒結構

CPU 程序

使用多個 CPU 程序可在網站與瀏覽器狀態之間實現效能與安全性隔離,以及與 GPU 硬體隔離穩定性和安全性。

CPU 處理程序各部分的圖表

  • 轉譯程序會轉譯、動畫、捲動及路徑單一網站和分頁組合的輸入內容。共有幾種轉譯程序,
  • 瀏覽器程序會轉譯、動畫及轉送瀏覽器 UI 的輸入項目 (包括網址列、分頁標題和圖示),並將所有剩餘輸入轉送至適當的轉譯程序。只有一個瀏覽器程序。
  • 「Viz 程序」匯總多個轉譯程序以及瀏覽器程序的組合。使用 GPU 光柵和繪圖。系統提供一個 Viz 程序。

不同的網站最終會經歷不同的轉譯程序。

同一網站的多個瀏覽器分頁或視窗通常會進入不同的轉譯程序,除非分頁有相關的關聯,例如一個分頁開啟另一個分頁。由於電腦版 Chromium 的記憶體壓力過大,可能會將同一個網站的多個分頁放到同一個轉譯程序,即使兩者無關也一樣。

在單一瀏覽器分頁中,不同網站的影格一律會有不同的轉譯程序,但同一個網站的影格一律屬於同一個轉譯程序。從轉譯的角度來看,多個轉譯程序的重要優點是,跨網站 iframe 和分頁會彼此隔離效能。此外,來源可以啟用進一步隔離措施

所有 Chromium 只有一個 Viz 程序,因為通常只有一個 GPU 和畫面可以繪製。

將 Viz 與其他處理程序進行區隔,會導致 GPU 驅動程式或硬體發生錯誤時,穩定性會有所提升。此外,也很適合用於隔離安全性,這對 Vulkan一般來說的安全性等 GPU API 至關重要。

由於瀏覽器可以有許多分頁和視窗,且所有視窗和視窗都有可繪製的瀏覽器 UI 像素,您可能會好奇:為什麼瀏覽器只有一個程序?原因在於,只有一個物件只專注於;實際上,看不到的瀏覽器分頁大多會停用,並捨棄所有 GPU 記憶體。不過,在轉譯程序 (也稱為 WebUI) 中,我們已逐漸導入複雜的瀏覽器 UI 轉譯功能。這並非因為效能隔離的因素,而是為了輕鬆使用 Chromium 的網頁轉譯引擎。

在較舊的 Android 裝置上,在 WebView 中使用時,系統會共用轉譯和瀏覽器程序 (這通常不適用於 Android 上的 Chromium,僅適用於 WebView)。在 WebView 中,瀏覽器程序也會與嵌入應用程式共用,而 WebView 只有一個轉譯程序。

有時也有公用程式程序可以解碼受保護的影片內容。 上述圖表並未說明這項程序。

執行緒

不管是緩慢工作、管道平行處理和多個緩衝區,執行緒都有助於維持效能隔離和回應速度。

轉譯程序的圖表。

  • 主要執行緒會執行指令碼、轉譯事件迴圈、文件生命週期、命中測試、指令碼事件分派,以及 HTML、CSS 和其他資料格式剖析。
    • 主執行緒輔助程式會執行多項工作,例如建立需要編碼或解碼的圖片點陣圖和 blob。
    • Web Workers 會執行指令碼,以及 OffscreenCanvas 的轉譯事件迴圈。
  • 合成器執行緒會處理輸入事件、執行網頁內容的捲動和動畫、計算最佳的網頁內容分層,並協調圖片解碼、繪製工作程式和光柵工作。
    • 合成器執行緒輔助程式會協調 Viz 光柵工作,並執行圖片解碼工作、繪製工作程式和備用光柵。
  • 媒體、demuxer 或音訊輸出執行緒,可用於解碼、處理及同步處理影片和音訊串流。(請記住,影片會與主要轉譯管道平行執行)。

將主要和合成器執行緒區隔,對於動畫及捲動與主要執行緒作業之間的效能隔離而言非常重要。

每個轉譯程序只有一個主要執行緒,但同一個網站的多個分頁或頁框可能會透過同一個程序執行。不過,也會隔離不同瀏覽器 API 的效能。舉例來說,在 Canvas API 中產生圖片點陣圖和 blob 時,會在主執行緒輔助執行緒中執行。

同樣地,每個轉譯程序只會有一個合成器執行緒。這通常不構成只有一個問題,因為合成器執行緒上的所有昂貴作業都會委派給合成器工作站執行緒或 Viz 程序,而這項工作可以透過輸入轉送、捲動或動畫同時完成。合成器工作站執行緒會協調在 Viz 程序中執行的工作,但 GPU 加速功能可能會因 Chromium 無法控制的原因 (例如驅動程式錯誤) 而失敗。在這種情況下,背景工作執行緒會在 CPU 上以備用模式執行工作。

合成器工作站執行緒數量取決於裝置功能。舉例來說,電腦通常會使用較多執行緒,因為執行緒的 CPU 核心更多,且電池受限的情況比行動裝置少。此為向上擴充及縮減的範例。

轉譯程序執行緒架構是套用三種不同最佳化模式的應用方式:

  • 輔助執行緒:將長時間執行的子工作傳送到其他執行緒,以便讓父項執行緒同時回應其他要求。主執行緒輔助程式和合成器輔助執行緒是這項技巧的絕佳範例。
  • 多重緩衝處理:在轉譯新內容時顯示先前轉譯的內容,以隱藏轉譯延遲時間。合成器執行緒會使用這項技巧。
  • 管道平行處理:在多個位置同時執行轉譯管道。這就是捲動和動畫的速度。即使發生主執行緒轉譯更新,捲動和動畫也可以同時執行。

瀏覽器處理程序

瀏覽器程序圖表,顯示轉譯和撰寫執行緒之間的關係,以及轉譯和合成執行緒輔助程式。

  • 轉譯和合成執行緒會回應瀏覽器 UI 中的輸入,將其他輸入內容轉送至正確的轉譯程序,並配置和繪製瀏覽器 UI。
  • 轉譯和組合執行緒輔助程式會執行圖片解碼工作,以及備用光柵或解碼。

瀏覽器程序的轉譯和合成執行緒與轉譯程序的程式碼和功能類似,差別在於主要執行緒和合成器執行緒會合併為單一執行緒。在本例中,只需要一個執行緒,因為設計不需要與長時間的主執行緒工作區隔效能,因為設計並不存在。

Viz 程序

Viz 程序包含 GPU 主執行緒和顯示合成器執行緒。

  • 「GPU 主執行緒」光柵會將清單和影片影格顯示在 GPU 紋理圖塊中,並在螢幕上繪製合成器影格。
  • 顯示合成器執行緒會匯總並最佳化每個轉譯程序和瀏覽器程序的合成作業,並最佳化成單一合成器頁框,以便在螢幕上呈現。

光柵和繪圖通常在同一個執行緒上發生,因為兩者都要依賴 GPU 資源,而且很難穩定地使用多執行緒 GPU (GPU 的多執行緒存取較簡單,是開發新的 Vulkan 標準的動機)。在 Android WebView 中,隨著 WebView 嵌入原生應用程式的方式,Android WebView 會使用獨立的 OS 層級轉譯執行緒。日後其他平台可能會有這類執行緒。

顯示合成器需要隨時回應,且不會在 GPU 主執行緒上發生速度變慢,因此位於其他執行緒上。GPU 主執行緒發生速度緩慢的原因之一,就是呼叫非 Chromium 程式碼 (例如供應商專屬的 GPU 驅動程式),但速度可能難以預測。

元件結構

在每個轉譯程序主要或合成器執行緒中,都有邏輯軟體元件,能以結構化的方式相互互動。

轉譯程序主執行緒元件

閃爍轉譯器的圖表。

在 Blink Renderer 中:

  • 「本機影格樹狀結構」代表本機影格的樹狀結構,以及影格中的 DOM。
  • 「DOM 和 Canvas API」元件包含所有這些 API 的實作。
  • 文件生命週期執行器會執行轉譯管道步驟,直到執行修訂版本步驟為止。
  • 「輸入事件命中測試和分派」元件會執行命中測試,找出事件指定的 DOM 元素,並執行輸入事件分派演算法和預設行為。

「轉譯事件迴圈排程器和執行器」會決定要在事件迴圈和時間執行什麼操作。可安排在與裝置螢幕相符的頻率執行轉譯作業。

框架樹狀結構的圖表。

本機頁框樹狀結構片段稍微複雜,提醒您,頁框樹狀結構是主頁面及其子 iframe,並以遞迴方式進行。如果影格是在該程序中轉譯,則屬於轉譯程序的「本機」,在其他情況下則為遠端的影格。

您可以根據轉譯程序設計為影格著色。在上圖中,綠色圓圈代表一個轉譯程序中的所有影格;橘色代表數在一秒,藍色則代表三分之一。

本機頁框樹狀結構片段是影格樹狀結構中相同顏色的連接元件。圖片中有四個本機頁框樹狀結構:一個用於網站 A、一個用於網站 B,另一個用於網站 C。每個本機頁框樹狀結構都有自己的 Blink 轉譯器元件。本機影格樹狀結構的 Blink 轉譯器不一定與其他本機影格樹狀結構相同。其取決於選取轉譯程序的方式。

轉譯程序合成器執行緒結構

顯示轉譯程序合成器元件的圖表。

轉譯程序合成器元件包括:

  • 資料處理常式,負責維護複合式圖層清單、顯示清單及屬性樹狀結構。
  • 生命週期執行器,可執行動畫、捲動、合成、光柵、解碼,並啟用算繪管道步驟。(請注意,動畫和捲動都可能發生在主要執行緒和合成器中)。
  • 輸入和命中測試處理常式會以複合圖層的解析度執行輸入處理和命中測試,判斷捲動手勢是否能在合成執行緒上執行,以及應指定哪些轉譯程序命中測試。

架構範例

這個範例中有三個分頁:

分頁 1:foo.com

<html>
  <iframe id=one src="foo.com/other-url"></iframe>
  <iframe  id=two src="bar.com"></iframe>
</html>

分頁 2:bar.com

<html>
 …
</html>

分頁 3:baz.com html <html> … </html>

這些分頁的處理程序、執行緒和元件結構如下:

分頁程序的圖表。

接下來將逐步說明轉譯作業的四個主要工作範例。提醒事項:

  1. 將內容算繪為螢幕上的像素。
  2. 針對內容在不同狀態間的內容動畫效果。
  3. 捲動以回應輸入。
  4. 有效率地將輸入內容轉送至正確位置,以便開發人員指令碼和其他子系統做出回應。

如要轉譯分頁 1 中已變更的 DOM:

  1. 開發人員指令碼會變更 foo.com 的轉譯程序中的 DOM。
  2. 閃爍轉譯器會通知合成器需要轉譯。
  3. 合成器會指示 Viz 需要轉譯。
  4. Viz 會將轉譯的開始傳回給合成器。
  5. 合成器會將起始訊號轉送至 Blink 轉譯器。
  6. 主執行緒事件迴圈執行器會執行文件生命週期。
  7. 主執行緒將結果傳送至合成器執行緒。
  8. 合成器事件迴圈執行器會執行合成生命週期。
  9. 任何光柵工作都會傳送至光柵工作 (通常會有多個任務)。
  10. GPU 上的 Viz 光柵內容。
  11. Viz 確認完成光柵工作。注意:Chromium 通常不會等待光柵完成,而是使用稱為同步權杖的項目,這類權杖必須在執行步驟 15 前執行光柵工作解析。
  12. 合成器框架會傳送至 Viz。
  13. Viz 會匯總 foo.com 轉譯程序、 bar.com iframe 轉譯程序,以及瀏覽器 UI。
  14. 維茲排定抽獎時間。
  15. Viz 會在螢幕上繪製匯總的合成器框架。

如何在第 2 分頁為 CSS 轉換轉換加上動畫效果

  1. bar.com 轉譯程序的合成器執行緒會變更現有的屬性樹狀結構,在合成器事件迴圈中黏附動畫。接著,系統會重新執行合成器生命週期。(光柵和解碼工作可能會發生,但此處並未說明此情況)。
  2. 合成器框架會傳送至 Viz。
  3. Viz 會匯總 foo.com 轉譯程序、 bar.com 轉譯程序,以及瀏覽器 UI 的合成器框架。
  4. 維茲排定抽獎時間。
  5. Viz 會在螢幕上繪製匯總的合成器框架。

如何捲動分頁三上的網頁:

  1. 一系列 input 事件 (滑鼠、觸控或鍵盤) 皆屬於瀏覽器程序。
  2. 每個事件都會轉送至 baz.com 的轉譯程序合成器執行緒。
  3. 合成器會決定主執行緒是否需要瞭解事件。
  4. 如有需要,系統會將事件傳送至主執行緒。
  5. 主要執行緒會觸發 input 事件監聽器 (pointerdowntouchstarpointermovetouchmovewheel),查看事件監聽器是否會在事件上呼叫 preventDefault
  6. 主執行緒會傳回是否已向合成器呼叫 preventDefault
  7. 否則系統會將輸入事件傳回瀏覽器程序。
  8. 瀏覽器程序結合其他近期事件,將轉換轉換為捲動手勢。
  9. 捲動手勢會再次傳送至 baz.com 的轉譯程序合成器執行緒。
  10. 在這裡套用捲動,讓 bar.com 轉譯程序的合成器執行緒會在合成器事件迴圈中放置動畫。這樣會變更屬性樹狀結構中的捲動位移,並重新執行合成器生命週期。也會指示主執行緒觸發 scroll 事件 (此處未描述)。
  11. 合成器框架會傳送至 Viz。
  12. Viz 會匯總 foo.com 轉譯程序、 bar.com 轉譯程序,以及瀏覽器 UI 的合成器框架。
  13. 維茲排定抽獎時間。
  14. Viz 會在螢幕上繪製匯總的合成器框架。

如何路徑分頁 1 上 iframe #two 超連結上的 click 事件:

  1. input 事件 (滑鼠、觸控或鍵盤) 用於瀏覽器程序。系統會執行近似命中測試,判斷 bar.com iframe 轉譯程序應接收點擊並傳送至該處。
  2. bar.com 的合成器執行緒會將 click 事件轉送至 bar.com 的主執行緒,並安排了轉譯事件迴圈工作來進行處理。
  3. 針對 bar.com 主要執行緒命中測試的輸入事件處理工具,可判斷使用者點選 iframe 中的哪個 OM 元素,並觸發 click 事件讓指令碼觀察。聽不到「preventDefault」,系統將導向超連結。
  4. 載入超連結的到達網頁後,系統就會轉譯新狀態,步驟與前一個例子中的「算繪已變更 DOM」類似。(本文未說明後續變更)。

重點摘要

思考並內部處理轉譯作業可能需要花費大量時間。

最重要的是,透過謹慎的模組化與細節注意,轉譯管道已分割為多個獨立元件。接著,這些元件會拆分到平行程序和執行緒,盡可能提高可擴充效能擴充性的機會。

在提供現代化網頁應用程式的效能和功能時,每個元件都扮演著關鍵角色。

請繼續閱讀瞭解金鑰資料結構,這些結構對於 RenderingNG 作為程式碼元件的重要性。


插圖:Una Kravets。