GPU加速在前端的应用
概述
GPU(Graphics Processing Unit) 圖形處理單元,又稱圖形處理器,是我們所周知的顯卡的核心部件,是顯卡的“心臟”。
按照字面意思我們可以猜測得到GPU是和顯示(圖像相關)的,再結合CPU一起理解,我們可以推測GPU也是有運算(計算能力的)。
GPU到底有何作用和能力呢?
GPU是專為復雜數學運算和幾何運算而設計的芯片,它的用途我們平常所周知的就是用于圖形圖像處理(顯卡),但是實際用途不僅僅如此(依托GPU強大的計算能力(多強大下面會講)進行挖礦、機器學習算法)。
CPU與GPU
上面我們知道GPU可以處理復雜的運算,處理能力比CPU很強,那到底有多強呢,有個數據可以說明:
現在主流的i7處理器的浮點計算能力是主流的英偉達GPU處理器浮點計算能力的1/12。
為什么GPU的處理能力比CPU強,這就需要從邏輯結構來分析一下。
其中Control是控制器,ALU是算術邏輯單元、Cache是CPU內部緩存、DRAM是內存。從上圖我們可以知道GPU將更多的空間(晶體管)用作執行單元,而不是像CPU那樣用作復雜的控制單元和緩存(CPU需要同時很好的支持并行和串行操作,需要很強的通用性來處理各種不同的數據類型,同時又要支持復雜通用的邏輯判斷,這樣會引入大量的分支跳轉和中斷的處理。這些都使得CPU的內部結構異常復雜,計算單元的比重被降低了),實際來看CPU的芯片控件5%是ALU,而GPU則高達40%(GPU面對的則是類型高度統一的、相互無依賴的大規模數據和不需要被打斷的純凈的計算環境。因此GPU的芯片比CPU芯片簡單很多),這也就是為啥GPU運算能力超強的原因。
GPU加速
上面我們對比了GPU和CPU在邏輯結構上的差異,從中我們知道得益于GPU密集的邏輯處理單元(高并行結構),GPU適合對高密集的數據進行并行處理,CPU執行計算任務時,一個時刻只能處理一個數據,不存在真正意義上的并行(在多核CPU中,真正的并行有了可能。即在多線程設計中一部分可用來處理前臺任務,一部分可用來處理后臺任務,實現真正意義上的并行。),而GPU具有多個處理器核,在一個時刻可以并行處理多個數據,真正意義上實現了高并行。我們所說的GPU加速其實原理就是利用了GPU的高并行計算能力,比如我們在前端中利用GPU來處理復合圖層(像素密集型)進行“加速”。
GPU采用流式并行計算模式,可對每個數據進行獨立的并行計算,所謂“對數據進行獨立計算”,即,流內任意元素的計算不依賴于其它同類型數據,例如,計算一個頂點的世界位置坐標,不依賴于其他頂點的位置。而所謂“并行計算”是指“多個數據可以同時被使用,多個數據并行運算的時間和1個數據單獨執行的時間是一樣的”。
GPU加速在前端的應用
首先我們要知道為什么要用(開啟)GPU加速(硬件加速), 然后我們才能去探討如何以及怎么樣去應用GPU加速。
為什么要開啟GPU加速。
回答這個問題前我們可以先來看兩個CSS Animation(都是應用了幀動畫,但是一個沒有開啟GPU加速,一個開啟了GPU加速)
沒有開啟:
https://codepen.io/feshionxu/pen/xxGJvKa
開啟:
https://codepen.io/feshionxu/pen/bGdjXbe
通過兩個動畫對比,第一個動畫運行會有卡頓(沒有達到60fps),而第二個則perfect(not reflow,not always repaint when animation running),運行順暢。
那么為什么要開啟GPU加速呢,答案很明顯,為了體驗,用戶體驗!!!
如何在前端中應用GPU加速
首先我們先回顧下前端頁面渲染過程。
再結合下瀏覽器的內部結構看下
在第一張圖中我們知道,頁面最終呈現是需要經過一個我們通常不是很關注的步驟--繪制,實際上在Painting之后Display之前有還有一個步驟--Composite(渲染層合并)。
結合第二張圖,Painting(繪制)的具體工作是由瀏覽器UI后端部分負責完成的,在Painting階段,會調用引擎的paint api(canvas會調用draw api)進行像素級信息計算與繪制,像素級信息具體表現為幀信息(圖層),瀏覽器會將各層的信息發送給GPU(GPU進程:最多一個,用于3D繪制等),GPU會將各層合成(composite),顯示在屏幕上。接下來我們具體來看來看下Composite干了什么?
概括下Composite干了什么:頁面中 DOM 元素的繪制是在多個層上進行的。在每個層上完成繪制過程之后,瀏覽器會將所有層按照合理的順序合并成一個圖層,然后顯示在屏幕上。對于有位置重疊的元素的頁面,這個過程尤其重要,因為一旦圖層的合并順序出錯,將會導致元素顯示異常。
我們經常說要避免回流(reflow:重新計算元素幾何尺寸和位置),為什么可以避免呢,這是因為在實際場景下,大致會出現三種常見的渲染流程(Layout和Paint步驟是可避免的):
But what and why?這就需要我們繼續深挖下瀏覽器(webkit內核)繪制工作。
上文提到了層的概念,首先我們先來了解下層是什么鬼?
從上圖(結合瀏覽器的基本渲染過程圖)我們可以知道層的產生過程,渲染樹最終會轉換成層樹(Layer tree),從上圖我們也可以知道其實chrome(webkit)有兩種類型的層。
RenderLayers 渲染層,這是負責對應 DOM 子樹
GraphicsLayers 圖形層,這是負責對應 RenderLayers子樹。
在 DOM 樹中每個節點都會對應一個 LayoutObject,當他們的 LayoutObject 處于相同的坐標空間時,就會形成一個 RenderLayers ,也就是渲染層。RenderLayers 來保證頁面元素以正確的順序合成,這時候就會出現層合成(composite),從而正確處理透明元素和重疊元素的顯示。
某些特殊的渲染層會被認為是合成層(Compositing Layers),合成層擁有單獨的 GraphicsLayer,而其他不是合成層的渲染層,則和其第一個擁有 GraphicsLayer 父層公用一個。
而每個GraphicsLayer(合成層單獨擁有的圖層) 都有一個 GraphicsContext,GraphicsContext 會負責輸出該層的位圖,位圖是存儲在共享內存中,作為紋理上傳到 GPU 中,最后由 GPU 將多個位圖進行合成,然后顯示到屏幕上,到這里終于道出了瀏覽器頁面渲染呈現GPU的存在,再結合我們上文提到的GPU對于密集型數據(比如圖像像素級)的運算能力,我們也差不多說明了GPU加速為何可以在前端中進行應用 --讓需要進行復雜動畫的元素(或所在元素)單獨擁有一個合成圖層。
在回答怎么變成合成層之前,我們看下合成層的優點:
合成層的位圖,會交由 GPU 合成,比 CPU 處理要快
當需要 repaint 時,只需要 repaint 本身,不會影響到其他的層
對于 transform 和 opacity 效果,不會觸發 layout 和 paint
然后我們再看下如何變成合成層,如何應用GPU加速(硬件加速):
3D 或透視變換(perspective transform) CSS 屬性
使用加速視頻解碼的?<video>?元素 擁有 3D
(WebGL) 上下文或加速的 2D 上下文的?<canvas>?元素
混合插件(如 Flash)
對自己的 opacity 做 CSS動畫或使用一個動畫變換的元素
擁有加速 CSS 過濾器的元素
元素有一個包含復合層的后代節點(換句話說,就是一個元素擁有一個子元素,該子元素在自己的層里)
元素有一個z-index較低且包含一個復合層的兄弟元素(換句話說就是該元素在復合層上面渲染)
提升合成層的最好方式是使用 CSS 的 will-change屬性。will-change 可以設置為opacity、transform、top、left、bottom、right。
注意事項
提升到合成層后合成層的位圖會交GPU處理,但請注意,僅僅只是合成的處理(把繪圖上下文的位圖輸出進行組合)需要用到GPU,生成合成層的位圖處理(繪圖上下文的工作)是需要CPU。
當需要repaint的時候可以只repaint本身,不影響其他層,但是paint之前還有style, layout,那就意味著即使合成層只是repaint了自己,但style和layout本身就很占用時間。
僅僅是transform和opacity不會引發layout 和paint,那么其他的屬性不確定。
最后,也說說缺點或者說容易踩坑的地方(要學會權衡、學會克制):
合成層占用內存的問題。
層爆炸,由于某些原因可能導致產生大量不在預期內的合成層,雖然有瀏覽器的層壓縮機制,但是也有很多無法進行壓縮的情況,這就可能出現層爆炸的現象(簡單理解就是,很多不需要提升為合成層的元素因為某些不當操作成為了合成層)。解決層爆炸的問題,最佳方案是打破 overlap 的條件,也就是說讓其他元素不要和合成層元素重疊。簡單直接的方式:使用3D硬件加速提升動畫性能時,最好給元素增加一個z-index屬性,人為干擾合成的排序,可以有效減少創建不必要的合成層,提升渲染性能,移動端優化效果尤為明顯。
關于本文作者:@250的夢想原文:GPU
總結
以上是生活随笔為你收集整理的GPU加速在前端的应用的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: html表白程序源码 html生日快乐网
 - 下一篇: 后台数据逻辑的测试分析方法