欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

iOS離屏渲染過(guò)程示例解析

 更新時(shí)間:2023年08月21日 14:16:52   作者:奶茶大叔  
這篇文章主要為大家介紹了iOS離屏渲染過(guò)程示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

界面渲染

UIView繼承自UIResponder,可以處理系統(tǒng)傳遞過(guò)來(lái)的事件,如:UIApplication、UIViewController、UIView,以及所有從UIView派生出來(lái)的UIKit類(lèi)。每個(gè)UIView內(nèi)部都有一個(gè)CALayer提供內(nèi)容的繪制和顯示,并且作為內(nèi)部RootLayer的代理視圖。

下圖為CALayer的結(jié)構(gòu)圖:

RunLoop有一個(gè)60fps的回調(diào),即每16.7ms繪制一次屏幕,所以view的繪制必須在這個(gè)時(shí)間內(nèi)完成,view內(nèi)容的繪制是CPU的工作,然后把繪制的內(nèi)容交給GPU渲染,包括多個(gè)View的拼接(Compositing)、紋理的渲染(Texture)等等,最后顯示在屏幕上。但是,如果無(wú)法是16.7ms內(nèi)完成繪制,就會(huì)出現(xiàn)丟幀的問(wèn)題,一般情況下,如果幀率保證在30fps以上,界面卡頓效果不明顯,那么就需要在33.4ms內(nèi)完成View的繪制,而低于這個(gè)幀率,就會(huì)產(chǎn)生卡頓的效果,影響體驗(yàn)。

渲染的過(guò)程

UIView的layer層有一個(gè)content,指向一塊緩存,即backing store
UIView繪制時(shí),會(huì)調(diào)用drawRect方法,通過(guò)context將數(shù)據(jù)寫(xiě)入backing store
在backing store寫(xiě)完后,通過(guò)render server交給GPU去渲染,將backing store中的bitmap數(shù)據(jù)顯示在屏幕上

渲染的過(guò)程

ios離屏渲染

On-Screen Rendering:當(dāng)前屏幕渲染,指的是 GPU 的渲染操作是在當(dāng)前用于顯示的屏幕緩沖區(qū)中進(jìn)行
Off-Screen Rendering:離屏渲染,分為 CPU 離屏渲染和 GPU 離屏渲染兩種形式。GPU 離屏渲染指的是 GPU 在當(dāng)前屏幕緩沖區(qū)外新開(kāi)辟一個(gè)緩沖區(qū)進(jìn)行渲染操作

為什么會(huì)使用離屏渲染

當(dāng)使用圓角,陰影,遮罩的時(shí)候,圖層屬性的混合體被指定為在未預(yù)合成之前不能直接在屏幕中繪制,所以就需要屏幕外渲染被喚起。

GPU 離屏渲染的代價(jià)是很大的
離屏渲染之所以會(huì)特別消耗性能,是因?yàn)橐獎(jiǎng)?chuàng)建一個(gè)屏幕外的緩沖區(qū),然后從當(dāng)屏緩沖區(qū)切換到屏幕外的緩沖區(qū),然后再完成渲染;其中,創(chuàng)建緩沖區(qū)和切換上下文最消耗性能,而繪制其實(shí)不是性能損耗的主要原因。

上下文之間的切換這個(gè)過(guò)程的消耗會(huì)比較昂貴,涉及到 OpenGL的 pipeline 跟 barrier,而且 offscreen-render 在每一幀都會(huì)涉及到,因此處理不當(dāng)肯定會(huì)對(duì)性能產(chǎn)生一定的影響。另外由于離屏渲染會(huì)增加 GPU 的工作量,可能會(huì)導(dǎo)致 CPU+GPU 的處理時(shí)間超出 16.7ms,導(dǎo)致掉幀卡頓。

離屏渲染的場(chǎng)景和優(yōu)化

圓角優(yōu)化

方法一:

一般情況下我們會(huì)用這個(gè)方法去設(shè)置圓角:

iv.layer.cornerRadius = 30;
iv.layer.masksToBounds = YES;

使用cornerRadius進(jìn)行切圓角,在iOS9之前會(huì)產(chǎn)生離屏渲染,比較消耗性能,而之后系統(tǒng)做了優(yōu)化,則不會(huì)產(chǎn)生離屏渲染,但是操作最簡(jiǎn)單

方法二:

利用mask設(shè)置圓角,利用的是UIBezierPath和CAShapeLayer來(lái)完成

CAShapeLayer *mask = [[CAShapeLayer alloc] init];
mask1.opacity = 0.3;
mask1.path = [UIBezierPath bezierPathWithOvalInRect:iv.bounds].CGPath;
iv.layer.mask = mask;

方法三:

利用CoreGraphics畫(huà)一個(gè)圓形上下文,然后把圖片繪制上去,得到一個(gè)圓形的圖片

- (UIImage *)drawCircleImage:(UIImage*)image
{
    CGFloat side = MIN(image.size.width, image.size.height);
    UIGraphicsBeginImageContextWithOptions(CGSizeMake(side, side), false, [UIScreen mainScreen].scale);
    CGContextAddPath(UIGraphicsGetCurrentContext(), [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, side, side)].CGPath);
    CGContextClip(UIGraphicsGetCurrentContext());
    CGFloat marginX = -(image.size.width - side) * 0.5;
    CGFloat marginY = -(image.size.height - side) * 0.5;
    [image drawInRect:CGRectMake(marginX, marginY, image.size.width, image.size.height)];
    CGContextDrawPath(UIGraphicsGetCurrentContext(), kCGPathFillStroke);
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}

三種方法里面,方法三是性能最好的。

當(dāng)然了,直接讓美工畫(huà)一個(gè)圓角的圖效率是最高的。

shadow優(yōu)化

我們可以通過(guò)設(shè)置shadowPath來(lái)優(yōu)化性能,能大幅提高性能

imageView.layer.shadowColor=[UIColorgrayColor].CGColor;
imageView.layer.shadowOpacity=1.0;
imageView.layer.shadowRadius=2.0;
UIBezierPath *path=[UIBezierPathbezierPathWithRect:imageView.frame];
imageView.layer.shadowPath=path.CGPath;

組不透明

開(kāi)啟CALayer的 allowsGroupOpacity 屬性后,子 layer 在視覺(jué)上的透明度的上限是其父 layer 的 opacity (對(duì)應(yīng)UIView的 alpha ),并且從 iOS 7 以后默認(rèn)全局開(kāi)啟了這個(gè)功能,這樣做是為了讓子視圖與其容器視圖保持同樣的透明度。

所以,可以關(guān)閉 allowsGroupOpacity 屬性,按產(chǎn)品需求自己控制layer透明度。

關(guān)閉抗鋸齒

allowsEdgeAntialiasing屬性為YES(默認(rèn)為NO)

離屏渲染的檢測(cè)

Instruments的Core Animation工具中有幾個(gè)和離屏渲染相關(guān)的檢查選項(xiàng):

Color Offscreen-Rendered Yellow

開(kāi)啟后會(huì)把那些需要離屏渲染的圖層高亮成黃色,這就意味著黃色圖層可能存在性能問(wèn)題。

Color Hits Green and Misses Red

如果shouldRasterize被設(shè)置成YES,對(duì)應(yīng)的渲染結(jié)果會(huì)被緩存,如果圖層是綠色,就表示這些緩存被復(fù)用;如果是紅色就表示緩存會(huì)被重復(fù)創(chuàng)建,這就表示該處存在性能問(wèn)題了。

iOS版本上的優(yōu)化

iOS 9.0 之前UIimageView跟UIButton設(shè)置圓角都會(huì)觸發(fā)離屏渲染

iOS 9.0 之后UIButton設(shè)置圓角會(huì)觸發(fā)離屏渲染,而UIImageView里png圖片設(shè)置圓角不會(huì)觸發(fā)離屏渲染了,如果設(shè)置其他陰影效果之類(lèi)的還是會(huì)觸發(fā)離屏渲染的。

善用離屏渲染

盡管離屏渲染開(kāi)銷(xiāo)很大,但是當(dāng)我們無(wú)法避免它的時(shí)候,可以想辦法把性能影響降到最低。優(yōu)化思路也很簡(jiǎn)單:既然已經(jīng)花了不少精力把圖片裁出了圓角,如果我能把結(jié)果緩存下來(lái),那么下一幀渲染就可以復(fù)用這個(gè)成果,不需要再重新畫(huà)一遍了。

CALayer為這個(gè)方案提供了對(duì)應(yīng)的解法:shouldRasterize。一旦被設(shè)置為true,Render Server就會(huì)強(qiáng)制把layer的渲染結(jié)果(包括其子layer,以及圓角、陰影、group opacity等等)保存在一塊內(nèi)存中,這樣一來(lái)在下一幀仍然可以被復(fù)用,而不會(huì)再次觸發(fā)離屏渲染。有幾個(gè)需要注意的點(diǎn):

shouldRasterize的主旨在于降低性能損失,但總是至少會(huì)觸發(fā)一次離屏渲染。如果你的layer本來(lái)并不復(fù)雜,也沒(méi)有圓角陰影等等,打開(kāi)這個(gè)開(kāi)關(guān)反而會(huì)增加一次不必要的離屏渲染
離屏渲染緩存有空間上限,最多不超過(guò)屏幕總像素的2.5倍大小
一旦緩存超過(guò)100ms沒(méi)有被使用,會(huì)自動(dòng)被丟棄
layer的內(nèi)容(包括子layer)必須是靜態(tài)的,因?yàn)橐坏┌l(fā)生變化(如resize,動(dòng)畫(huà)),之前辛苦處理得到的緩存就失效了。如果這件事頻繁發(fā)生,我們就又回到了“每一幀都需要離屏渲染”的情景,而這正是開(kāi)發(fā)者需要極力避免的。針對(duì)這種情況,Xcode提供了“Color Hits Green and Misses Red”的選項(xiàng),幫助我們查看緩存的使用是否符合預(yù)期
其實(shí)除了解決多次離屏渲染的開(kāi)銷(xiāo),shouldRasterize在另一個(gè)場(chǎng)景中也可以使用:如果layer的子結(jié)構(gòu)非常復(fù)雜,渲染一次所需時(shí)間較長(zhǎng),同樣可以打開(kāi)這個(gè)開(kāi)關(guān),把layer繪制到一塊緩存,然后在接下來(lái)復(fù)用這個(gè)結(jié)果,這樣就不需要每次都重新繪制整個(gè)layer樹(shù)了

什么時(shí)候需要CPU渲染

絕大多數(shù)情況下,得益于GPU針對(duì)圖形處理的優(yōu)化,我們都會(huì)傾向于讓GPU來(lái)完成渲染任務(wù),而給CPU留出足夠時(shí)間處理各種各樣復(fù)雜的App邏輯。為此Core Animation做了大量的工作,盡量把渲染工作轉(zhuǎn)換成適合GPU處理的形式(也就是所謂的硬件加速,如layer composition,設(shè)置backgroundColor等等)。

但是對(duì)于一些情況,如文字(CoreText使用CoreGraphics渲染)和圖片(ImageIO)渲染,由于GPU并不擅長(zhǎng)做這些工作,不得不先由CPU來(lái)處理好以后,再把結(jié)果作為texture傳給GPU。除此以外,有時(shí)候也會(huì)遇到GPU實(shí)在忙不過(guò)來(lái)的情況,而CPU相對(duì)空閑(GPU瓶頸),這時(shí)可以讓CPU分擔(dān)一部分工作,提高整體效率。

一個(gè)典型的例子是,我們經(jīng)常會(huì)使用CoreGraphics給圖片加上圓角(將圖片中圓角以外的部分渲染成透明)。整個(gè)過(guò)程全部是由CPU完成的。這樣一來(lái)既然我們已經(jīng)得到了想要的效果,就不需要再另外給圖片容器設(shè)置cornerRadius。另一個(gè)好處是,我們可以靈活地控制裁剪和緩存的時(shí)機(jī),巧妙避開(kāi)CPU和GPU最繁忙的時(shí)段,達(dá)到平滑性能波動(dòng)的目的。

但要注意的是:

渲染不是CPU的強(qiáng)項(xiàng),調(diào)用CoreGraphics會(huì)消耗其相當(dāng)一部分計(jì)算時(shí)間,并且我們也不愿意因此阻塞用戶(hù)操作,因此一般來(lái)說(shuō)CPU渲染都在后臺(tái)線(xiàn)程完成(這也是AsyncDisplayKit的主要思想),然后再回到主線(xiàn)程上,把渲染結(jié)果傳回CoreAnimation。這樣一來(lái),多線(xiàn)程間數(shù)據(jù)同步會(huì)增加一定的復(fù)雜度

同樣因?yàn)镃PU渲染速度不夠快,因此只適合渲染靜態(tài)的元素,如文字、圖片(想象一下沒(méi)有硬件加速的視頻解碼,性能慘不忍睹)

作為渲染結(jié)果的bitmap數(shù)據(jù)量較大(形式上一般為解碼后的UIImage),消耗內(nèi)存較多,所以應(yīng)該在使用完及時(shí)釋放,并在需要的時(shí)候重新生成,否則很容易導(dǎo)致OOM

如果你選擇使用CPU來(lái)做渲染,那么就沒(méi)有理由再觸發(fā)GPU的離屏渲染了,否則會(huì)同時(shí)存在兩塊內(nèi)容相同的內(nèi)存,而且CPU和GPU都會(huì)比較辛苦。

以上就是iOS離屏渲染過(guò)程示例解析的詳細(xì)內(nèi)容,更多關(guān)于iOS離屏渲染的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • iOS狀態(tài)欄、導(dǎo)航欄的一些筆記分享

    iOS狀態(tài)欄、導(dǎo)航欄的一些筆記分享

    這篇文章主要給大家分享了關(guān)于iOS中狀態(tài)欄、導(dǎo)航欄的一些筆記,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)各位iOS開(kāi)發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • iOS動(dòng)態(tài)驗(yàn)證碼實(shí)現(xiàn)代碼

    iOS動(dòng)態(tài)驗(yàn)證碼實(shí)現(xiàn)代碼

    本文通過(guò)實(shí)例代碼給大家介紹了ios動(dòng)態(tài)驗(yàn)證碼的實(shí)現(xiàn)方法,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧
    2018-04-04
  • iOS 獲取當(dāng)前時(shí)間及時(shí)間戳的互換實(shí)例

    iOS 獲取當(dāng)前時(shí)間及時(shí)間戳的互換實(shí)例

    下面小編就為大家分享一篇iOS 獲取當(dāng)前時(shí)間及時(shí)間戳的互換實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-01-01
  • 淺析Objective-C中分類(lèi)Category的使用

    淺析Objective-C中分類(lèi)Category的使用

    這篇文章主要介紹了淺析Objective-C中分類(lèi)Category的使用,使用Category對(duì)類(lèi)進(jìn)行擴(kuò)展可以訪問(wèn)原始類(lèi)的實(shí)例變量,需要的朋友可以參考下
    2016-03-03
  • IOS HTTP請(qǐng)求的常見(jiàn)狀態(tài)碼總結(jié)

    IOS HTTP請(qǐng)求的常見(jiàn)狀態(tài)碼總結(jié)

    這篇文章主要介紹了IOS HTTP請(qǐng)求的常見(jiàn)狀態(tài)碼總結(jié)的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • iOS實(shí)現(xiàn)音頻進(jìn)度條效果

    iOS實(shí)現(xiàn)音頻進(jìn)度條效果

    這篇文章主要介紹了ios實(shí)現(xiàn)音頻進(jìn)度條效果,本文寫(xiě)了一個(gè)小demo通過(guò)實(shí)例代碼相結(jié)合的形式給大家詳細(xì)介紹,需要的朋友可以參考下
    2018-10-10
  • IOS 開(kāi)發(fā)之?dāng)?shù)據(jù)存儲(chǔ)writeToFile的應(yīng)用實(shí)例

    IOS 開(kāi)發(fā)之?dāng)?shù)據(jù)存儲(chǔ)writeToFile的應(yīng)用實(shí)例

    這篇文章主要介紹了IOS 開(kāi)發(fā)之?dāng)?shù)據(jù)存儲(chǔ)writeToFile的應(yīng)用實(shí)例的相關(guān)資料,這里提供實(shí)例幫助大家實(shí)現(xiàn)這樣的功能,需要的朋友可以參考下
    2017-09-09
  • 最新評(píng)論