iOS開發(fā)-視圖渲染與性能優(yōu)化

前言

關(guān)于iOS的視圖渲染流程丸边,以及性能優(yōu)化的建議。
源于WWDC視頻
我假設(shè)你是一個這樣的開發(fā)者:

  • 了解OpenGL ES佑刷;
  • 了解view hierarchy;
  • 了解instruments酿炸;

view hierarchy和instruments網(wǎng)上資料很多瘫絮,OpenGL ES的你可以看OpenGL ES文集

視圖渲染

UIKit是常用的框架填硕,顯示麦萤、動畫都通過CoreAnimation。
CoreAnimation是核心動畫扁眯,依賴于OpenGL ES做GPU渲染壮莹,CoreGraphics做CPU渲染;
最底層的GraphicsHardWare是圖形硬件姻檀。



下圖是另外一種表現(xiàn)的形式命满。在屏幕上顯示視圖,需要CPU和GPU一起協(xié)作绣版。一部數(shù)據(jù)通過CoreGraphics胶台、CoreImage由CPU預(yù)處理。最終通過OpenGL ES將數(shù)據(jù)傳送到 GPU杂抽,最終顯示到屏幕诈唬。

CoreImage支持CPU、GPU兩種處理模式缩麸。

顯示邏輯

  • 1铸磅、CoreAnimation提交會話,包括自己和子樹(view hierarchy)的layout狀態(tài)等杭朱;
  • 2阅仔、RenderServer解析提交的子樹狀態(tài),生成繪制指令弧械;
  • 3八酒、GPU執(zhí)行繪制指令;
  • 4梦谜、顯示渲染后的數(shù)據(jù)丘跌;


提交流程(以動畫為例)

第2步為prepare to commit animation (layoutSubviews,drawRect:)袭景;


1、布局(Layout)

調(diào)用layoutSubviews方法闭树;
調(diào)用addSubview:方法耸棒;

會造成CPU和I/O瓶頸;

2报辱、顯示(Display)

通過drawRect繪制視圖与殃;
繪制string(字符串);

會造成CPU和內(nèi)存瓶頸碍现;
每個UIView都有CALayer幅疼,同時圖層有一個像素存儲空間,存放視圖昼接;調(diào)用-setNeedsDisplay的時候爽篷,僅會設(shè)置圖層為dirty。
當渲染系統(tǒng)準備就緒慢睡,調(diào)用視圖的-display方法逐工,同時裝配像素存儲空間,建立一個CoreGraphics上下文(CGContextRef)漂辐,將上下文push進上下文堆棧泪喊,繪圖程序進入對應(yīng)的內(nèi)存存儲空間。

UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(10, 10)];
[path addLineToPoint:CGPointMake(20, 20)];
[path closePath];
path.lineWidth = 1;
[[UIColor redColor] setStroke];
[path stroke];

在-drawRect方法中實現(xiàn)如上代碼髓涯,UIKit會將自動生成的CGContextRef 放入上下文堆棧袒啼。
當繪制完成后,視圖的像素會被渲染到屏幕上纬纪;當下次再次調(diào)用視圖的-setNeedsDisplay蚓再,將會再次調(diào)用-drawRect方法。

3育八、準備提交(Prepare)

解碼圖片对途;
圖片格式轉(zhuǎn)換;

GPU不支持的某些圖片格式髓棋,盡量使用GPU能支持的圖片格式;

4惶洲、提交(Commit)

打包layers并發(fā)送到渲染server按声;
遞歸提交子樹的layers;
如果子樹太復(fù)雜恬吕,會消耗很大签则,對性能造成影響;

盡可能簡化viewTree铐料;

當顯示一個UIImageView時渐裂,Core Animation會創(chuàng)建一個OpenGL ES紋理豺旬,并確保在這個圖層中的位圖被上傳到對應(yīng)的紋理中。當你重寫-drawInContext方法時柒凉,Core Animation會請求分配一個紋理族阅,同時確保Core Graphics會將你在-drawInContext中繪制的東西放入到紋理的位圖數(shù)據(jù)中。

Tile-Based 渲染

這里有PDF文檔
Tiled-Based 渲染是移動設(shè)備的主流膝捞。整個屏幕會分解成N*Npixels組成的瓦片(Tiles)坦刀,tiles存儲于SoC 緩存(SoC=system on chip,片上系統(tǒng)蔬咬,是在整塊芯片上實現(xiàn)一個復(fù)雜系統(tǒng)功能鲤遥,如intel cpu,整合了集顯林艘,內(nèi)存控制器盖奈,cpu運核心,緩存狐援,隊列卜朗、非核心和I/O控制器)。
幾何形狀會分解成若干個tiles咕村,對于每一塊tile场钉,把必須的幾何體提交到OpenGL ES,然后進行渲染(光柵化)懈涛。完畢后逛万,將tile的數(shù)據(jù)發(fā)送回cpu。

傳送數(shù)據(jù)是非常消耗性能的批钠,相對來說宇植,多次計算比多次發(fā)送數(shù)據(jù)更加經(jīng)濟高效,但是額外的計算也會產(chǎn)生一些性能損耗埋心。
PS:在移動平臺控制幀率在一個合適的水平可以節(jié)省電能指郁,會有效的延長電池壽命,同時會相對的提高用戶體驗拷呆。這里有詳細的介紹

1闲坎、普通的Tile-Based渲染流程

1、CommandBuffer茬斧,接受OpenGL ES處理完畢的渲染指令腰懂;
2、Tiler项秉,調(diào)用頂點著色器绣溜,把頂點數(shù)據(jù)進行分塊(Tiling);
3娄蔼、ParameterBuffer怖喻,接受分塊完畢的tile和對應(yīng)的渲染參數(shù)底哗;
4、Renderer锚沸,調(diào)用片元著色器跋选,進行像素渲染;
5咒吐、RenderBuffer野建,存儲渲染完畢的像素;


2恬叹、離屏渲染 —— 遮罩(Mask)

1候生、渲染layer的mask紋理,同Tile-Based的基本渲染邏輯绽昼;
2唯鸭、渲染layer的content紋理,同Tile-Based的基本渲染邏輯硅确;
3目溉、Compositing操作,合并1菱农、2的紋理缭付;


3、離屏渲染 ——UIVisiualEffectView


使用UIBlurEffect循未,應(yīng)該是盡可能小的view陷猫,因為性能消耗巨大。


4的妖、渲染等待

由于每一幀的頂點和像素處理相對獨立绣檬,iOS會將CPU處理,頂點處理嫂粟,像素處理安排在相鄰的三幀中娇未。如圖,當一個渲染命令提交后星虹,要在當幀之后的第三幀零抬,渲染結(jié)果才會顯示出來。


5搁凸、光柵化

把視圖的內(nèi)容渲染成紋理并緩存媚值,可以通過CALayer的shouldRasterize屬性開啟光柵化。
注意护糖,光柵化的元素,總大小限制為2.5倍的屏幕嚼松。
更新內(nèi)容時嫡良,會啟用離屏渲染锰扶,所以更新代價較大,只能用于靜態(tài)內(nèi)容寝受;而且如果光柵化的元素100ms沒有被使用將被移除坷牛,故而不常用元素的光柵化并不會優(yōu)化顯示。

6很澄、組透明度

CALayer的allowsGroupOpacity屬性京闰,UIView 的alpha屬性等同于 CALayer opacity屬性。GroupOpacity=YES甩苛,子 layer 在視覺上的透明度的上限是其父 layer 的opacity蹂楣。當父視圖的layer.opacity != 1.0時,會開啟離屏渲染讯蒲。
layer.opacity == 1.0時痊土,父視圖不用管子視圖,只需顯示當前視圖即可墨林。

The default value is read from the boolean UIViewGroupOpacity property in the main bundle’s Info.plist file. If no value is found, the default value is YES for apps linked against the iOS 7 SDK or later and NO for apps linked against an earlier SDK.
為了讓子視圖與父視圖保持同樣的透明度赁酝,從 iOS 7 以后默認全局開啟了這個功能。

性能優(yōu)化

這個是WWDC推薦的檢查項目:



1旭等、幀率一般在多少酌呆?

60幀每秒;(TimeProfiler)

2搔耕、是否存在CPU和GPU瓶頸隙袁? (查看占有率)

更少的使用CPU和GPU可以有效的保存電量;

3度迂、額外的使用CPU來進行渲染藤乙?

重寫了drawRect會導(dǎo)致CPU渲染;在CPU進行渲染時惭墓,GPU大多數(shù)情況是處于等待狀態(tài)坛梁;

4、是否存在過多離屏渲染腊凶?

越少越好划咐;離屏渲染會導(dǎo)致上下文切換,GPU產(chǎn)生idle钧萍;

5褐缠、是否渲染過多視圖?

視圖越少越好风瘦;透明度為1的視圖更受歡迎队魏;

6、使用奇怪的圖片格式和大小胡桨?

避免格式轉(zhuǎn)換和調(diào)整圖片大泄倭薄;一個圖片如果不被GPU支持昧谊,那么需要CPU來轉(zhuǎn)換刽虹。(Xcode有對PNG圖片進行特殊的算法優(yōu)化)

7、使用昂貴的特效呢诬?

理解特效的消耗涌哲,同時調(diào)整合適的大小尚镰;例如前面提到的UIBlurEffect阀圾;

8、視圖樹上不必要的元素钓猬?

理解視圖樹上所有點的必要性稍刀,去掉不必要的元素;忘記remove視圖是很常見的事情敞曹,特別是當View的類比較大的時候账月。


以上,是8個問題對應(yīng)的工具澳迫。遇到性能問題朗徊,先分析昏翰、定位問題所在,而不是埋頭鉆進代碼的海洋。

性能優(yōu)化實例

1痊银、陰影


上面的做法攒岛,會導(dǎo)致離屏渲染谎碍;下面的做法是正確的做法兽叮。

2、圓角


不要使用不必要的mask卒稳,可以預(yù)處理圖片為圓形蹋半;或者添加中間為圓形透明的白色背景視圖。即使添加額外的視圖充坑,會導(dǎo)致額外的計算减江;但仍然會快一點,因為相對于切換上下文捻爷,GPU更擅長渲染辈灼。
離屏渲染會導(dǎo)致GPU利用率不到100%,幀率卻很低也榄。(切換上下文會產(chǎn)生idle time)

3巡莹、工具

使用instruments的CoreAnimation工具來檢查離屏渲染,黃色是我們不希望看到的顏色。


使用真機來調(diào)試榕莺,因為模擬器使用的CALayer是OSX的CALayer俐芯,不是iOS的CALayer棵介。如果用模擬器調(diào)試钉鸯,會發(fā)現(xiàn)所有的視圖都是黃色。

總結(jié)

視頻中的這一句話邮辽,讓我對iOS的視圖渲染茅塞頓開唠雕。

CALayer in CA is two triangles.

文章中關(guān)于Tile-Based架構(gòu),以及像素顯示渲染的理解基于我對OpenGL ES學習以及iOS開發(fā)收獲吨述。
iOS開發(fā)收獲很容易找到岩睁,但是OpenGL ES相對來說很少。越來越覺得自己花時間去研究是值得的揣云。

Core Animation的核心是OpenGL ES的一個抽象物捕儒,CoreAnimation讓你直接使用OpenGL ES的功能,卻不需要處理OpenGL ES的復(fù)雜操作邓夕。
可是我仍越過CoreAnimation去學習OpenGL ES刘莹。因為我不滿足用Apple提供的API拼湊界面。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末焚刚,一起剝皮案震驚了整個濱河市点弯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌矿咕,老刑警劉巖抢肛,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異碳柱,居然都是意外死亡捡絮,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門莲镣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來福稳,“玉大人,你說我怎么就攤上這事剥悟×樗拢” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵区岗,是天一觀的道長略板。 經(jīng)常有香客問我,道長慈缔,這世上最難降的妖魔是什么叮称? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上瓤檐,老公的妹妹穿的比我還像新娘赂韵。我一直安慰自己,他們只是感情好挠蛉,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布祭示。 她就那樣靜靜地躺著,像睡著了一般谴古。 火紅的嫁衣襯著肌膚如雪质涛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天掰担,我揣著相機與錄音汇陆,去河邊找鬼。 笑死带饱,一個胖子當著我的面吹牛毡代,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播勺疼,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼教寂,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了恢口?” 一聲冷哼從身側(cè)響起孝宗,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎耕肩,沒想到半個月后因妇,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡猿诸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年婚被,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片梳虽。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡址芯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出窜觉,到底是詐尸還是另有隱情谷炸,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布禀挫,位于F島的核電站旬陡,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏语婴。R本人自食惡果不足惜描孟,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一驶睦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧匿醒,春花似錦场航、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蜜另,卻和暖如春适室,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背举瑰。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蔬螟,地道東北人此迅。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像旧巾,于是被迫代替她去往敵國和親耸序。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 屏幕的顯示原理 CRT電子槍按照圖片上的方式鲁猩,從上到下坎怪、從左到右的方式一行行掃描,掃描完成之后顯示器就會顯示一幀的...
    Terrnce閱讀 6,766評論 1 32
  • 圓角是一種很常見的視圖效果廓握,相比于直角搅窿,它更加柔和優(yōu)美,易于接受隙券。設(shè)置圓角會帶來一定的性能損耗男应,如何提高性能是一個...
    Chars閱讀 553評論 0 8
  • 本系列文章的重點是關(guān)注在總結(jié)iOS圖形圖像的原理和性能優(yōu)化的常規(guī)解決方案。 事先聲明娱仔,本文絕大多數(shù)概念和內(nèi)容均來源...
    ac3閱讀 3,806評論 10 14
  • 客戶端的開發(fā)沐飘,無非離不開數(shù)據(jù)和展示,而展示這個方面牲迫,首當其沖的就是視圖耐朴、動畫的渲染,切換等等盹憎。而且在用戶的使用中筛峭,...
    不忘初心1990閱讀 1,032評論 0 2
  • 天氣越來越暖和了,但是西北的風也是很厲害滴脚乡,怕下午刮風蜒滩,早上看著天氣不錯滨达,九點帶元寶出門轉(zhuǎn),早晨還是有點冷的俯艰,小區(qū)...
    小滿xm閱讀 228評論 0 0