iOS面試題:聊一聊iOS 中的離屏渲染?

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面試題合集

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • GPU渲染機制: CPU 計算好顯示內(nèi)容提交到 GPU,GPU 渲染完成后將渲染結(jié)果放入幀緩沖區(qū),隨后視頻控制器會...
    尋找最亮的光閱讀 4,795評論 1 19
  • GPU渲染機制:CPU 計算好顯示內(nèi)容提交到 GPU,GPU 渲染完成后將渲染結(jié)果放入幀緩沖區(qū),隨后視頻控制器會按...
    ScaryMonsterLyn閱讀 1,677評論 0 7
  • 相比于當(dāng)前屏幕渲染,離屏渲染的代價是很高的,這也是iOS移動端優(yōu)化的必要部分。 OpenGL中,GPU屏幕渲染有以...
    一個人在路上走下去閱讀 9,109評論 0 74
  • 圖像顯示原理 圖像顯示的大概流程: 程序運行從內(nèi)存中讀取數(shù)據(jù)對圖片進(jìn)行解壓得到像素數(shù)據(jù),若GPU不支持圖片的顏色格...
    foreverSun_122閱讀 718評論 0 2
  • 肉肉的腳丫,嫩嫩的小手,砰砰的小心跳,有機而輕快的呼吸,你睡在我身邊,就像這世界的全部,感覺欣慰滿足。 你一天天長...
    尼采_07b5閱讀 228評論 0 0

友情鏈接更多精彩內(nèi)容