GPU 渲染機制:CPU 計算好顯示內(nèi)容提交到 GPU,GPU 渲染完成后將渲染結(jié)果放入幀緩沖區(qū),隨后視頻控制器會按照 VSync 信號逐行讀取幀緩沖區(qū)的數(shù)據(jù),經(jīng)過可能的數(shù)模轉(zhuǎn)換傳遞給顯示器顯示。
GPU 屏幕渲染有以下兩種方式:
- 1)On-Screen Rendering,意為當(dāng)前屏幕渲染,指的是 GPU 的渲染操作是在當(dāng)前用于顯示的屏幕緩沖區(qū)中進(jìn)行。
- 2)Off-Screen Rendering,意為離屏渲染,指的是 GPU 在當(dāng)前屏幕緩沖區(qū)以外新開辟一個緩沖區(qū)進(jìn)行渲染操作。
特殊的離屏渲染:如果將不在 GPU 的當(dāng)前屏幕緩沖區(qū)中進(jìn)行的渲染都稱為離屏渲染,那么就還有另一種特殊的“離屏渲染”方式:CPU 渲染。如果我們重寫了 drawRect 方法,并且使用任何 Core Graphics 的技術(shù)進(jìn)行了繪制操作,就涉及到了 CPU 渲染。整個渲染過程由 CPU 在 App 內(nèi)同步地 完成,渲染得到的 bitmap 最后再交由 GPU 用于顯示。備注:Core Graphics 通常是線程安全的,所以可以進(jìn)行異步繪制,顯示的時候再放回主線程,一個簡單的異步繪制過程大致如下:
- (void)display {
dispatch_async(backgroundQueue, ^{
CGContextRef ctx = CGBitmapContextCreate(...);
// draw in context...
CGImageRef img = CGBitmapContextCreateImage(ctx);
CFRelease(ctx);
dispatch_async(mainQueue, ^{
layer.contents = img;
});
});
}
離屏渲染的觸發(fā)方式:
- 1)shouldRasterize(光柵化),光柵化是比較特別的一種。光柵化概念:將圖轉(zhuǎn)化為一個個柵格組成的圖象。光柵化特點:每個元素對應(yīng)幀緩沖區(qū)中的一像素。shouldRasterize = YES 在其他屬性觸發(fā)離屏渲染的同時,會將光柵化后的內(nèi)容緩存起來,如果對應(yīng)的 layer 及其 sublayers 沒有發(fā)生改變,在下一幀的時候可以直接復(fù)用。shouldRasterize = YES 這將隱式的創(chuàng)建一個位圖,各種陰影遮罩等效果也會保存到位圖中并緩存起來,從而減少渲染的頻度。相當(dāng)于光柵化是把 GPU 的操作轉(zhuǎn)到 CPU 上了,生成位圖緩存,直接讀取復(fù)用。當(dāng)你使用光柵化時,你可以開啟 Color Hits Green and Misses Red 來檢查該場景下光柵化操作是否是一個好的選擇。綠色表示緩存被復(fù)用,紅色表示緩存在被重復(fù)創(chuàng)建。如果光柵化的層變紅得太頻繁那么光柵化對優(yōu)化可能沒有多少用處。位圖緩存從內(nèi)存中刪除又重新創(chuàng)建得太過頻繁,紅色表明緩存重建得太遲??梢葬槍π缘倪x擇某個較小而較深的層結(jié)構(gòu)進(jìn)行光柵化,來嘗試減少渲染時間。對于經(jīng)常變動的內(nèi)容,這個時候不要開啟,否則會造成性能的浪費。例如經(jīng)常打交道的 TableViewCell,因為 TableViewCell 的重繪是很頻繁的(因為 Cell 的復(fù)用),如果 Cell 的內(nèi)容不斷變化,則 Cell 需要不斷重繪,如果此時設(shè)置了 cell.layer 可光柵化,則會造成大量的離屏渲染,降低圖形性能。
- 2)masks(遮罩)
- 3)shadows(陰影)
- 4)edge antialiasing(抗鋸齒)
- 5)group opacity(不透明)
- 6)復(fù)雜形狀設(shè)置圓角等
- 7)漸變
為什么會使用離屏渲染:當(dāng)使用圓角,陰影,遮罩的時候,圖層屬性的混合體被指定為在未預(yù)合成之前(下一個 VSync 信號開始前)不能直接在屏幕中繪制,所以就需要屏幕外渲染被喚起。屏幕外渲染并不意味著軟件繪制,但是它意味著圖層必須在被顯示之前在一個屏幕外上下文中被渲染(不論 CPU 還是 GPU)。所以當(dāng)使用離屏渲染的時候會很容易造成性能消耗,因為離屏渲染會單獨在內(nèi)存中創(chuàng)建一個屏幕外緩沖區(qū)并進(jìn)行渲染,而屏幕外緩沖區(qū)跟當(dāng)前屏幕緩沖區(qū)上下文切換是很耗性能的。由于垂直同步的機制,如果在一個 VSync 時間內(nèi),CPU 或者 GPU 沒有完成內(nèi)容提交,則那一幀就會被丟棄,等待下一次機會再顯示,而這時顯示屏?xí)A糁暗膬?nèi)容不變。這就是界面卡頓的原因。
Instruments 監(jiān)測離屏渲染:
- 1)Color Offscreen-Rendered Yellow,開啟后會把那些需要離屏渲染的圖層高亮成黃色,這就意味著黃色圖層可能存在性能問題。
- 2)Color Hits Green and Misses Red,如果 shouldRasterize 被設(shè)置成 YES,對應(yīng)的渲染結(jié)果會被緩存,如果圖層是綠色,就表示這些緩存被復(fù)用;如果是紅色就表示緩存會被重復(fù)創(chuàng)建,這就表示該處存在性能問題了。
iOS 版本上的優(yōu)化:
- 1)iOS 9.0 之前 UIimageView、UIButton 設(shè)置圓角都會觸發(fā)離屏渲染。
- 2)iOS 9.0 之后 UIButton 設(shè)置圓角會觸發(fā)離屏渲染,而 UIImageView 里 png 圖片設(shè)置圓角不會觸發(fā)離屏渲染了,如果設(shè)置其他陰影效果之類的還是會觸發(fā)離屏渲染的。
更多:iOS面試題合集