解決方案
瀏覽器多年來一直靠「少做一點」來提升流暢度:只讓變更過的矩形區域失效、把各部分快取成圖層、將它們合成,最後再把這兩項工作都移到 GPU 上。2017 年 10 月,Lin Clark 在 Mozilla Hacks 上解釋了為什麼頁面仍會卡頓。圖層會佔用記憶體與傳輸時間,而瀏覽器必須猜測一個頁面需要多少圖層。圖層太多會耗盡記憶體並拖慢合成器;圖層太少則意味著某個被重繪的圖層在沒有任何變動的情況下仍被合成,導致每個像素被處理兩次。無論如何,為背景顏色製作動畫都會強制整個圖層重繪。
WebRender 是 Servo 的技術,以 Quantum Render 之名進入 Firefox,它遵循了不同的先例:3D 遊戲引擎會重繪每一幀的每一個像素,並在擁有數百或數千個可平行著色像素的核心的 GPU 上,比瀏覽器更可靠地維持 60 FPS。因此,WebRender 移除了繪製與合成之間的界線。版面配置的輸出變成一份顯示清單,由高階繪圖指令組成,不綁定任何圖形 API。WebRender 的 RenderBackend 將該清單轉換為批次化的 GPU 繪製呼叫,GPU 則每一幀重繪頁面整個可見場景,無需猜測圖層。
要讓整幀重繪變得可負擔,必須消除多餘工作。螢幕外的項目在到達 GPU 之前就被剔除。渲染任務樹會為濾鏡與堆疊上下文規劃出最少數量的昂貴離屏紋理。繪製呼叫會被批次化,以讓 GPU 的平行核心保持忙碌。渲染被拆分為一個由前到後的不透明階段(跳過被覆蓋的像素)與一個由後到前的半透明階段——文章稱之為 z-culling,並表示這在典型頁面上是一大勝利。文字字形仍由 CPU 處理,但會快取在一個逐幀保留的紋理中。
目標是一致性,而不只是速度:沒有效能斷崖,無論顯示器多大或頁面有多少部分變動,都能維持流暢的 60 FPS。文章報導,在 Chrome 或當時的 Firefox 中以 15 FPS 緩慢運行的頁面,在 WebRender 下能以 60 FPS 運行,並將這項工作定位為對 4K 顯示器與 WebVR 的準備,後者需為每隻眼睛以 90 FPS 渲染一幀。
達成了什麼
停止猜測圖層:把一份高階顯示清單交給 GPU,並像遊戲引擎那樣每一幀重繪整個頁面
為何有效
GPU 擁有數百到數千個可平行著色像素的核心,因此每一幀重繪整個可見頁面正是它們被打造來處理的工作負載,而非 CPU 規模的工作。
保留式顯示清單是對場景的一份小型、與 API 無關的描述,因此 CPU 只建構一次指令,RenderBackend 便能在任何像素工作發生之前對它們進行剔除、排序與批次化。
整場景重繪消除了圖層猜測及其失效模式:沒有誤判的圖層數量,沒有像素的雙重處理,因此幀時間不再跌落效能斷崖。
工作消除讓重繪保持低廉:剔除、更少的離屏目標、批次化與 z-culling 縮小了 GPU 著色的範圍,而由 CPU 渲染的字形則存放在紋理快取中,不在逐幀路徑上。
可套用之處
當漸進式啟發法不斷撞上最壞情況的斷崖時,改變模型:一次描述整個場景,讓大規模平行硬體每一幀重繪它
後續發展
WebRender 並未包含在隨後發布的 Firefox Quantum 版本中:Lin Clark 在文章留言中寫道,它要到 Firefox 57 之後才會推出,而文章規劃在 Quantum Render 專案下於 2018 年完成整合,當時已有早期版本可透過旗標使用。文章連結的示範顯示,在 Chrome 或當時的 Firefox 中以 15 FPS 運行的頁面,在 WebRender 下能以 60 FPS 運行,而這篇解說文在 2017 年 10 月 10 日於 Hacker News 上獲得 853 點與 207 則留言。
追溯依據
參考來源
- The whole web at maximum FPS: How WebRender gets rid of jank Mozilla Hacks · hacks.mozilla.org ·
- Hacker News discussion: The whole web at maximum FPS — How WebRender gets rid of jank Hacker News · news.ycombinator.com ·