GPU渲染機(jī)制:
CPU 計(jì)算好顯示內(nèi)容提交到 GPU,GPU 渲染完成后將渲染結(jié)果放入幀緩沖區(qū)阿趁,隨后視頻控制器會(huì)按照 VSync 信號逐行讀取幀緩沖區(qū)的數(shù)據(jù)送巡,經(jīng)過可能的數(shù)模轉(zhuǎn)換傳遞給顯示器顯示。
GPU屏幕渲染有以下兩種方式:
-
On-Screen Rendering
意為當(dāng)前屏幕渲染善茎,指的是GPU的渲染操作是在當(dāng)前用于顯示的屏幕緩沖區(qū)中進(jìn)行。
-
Off-Screen Rendering
意為離屏渲染,指的是GPU在當(dāng)前屏幕緩沖區(qū)以外新開辟一個(gè)緩沖區(qū)進(jìn)行渲染操作撞鹉。
特殊的離屏渲染:
如果將不在GPU的當(dāng)前屏幕緩沖區(qū)中進(jìn)行的渲染都稱為離屏渲染,那么就還有另一種特殊的“離屏渲染”方式: CPU渲染颖侄。
如果我們重寫了drawRect方法鸟雏,并且使用任何Core Graphics的技術(shù)進(jìn)行了繪制操作,就涉及到了CPU渲染览祖。整個(gè)渲染過程由CPU在App內(nèi) 同步地
完成孝鹊,渲染得到的bitmap最后再交由GPU用于顯示。
備注:CoreGraphic通常是線程安全的展蒂,所以可以進(jìn)行異步繪制又活,顯示的時(shí)候再放回主線程苔咪,一個(gè)簡單的異步繪制過程大致如下
- (void)display {
dispatch_async(backgroundQueue, ^{
CGContextRef ctx = CGBitmapContextCreate(...);
// draw in context...
CGImageRef img = CGBitmapContextCreateImage(ctx);
CFRelease(ctx);
dispatch_async(mainQueue, ^{
layer.contents = img;
});
});
}
離屏渲染的觸發(fā)方式
設(shè)置了以下屬性時(shí),都會(huì)觸發(fā)離屏繪制:
-
shouldRasterize(光柵化)
-
masks(遮罩)
-
shadows(陰影)
-
edge
-
antialiasing(抗鋸齒)
-
group opacity(不透明)
-
復(fù)雜形狀設(shè)置圓角等
-
漸變
其中shouldRasterize(光柵化)是比較特別的一種:
光柵化概念:將圖轉(zhuǎn)化為一個(gè)個(gè)柵格組成的圖象柳骄。
光柵化特點(diǎn):每個(gè)元素對應(yīng)幀緩沖區(qū)中的一像素团赏。shouldRasterize = YES在其他屬性觸發(fā)離屏渲染的同時(shí),會(huì)將光柵化后的內(nèi)容緩存起來耐薯,如果對應(yīng)的layer及其sublayers沒有發(fā)生改變舔清,在下一幀的時(shí)候可以直接復(fù)用。shouldRasterize = YES可柿,這將隱式的創(chuàng)建一個(gè)位圖鸠踪,各種陰影遮罩等效果也會(huì)保存到位圖中并緩存起來,從而減少渲染的頻度(不是矢量圖)复斥。相當(dāng)于光柵化是把GPU的操作轉(zhuǎn)到CPU上了营密,生成位圖緩存,直接讀取復(fù)用目锭。當(dāng)你使用光柵化時(shí)评汰,你可以開啟“Color Hits Green and Misses Red”來檢查該場景下光柵化操作是否是一個(gè)好的選擇。綠色表示緩存被復(fù)用痢虹,紅色表示緩存在被重復(fù)創(chuàng)建被去。如果光柵化的層變紅得太頻繁那么光柵化對優(yōu)化可能沒有多少用處。位圖緩存從內(nèi)存中刪除又重新創(chuàng)建得太過頻繁奖唯,紅色表明緩存重建得太遲惨缆。可以針對性的選擇某個(gè)較小而較深的層結(jié)構(gòu)進(jìn)行光柵化丰捷,來嘗試減少渲染時(shí)間坯墨。
注意:
對于經(jīng)常變動(dòng)的內(nèi)容,這個(gè)時(shí)候不要開啟,否則會(huì)造成性能的浪費(fèi)
例如我們?nèi)粘探?jīng)常打交道的TableViewCell,因?yàn)門ableViewCell的重繪是很頻繁的(因?yàn)镃ell的復(fù)用),如果Cell的內(nèi)容不斷變化,則Cell需要不斷重繪,如果此時(shí)設(shè)置了cell.layer可光柵化。則會(huì)造成大量的離屏渲染,降低圖形性能病往。
離屏渲染的代價(jià)
相比于當(dāng)前屏幕渲染捣染,離屏渲染的代價(jià)是很高的,主要體現(xiàn)在兩個(gè)方面:
-
創(chuàng)建新緩沖區(qū)
要想進(jìn)行離屏渲染停巷,首先要?jiǎng)?chuàng)建一個(gè)新的緩沖區(qū)耍攘。
-
上下文切換
離屏渲染的整個(gè)過程,需要多次切換上下文環(huán)境:先是從當(dāng)前屏幕(On-Screen)切換到離屏(Off-Screen)畔勤;等到離屏渲染結(jié)束以后蕾各,將離屏緩沖區(qū)的渲染結(jié)果顯示到屏幕上有需要將上下文環(huán)境從離屏切換到當(dāng)前屏幕。而上下文環(huán)境的切換是要付出很大代價(jià)的硼被。
為什么會(huì)使用離屏渲染
當(dāng)使用圓角示损,陰影,遮罩的時(shí)候嚷硫,圖層屬性的混合體被指定為在未預(yù)合成之前不能直接在屏幕中繪制检访,所以就需要屏幕外渲染被喚起始鱼。
屏幕外渲染并不意味著軟件繪制,但是它意味著圖層必須在被顯示之前在一個(gè)屏幕外上下文中被渲染(不論CPU還是GPU)脆贵。
所以當(dāng)使用離屏渲染的時(shí)候會(huì)很容易造成性能消耗医清,因?yàn)樵贠PENGL里離屏渲染會(huì)單獨(dú)在內(nèi)存中創(chuàng)建一個(gè)屏幕外緩沖區(qū)并進(jìn)行渲染,而屏幕外緩沖區(qū)跟當(dāng)前屏幕緩沖區(qū)上下文切換是很耗性能的卖氨。
iOS版本上的優(yōu)化