iOS 原生渲染與 Flutter 有什麼區別 (上)

語言: CN / TW / HK

theme: smartblue

「這是我參與2022首次更文挑戰的第19天,活動詳情查看:2022首次更文挑戰」。

前言

今天,我們在這篇文章中來聊聊渲染原理以及iOS原生是如何渲染的。

iOS 原生渲染與 Flutter 有什麼區別

渲染原理

首先我們説説渲染原理,對於我們看到的手機界面,都是使用CPU + GPU運算繪製出來的,CPUGPU在設計的的初始時職責就有所不同,CPU擁有強大的運算能力,是整個系統的控制核心,通常會幫助計算顯示內容,GPU是專門進行繪圖運算工作的處理器,並行計算能力更強,能夠通過計算將圖形結果顯示在屏幕上。我們通常説的渲染也就是內存中的圖形數據再經過計算和轉換,最終呈現到屏幕上的過程。

在渲染過程中,CPU則處理渲染內容的計算,如視圖創建、計算佈局、圖片解碼等,內容計算完成後,再傳輸給 GPU 進行渲染。

GPU 主要是將 3D 座標轉化成 2D 座標 繼而再轉成實際像素,具體實現可以分為頂點着色器(確定形狀的點)、形狀裝配(確定形狀的線)、幾何着色器(確定三角形個數)、光柵化(確定屏幕像素點)、片段着色器(對像素點着色)、測試與混合(檢查深度和透明度進行混合)六個階段。

原生渲染

原生渲染的層級可以分為以下幾個層級: Untitled-2022-02-20-2256.png UIKitCore AnimationOpenGL ESGraphics Hardware

  • UIKit:UI基礎庫,用來滿足我們上層開發;
  • Core Animation:負責圖形渲染與動畫的基礎設施,Core Animation將大部分實際的繪圖任務交給了圖形硬件來處理。
  • OpenGL ES:OpenGL 的子集,一套專門處理GPU繪製的API。
  • Core Graphics: 基於 Quartz 高級繪圖引擎。它提供了具有無與倫比的輸出保真度的低級別輕量級 2D 渲染。您可以使用此框架來處理基於路徑的繪圖,轉換,顏色管理,離屏渲染,圖案,漸變和陰影,圖像數據管理,圖像創建和圖像遮罩以及 PDF 文檔創建,顯示和分析。
  • Graphics Hardware: 圖形硬件,

原生界面更新渲染的流程,可以分為以下流程。

第一步,更新視圖樹,同步更新圖層樹。當在操作 UI 時 如果改變了視圖Frame或者更新了 UIView / CALayer的層級時,或者手動調用了 UIView / CALayersetNeedsLayout / setNeedsDisplay方法後,在此過程中 app 可能需要更新 視圖樹,相應地,圖層樹 也會被更新;

第二步,CPU 計算要顯示的內容,包括視圖創建(設置 Layer 的屬性)、佈局計算、視圖繪製(創建 Layer 的 Backing Image)、圖像解碼轉換。當 runloopBeforeWaiting 和 Exit狀態時,會通知註冊的監聽,然後對圖層打包,打完包後,將打包數據發送給一個獨立負責渲染的進程 Render Server

第三步,數據到達 Render Server 後會被反序列化,得到圖層樹,按照圖層樹中圖層順序、RGBA 值、圖層 frame 過濾圖層中被遮擋的部分,過濾後將圖層樹轉成渲染樹,渲染樹的信息會轉給 OpenGL ES/Metal。前面 CPU 所處理的這些事情統稱為 Commit Transaction

第四步Render Server 會調用 GPUGPU 開始進行前面提到的頂點着色器、形狀裝配、幾何着色器、光柵化、片段着色器、測試與混合六個階段。完成這六個階段的工作後,再將 CPUGPU 計算後的數據顯示在屏幕的每個像素點上。整個渲染過程,如下圖所示: Render.png

如上圖所示,CPU 處理完渲染內容會輸入到 Render Server 中,經圖層樹和渲染樹的轉換,通過 OpenGL 接口提供給 GPUGPU 處理完後在屏幕上顯示。渲染過程中 Commit Trasaction 的佈局計算會重載視圖 layoutSubviews 方法,以及執行 addSubview 方法來添加視圖。視圖繪製會重載視圖的 drawRect 方法。這幾個方法都是 iOS 開發中常用的。移動視圖位置、刪除視圖、隱藏或顯示視圖、調用 setNeedsDisplaysetNeedsDisplayInRect 方法,都會觸發界面更新,執行渲染流程。

Render Server

Render Server六個階段如下: 1. 頂點着色器(Vertex Shader)。該階段的輸入是 頂點數據(Vertex Data),比如以數組的形式傳遞 3 個 3D 座標用來表示一個三角形。頂點數據是一系列頂點的集合。頂點着色器主要的目的是把 3D 座標轉為另一種 3D 座標,同時頂點着色器可以對頂點屬性進行一些基本處理。

  1. 形狀(圖元)裝配(Shape Assembly)。該階段將頂點着色器輸出的所有頂點作為輸入,並將所有的點裝配成指定圖元的形狀。圖中則是一個三角形。圖元(Primitive) 用於表示如何渲染頂點數據,如:點、線、三角形。

  2. 幾何着色器(Geometry Shader)。該階段把圖元形式的一系列頂點的集合作為輸入,它可以通過產生新頂點構造出新的(或是其它的)圖元來生成其他形狀。例子中,它生成了另一個三角形。

  3. 光柵化(Rasterization)。該階段會把圖元映射為最終屏幕上相應的像素,生成片段。片段(Fragment) 是渲染一個像素所需要的所有數據。

  4. 片段着色器(Fragment Shader)。該階段首先會對輸入的片段進行 裁切(Clipping)。裁切會丟棄超出視圖以外的所有像素,用來提升執行效率。

  5. 測試與混合(Tests and Blending)。該階段會檢測片段的對應的深度值(z 座標),判斷這個像素位於其它物體的前面還是後面,決定是否應該丟棄。此外,該階段還會檢查 alpha 值( alpha 值定義了一個物體的透明度),從而對物體進行混合。因此,即使在片段着色器中計算出來了一個像素輸出的顏色,在渲染多個三角形的時候最後的像素顏色也可能完全不同。

Render Server

寫在最後

本章着重聊了聊渲染的原理以及iOS原生渲染的過程,那麼在下一篇文章中,我們在聊聊目前火熱的Flutter它的渲染流程是如何的,以及它跟原生渲染還有一些其他的前端渲染有何區別。敬請期待!