淺談 GPU 及 「App渲染流程」

級別:★★☆☆☆
標籤:「GPU」「原生渲染」「大前端」「Flutter」
做者: 647
審校: QiShare團隊php


前言:
最近,研究了一下GPU以及App的渲染流程與原理。
首先,感謝 QiShare團隊 的指導與支持,以及 鵬哥(@snow) 對本文的審覈與幫助。
接下來,讓咱們開始咱們今天的探索之旅。
css


1、淺談GPU

GPU(Graphics Processing Unit):
又名圖形處理器,是顯卡的 「核心」。
主要負責圖像運算工做,具備高並行能力,經過計算將圖像顯示在屏幕像素中。
html

現代圖形系統

GPU的工做原理,簡單來講就是:
—— 「3D座標」 轉換成 「2D座標」 ,再將 「2D座標」 轉換爲 「實際有顏色的像素」前端

那麼,GPU具體的工做流水線 會分爲「六個階段」,分別是:git

頂點着色器 => 形狀裝配 => 幾何着色器 => 光柵化 => 片斷着色器 => 測試與混合github

  • 第一階段:頂點着色器(Vertex Shader)

該階段輸入的是頂點數據(Vertex Data),頂點數據是一系列頂點的集合。頂點着色器主要的目的是把 3D 座標轉爲 「2D」 座標,同時頂點着色器能夠對頂點屬性進行一些基本處理。 ( 一句話簡單說,肯定形狀的點。編程

  • 第二階段:形狀裝配(Shape Assembly)

該階段將頂點着色器輸出的全部頂點做爲輸入,並將全部的點裝配成指定圖元的形狀。 圖元(Primitive) 用於表示如何渲染頂點數據,如:點、線、三角形。 這個階段也叫圖元裝配。 ( 一句話簡單說,肯定形狀的線。json

  • 第三階段:幾何着色器(Geometry Shader)

該階段把圖元形式的一系列定點的集合做爲輸入,經過生產新的頂點,構造出全新的(或者其餘的)圖元,來生成幾何形狀。 ( 一句話簡單說,肯定三角形的個數,使之變成幾何圖形。小程序

GPU並行處理

該階段會把圖元映射爲最終屏幕上相應的像素,生成片斷。片斷(Fragment) 是渲染一個像素所須要的全部數據。 ( 一句話簡單說,將圖轉化爲一個個實際屏幕像素。swift

  • 第五階段:片斷着色器(Fragment Shader)

該階段首先會對輸入的片斷進行裁切(Clipping)。裁切會丟棄超出視圖之外的全部像素,用來提高執行效率。並對片斷(Fragment)進行着色。 ( 一句話簡單說,對屏幕像素點着色。

  • 第六階段:測試與混合(Tests and Blending)

該階段會檢測片斷的對應的深度值(z 座標),來判斷這個像素位於其它圖層像素的前面仍是後面,決定是否應該丟棄。此外,該階段還會檢查 alpha 值( alpha 值定義了一個像素的透明度),從而對圖層進行混合。 ( 一句話簡單說,檢查圖層深度和透明度,並進行圖層混合。

(PS:這個很關鍵,會在以後推出的「App性能優化實戰」系列博客中,是我會提到優化UI性能的一個點。)

所以,即便在片斷着色器中計算出來了一個像素輸出的顏色,在經歷測試與混合圖層以後,最後的像素顏色也可能徹底不一樣。

關於混合,GPU採用以下公式進行計算,並得出最後的實際像素顏色。

R = S + D * (1 - Sa)
含義:
R:Result,最終像素顏色。
S:Source,來源像素(上面的圖層像素)。
D:Destination,目標像素(下面的圖層像素)。
a:alpha,透明度。
結果 = S(上)的顏色 + D(下)的顏色 * (1 - S(上)的透明度)

GPU渲染流水線的完整過程,以下圖所示:

GPU圖形渲染流水線

問:CPU vs. GPU?

這裏引用咱們團長(@月影)以前分享的一頁PPT:

CPU vs. GPU

因爲屏幕每一個像素點有每一幀的刷新需求,因此對GPU的並行工做效率要求更高。


簡單說完了GPU渲染的流水線,咱們來聊一聊App的渲染流程與原理。
iOS App的渲染主要分爲如下三種:

  • 原生渲染
  • 大前端渲染(WebView、類React Native
  • Flutter渲染

2、原生渲染

說到原生渲染,首先想到的就是咱們最熟悉使用的iOS渲染框架:UIKitSwiftUICore AnimationCore GraphicsCore ImageOpenGL ESMetal

  • UIKit:平常開發最經常使用的UI框架,能夠經過設置UIKit組件的佈局以及相關屬性來繪製界面。其實自己UIView並不擁有屏幕成像的能力,而是View上的CALayer屬性擁有展現能力。(UIView繼承自UIResponder,其主要負責用戶操做的事件響應,iOS事件響應傳遞就是通過視圖樹遍歷實現的。)
  • SwiftUI:蘋果在WWDC-2019推出的一款全新的「聲明式UI」框架,使用Swift編寫。一套代碼,便可完成iOSiPadOSmacOSwatchOS的開發與適配。(關於SwiftUI,我去年寫過一篇簡單的Demo,可供參考:《用SwiftUI寫一個簡單頁面》
  • Core Animation:核心動畫,一個複合引擎。儘量快速的組合屏幕上不一樣的可視內容。分解成獨立的圖層(CALayer),存儲在圖層樹中。
  • Core Graphics:基於 Quartz 高級繪圖引擎,主要用於運行時繪製圖像。
  • Core Image:運行前圖像繪製,對已存在的圖像進行高效處理。
  • OpenGL ESOpenGL for Embedded Systems,簡稱 GLES,是 OpenGL 的子集。由GPU廠商定製實現,可經過C/C++編程操控GPU
  • Metal:由蘋果公司實現,WWDC-2018已經推出Metal2,渲染性能比OpenGL ES高。爲了解決OpenGL ES不能充分發揮蘋果芯片優點的問題。

那麼,iOS原生渲染的流程有那幾部分組成呢?
主要分爲如下四步:

  • 第一步:更新視圖樹、圖層樹。(分別對應View的層級結構、View上的Layer層級結構)

  • 第二步:CPU開始計算下一幀要顯示的內容(包括視圖建立、佈局計算、視圖繪製、圖像解碼)。當 runloopkCFRunLoopBeforeWaitingkCFRunLoopExit 狀態時,會通知註冊的監聽,而後對圖層打包,打完包後,將打包數據發送給一個獨立負責渲染的進程 Render Server。 前面 CPU 所處理的這些事情統稱爲 Commit Transaction

commit-transaction

  • 第三步:數據到達 Render Server 後會被反序列化,獲得圖層樹,按照圖層樹的圖層順序、RGBA 值、圖層 frame 來過濾圖層中被遮擋的部分,過濾後將圖層樹轉成渲染樹,渲染樹的信息會轉給 OpenGL ES/Metal

WWDC14-Session-419

  • 第四步:Render Server 會調用 GPUGPU 開始進行前面提到的頂點着色器、形狀裝配、幾何着色器、光柵化、片斷着色器、測試與混合六個階段。完成這六個階段的工做後,就會將 CPUGPU 計算後的數據顯示在屏幕的每一個像素點上。

WWDC14-實際並行時圖解

那麼,關於iOS原生渲染的總體流程,我也畫了一張圖:

iOS-原生渲染流程


3、大前端渲染

1. WebView:

對於WebView渲染,其主要工做在WebKit中完成。
WebKit自己的渲染基於macOSLay Rendering架構,iOS自己渲染也是基於這套架構。
所以,自己從渲染的實現方式來講,性能應該和原生差異不大。

但爲何咱們能明顯感受到使用WebView渲染要比原生渲染的慢呢?

  • 第一,首次加載。會額外多出網絡請求和腳本解析工做。 即便是本地網頁加載,WebView也要比原生多出腳本解析的工做。 WebView要額外解析HTML+CSS+JavaScript代碼。

  • 第二,語言解釋執行性能來看。JS的語言解析執行性能要比原生弱。 特別是遇到複雜的邏輯與大量的計算時,WebView 的解釋執行性能要比原生慢很多。

  • 第三,WebView的渲染進程是獨立的,每一幀的更新都要經過IPC調用GPU進程,會形成頻繁的IPC進程通訊,從而形成性能消耗。而且,兩個進程沒法共享紋理資源,GPU沒法直接使用context光柵化,而必需要等待WebView經過IPCcontext傳給GPU再光柵化。所以GPU自身的性能發揮也會受影響。

所以,WebView的渲染效率,是弱於原生渲染的。

2. 類React Native(使用JavaScriptCore引擎作爲虛擬機方案)

表明:React NativeWeex、小程序等。

咱們以 ReactNative 舉例:
React Native的渲染層直接走的是iOS原生渲染,只不過是多了Json+JavaScript腳本解析工做。
經過JavaScriptCore引擎將「JS」與「原生控件」產生相對應的關聯。
進而,達成經過JS來操控iOS原生控件的目標。 (簡單來講,這個json就是一個腳本語言到本地語言的映射表,KEY是腳本語言認識的符號,VALUE是本地語言認識的符號。)

簡單介紹一下,JavaScriptCore
JavaScriptCoreiOS 原生與 JS 之間的橋樑,其本來是 WebKit 中解釋執行 JavaScript 代碼的引擎。目前,蘋果公司有 JavaScriptCore 引擎,谷歌有V8引擎。

但與 WebView 同樣,RN也須要面臨JS語言解釋性能的問題。

所以,從渲染效率角度來講,WebView < 類ReactNative < 原生。 (由於json的複雜度比html+css低)


4、Flutter渲染

首先,推薦YouTube上的一個視頻:《Flutter's Rendering Pipeline》專門講Flutter渲染相關的知識。

1. Flutter的架構:

Flutter架構

能夠看到,Flutter重寫了UI框架,從UI控件到渲染所有本身從新實現了。
不依賴 iOSAndroid 平臺的原生控件,
依賴Engine(C++)層的Skia圖形庫與系統圖形繪製相關接口。
所以,在不一樣的平臺上有了相同的體驗。

2. Flutter的渲染流程:

Flutter渲染流程

簡單來講,Flutter的界面由Widget組成。
全部Widget會組成Widget Tree
界面更新時,會更新Widget Tree
再更新Element Tree,最後更新RenderObjectTree

更新Widget的邏輯以下:

\ newWidget == null newWidget != null
child == null 返回null 返回新的Element
child != null 移除舊的child並返回null 若是舊child被更新就返回child,不然返回新的Element

image

接下來的渲染流程,
Flutter 渲染在 Framework 層會有 BuildWidget TreeElement TreeRenderObject TreeLayoutPaintComposited Layer 等幾個階段。
FlutterC++ 層,使用 Skia 庫,將 Layer 進行組合,生成紋理,使用 OpenGL 的接口向 GPU 提交渲染內容進行光柵化與合成。
提交到 GPU 進程後,合成計算,顯示屏幕的過程和 iOS 原生渲染基本是相似的,所以性能上是差很少的。

5、總結對比

渲染方式 語言 性能 對應羣體
原生 Objective-C、Swift ★★★ iOS開發者
WebView HTML、CSS、JavaScript 前端開發者
類React Native JavaScript ★★ 前端開發者
Flutter Dart ★★★ Dart開發者

但Flutter的優點在於:

  1. 跨平臺,能夠同時運行在 iOSAndroid 兩個平臺。
  2. 熱重載(Hot Reload),省去了從新編譯代碼的時間,極大的提升了開發效率。
  3. 以及將來谷歌新系統 「Fuchsia」 的發佈與加持。若是谷歌將來的新系統 Fuchsia 能應用到移動端,而且替代 Android 。因爲Fuchsia的上層是Flutter編寫的,所以Flutter開發成爲了移動端領域的必選項。同時Flutter又支持跨平臺開發,那麼其餘移動端領域的技術棧存在的價值會愈來愈低。

固然,蘋果的但願在於 SwiftUI。 若是 Fuchisa 最終失敗了,SwiftUI 也支持跨端了。同時,SwiftUI自己也支持熱重載。也許也是一個將來呢。

期待,蘋果今年6月的線上WWDC-2020吧,但願能給咱們帶來不同的驚喜。

參考與致謝:
1.《iOS開發高手課》(戴銘老師)
2.《你不知道的GPU》(月影大大)
3.《Flutter從加載到顯示》 (聖文前輩)
4.《UIKit性能調優實戰講解》(bestswifter)
5.《iOS - 渲染原理》
6.《iOS 圖像渲染原理》
7.《計算機那些事(8)——圖形圖像渲染原理》
8.《WWDC14:Advanced Graphics and Animations for iOS Apps》


瞭解更多iOS及相關新技術,請關注咱們的公衆號:

可添加以下小編微信,並備註加入QiShare技術交流羣,小編會邀請你加入《QiShare技術交流羣》。

小編微信

關注咱們的途徑有:
QiShare(簡書)
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公衆號)

推薦文章:
iOS 查看及導出項目運行日誌
Flutter Platform Channel 使用與源碼分析
開發沒切圖怎麼辦?矢量圖標(iconFont)上手指南
DarkMode、WKWebView、蘋果登陸是否必須適配?
iOS 接入 Google、Facebook 登陸(二)
iOS 接入 Google、Facebook 登陸(一)
Nginx 入門實戰 iOS中的3D變換(二)
iOS中的3D變換(一)
WebSocket 雙端實踐(iOS/ Golang)
今天咱們來聊一聊WebSocket(iOS/Golang)
奇舞團安卓團隊——aTaller
奇舞週刊

相關文章
相關標籤/搜索