標籤:
介面的繪製和渲染
UIView是如何到顯示的螢幕上的。
這件事要從RunLoop開始,RunLoop是一個60fps的回調,也就是說每16.7ms繪製一次螢幕,也就是我們需要在這個時間內完成view的緩衝區建立,view內容的繪製這些是CPU的工作;然後把緩衝區交給GPU渲染,這裡包括了多個View的拼接(Compositing),紋理的渲染(Texture)等等,最後Display到螢幕上。但是如果你在16.7ms內做的事情太多,導致CPU,GPU無法在指定時間內完成指定的工作,那麼就會出現卡頓現象,也就是丟幀。
60fps是Apple給出的最佳幀率,但是實際中我們如果能保證幀率可以穩定到30fps就能保證不會有卡頓的現象,60fps更多用在遊戲上。所以如果你的應用能夠保證33.4ms繪製一次螢幕,基本上就不會卡了。
總的來說,UIView從Draw到Render的過程有如下幾步:
每一個UIView都有一個layer,每一個layer都有個content,這個content指向的是一塊緩衝,叫做backing store。
UIView的繪製和渲染是兩個過程,當UIView被繪製時,CPU執行drawRect,通過context將資料寫入backing store。
當backing store寫完後,通過render server交給GPU去渲染,將backing store中的bitmap資料顯示在螢幕上。
就是從CPU到GPU的過程
pic_5.jpeg
其實說到底CPU就是做繪製的操作把內容放到緩衝裡,GPU負責從緩衝裡讀取資料然後渲染到螢幕上。
就如同的所示
pic_4.jpeg
整個過程也就是一件事:CPU將準備好的bitmap放到RAM裡,GPU去搬這快記憶體到VRAM中處理。
而這個過程GPU所能承受的極限大概在16.7ms完成一幀的處理,所以最開始提到的60fps其實就是GPU能處理的最高頻率。
因此,GPU的挑戰有兩個:
將資料從RAM搬到VRAM中
將Texture渲染到螢幕上
這兩個中瓶頸基本在第二點上。渲染Texture基本要處理這麼幾個問題:
合成(Compositing):
Compositing是指將多個紋理拼到一起的過程,對應UIKit,是指處理多個view合到一起的情況(drawRect只有當addsubview情況下才會觸發)
[self.view addsubview:subview]
如果view之間沒有疊加,那麼GPU只需要做普通渲染即可。 如果多個view之間有疊加部分,GPU需要做blending。
尺寸(Size):
這個問題,主要是處理image帶來的,假如記憶體裡有一張400x400的圖片,要放到100x100的imageview裡,如果不做任何處理,直接丟進去,問題就大了,這意味著,GPU需要對大圖進行縮放到小的地區顯示,需要做像素點的sampling,這種smapling的代價很高,又需要兼顧pixel alignment。計算量會飆升。
離屏渲染(Offscreen Rendering And Mask):
我們來看一下關於iOS中圖形繪製架構的大致結構
pic_3.jpeg
UIKit是iOS中用來系統管理使用者圖形互動的架構,但是UIKit本身構建在CoreAnimation架構之上,CoreAnimation分成了兩部分OpenGL ES和Core Graphics,OpenGL ES是直接調用底層的GPU進行渲染;Core Graphics是一個基於CPU的繪製引擎;
我們平時所說的硬體加速其實都是指OpenGL,Core Animation/UIKit基於GPU之上對電腦圖形合成以及繪製的實現,由於CPU是渲染能力要低於GPU,所以當採用CPU繪製時動畫時會有明顯的卡頓。
但是其中的有些繪製會產生離屏渲染,額外增加GPU以及CPU的繪製渲染。
OpenGL中,GPU螢幕渲染有以下兩種方式:
離屏渲染的代價主要包括兩方面內容:
為什麼需要離屏渲染?
目的在於當使用圓角,陰影,遮罩的時候,圖層屬性的混合體被指定為在未預合成之前不能直接在螢幕中繪製,即當主屏的還沒有繪製好的時候,所以就需要螢幕外渲染,最後當主屏已經繪製完成的時候,再將離屏的內容轉移至主屏上。
離屏渲染的觸發方式:
shouldRasterize(光柵化)
masks(遮罩)
shadows(陰影)
edge antialiasing(消除鋸齒)
group opacity(不透明)
上述的一些屬性設定都會產生離屏渲染的問題,大大降低GPU的渲染效能。
CPU渲染:
以上所說的都是離屏渲染髮生在OpenGL SE也就是GPU中,但是CPU也會發生特殊的渲染,我們的CPU渲染,也就是我們使用Core Graphics的時候,但是要注意的一點的是只有在我們重寫了drawRect方法,並且使用任何Core Graphics的技術進行了繪製操作,就涉及到了CPU渲染。整個渲染過程由CPU在App內 同步地 完成,渲染得到的bitmap最後再交由GPU用於顯示。
理論上CPU渲染應該不算是標準意義上的離屏渲染,但是由於CPU自身做渲染的效能也不好,所以這種方式也是需要盡量避免的。
分析
所以對於當屏渲染,離屏渲染和CPU渲染的來說,當屏渲染永遠是最好的選擇,但是考慮到GPU的浮點運算能力要比CPU強,但是由於離屏渲染需要重新開闢緩衝區以及螢幕的環境切換,所以在離屏渲染和CPU渲染的效能比較上需要根據實際情況作出選擇。
總結
其實第一部分的實現當時並沒有太多考慮效能上的一些問題,所以具體繪圖效能方面的最佳化,我會在下次的文章中闡述,也是我們App中實際遇到的一些情況以及對應的解決方案。
iOS介面的繪製和渲染