什么是離屏渲染
首先我們來看一下渲染架構(gòu):

CPU 計算好顯示內(nèi)容提交到 GPU,如果要在顯示屏上顯示內(nèi)容,我們至少需要一塊與屏幕像素數(shù)據(jù)量一樣大的幀緩沖區(qū)(frame buffer),作為像素數(shù)據(jù)存儲區(qū)域,而這也是GPU存儲渲染結(jié)果的地方。GPU 渲染完成后將渲染結(jié)果放入frame buffer,隨后視頻控制器會按照 VSync 信號逐行讀取frame buffer的數(shù)據(jù),經(jīng)過可能的數(shù)模轉(zhuǎn)換傳遞給顯示器顯示。顯示完成后,frame buffer中的數(shù)據(jù)直接丟棄。
如果有時因為面臨一些限制,無法把渲染結(jié)果直接寫入frame buffer,而是先暫存在另外的內(nèi)存區(qū)域,之后再寫入frame buffer,那么這個過程被稱之為離屏渲染。

這里要注意,被iOS認(rèn)定的離屏渲染是GPU產(chǎn)生的,如果重寫了drawRect方法,并且使用任何Core Graphics 的技術(shù)進行了繪制操作,就涉及到CPU渲染。這種CPU渲染可以成為軟件渲染,不會被iOS系統(tǒng)認(rèn)定為離屏渲染。
離屏渲染帶來的影響
1)額外的內(nèi)存
離屏渲染需要開放一塊內(nèi)存存放渲染數(shù)據(jù),這部分內(nèi)存最大為屏幕展示的2.5倍
2)上下文切換
離屏渲染的整個過程需要切換上下文環(huán)境,先從當(dāng)前屏幕切換到離屏,等結(jié)束后,又要將上下文環(huán)境切換回來。雖然在iOS中,設(shè)備主存和GPU的顯存共享物理內(nèi)存,這樣可以省去一些數(shù)據(jù)傳輸開銷,但是還是要占用系統(tǒng)資源。
離屏渲染的原因
先說下我的理解:
離屏渲染是由于渲染層之間存在依賴引發(fā)的。
在上面的渲染流水線示意圖中我們可以看到,主要的渲染操作都是由CoreAnimation的Render Server模塊,通過調(diào)用顯卡驅(qū)動所提供的OpenGL/Metal接口來執(zhí)行的。通常對于每一層layer,Render Server會遵循“畫家算法”,按次序輸出到frame buffer,后一層 After Layer 會覆蓋前一層 Before Layer,就能得到最終的顯示結(jié)果。
但是,如果此時After Layer的渲染數(shù)據(jù)是半透明的,需要混合Before Layer的數(shù)據(jù),按照正常的渲染流程,此時frame buffer中Before Layer已經(jīng)被丟棄了,根本無法進行混合。為了保留Before Layer,iOS開辟了離屏渲染緩沖區(qū),對Before Layer進行存儲。
圓角 與 masksToBounds
首先我們要了解 CALayer的層次結(jié)構(gòu):CALayer由背景色backgroundColor、內(nèi)容contents、邊緣borderWidth&borderColor構(gòu)成

cornerRadius的文檔中明確說明:
cornerRadius的設(shè)置只對 CALayer 的背景色層和邊緣層起作用
當(dāng)我們只配置cornerRadius時,背景色層和邊緣層生成圓角,內(nèi)容層的渲染數(shù)據(jù)是直接覆蓋背景色層,邊緣層的數(shù)據(jù)也是同樣,這時候不會觸發(fā)離屏渲染
當(dāng)我們配置 masksToBounds的時候,這個時候,內(nèi)容層也要被裁剪圓角,而裁剪方式依賴邊緣層。還記得我們說過的,離屏渲染是由于渲染層之間存在依賴引發(fā)的。現(xiàn)在內(nèi)容層與邊緣層就相互依賴了,從而導(dǎo)致了離屏渲染。
常見的觸發(fā)離屏渲染情況
- 需要進行裁剪的 layer (layer.masksToBounds / view.clipsToBounds)
在View上設(shè)置相同形狀的Mask View,要背裁剪掉的部分設(shè)置成背景色

- 設(shè)置了組透明度為 YES,并且透明度不為 1 的 layer (layer.allowsGroupOpacity/ layer.opacity)
這個只能盡量不要使用
- 添加了投影的 layer (layer.shadow*)
使用陰影路徑計算
繪制了文字的 layer (UILabel, CATextLayer, Core Text 等)
盡量使用Label代替采用了光柵化的 layer (layer.shouldRasterize)
這是主動進行離屏渲染,提高渲染效率.
