OpenGL--深入解析離屏渲染的原理

什么是離屏渲染

首先我們要了解GPU的渲染機(jī)制以及屏幕渲染的方式

  • GPU渲染機(jī)制:
    CPU通過(guò)解壓計(jì)算好顯示內(nèi)容通過(guò)系統(tǒng)總線(xiàn)到 GPU,GPU 渲染完成后將渲染結(jié)果放入幀緩沖區(qū)锯仪,隨后視頻控制器會(huì)按照VSync 信號(hào)逐行讀取幀緩沖區(qū)的數(shù)據(jù)疯汁,經(jīng)過(guò)可能的數(shù)模轉(zhuǎn)換傳遞給顯示器顯示。

GPU屏幕渲染有以下兩種方式:

  • OnScreen Rendering表示當(dāng)前屏幕渲染卵酪,指的是GPU的渲染操作是在當(dāng)前用于顯示的屏幕緩沖區(qū)中進(jìn)行幌蚊。

    正常渲染流程

    APP通過(guò)CPU計(jì)算和GPU渲染,然后將他們的結(jié)果放到幀緩存區(qū)frame buffer中溃卡,在通過(guò)視頻控制器將幀緩存區(qū)中的結(jié)果取出溢豆,顯示到屏幕上面。

  • OffScreen Rendering表示離屏渲染瘸羡,指的是GPU在當(dāng)前屏幕緩沖區(qū)以外新開(kāi)辟一個(gè)緩沖區(qū)進(jìn)行渲染操作漩仙。

    離屏渲染流程

當(dāng)App需要進(jìn)行額外的渲染和合并時(shí),例如圖片切圓角犹赖,我們需要對(duì)圖片中所有的圖層進(jìn)行圓角剪切队他,然后在將所有圖層的處理后的結(jié)果存入幀緩存區(qū)中,再由視頻控制器從幀緩存區(qū)中取出由屏幕來(lái)顯示峻村;在OnScreen Rendering中是無(wú)法做到對(duì)所有的圖層進(jìn)行裁剪圓角的麸折,因?yàn)閷?duì)多圖層圖片進(jìn)行分層裁剪時(shí),是用完一個(gè)丟棄一個(gè)的粘昨,從而節(jié)省空間垢啼。這使得我們需要提前將處理好的結(jié)果放入到離屏緩存區(qū)中,等待所有圖層處理完后张肾,再將所有的圖層合并到一起芭析。

離屏渲染的邏輯

特殊的離屏渲染:如果將不在GPU的當(dāng)前屏幕緩沖區(qū)中進(jìn)行的渲染都稱(chēng)為離屏渲染,那么就還有另一種特殊的“離屏渲染”方式: CPU渲染吞瞪。如果我們重寫(xiě)了drawRect方法馁启,并且使用任何Core Graphics的技術(shù)進(jìn)行了繪制操作,就涉及到了CPU渲染芍秆。整個(gè)渲染過(guò)程由CPU在App內(nèi) 同步地完成惯疙,渲染得到的bitmap最后再交由GPU用于顯示。
離屏渲染一些問(wèn)題的總結(jié):
1.離屏緩存區(qū)再給我們帶來(lái)方便同時(shí)浪听,也會(huì)帶來(lái)一些問(wèn)題螟碎,由于離屏渲染是額外開(kāi)辟一個(gè)空間,所以在數(shù)據(jù)的轉(zhuǎn)存到幀緩存區(qū)時(shí)需要時(shí)間迹栓,并且在轉(zhuǎn)存過(guò)程中可能會(huì)出現(xiàn)掉幀的情況掉分。
2.離屏緩存空間并不是無(wú)限大的俭缓,它最大只能是屏幕像素大小的2.5倍。
3.離屏渲染在我們處理一些特殊效果酥郭,這種效果不能一次性完成华坦,需要使用離屏緩存區(qū)來(lái)保持 中間的狀態(tài),也就是 不得不使用的時(shí)候不从,這時(shí)候離屏渲染是系統(tǒng)觸發(fā)的惜姐,比如:光柵化、高斯模糊等椿息。
4.如果一個(gè)效果需要實(shí)現(xiàn)多次歹袁,我們可以提前渲染保存到離屏緩存區(qū),來(lái)達(dá)到復(fù)用的目的寝优,這個(gè)時(shí)候就需要開(kāi)發(fā)者手動(dòng)觸發(fā)条舔。

離屏渲染實(shí)例化剖析

1,如何檢測(cè)項(xiàng)目中哪些圖層觸發(fā)了離屏渲染

  • 打開(kāi)模擬器設(shè)置點(diǎn)擊Debug按鈕-勾選Color Off-screen Render
    模擬器設(shè)置

2乏矾,代碼解析離屏渲染

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    //1.按鈕存在背景圖片
    UIButton *btn1 = [UIButton buttonWithType:UIButtonTypeCustom];
    btn1.frame = CGRectMake(100, 30, 100, 100);
    btn1.layer.cornerRadius = 50;
    [self.view addSubview:btn1];
    
    [btn1 setImage:[UIImage imageNamed:@"btn.png"] forState:UIControlStateNormal];
    btn1.clipsToBounds = YES;
    
    //2.按鈕不存在背景圖片
    UIButton *btn2 = [UIButton buttonWithType:UIButtonTypeCustom];
    btn2.frame = CGRectMake(100, 180, 100, 100);
    btn2.layer.cornerRadius = 50;
    btn2.backgroundColor = [UIColor blueColor];
    [self.view addSubview:btn2];
    btn2.clipsToBounds = YES;
    
    //3.UIImageView 設(shè)置了圖片+背景色;
    UIImageView *img1 = [[UIImageView alloc]init];
    img1.frame = CGRectMake(100, 320, 100, 100);
    img1.backgroundColor = [UIColor blueColor];
    [self.view addSubview:img1];
    img1.layer.cornerRadius = 50;
    img1.layer.masksToBounds = YES;
    img1.image = [UIImage imageNamed:@"btn.png"];
    
    //4.UIImageView 只設(shè)置了圖片,無(wú)背景色;
    UIImageView *img2 = [[UIImageView alloc]init];
    img2.frame = CGRectMake(100, 480, 100, 100);
    [self.view addSubview:img2];
    img2.layer.cornerRadius = 50;
    img2.layer.masksToBounds = YES;
    img2.image = [UIImage imageNamed:@"btn.png"];
    
}

結(jié)合上面的代碼孟抗,設(shè)置模擬器就可以查看查看離屏渲染的圖層,黃色背景的就是觸發(fā)了離屏渲染
離屏渲染

3钻心,離屏渲染的原因

  • shouldRasterize 光柵化凄硼,當(dāng)開(kāi)啟光柵化,就會(huì)將layer渲染為位圖并保存在緩存中捷沸,在下次使用就可以直接進(jìn)行復(fù)用摊沉,來(lái)提高效率。
    When the value of this property is YES, the layer is rendered as a bitmap in its local coordinate space and then composited to the destination with any other content.亿胸。
    shouldRasterize光柵化使用建議:
    1坯钦,如果layer不能被復(fù)用,則沒(méi)有必要打開(kāi)光柵化侈玄;
    2,如果layer不是靜態(tài)的吟温,需要被頻繁修改序仙,比如處于動(dòng)畫(huà)之中,那么開(kāi)啟離屏渲染 反而影響效率了鲁豪;
    3潘悼,離屏渲染緩存內(nèi)容有時(shí)間限制,緩存內(nèi)容100ms內(nèi)容如果沒(méi)有被使用爬橡,那么它就會(huì)被丟棄治唤,無(wú)法進(jìn)行復(fù)用了;
    4糙申,離屏渲染緩存空間有限宾添,超過(guò)2.5倍屏幕像素大小的話(huà),也無(wú)法進(jìn)行復(fù)用了;
  • 圓角觸發(fā)離屏渲染offscreen Rendering缕陕,我們首先要清楚CALayer的組成結(jié)構(gòu)粱锐,包括:backgroundColor、contents扛邑、borderWidth&borderColor三部分怜浅。
    offscreen Rendering

    設(shè)置layer.cornerRaclius只會(huì)設(shè)置backgroundColor的圓角,不會(huì)設(shè)置content的圓角蔬崩,除非同時(shí)設(shè)置了layer.masksToBoundsTrue(對(duì)應(yīng)view中的clipsToBounds屬性);圓角的離屏渲染的原因view.layer.masksToBounds = true;恶座。

總結(jié):常見(jiàn)觸發(fā)離屏渲染的幾種情況

  • 使用了mask的layer(layer.mask)
  • 需要進(jìn)行裁剪的layer(layer.masksToBounds / view.clipsToBounds);
  • 設(shè)置了組透明度為Yes沥阳,并且透明度不為1的layer(layer.allowsGroupOpacity / layer.opacity)奥裸;
  • 添加了投影的layer(layer.shadow);
  • 采用了光柵化的layer(layer.shouldRaterize);
  • 繪制了文字的layer(UILable,CAtextLayer,Core Text等);
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市沪袭,隨后出現(xiàn)的幾起案子湾宙,更是在濱河造成了極大的恐慌,老刑警劉巖冈绊,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件侠鳄,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡死宣,警方通過(guò)查閱死者的電腦和手機(jī)伟恶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)毅该,“玉大人博秫,你說(shuō)我怎么就攤上這事】粽疲” “怎么了挡育?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)朴爬。 經(jīng)常有香客問(wèn)我即寒,道長(zhǎng),這世上最難降的妖魔是什么召噩? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任母赵,我火速辦了婚禮,結(jié)果婚禮上具滴,老公的妹妹穿的比我還像新娘凹嘲。我一直安慰自己,他們只是感情好构韵,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布周蹭。 她就那樣靜靜地躺著趋艘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪谷醉。 梳的紋絲不亂的頭發(fā)上致稀,一...
    開(kāi)封第一講書(shū)人閱讀 51,443評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音俱尼,去河邊找鬼抖单。 笑死,一個(gè)胖子當(dāng)著我的面吹牛遇八,可吹牛的內(nèi)容都是我干的矛绘。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼刃永,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼货矮!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起斯够,我...
    開(kāi)封第一講書(shū)人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤囚玫,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后读规,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體抓督,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年束亏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了铃在。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡碍遍,死狀恐怖定铜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情怕敬,我是刑警寧澤揣炕,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站赖捌,受9級(jí)特大地震影響祝沸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜越庇,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望奉狈。 院中可真熱鬧卤唉,春花似錦、人聲如沸仁期。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至熬的,卻和暖如春痊硕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背押框。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工岔绸, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人橡伞。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓盒揉,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親兑徘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子刚盈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354