Instruments 之 圖像繪制性能優(yōu)化(三)

繪圖和動(dòng)畫(huà)有兩種處理方式钳幅,CPU和GPU(圖形處理器)。CPU理論上可以做任何事情炎滞,但對(duì)于圖像處理敢艰,通常硬件會(huì)更快,因?yàn)镚PU使用圖像對(duì)高度并行的浮點(diǎn)運(yùn)算做了優(yōu)化册赛。通常會(huì)把屏幕渲染工作交給GPU來(lái)處理钠导,但當(dāng)GPU資源用完的話,性能就逐漸下降了森瘪。
大多數(shù)動(dòng)畫(huà)性能優(yōu)化都是關(guān)于對(duì)GPU和CPU使用的優(yōu)化牡属,不超出負(fù)荷。

當(dāng)運(yùn)行一段動(dòng)畫(huà)時(shí)扼睬,分為四個(gè)階段

  • 1.布局 - 確定視圖層級(jí)關(guān)系逮栅,以及設(shè)置圖層屬性(位置,背景色痰驱,邊框等)证芭。
  • 2.顯示 - 繪制圖層寄宿圖片,繪制有可能涉及你的- drawRect:-drawLayer:inContext:方法的調(diào)用路徑担映。
  • 3.準(zhǔn)備 - 準(zhǔn)備發(fā)送動(dòng)畫(huà)數(shù)據(jù)到渲染服務(wù)废士。
  • 4.提交 - Core Animation 打包所有圖層和動(dòng)畫(huà)屬性,然后發(fā)送到渲染服務(wù)顯示蝇完。
    在動(dòng)畫(huà)在屏幕上顯示之前仍然有更多的工作官硝。一旦打包的圖層和動(dòng)畫(huà)到達(dá)渲染服務(wù)進(jìn)程矗蕊,他們會(huì)被反序列化來(lái)形成另一個(gè)叫做渲染樹(shù)的圖層樹(shù)。使用這個(gè)樹(shù)狀結(jié)構(gòu)氢架,渲染服務(wù)對(duì)動(dòng)畫(huà)的每一幀做出如下工作:
  • 5.對(duì)所有的圖層屬性計(jì)算中間值傻咖,設(shè)置OpenGL幾何形狀(紋理化的三角形)來(lái)執(zhí)行渲染
  • 6.在屏幕上渲染可見(jiàn)的三角形

注:最后5,6兩個(gè)階段在動(dòng)畫(huà)過(guò)程中不斷地重復(fù)執(zhí)行岖研,其中前五個(gè)階段在軟件層面通過(guò)CPU處理卿操,最后一個(gè)渲染通過(guò)GPU來(lái)執(zhí)行。開(kāi)發(fā)者可以控制的只有前兩個(gè)階段:布局和顯示孙援。開(kāi)發(fā)者可以再這兩個(gè)階段決定哪些由CPU執(zhí)行害淤,哪些由GPU處理。

如何對(duì)GPU操作進(jìn)行優(yōu)化

GPU 的優(yōu)化體現(xiàn)在采集圖片和形狀(三角形)拓售,運(yùn)行變換窥摄,應(yīng)用紋理及混合然后輸送到屏幕的過(guò)程。如果想要在這些操作上有更多的靈活性础淤,可以讓開(kāi)Core Animation自己實(shí)現(xiàn)OpenGL著色器崭放,從根本上解決硬件加速問(wèn)題。我們這里只考慮如何從軟件層面優(yōu)化

1.一般來(lái)說(shuō)CALayer 的屬性都是用GPU來(lái)繪制的鸽凶。比如設(shè)置圖層背景币砂,邊框顏,這些可以通過(guò)著色三角板實(shí)時(shí)繪制出來(lái)吱瘩。如果對(duì)一個(gè)contents屬性設(shè)置一張圖片道伟,然后剪裁,就是通過(guò)GPU直接繪制使碾。

避免降低GPU效率的圖層繪制
  • 避免太多的幾何結(jié)構(gòu)蜜徽,在Core Animation中幾何結(jié)構(gòu)并不是GPU的瓶頸,但太多的圖層會(huì)引起CPU的瓶頸票摇,限制一次展示的圖層個(gè)數(shù)
  • 避免每一幀用相同的像素填充多次拘鞋,即重繪,主要由重疊的半透明圖層引起矢门。GPU的填充比率(用顏色填充像素的比率)是有限的盆色,所以要避免重繪。當(dāng)然在硬件的提升下祟剔,適量的重繪不影響性能隔躲。
  • 避免離屏繪制,離屏繪制一般發(fā)生在當(dāng)不能直接在屏幕上繪制物延,并且必須繪制到離屏圖片的上下文的時(shí)候宣旱。離屏繪制發(fā)生在基于CPU或者GPU渲染或者是為離屏圖片分配額外內(nèi)存,以及切換繪制上下文叛薯,這些都會(huì)降低GPU性能浑吟。對(duì)于特定圖層效果的使用笙纤,比如圓角,圖層遮罩组力,陰影或者圖層光柵化都會(huì)強(qiáng)制Core Animation提前渲染圖層的離屏繪制省容。但這不意味著你需要避免使用這些效果,只是需要知道這會(huì)帶來(lái)負(fù)面影響燎字。
  • 避免過(guò)大的圖片腥椒,如果視圖繪制超過(guò)GPU支持的20482048或者40964096尺寸的紋理,就必須要CPU在圖層沒(méi)實(shí)現(xiàn)是之前對(duì)圖片進(jìn)行預(yù)處理轩触,同樣也會(huì)降低性能寞酿。

如何對(duì)CPU操作進(jìn)行優(yōu)化

一般CPU處理都會(huì)在動(dòng)畫(huà)開(kāi)始之前家夺,不會(huì)影響到幀率脱柱,但是會(huì)延遲動(dòng)畫(huà)開(kāi)始的時(shí)間,使界面看起來(lái)遲緩拉馋。
影響動(dòng)畫(huà)開(kāi)始時(shí)間的CPU操作有:

  • 布局計(jì)算榨为,當(dāng)視圖層級(jí)過(guò)于復(fù)雜,當(dāng)視圖呈現(xiàn)或者修改時(shí)煌茴,計(jì)算圖層幀率就會(huì)消耗一部分時(shí)間随闺。特別是使用AutoLayout尤為明顯,AutoLayout比以前的AutoResizing消耗更多的CPU蔓腐。
  • 視圖的懶加載矩乐,一個(gè)試圖將要顯示到屏幕時(shí)才會(huì)加載它。者對(duì)于內(nèi)存使用和縮短程序啟動(dòng)時(shí)間很有幫助回论,但是當(dāng)呈現(xiàn)到屏幕上之前散罕,按下按鈕導(dǎo)致的許多工作都會(huì)不能被及時(shí)響應(yīng)。比如控制器從數(shù)據(jù)庫(kù)中獲取數(shù)據(jù)傀蓉,或者視圖從一個(gè)nib文件中加載欧漱,或者涉及IO的圖片顯示(見(jiàn)后續(xù)“IO相關(guān)操作”),都會(huì)比CPU正常操作慢得多葬燎。
  • Core Graphics繪制 - 如果對(duì)視圖實(shí)現(xiàn)了-drawRect:方法误甚,或者CALayerDelegate的-drawLayer:inContext:方法,那么在繪制任何東西之前都會(huì)產(chǎn)生一個(gè)巨大的性能開(kāi)銷谱净。為了支持對(duì)圖層內(nèi)容的任意繪制窑邦,Core Animation必須創(chuàng)建一個(gè)內(nèi)存中等大小的寄宿圖片。然后一旦繪制結(jié)束之后壕探,必須把圖片數(shù)據(jù)通過(guò)IPC傳到渲染服務(wù)器冈钦。在此基礎(chǔ)上,Core Graphics繪制就會(huì)變得十分緩慢浩蓉,所以在一個(gè)對(duì)性能十分挑剔的場(chǎng)景下這樣做十分不好派继。
  • 解壓圖片 - PNG或者JPEG壓縮之后的圖片文件會(huì)比同質(zhì)量的位圖小得多宾袜。但是在圖片繪制到屏幕上之前,必須把它擴(kuò)展成完整的未解壓的尺寸(通常等同于圖片寬 x 長(zhǎng) x 4個(gè)字節(jié))驾窟。為了節(jié)省內(nèi)存庆猫,iOS通常直到真正繪制的時(shí)候才去解碼圖片。根據(jù)你加載圖片的方式绅络,第一次對(duì)圖層內(nèi)容賦值的時(shí)候(直接或者間接使用UIImageView
    )或者把它繪制到Core Graphics中月培,都需要對(duì)它解壓,這樣的話恩急,對(duì)于一個(gè)較大的圖片杉畜,都會(huì)占用一定的時(shí)間。
  • I/O相關(guān)的優(yōu)化
    如果動(dòng)畫(huà)需要I/O操作來(lái)加載衷恭,
    IO比內(nèi)存訪問(wèn)更慢此叠,所以如果動(dòng)畫(huà)涉及到IO,就是一個(gè)大問(wèn)題随珠∶鹪總的來(lái)說(shuō),這就需要使用聰敏但尷尬的技術(shù)窗看,也就是多線程茸歧,緩存和投機(jī)加載(提前加載當(dāng)前不需要的資源,但是之后可能需要用到)显沈。

如何測(cè)量是否有必要優(yōu)化

  • 真機(jī)提供參數(shù)的真實(shí)性软瞎。不同硬件上測(cè)試,關(guān)注用戶的設(shè)備以及系統(tǒng)拉讯。
  • 保持一定的幀率涤浇,為了做到動(dòng)畫(huà)的平滑,需要以60FPS(幀每秒)的速度運(yùn)行遂唧,同步屏幕刷新頻率芙代。如果不保持60FPS的速率,可能隨機(jī)丟幀盖彭,影響體驗(yàn)纹烹。
Core Animation Debug Options & 優(yōu)化
Core Animation2

Color Blended Layers (圖層混合)
界面都是會(huì)出現(xiàn)多個(gè)UI控件疊加的情況,如果有透明或者半透明的控件召边,那么GPU會(huì)去計(jì)算這些這些layer最終的顯示的顏色铺呵。基于渲染程度對(duì)屏幕中混合區(qū)域進(jìn)行綠到紅的高亮顯示隧熙,越紅表示性能越差片挂,會(huì)對(duì)幀率等指標(biāo)造成較大影響。

優(yōu)化方法:
如果出現(xiàn)圖層混合了,如何優(yōu)化呢音念?
(1)設(shè)置opaque 屬性為true沪饺。(2)調(diào)整布局(3)給View設(shè)置一個(gè)不透明的顏色,沒(méi)有特殊需要設(shè)置白色即可闷愤。
label.backgroundColor = [UIColor whiteColor];
label.layer.masksToBounds = YES;

如果label的內(nèi)容是中文整葡,label實(shí)際渲染區(qū)域要大于label的size,最外層多了一個(gè)sublayer讥脐,如果不設(shè)置masksToBounds遭居,邊緣外層會(huì)出現(xiàn)圖層混合的紅色。
單獨(dú)使用layer.masksToBounds = YES是不會(huì)發(fā)生離屏渲染旬渠。
UIImageView控件比較特殊俱萍,不僅需要自身這個(gè)容器是不透明的,并且imageView包含的內(nèi)容圖片也必須是不透明的告丢,如果你自己的圖片出現(xiàn)了圖層混合紅色枪蘑,如果確認(rèn)代碼沒(méi)問(wèn)題,就是圖片自身的問(wèn)題

Color Hits Green and Misses Red(光柵化)
當(dāng)UIView.layer.shouldRasterize = YES 時(shí)芋齿,耗時(shí)的圖片繪制會(huì)被緩存腥寇,并當(dāng)做一個(gè)簡(jiǎn)單的扁平圖片來(lái)呈現(xiàn)。
適用情況:一般在圖像內(nèi)容不變的情況下才使用光柵化觅捆,例如設(shè)置陰影耗費(fèi)資源比較多的靜態(tài)內(nèi)容,如果使用光柵化對(duì)性能的提升有一定幫助麻敌。
不適用的情況:如果內(nèi)容會(huì)經(jīng)常變動(dòng),這個(gè)時(shí)候不要開(kāi)啟,否則會(huì)造成性能的浪費(fèi)栅炒。例如我們?cè)谑褂胻ableViewCell中,一般不要用光柵化术羔,因?yàn)閠ableViewCell的繪制非常頻繁赢赊,內(nèi)容在不斷的變化,如果使用了光柵化级历,會(huì)造成大量的離屏渲染降低性能释移。
(1)系統(tǒng)給光柵化緩存分配了一個(gè)固定的大小,因此不能過(guò)度使用寥殖,如果超出了緩存也會(huì)造成離屏渲染玩讳。(2)緩存的時(shí)間為100ms,因此如果在100ms內(nèi)沒(méi)有使用緩存的對(duì)象嚼贡,則會(huì)從緩存中清除熏纯。

Color Copied Images(圖片顏色格式)
如果使用Color Copied Images去調(diào)試發(fā)現(xiàn)是藍(lán)色,可以去找UI重新做一張粤策。蘋(píng)果的GPU只解析32bit的顏色格式樟澜,對(duì)于GPU不支持的色彩格式的圖片只能由CPU來(lái)處理,這樣的圖片為藍(lán)色,藍(lán)色越多性能越差秩贰。因?yàn)槿绻跐L動(dòng)加載大量圖片時(shí)霹俺,由CPU來(lái)處理圖片,可能會(huì)阻塞主線程毒费。
知識(shí)擴(kuò)展:32bit指的是圖片顏色深度吭服,用“位”來(lái)表示,用來(lái)表示顯示顏色數(shù)量蝗罗,例如一個(gè)圖片支持256種顏色艇棕,那么就需要256個(gè)不同的值來(lái)表示不同的顏色,也就是從0到255串塑,二進(jìn)制表示就是從00000000到11111111沼琉,一共需要8位二進(jìn)制數(shù),所以顏色深度是8桩匪。通常32bit色彩中使用三個(gè)8bit分別表示R紅G綠B藍(lán),還有一個(gè)8bit常用來(lái)表示透明度(Alpha)打瘪。
Color Immediately(顏色刷新頻率)
通常Core Animation Instruments以每毫秒10次的頻率更新圖層調(diào)試顏色,如果某些效果覺(jué)得不夠用傻昙,這個(gè)選項(xiàng)可以設(shè)置每幀都更新(不建議使用闺骚,可能會(huì)影響到渲染性能)
Color Misaligned Images(圖片大小)
這個(gè)選項(xiàng)檢查了image size和imageView size不匹配,圖片是否被縮放妆档,以及像素是否對(duì)齊僻爽。被放縮的圖片會(huì)被標(biāo)記為黃色,像素不對(duì)齊則會(huì)標(biāo)注為紫色贾惦。黃色胸梆、紫色越多,性能越差须板。

Color Offscreen-Rendered Yellow(離屏渲染)
將離屏渲染標(biāo)為黃色碰镜,黃色越多性能越差,可以用shadowPath 或者 shouldRasterize 來(lái)優(yōu)化习瑰。
觸發(fā)離屏渲染Offscreen rendering的行為:
(1)drawRect:方法
(2)layer.shadow
(3)layer.allowsGroupOpacity or layer.allowsEdgeAntialiasing
(4)layer.shouldRasterize
(5)layer.mask
(6)layer.masksToBounds && layer.cornerRadius
這里有需要注意的是第三條layer.shouldRasterize 绪颖,其實(shí)就是我們本文講的第三個(gè)選項(xiàng)光柵化,光柵化會(huì)觸發(fā)離屏渲染甜奄,因此光柵化慎用柠横。
第六條設(shè)置圓角會(huì)觸發(fā)離屏渲染,如果在某個(gè)頁(yè)面大量使用了圓角贺嫂,會(huì)非常消耗性能造成FPS急劇下降滓鸠,設(shè)置圓角觸發(fā)離屏渲染要同時(shí)滿足下面兩個(gè)條件:
layer.masksToBounds = YES;
layer.cornerRadius = 5;

為了盡可能避免觸發(fā)離屏渲染,我們可以換其他手段來(lái)實(shí)現(xiàn)必要的功能:

/**
 * Method : CAShapeLayer設(shè)置圓角
 * rectCorner  : UIRectCorner
 * 需要導(dǎo)入<AVFoundation/AVFoundation.h>
 */
- (void)shapeLayerCornerRadiusWithView:(UIView *)view withRectCorner:(UIRectCorner)rectCorner
{
    //使用UIBezierPath 和 CAShapeLayer 設(shè)置圓角 內(nèi)存占用最小且渲染快速

    UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:view.bounds byRoundingCorners:UIRectCornerAllCorners cornerRadii:view.bounds.size];
    
    CAShapeLayer *maskLayer = [[CAShapeLayer alloc]init];
    //設(shè)置大小
    maskLayer.frame = view.bounds;
    //設(shè)置圖形樣子
    maskLayer.path = maskPath.CGPath;
    view.layer.mask = maskLayer;
}


/**
 * Method : shadowPath設(shè)置圓角
 * Return : return
 */
- (void)shadowPathOfView:(UIView *)view{
    
    CGMutablePathRef squarePath = CGPathCreateMutable();
    CGPathAddRect(squarePath, NULL, view.bounds);
    view.layer.shadowPath = squarePath;
    CGPathRelease(squarePath);
}

Color Compositing Fast-Path Blue (快速路徑)
將直接使用OpenGL繪制的圖層顯示為藍(lán)色第喳。藍(lán)色越多糜俗,性能越好。如果使用CLKView或者CAEAGLLayer,但不顯示藍(lán)色則說(shuō)明你正在強(qiáng)制CPU渲染額外的紋理悠抹,而不是繪制到屏幕珠月。
Flash Updated Regions (重繪區(qū)域)
將重新繪制的內(nèi)容顯示為黃色,盡量減少不需要的重新繪制楔敌。這種繪圖的速度很慢啤挎。如果頻繁發(fā)生這種情況的話,這意味著有一個(gè)隱藏的bug或者說(shuō)通過(guò)增加緩存或者使用替代方案會(huì)有提升性能的空間卵凑。

OpenGL ES Analysis 測(cè)量GPU的利用率

OpenGL ES Analysis

OpenGL ES Analysis

Renderer Utilization - 如果這個(gè)值超過(guò)了~50%庆聘,就意味著你的動(dòng)畫(huà)可能對(duì)幀率有所限制,很可能因?yàn)殡x屏渲染或者是重繪導(dǎo)致的過(guò)度混合勺卢。

Tiler Utilization - 如果這個(gè)值超過(guò)了~50%伙判,就意味著你的動(dòng)畫(huà)可能限制于幾何結(jié)構(gòu)方面,也就是在屏幕上有太多的圖層占用了黑忱。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末宴抚,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子甫煞,更是在濱河造成了極大的恐慌菇曲,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抚吠,死亡現(xiàn)場(chǎng)離奇詭異常潮,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)埃跷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)蕊玷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人弥雹,你說(shuō)我怎么就攤上這事⊙咏欤” “怎么了剪勿?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)方庭。 經(jīng)常有香客問(wèn)我厕吉,道長(zhǎng),這世上最難降的妖魔是什么械念? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任头朱,我火速辦了婚禮,結(jié)果婚禮上龄减,老公的妹妹穿的比我還像新娘项钮。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布烁巫。 她就那樣靜靜地躺著署隘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪亚隙。 梳的紋絲不亂的頭發(fā)上磁餐,一...
    開(kāi)封第一講書(shū)人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音阿弃,去河邊找鬼诊霹。 笑死,一個(gè)胖子當(dāng)著我的面吹牛渣淳,可吹牛的內(nèi)容都是我干的脾还。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼水由,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼荠呐!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起砂客,我...
    開(kāi)封第一講書(shū)人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤泥张,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后鞠值,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體媚创,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年彤恶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了钞钙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡声离,死狀恐怖芒炼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情术徊,我是刑警寧澤本刽,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站赠涮,受9級(jí)特大地震影響子寓,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜笋除,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一斜友、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧垃它,春花似錦鲜屏、人聲如沸烹看。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)听系。三九已至,卻和暖如春虹菲,著一層夾襖步出監(jiān)牢的瞬間靠胜,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工毕源, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留浪漠,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓霎褐,卻偏偏與公主長(zhǎng)得像址愿,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子冻璃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

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