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它的渲染流程是如何的,以及它跟原生渲染還有一些其他的前端渲染有何區別。敬請期待!