iOS 原生渲染與 Flutter 有什麼區別 (上)
theme: smartblue
「這是我參與2022首次更文挑戰的第19天,活動詳情檢視:2022首次更文挑戰」。
前言
今天,我們在這篇文章中來聊聊渲染原理以及iOS原生是如何渲染的。
iOS 原生渲染與 Flutter 有什麼區別
渲染原理
首先我們說說渲染原理,對於我們看到的手機介面,都是使用CPU + GPU
運算繪製出來的,CPU
和GPU
在設計的的初始時職責就有所不同,CPU
擁有強大的運算能力,是整個系統的控制核心,通常會幫助計算顯示內容,GPU
是專門進行繪圖運算工作的處理器,平行計算能力更強,能夠通過計算將圖形結果顯示在螢幕上。我們通常說的渲染也就是記憶體中的圖形資料再經過計算和轉換,最終呈現到螢幕上的過程。
在渲染過程中,CPU
則處理渲染內容的計算,如檢視建立、計算佈局、圖片解碼等,內容計算完成後,再傳輸給 GPU
進行渲染。
而GPU
主要是將 3D
座標轉化成 2D
座標 繼而再轉成實際畫素,具體實現可以分為頂點著色器(確定形狀的點)、形狀裝配(確定形狀的線)、幾何著色器(確定三角形個數)、光柵化(確定螢幕畫素點)、片段著色器(對畫素點著色)、測試與混合(檢查深度和透明度進行混合)六個階段。
原生渲染
原生渲染的層級可以分為以下幾個層級:
UIKit
、Core Animation
、OpenGL ES
、Graphics Hardware
UIKit
:UI基礎庫,用來滿足我們上層開發;Core Animation
:負責圖形渲染與動畫的基礎設施,Core Animation
將大部分實際的繪圖任務交給了圖形硬體來處理。OpenGL ES
:OpenGL 的子集,一套專門處理GPU繪製的API。Core Graphics
: 基於 Quartz 高階繪圖引擎。它提供了具有無與倫比的輸出保真度的低級別輕量級 2D 渲染。您可以使用此框架來處理基於路徑的繪圖,轉換,顏色管理,離屏渲染,圖案,漸變和陰影,影象資料管理,影象建立和影象遮罩以及 PDF 文件建立,顯示和分析。Graphics Hardware
: 圖形硬體,
原生介面更新渲染的流程,可以分為以下流程。
第一步,更新檢視樹,同步更新圖層樹。當在操作 UI 時 如果改變了檢視Frame或者更新了 UIView / CALayer
的層級時,或者手動呼叫了 UIView / CALayer
的 setNeedsLayout / setNeedsDisplay
方法後,在此過程中 app 可能需要更新 檢視樹
,相應地,圖層樹
也會被更新;
第二步,CPU 計算要顯示的內容,包括檢視建立(設定 Layer 的屬性)、佈局計算、檢視繪製(建立 Layer 的 Backing Image)、影象解碼轉換。當 runloop
在 BeforeWaiting 和 Exit
狀態時,會通知註冊的監聽,然後對圖層打包,打完包後,將打包資料傳送給一個獨立負責渲染的程序 Render Server
。
第三步,資料到達 Render Server
後會被反序列化,得到圖層樹,按照圖層樹中圖層順序、RGBA 值、圖層 frame 過濾圖層中被遮擋的部分,過濾後將圖層樹轉成渲染樹,渲染樹的資訊會轉給 OpenGL ES/Metal
。前面 CPU
所處理的這些事情統稱為 Commit Transaction
。
第四步,Render Server
會呼叫 GPU
,GPU
開始進行前面提到的頂點著色器、形狀裝配、幾何著色器、光柵化、片段著色器、測試與混合六個階段。完成這六個階段的工作後,再將 CPU
和 GPU
計算後的資料顯示在螢幕的每個畫素點上。整個渲染過程,如下圖所示:
如上圖所示,CPU
處理完渲染內容會輸入到 Render Server
中,經圖層樹和渲染樹的轉換,通過 OpenGL
介面提供給 GPU
,GPU
處理完後在螢幕上顯示。渲染過程中 Commit Trasaction
的佈局計算會過載檢視 layoutSubviews
方法,以及執行 addSubview
方法來新增檢視。檢視繪製會過載檢視的 drawRect
方法。這幾個方法都是 iOS
開發中常用的。移動檢視位置、刪除檢視、隱藏或顯示檢視、呼叫 setNeedsDisplay
或 setNeedsDisplayInRect
方法,都會觸發介面更新,執行渲染流程。
Render Server
Render Server
六個階段如下:
1. 頂點著色器(Vertex Shader
)。該階段的輸入是 頂點資料(Vertex Data
),比如以陣列的形式傳遞 3 個 3D 座標用來表示一個三角形。頂點資料是一系列頂點的集合。頂點著色器主要的目的是把 3D 座標轉為另一種 3D 座標,同時頂點著色器可以對頂點屬性進行一些基本處理。
-
形狀(圖元)裝配(
Shape Assembly
)。該階段將頂點著色器輸出的所有頂點作為輸入,並將所有的點裝配成指定圖元的形狀。圖中則是一個三角形。圖元(Primitive) 用於表示如何渲染頂點資料,如:點、線、三角形。 -
幾何著色器(
Geometry Shader
)。該階段把圖元形式的一系列頂點的集合作為輸入,它可以通過產生新頂點構造出新的(或是其它的)圖元來生成其他形狀。例子中,它生成了另一個三角形。 -
光柵化(
Rasterization
)。該階段會把圖元對映為最終螢幕上相應的畫素,生成片段。片段(Fragment) 是渲染一個畫素所需要的所有資料。 -
片段著色器(
Fragment Shader
)。該階段首先會對輸入的片段進行 裁切(Clipping)。裁切會丟棄超出檢視以外的所有畫素,用來提升執行效率。 -
測試與混合(
Tests and Blending
)。該階段會檢測片段的對應的深度值
(z 座標),判斷這個畫素位於其它物體的前面還是後面,決定是否應該丟棄。此外,該階段還會檢查alpha
值( alpha 值定義了一個物體的透明度),從而對物體進行混合。因此,即使在片段著色器中計算出來了一個畫素輸出的顏色,在渲染多個三角形的時候最後的畫素顏色也可能完全不同。
寫在最後
本章著重聊了聊渲染的原理以及iOS原生渲染的過程,那麼在下一篇文章中,我們在聊聊目前火熱的Flutter
它的渲染流程是如何的,以及它跟原生渲染還有一些其他的前端渲染有何區別。敬請期待!
- LeetCode 初級演算法之陣列(上),看看你都學會了嗎?
- LeetCode 初級演算法之連結串列,看看你都學會了嗎?
- LeetCode 初級演算法之字串(上),看看你都學會了嗎?
- 純程式碼佈局,也可以一樣的簡潔
- UIStackView之一問一答
- 使用UIStackView來簡化iOS的介面佈局
- 夏天來了,iOS開發者們該如何減少App耗電?(上)
- 夏天來了,App開發者們如何看待手機發燙問題?
- 聊聊iOS中UITableView複用的那些事
- 曾經經典的微信打飛機遊戲還有人記得嗎?
- iOS 原生渲染與 Flutter 有什麼區別 (上)
- 瞭解 Mach-O檔案
- CocoaPods中podsepc檔案設定詳解
- iOS 原生渲染與 Flutter 有什麼區別 (下)
- 簡單瞭解 iOS CVPixelBuffer (上)
- 談談 iOS 包瘦身方案
- 播放器重構的探索之路
- 如何使用CocoaPods製作私有庫
- iOS 元件化方案