天天看點

浏覽器之硬體加速機制

浏覽器之硬體加速機制

如有問題或建議,請背景留言,我會盡力解決你的問題。

前言

此文章是我最近在看的【WebKit 技術内幕】一書的一些了解和做的筆記。

而【WebKit 技術内幕】是基于 WebKit 的 Chromium 項目的講解。

書接上文 浏覽器核心之渲染基礎

1. 硬體加速基礎

1.1 概念

硬體加速技術是指:使用 GPU 的硬體能力為幫助渲染網頁,在為 GPU 的作用主要是用來繪制 3D 圖形并且性能特别好。

對于 GPU 繪圖而言,當網頁分層之後,部分區域的更新可能隻在網頁的一層或者幾層,而不需要将整個網頁都重新繪制。 通過重新繪制網頁的一個或者幾個層,并将它們和其他之前繪制完的層合成起來,既能使用 GPU 的能力,又能減少重繪的開銷。

每個 RenderLayer 對象都有一個後端存儲與其對應,好處是:當每一層更新的時候,WebKit 隻需要更新 RenderLayer 對象包含的節點即可。是以當某一層有作保更新的時候,WebKit 重繪該層的所在内容, 這是理想的情況。現實中,由于硬體能力和資源有限。為了節省 GPU 的記憶體資源,硬體加速機制在 RenderLayer 樹建立之後需要做三件事情來完成網頁的渲染。

- WebKit 決定将哪些 RenderLayer 對象組合在一起,形成一個有後端存儲的新層,這一新層不久後會用于之後的合成(Compositing),這裡面稱之為合成層(Compositing Layer)。每個新層都有一個或者多個後端存儲,這裡的後端存儲可能是 GPU 的記憶體。對于一個 RenderLayer 對象,如果它沒有後端存儲的新層,那麼就使用它的父親所使用的合成層。

- 将每個合成層包含的這些 RenderLayer 内容繪制在合成層的後端存儲中,這裡的繪制可以是軟體繪制也可以是硬體繪制。

- 由合成層(Compositor)将多個合成層合成起來,形成網頁的最終可視化結果,實際就是一張圖檔。 合成器是一種能夠将多個合成層按照這些層的前後順序、合成層的 3D 變形等設定而合成一個圖像結果的設施。

在 WebKit 中,隻有把編譯的 C 代碼宏(macro)“ACCELERATED_COMPOSITING” 打開之後,硬體加速機制才會被開啟,有關硬體加速的基礎設施才會被編譯進去。

1.2 WebKit 硬體加速設施

一個 RenderLayer 對象如果需要後端存儲,它會建立一個 RenderLayerBacking 對象,該對象負責 RenderLayer 對象所需要的各種存儲。理想情況下,每個 RenderLayer 都可以建立自己的後端存儲,但事實上不是所有 RenderLayer 都有自己的 RenderLayerBacking 對象。如果一個 RenderLayer 對象被 WebKit 按照一定的規則建立了後端存儲,那麼該 RenderLayer 被稱為合成層。

每個合成層都有一個 RenderLayerBacking, RenderLayerBacking 負責管理 RenderLayer 所需要的所有後端存儲,因為後端存儲可能需要多個存儲空間。在 WebKit 中,存儲空間使用 GraphicsLayer 類來表示。

浏覽器之硬體加速機制

其中圖中的 GraphicsLayer 表示 RenderLayer 中前景層、背景層所需要的一個後端存儲。每一個 GraphicsLayer 都使用一個 GraphicsLayerClient 對象,該對象能夠收到 GraphicsLayer 的一些狀态更新資訊,并且包含一個繪制該 GraphicsLayer 對象的方法,RenderLayerBacking 繼承于該類。GraphicsLayer 是 WebKit 中的基礎類,主要定義一套标準接口。

如果一個 RenderLayer 對象具有以下特征之一,那麼它就是合成層。

  • RenderLayer 具有 CSS 3D 屬性或者 CSS 透視效果。
  • RenderLayer 包含的 RenderObject 節點表示的是使用硬體加速的視訊解碼技術的 HTML5 “video” 元素。
  • RenderLayer 包含的 RenderObject 節點表示的是使用硬體加速的 Canvas 2D 元素或者 WebGL 技術。
  • RenderLayer 使用了 CSS 透明效果的動畫或者 CSS 變換的動畫。
  • RenderLayer 使用了硬體加速的 CSS Filters 技術。
  • RenderLayer 使用了剪裁(Clip)或者反射(Reflection)屬性,并且它的後代中包括一個合成層。
  • RenderLayer 有一個 Z 坐标比自己小的兄弟節點,且該節點是一個合成層。

這麼做的原因有三個:

首先當然是合并一些 RenderLayer 層,這樣可以減少記憶體的使用量;

其二是在合并之後,盡量減少合并帶來的重繪性能和處理上的困難;

其三對于那些使用單獨層能夠顯著提升性能的 RenderLayer 對象,可以繼續使用這些好處。

浏覽器之硬體加速機制

為什麼一個 RenderLayerBacking 對象需要這麼多層?原因有很多,例如,WebKit 需要将滾動條獨立開來稱為一個層,需要兩個容器層來表示 RenderLayer 對應的 Z坐标為正數的子女和 Z 坐标為負數的子女,需要滾動的内容建立新層,還可能需要剪裁層和反射層。

圖 8-4 中的樹狀結構描述了所有層的繪制順序,按照先根順序周遊的結果即是繪制順序,圖中每個層就是一個 GraphicsLayer 對象。

浏覽器之硬體加速機制

管理這些合成層等工作的是 RenderLayerCompositor 類,可以說是個 “大管家”。

1.3 硬體渲染過程

首先,WebKit 決定哪些些是合成層并為它們配置設定後端存儲。

其次,WebKit 需要周遊和繪制每一個合成層,也就是每個合成層可能有一個或者多個 RenderLayer 對象。

最後,渲染引擎将所有繪制完的合成層合成起來,這個是由 WebKit 的移植來完成的。

1.4 3D 圖形上下文

WebKit 中的 3D 圖形上下文主要是提供一組抽象接口,這組接口能夠提供類似 OpenGLES(使用 GPU 硬體能力的 3D 圖形應用程式設計接口)的功能,其主要目的當然是使用 OpenGL 繪制 3D 圖形的能力。這一層抽象能夠将 WebKit 各個移植的不同部分隐藏起來,WebCore 隻是使用統一的抽象接口。在 WebKit 中,3D 圖形上下文的主要用途是 WebGL,當然啟用硬體加速的 Canvas2D 等 HTML5 技術也會使用 3D 圖形技術,不過情況有些不同。

1.2 Chromium 的硬體加速機制

1.2.1 GraphicsLayer 的支援

GraphicsLayer 對象是對一個渲染後端存儲中某一層的抽象,同衆多其他 WebKit 所定義的抽象類一樣,在 WebKit 移植中,它還需要具體的實作類來支援該類所要提供的功能。

1.2.2 架構

在 Chromium 中,是以使用 GPu 硬體加速(也就是調用 OpenGL程式設計接口)的操作都是由一個程序(稱為 GPU 程序)負責來完成的,這其中包括使用 GPU 硬體來進行繪圖和合成。

Chromium 是多程序架構,每個網頁的 Renderer 程序都是将之前介紹的 3D 繪圖和合成操作通過 IPC 傳遞給 GPU 程序,由它來統一排程并執行。

在 Chromium 的 Android 版本中,GPU 程序并不存在, Chromium 是将 GPU 的所有工作放在 Browser 程序中的一個線程來完成,這得益于結構設計的靈活性。但是本質上,GPU 程序和 GPU 線程并無太大差別。

浏覽器之硬體加速機制

上圖 描述了 Chromium 的多程序架構中 GPU 程序同其他程序之間的聯系,事實上每個 Renderer 程序都依賴 GPU 程序來渲染網頁,當然 Browser 程序也會同 GPU 程序進行通信,其作用是建立該程序并提供網頁渲染過程最後繪制的目标存儲。

那麼 GPU 程序和 Render 程序是如何同步這些指令的呢?答案是,GPU 程序處理一些指令後,會向 Renderer 程序報告自己目前的狀态, Renderer 程序通過檢查狀态資訊和自己的期望結果來确定是否滿足自己的條件。

GPU 程序最終繪制的結果不再像軟體渲染那樣通過共享記憶體傳遞給 Browser 程序,而是直接将頁面的内容繪制在浏覽器的标簽視窗内。

1.2.3 指令緩沖區

指令緩沖區(Command Buffer)主要用于 GPU 程序和 GPU 的調用都程序傳遞 GL 操作指令。從接口上來講,這一設計隻提供一些基本的接口來管理緩沖區,寬并沒有對緩沖區的具體方式和指令的類型進行任何限制,不過目前 Chromium 隻有 GLES 一種實作方式。

1.2.4 Chromium 合成器(Chromium Compositor)

合成器的作用就是将多個合成層合成并輸出一個最終的結果,是以它的輸入是多個待合成的合成層,每個層都有一些屬性(如 3D 變形等),它的輸出就是一個後端存儲,例如一個 GPU 的紋理緩沖區。

Chromium 合成器是一個獨立并且複雜的子產品,它的作用是合成網頁劃分後的合成層。

總結

  • 硬體加速是指用GPU的硬體能力來渲染網頁,GPU的主要作用是用來繪制3D圖形并且有很好的性能,對于GPU繪圖而言,通常不像軟體渲染那樣隻是計算其中更新的區域,一旦有新的更新請求,如果沒有分層,引擎可能會重新繪制所有的區域,因為計算更新部分對GPU來說可能耗費更多的時間,當網頁分層之後,部分區域的更新可能隻在一層或幾層,而不需要更新整個網頁,通過重新繪制網頁的一個或幾個層,并将它們和其他之前繪制完的層合成起來,既能使用GPU的能力,又能夠減少重繪的開銷。

最後

希望本文對你有點幫助。

下期分享 【第九章 JavaScript 引擎】 敬請期待。

送上 資源分享——Python、Java、Linux、Go、vue、react、javaScript

對 全棧開發 有興趣的朋友可以掃下方二維碼關注我的公衆号 —— 愛寫bugger的阿拉斯加

分享 web 開發相關的技術文章,熱點資源,全棧程式員的成長之路。