很遺憾 Chromium 的工程師沒有寫一篇 How Viz Works 的文章來詳細解析 Viz 這個重要的子產品,能找到的一些相關文檔都比較零散,是以我打算自己來寫,不過個人研究深度有限,無法包括所有的細節,還請讀者見諒。
計劃寫兩到三篇文章,第一篇文章對 Viz 做一個概要的介紹,和它在 Chromium 整個合成器架構裡面的角色。因為 Viz 的代碼變動很快,是以文章的内容隻是針對目前的版本 M75,部分内容在未來有可能會失效。
Viz 作為 Visual 的縮寫,一開始的代碼是源自 cc,gpu 等子產品,它是 Chromium 整體架構轉向服務化的一個重要組成部分。
官方的文檔 裡面說明 Viz 預計為 Chromium 其它子產品提供以下四種服務:- compositing - 合成輸出;
- gl - 實際上就是 GPU 通路,對外部提供 GPU Service,内部使用 GL 或者 Vulkan API 通路 GPU;
- hit testing - Surface 的點選測試;
- media - 多媒體,包括視訊,VR/AR 等;
Viz clients 分為兩類,一種是 privileged client (特權客戶),它隻有一個,負責啟動 Viz 服務,和為 unprivileged clients(非特權客戶)提供 Viz 服務的通路接口,而 unprivileged clients 則僅僅是使用 Viz 服務,它可以同時存在多個。
對一個作為浏覽器(非 Chrome OS)的 Chromium 來說,隻有 Browser 程序可以作為 privileged client,Renderer 程序隻能作為 unprivileged client。
Viz 運作在 Viz 程序,也就是以前的 GPU 程序,當然,在單程序架構下,Browser 程序可以兼做 Viz 程序。
Viz 的代碼結構
Viz 的代碼主要分布在
/services/viz和
/components/viz兩個目錄,從目錄名字就差不多能夠猜的出來:
- /services/viz 的代碼主要是 Viz Mojo Service 對外的接口和 Viz Mojo Service 的啟動和注冊;
- /components/viz 是 Viz 對外提供服務的内部實作,包括 Service 接口的實作和具體功能的實作,比如 Display Compositor 等;
不過從官方文檔的說明來看,/components/viz 目錄下的代碼未來可能會遷入 /services/viz 裡面。
Viz Mojo Service 對外提供了兩個最重要的接口是
FrameSinkManager CompositorFrameSink。
privileged client 通過
接口請求建立一個
的實作,包括對應的
Surface,并把傳回的接口傳遞給 unprivileged client,unprivileged client 則使用
的接口來送出
CompositorFrame給 Display Compositor。我們後面還會詳細講述。
- /components/viz/common - 公共的資料結構和輔助類;
- /components/viz/client - unprivileged client ,比如 cc,需要使用的一些類;
- /components/viz/host - privileged client,需要使用的一些類;
- /components/viz/service - Viz Service 的實作,包括 Service 接口的實作和功能的實作;其中 frame_sinks 是 這兩個接口相關的實作;gl 是 GPU Service 的實作;display, display_embedder,surfaces 一起構成了 Display Compositor;
合成器架構
在繼續解析 Viz 之前,我們需要了解目前 Chromium 合成輸出的合成器架構,
Compositor Stack這篇文檔比較詳細地介紹了 Chromium 合成器架構的曆史變遷,可以作為讀者的參考。關于 Layer Compositor,更詳盡的資訊可以參考文章
How cc Works
上圖顯示網頁内容合成輸出的一個合成器架構的簡化示意圖,需要說明的是 Chromium 目前的合成器架構并不僅僅限于網頁内容的合成,包括浏覽器 UI,多媒體,插件,Offscreen Canvas 等都可以通過這套合成器架構進行合成輸出。Surface 和 Display 并不是一一對應的關系,一個 Display 實際上對應的是一棵父子結構的 Surfae 樹。
從上圖我們可以看到:
- 以 LayerTreeHostImpl/LayerTreeHost 為核心的 Layer Compositor 是 CompositorFrame 的來源之一,對網頁來說,這個 CompositorFrame 包含了目前 Viewport 的網頁繪制結果;
- LayerTreeFrameSink 是 Layer Compositor 送出 CompositorFrame 的接口,具體的實作由 cc 的 embedder 提供;
- LayerTreeFrameSink 的實作把 CompositorFrame 通過 CompositorFrameSink 接口送出給 Viz Service;
- Viz Service 把接收到的 CompositorFrame 傳遞給目标 Surface;
- Display 關聯的多個 Surface 被聚合,最終結果輸出到 Display 指定的 OutputSurface;
後面的文章再繼續講述不同的 Chromium Configurations 實際的合成器架構。