iOS 渲染框架

UIKit

UIKit是iOS開發最經常使用的框架,能夠經過設置UIKit組件的佈局以及相關屬性來繪製界面。
事實上,UIKit自身並不具有在屏幕成像的能力,其主要負責對用戶操做事件的響應(UIView繼承自UIResponder),事件響應的傳遞大致是通過逐層的視圖樹遍歷實現的。ios

Core Animation

Core Animation源自於Layer Kit,動畫只是Core Animation的冰山一角。 Core Animation是一個複合引擎,其職責是儘量快地組合屏幕上不一樣的可視內容,這些可視內容可被分解成獨立的圖層(即CALayer),這些圖層會被存儲在一個叫作圖層樹的體系之中。從本質上而言,CALayer是用戶所能在屏幕上看見的一切的基礎。緩存

Core Graphics

Core Graphics基於Quartz高級繪圖引擎,主要用於運行時繪製圖像。開發者可使用此框架來處理基於路徑的繪圖,轉換,顏色管理,離屏渲染,圖案,漸變和陰影,圖像數據管理,圖像建立和圖像遮罩以及PDF文檔建立,顯示和分析。bash

當開發者須要在運行時建立圖像時,可使用Core Graphics去繪製。與之相對的是運行前建立圖像,例如用Photoshop提早作好圖片素材直接導入應用。相比之下,咱們更須要Core Graphics去在運行時實時計算、繪製一系列圖像幀來實現動畫。app

Core Image

Core ImageCore Graphics偏偏相反,Core Graphics用於在運行時建立圖像,而Core Image用於處理運行前建立的圖像。Core Image框架擁有一系列現成的圖像過濾器,能對一寸照的圖像進行高效的處理。
大部分狀況下,Core Image會在GPU中完成工做,若是GPU忙,會使用CPU進行處理。框架

OpenGL ES

OpenGL ESOpenGL的子集。在圖形渲染原理一文中提到過OpenGL是一套第三方標準,函數的內部實現由對應的GPU廠商開發實現。OpenGL / OpenGL ES入門篇,請參考OpenGL/OpenGL ES 入門:圖形API以及專業名詞解析等系列文章函數

UIView與CALayer的關係

CALayer事實上是用戶所能在屏幕上看見的一切的基礎。爲何UIKit中的視圖可以呈現可視化內容,就是由於UIKit中的每個UI視圖控件其實內部都有一個關聯的CALayer,即backing layer
因爲這種一一對應的關係,視圖層級有用視圖樹的樹形結構,對應CALayer層級也擁有圖層樹的樹形結構。oop

其中,視圖的職責是建立並管理圖層,以確保當子視圖在層級關係中添加或被移除時,其關聯的圖層在圖層樹中也有相同的操做,即保證視圖樹和圖層樹在結構上的一致性。佈局

爲何iOS要基於UIView和CALayer提供兩個平行的層級關係呢?post

其緣由在於要作職責分離,這樣也能避免不少重複代碼。在iOS和Mac OSX兩個平臺上,事件和用戶交互有不少地方的不一樣,基於多點觸控的用戶界面和基於鼠標鍵盤的交互有着本質的區別,這就是爲何iOS有UIKitUIView,對應Mac OSX有AppKitNSView的緣由。它們在功能上很類似,可是在實現上有着顯著的區別。動畫

實際上,這裏並非兩個層級關係,而是四個。每個都扮演着不一樣的角色。除了視圖樹圖層樹,還有呈現樹渲染樹

CALayer
那麼爲何CALayer能夠呈現可視化內容呢?由於CALayer基本等同於一個紋理。紋理是GPU進行圖像渲染的重要依據。

圖形渲染原理中提到紋理本質上就是一張圖片,所以CALayer也包含一個contents屬性指向一塊緩存區,稱爲backing store,能夠存放位圖(Bitmap)。iOS中將該緩存區保存的圖片稱爲寄宿圖

圖形渲染流水線支持從頂點開始進行繪製(在流水線中,頂點會被處理生成紋理),也支持直接使用紋理(圖片)進行渲染。相應地,在實際開發中,繪製界面也有兩種方式: 一種是手動繪製;另外一種是使用圖片

對此,iOS中也有兩種相應的實現方式:

  • 使用圖片:contents image
  • 手動繪製:custom drawing

Contents Image
Contents Image是指經過CALayercontents屬性來配置圖片。然而,contents屬性的類型爲id,在這種狀況下,能夠給contents屬性賦予任何值,app仍能夠編譯經過。可是在實踐中,若是contents的值不是CGImage,獲得的圖層將是空白的。

既然如此,爲何要將contents的屬性類型定義爲id而非CGImage。由於在Mac OS系統中,該屬性對CGImageNSImage類型的值都起做用,而在iOS系統中,該屬性只對CGImage起做用。

本質上,contents屬性指向的一塊緩存區域,稱爲backing store,能夠存放bitmap數據。

Custom Drawing
Custom Drawing是指使用Core Graphics直接繪製寄宿圖。實際開發中,通常經過繼承UIView並實現-drawRect:方法來自定義繪製。

雖然-drawRect:是一個UIView方法,但事實上都是底層的CALayer完成了重繪工做並保存了產生的圖片。 下圖所示爲drawRect:繪製定義寄宿圖的基本原理

  • UIView有一個關聯圖層,即CALayer
  • CALayer有一個可選的delegate屬性,實現了CALayerDelegate協議。UIView做爲CALayer的代理實現了CALayerDelegate協議。
  • 當須要重繪時,即調用-drawRect:CALayer請求其代理給予一個寄宿圖來顯示。
  • CALayer首先會嘗試調用-displayLayer:方法,此時代理能夠直接設置contents屬性。
- (void)displayLayer:(CALayer *)layer;
複製代碼
  • 若是代理沒有實現-displayLayer:方法,CALayer則會嘗試調用-drawLayer:inContext:方法。在調用該方法前,CALayer會建立一個空的寄宿圖(尺寸由boundscontentScale決定)和一個Core Graphics的繪製上下文,爲繪製寄宿圖作準備,做爲ctx參數傳入。
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx;
複製代碼
  • 最後,有Core Graphics繪製生成的寄宿圖會存入backing store

Core Animation 流水線

介紹一下Core Animation流水線的工做原理:

事實上,app自己並不負責渲染,渲染則是由一個獨立的進程負責,即 Render Server進程。

App經過IPC將渲染任務及相關數據提交給Render ServerRender Server處理完數據後,再傳遞至GPU。最後由GPU調用iOS的圖像設備進行顯示。

Core Animation流水線的詳細過程以下:

  • 首先,由app處理事件(Handle Events),如:用戶點擊操做,在此過程當中app可能須要更新視圖樹,相應地,圖層樹也會被更新。
  • 其次,app經過CPU完成對顯示內容的計算,如:視圖的建立、佈局計算、圖片解碼、文本繪製等。在完成對現實內容的計算以後,app對圖層進行打包,並在下一次RunLoop時將其發送至Render Server,即完成了一次commit Transaction操做。
  • Render Server主要執行OpenGL、Core Graphics相關程序,並調用GPU。
  • GPU則在物理層上完成了對圖像的渲染。
  • 最終,GPU經過Frame Buffer、視頻控制器等相關部件,將圖像顯示在屏幕上。

對上述步驟進行串聯,他們執行所消耗的時間圓圓超過16.67ms,所以爲了知足對屏幕的60FPS刷新率的支持,須要將這些步驟進行分解,經過流水線的方式並行執行,以下圖:

Commit Transaction

Core Animation流水線中,app調用Render Server前的最後一步Commit Transaction其實能夠細分爲4個步驟:

  • Layout
  • Display
  • Prepare
  • Commit

Layout

Layout階段主要進行視圖構建,包括:LayoutSubviews方法的重載,addSubview:方法填充子視圖等。

Display

Display階段主要進行視圖繪製,這裏僅僅是設置成像的圖元數據。重載視圖的drawRect:方法能夠自定義UIView的顯示,其原理是在drawRect:方法內部繪製寄宿圖,該過程使用GPU和內存。

Prepare

Prepare階段屬於附加步驟,通常處理圖像的解碼和轉碼等操做。

Commit

commit階段主要將圖層進行打包,並將它們發送至Render Server。該過程會遞歸執行,由於圖層和視圖都是以樹形結構存在。

動畫渲染原理

iOS動畫的渲染也是基於上述Core Animation流水線完成的。這裏咱們重點關注app與Render Server的執行流程。

平常開發中,若是不是特別的複雜動畫,通常使用UIView Animation實現,iOS將其處理過程分爲以下三部階段:

  • Step1:調用animationWithDuration:animations:方法
  • Step2:在Animation Block中進行Layout,Display,Prepare,Commit等步驟。
  • Step3:Render Server根據Animation逐幀進行渲染。

參考博客 iOS圖像渲染原理

相關文章
相關標籤/搜索