1. 測試代碼
Instrument 中的 Display 模塊:
iOS 中采用雙重緩沖和三重緩沖一起使用雾狈,從 display 中就可以看出來爪飘。即:雙緩沖不夠用了就采用三緩沖孩饼。
先上測試代碼:
2. 幾種情況分析
首先看看雙重緩沖:
如上具钥,此時雙緩沖很夠用舌狗,每次 Vsync 來到之前,上一幀的 frame buffer(apple叫做surface + ID)做入,所以幀率很高缭嫡,基本在 60 FPS喂很。
其中 frame xxx 表示第幾幀惜颇。例子中使用的 Layer 來畫 Path,Path 不會重新生成少辣,而是一直 addLineTo凌摄,所以內(nèi)容會越來越多:
接著看隨著內(nèi)容的增多增加,進(jìn)而使用三緩沖:
如上圖漓帅,出現(xiàn)了 surface 3锨亏、41、5 三個緩沖區(qū)忙干,且隨著 Vsync 信號的到來器予,在三個 surface 之間切換,這明顯是三緩沖策略捐迫。
上圖可以看到乾翔,每次的繪圖時間沒有明顯變長,仍然維持在一個 Vsync 信號間隔之間(16ms)施戴,所以 FPS 依然比較高末融,維持在 60FPS 左右:
這里的耗時辯證來看钧惧,有可能 commit 之后渲染的是上一次 commit 的畫面;
來看看之前的雙緩沖的情況:
如上圖勾习,雙緩沖時浓瞪,從視覺效果上看,渲染時間大概是三分之一個 Vsync 間隔巧婶,而三緩沖時乾颁,大概是二分之一個 Vsync 間隔,從這里大概可以看出三緩沖是一種補(bǔ)充措施艺栈,盡量維持渲染效率英岭。另外,這里涉及到 GPU 復(fù)雜的工作原理湿右,單純的這么分析不一定準(zhǔn)確诅妹,需要結(jié)合實際情況分析。
上述幾種情況都是沒有掉幀的情況下毅人,接下來看看三緩沖情況下不夠用了吭狡,出現(xiàn)掉幀的情況:
如上圖,出現(xiàn)了多個 surface 展示兩幀的情況丈莺,其原因就是因為 frame buffer 沒有渲染完成划煮。所以這種情況下,F(xiàn)PS 基本在 30 左右缔俄;
再來看一個嚴(yán)重掉幀的情況:
如上圖弛秋,藍(lán)色畫面停留了 9 幀,而 commits 頻率很正常俐载,耗時也很短蟹略,所以這肯定不是 CPU 卡頓。
上圖中遏佣,和之前明顯不一樣的地方在于科乎,stutters 中也有了展示,這個詞是口吃的意思贼急。難道這就是”微型口吃“?
確實是微型口吃捏萍;
3. commit層級
看看之前的雙緩沖的情況:
這張圖片中太抓, commits 之前就已經(jīng)渲染完了?顯然不是令杈,surface5 顯示的是上一幀的畫面走敌,第一個 commits 渲染完成的畫面由 surface41 展示。
GPU 渲染的規(guī)則和機(jī)制可能有很多逗噩,后期需要深入研究后才能看的更清晰掉丽。比如可能 Surface5 已經(jīng)渲染完成跌榔,如果雙緩沖夠用,那么在展示 Surface5 之前不會開始渲染 Surface41捶障,所以很多地方需要辯證來看僧须;
4. 微型口吃
定義:幀率不一樣。某幾個畫面渲染時間大于顯示器的 Vsync 間隔项炼,而其他的畫面渲染時間小于 Vsync担平。即:游戲/app 的幀率(如40FPS/25ms一次) < 顯示器幀率(60FPS/16ms)
現(xiàn)象:
幀率表現(xiàn):
原因:FPS雖然高,但是FPS不一致導(dǎo)致人眼視覺上看起來更卡頓锭部。幀率不一致暂论,不平滑是關(guān)鍵;因此拌禾,相對而言取胎,此種情況下,幀率不一致比幀率低更顯得卡頓湃窍。
做法闻蛀,就是使用 Metal 中的 Api 來設(shè)置固定的幀率:
核心點(diǎn):在自己 App/游戲的最大能力范圍內(nèi),保持幀率的一致坝咐;
因此循榆,此種方案,幀率從 40FPS 降低到了 30FPS墨坚,但是視覺效果上看上去更流暢了秧饮。
不使用 Metal 框架時的另外一種做法:
但是這種做法需要注意 CPU 的使用,每秒刷新 60 次相當(dāng)于執(zhí)行 60 次 commit泽篮,如果 commit 階段占用過多 CPU盗尸,那么 CPU 可能會報表。
理想情況:
上圖是靜止畫面時做的測試帽撑。如果不使用固定刷新頻率泼各,那么 FPS 基本上就是 0。而上圖就是采用了固定 60hz 的刷新頻率亏拉。
上圖是理想狀態(tài)下扣蜻,此時,commits 階段代碼比較簡單及塘,將主要渲染流程交給了 Core Animation莽使,進(jìn)而轉(zhuǎn)嫁到了 GPU,所以 CPU 占用很低笙僚。另外芳肌,由于畫面沒有更新,所以 GPU 基本上就是在兩個或三個 frame buffer 上來回切換,基本上不占用 GPU亿笤,估計就是視頻控制器和顯示器比較忙活~~~
不理想的情況:
如上圖翎迁,此時雖然 GPU 占比很低,但是 CPU 長期穩(wěn)定在 43%净薛,這樣還不如不使用這種固定刷新頻率的方法汪榔,直接不刷新可能會更好。因為不刷新時罕拂,如果畫面沒有發(fā)生變化揍异,就不會有 CPU 和 GPU 的消耗。
注意:上述兩個例子都是在靜止畫面的情況下所列舉的例子爆班,目的只是加深對固定刷新頻率的理解衷掷,千萬不要無腦直接使用到自己的項目上。
5. 補(bǔ)充
游戲類 App 比較追求幀率柿菩,因為游戲即使處于無交互的狀態(tài)戚嗅,因為有很多動畫,畫面也幾乎都是在變化的枢舶,所以游戲中的幀率是實實在在的畫面變化頻率懦胞。
而普通的 App 在無交互時,大部分情況下只是視頻顯示器在重復(fù)掃描同一個 frame buffer 并將信號傳遞給顯示器進(jìn)行光學(xué)展示凉泄。這種固定幀率的方式如果用到普通 App 上躏尉,對于靜止畫面而言,本質(zhì)上就是讓視頻控制器改變其 frame buffer 的指向后众,在兩個或多個 frame buffer 之間切換掃描胀糜,而這兩個 frame buffer 其實都是沒有發(fā)生變化的,所以更像是一種假象或是模擬刷新的行為蒂誉。
所以教藻,固定幀率對于游戲 App 而言,是在沒辦法達(dá)到高幀率的情況下的一種折中方案右锨。固定幀率對于普通 App 而言括堤,意義并不大,甚至可能會掩蓋問題或引入性能問題绍移。因為普通 App 的渲染瓶頸一般都是在 CPU悄窃,或者說是 CPU 和 GPU 之間的負(fù)載均衡。