【轉(zhuǎn)】【Unity】渲染性能優(yōu)化---經(jīng)驗總結(jié)

轉(zhuǎn)自:【Unity】渲染性能優(yōu)化---經(jīng)驗總結(jié)(一) - 嗶哩嗶哩 (bilibili.com)

1持灰、渲染優(yōu)化的幾大性能點

我們來簡單瀏覽一下渲染的主要過程:

CPU計算和收集渲染所需數(shù)據(jù)組裝描述符和材質(zhì)--->CPU向GPU傳遞渲染所需數(shù)據(jù)--->CPU發(fā)起DrawCall--->GPU進(jìn)行渲染和計算--->在一些情況下GPU會向CPU回傳數(shù)據(jù)(例如一些ComputeShader)

這里首先引出一個關(guān)鍵點:渲染流程中實際上大部分階段都是需要CPU參與的Eァ!H鹋濉复旬!?有時程序在定位性能熱點時慨飘,覺得項目中沒有多少GC和復(fù)雜運算某残,那么性能問題就一定是發(fā)生在GPU上代咸,實際上不然蹈丸。就我個人而言,不論是PC呐芥、主機還是移動端的GPU白华,其性能我還是比較自信的,如果沒有什么騷操作贩耐,GPU中的運算通常不會引發(fā)嚴(yán)重的性能問題弧腥。

那么根據(jù)上面的渲染流程,也就可以得出渲染中的幾大性能點:

1潮太、對于 CPU計算和收集渲染所需數(shù)據(jù)組裝描述符和材質(zhì) 階段:項目中存在大量零散瑣碎的物體管搪;有大量可以共用材質(zhì)的物體卻沒有共用材質(zhì)虾攻;有大量復(fù)雜的動畫運算和蒙皮運算等,這些都會使CPU計算和收集渲染數(shù)據(jù)的時間延長更鲁。

2霎箍、對于 CPU向GPU傳遞渲染所需數(shù)據(jù) 階段:該階段產(chǎn)生的性能問題就是常說的 帶寬問題,CPU 與 GPU 用于傳遞數(shù)據(jù)的通道澡为,其傳輸速率有限(而這個傳輸速率就稱為帶寬)漂坏,當(dāng)一幀內(nèi)傳輸?shù)膬?nèi)容大小大于一幀的傳輸速率時,就會出現(xiàn)傳輸排隊媒至,導(dǎo)致后續(xù)渲染延遲顶别。 尤其對于移動端,由于移動端的 CPU 和 GPU 間的帶寬本來就較小拒啰,且移動端 CPU 和 GPU 都在一塊芯片上驯绎,共用一整塊功率,當(dāng)出現(xiàn)帶寬問題時谋旦,使用功率上升剩失,導(dǎo)致手機發(fā)熱較快。?貼圖占用內(nèi)存過大册着、網(wǎng)格數(shù)據(jù)占用內(nèi)存過大拴孤、一些大物體在CPU端視錐體檢測無法被篩掉等,這些都會觸發(fā)帶寬問題甲捏。

3演熟、對于?CPU發(fā)起DrawCall 階段:這一階段導(dǎo)致性能問題的就是 DrawCall 的數(shù)量 和 DrawCall 本身的復(fù)雜度了。DrawCall 就是 CPU 的一種指令摊鸡,所以其耗時就是本身指令執(zhí)行的耗時绽媒。通常我們認(rèn)為渲染在GPU上有性能問題時,往往最終是由于 DrawCall 數(shù)過多導(dǎo)致GPU開始渲染的時間節(jié)點被大幅延遲導(dǎo)致的免猾。該合批的沒有合批是辕、該用同一個材質(zhì)的沒有用同種材質(zhì)、美術(shù)資源的制作上導(dǎo)致合批困難猎提、材質(zhì)有大量的屬性和變量等获三,都會導(dǎo)致 DrawCall 數(shù)量的上升 和 DrawCall本身指令的復(fù)雜化。

4锨苏、對于 GPU進(jìn)行渲染和計算 階段:這一階段才算徹底的走到了GPU的內(nèi)部疙教,也就是我們覺得要改Shader的時候。但實際上伞租,這一階段出現(xiàn)的一些問題也不是需要簡化Shader運算才能解決的贞谓。這一階段會產(chǎn)生性能問題的主要原因有:渲染順序的不合理和特效面片的不合理導(dǎo)致過多的Overdraw、Shader中冗余或復(fù)雜的計算葵诈、貼圖或網(wǎng)格數(shù)據(jù)過大導(dǎo)致運算時加載數(shù)據(jù)過慢裸弦、對于移動端 一些騷操作或者不合理的渲染流程還會觸發(fā) TileBase 架構(gòu)的 GMEM_Load 操作導(dǎo)致渲染過程變慢祟同。

5、對于 在一些情況下GPU會向CPU回傳數(shù)據(jù) 階段:通常游戲開發(fā)中不會遇到這一階段理疙。對于這一階段我們只需要留意使用 GPU 做計算功能時晕城,其結(jié)果應(yīng)該盡可能的是留在GPU的內(nèi)存中,作為GPU后面計算或渲染的輸入窖贤,如果一定要把結(jié)果傳給CPU砖顷,那就要注意結(jié)果的大小,避免產(chǎn)生帶寬問題赃梧。

2滤蝠、如何確定渲染性能點是在CPU還是GPU?

通過上面我們知道槽奕,對于渲染流程有的過程是在CPU几睛、有的過程是在GPU房轿,因此渲染的性能點也是有的在CPU粤攒、有的在GPU。那么究竟怎么確定到底是CPU的問題還是GPU的問題呢囱持?

這里我推薦的是使用 Unity 自帶的性能分析器:Profiler (注意:如果游戲目標(biāo)平臺不是PC那么 Profiler 一定要是真機測試:唤印!7鬃薄)

Profiler 的 Timeline 視圖展示了每一幀中 CPU?和 GPU 進(jìn)行的主要階段盔几。在一幀中,大致的流程為:CPU執(zhí)行一系列運算后確定動畫掩幢、網(wǎng)格和材質(zhì)信息--->CPU發(fā)起DrawCall--->GPU收到DrawCall和數(shù)據(jù)開始渲染--->在GPU渲染的同時 CPU 可繼續(xù)向后運行

那么如果在 CPU 發(fā)起 DrawCall 之前逊拍,GPU 沒有正在運行的渲染任務(wù),那么GPU就會處在等待狀態(tài)际邻。而如果 CPU 在發(fā)起 DrawCall 時芯丧,GPU還有渲染任務(wù)沒有處理完,那么 CPU 就會處在等待狀態(tài)世曾,等待GPU將當(dāng)前任務(wù)完成后再發(fā)起DrawCall缨恒。(這里是一種簡單的說法,對于 Vulkan 和 DX12 這些現(xiàn)代圖形API情況會有些不同轮听,但其實也是大同小異)

對于等待的階段骗露,Profiler 會用 灰色塊 表示:

圖2.1 灰色塊 Gfx.WaitForGfxCommandsFromMainThread 表示當(dāng)前GPU正在等待CPU

圖2.2 灰色塊 Semaphore.WaitForSignal 表示當(dāng)前 CPU 正在等待 GPU

那么如果 GPU 等待 CPU 的 灰色塊(如上圖2.1?渲染線程的 Gfx.WaitForGfxCommandsFormMainThread),所占時間過長血巍,那就說明 CPU 在渲染階段運行時間過長萧锉,渲染性能點出現(xiàn)在 CPU 端。

而如果 當(dāng)前幀內(nèi) 渲染線程(RenderThread) 的開頭出現(xiàn)了灰綠色塊(如圖2.2 渲染線程開頭的灰綠色塊) 且自身的綠色塊也很長一直到排到最后述寡;或者出現(xiàn)了CPU等待GPU的灰色塊(如圖2.2 的 Semaphore.WaitForSignal) 這就說明 GPU 在渲染時花費了大量時間柿隙,甚至在一幀的時間內(nèi)都沒有處理完任務(wù)玫恳,一直到下一幀還在處理。 也就是說渲染性能點出現(xiàn)在了 GPU 端优俘。

這里也引出了 Profiler 的一個迷惑人的點:當(dāng) CPU 等待 GPU 時京办,Profiler 會一直拉長 CPU 當(dāng)前所處階段的時間。例如圖2.2帆焕,Semaphore.WaitForSingle 上面的?MeshSkinning.Update 惭婿,其顯示執(zhí)行了 7.33ms 但實際上它的執(zhí)行可能只花了 0.2ms,而之后都是在等待 GPU 任務(wù)的完成叶雹。因此當(dāng)我們發(fā)現(xiàn) CPU 某些任務(wù)執(zhí)行時間莫名過長時财饥,要檢查一下其下面是否有 Semaphore.WaitForSignal 這個灰色塊,如果有就說明不是CPU執(zhí)行這項任務(wù)過慢折晦,而是GPU出現(xiàn)了渲染性能問題钥星。

3、CPU端渲染性能熱點確定

知道了是CPU還是GPU的問題后我們就來進(jìn)一步的確定問題满着。

對于CPU端的渲染性能點谦炒,其實只要資源規(guī)范設(shè)定好,資源創(chuàng)作流水線定制好风喇,渲染流水線設(shè)定好宁改,那么就不會有太大的問題。

主要是多大的貼圖會產(chǎn)生帶寬問題魂莫?多少個DrawCall會造成明顯卡頓还蹲?多少個多少幀的動畫或者多少個多少骨骼的角色會造成明顯卡頓?這些定量的問題耙考,我還都沒有具體的去研究過谜喊,平常也沒有去記錄相關(guān)的數(shù)據(jù)。所以就算拿來一份指標(biāo)報告倦始,你讓我看著這些數(shù)據(jù)也很難直接的確定出問題 X...X

所以對于這一塊我的想法就是做好資源管理和規(guī)范斗遏,盡量避免出現(xiàn)問題,真出現(xiàn)問題了就用排除法楣号,其它地方?jīng)]問題最易,那一定就是這里有問題嘍。 所以在后面的資源管理章節(jié)我會再細(xì)說一這部分炫狱。

當(dāng)然藻懒,對于這一塊性能熱點的確定我也不是完全沒有辦法,這里我還是推薦使用 Untiy 的 Profiler视译,其 Timeline 把每個階段的耗時都標(biāo)出來了嬉荆,我們只需要結(jié)合經(jīng)驗看看那一塊的用時過高就可以確定問題所在啦。

Profiler 顯示的 動畫計算用時

4酷含、GPU端渲染性能熱點確定

這一部分首先根據(jù)自身經(jīng)驗和直覺鄙早,有些東西是可以直接定位出來的汪茧。 如當(dāng)我們看到項目里有大量特效疊加,且特效面片很大時限番,就會知道 GPU 渲染時可能產(chǎn)生了大量的 Overdraw舱污,之后在用 Unity 自身的 Overdraw 窗口檢查一下,就知道當(dāng)前 Overdraw 是否需要優(yōu)化了弥虐。

在Unity內(nèi)檢測Overdraw情況扩灯,越紅表示Overdraw越高。圖中的其實不算太高霜瘪,因為項目這里我已經(jīng)優(yōu)化過一波了

而對于渲染順序引起的Overdraw珠插,如果能和美術(shù)制定好流程規(guī)范,讓美術(shù)能夠理解 渲染隊列颖对、Early-Z捻撑、Overdraw 這些規(guī)范那就會非常Nice,不然的話就是在美術(shù)制作好場景后自己檢測一遍然后做修改咯缤底。

而對于其它直觀上難以確定的 GPU 性能點顾患,這里如果是移動端我推薦使用 SnapdragonProfiler 進(jìn)行抓幀分析,其它平臺推薦 RenderDoc训堆。SnapdragonProfiler 是高通出的性能分析器描验,因此其只有搭配使用高通芯片的手機才能完全的發(fā)揮它的作用白嘁,這里推薦小米和三星的手機坑鱼。

SnapdragonProfiler

RenderDoc

關(guān)于怎么使用 SnapdragonProfiler 來確定 GPU 端 具體的性能點,我會放在后面的抓幀工具篇細(xì)說絮缅。而至于 RenderDoc 由于我實際上用的不多鲁沥,所以就先不談了。

造成渲染性能點的原因以及如何解決

1耕魄、CPU計算和收集渲染所需數(shù)據(jù)組裝描述符和材質(zhì) 階段的性能點

物體的合批画恰。如果場景中存在大量的瑣碎的物體,那么 CPU 在做視錐體剔除 和 收集這些物體的渲染信息時的耗時就會增加吸奴。對于合批通常使用這三種方法:建模時就手動合并網(wǎng)格允扇、靜態(tài)合批、動態(tài)合批则奥。

對于建模合批:這里不建議在建模時就把各種物體的網(wǎng)格合并為一個考润,因為這樣做會產(chǎn)生一個巨大的且有很多頂點數(shù)的物體,由于其體積過大读处,CPU無法在視錐體剔除階段將其剔除糊治,那么就會有過多的網(wǎng)格信息需要從CPU傳到GPU,此時容易引發(fā)帶寬問題罚舱。這里推薦的做法是建模時要思考個體與整體的可見性問題井辜,例如:對于書架里的書绎谦,當(dāng)里面一本書可見時,通常一組書都可見粥脚,那么就可以把一組書的網(wǎng)格合并為一個窃肠,甚至當(dāng)一本書可見時通常整個書架都可見,所以書和書架的網(wǎng)格都可以在建模時就合并在一起刷允。

對于靜態(tài)合批:對于靜態(tài)不會動的物體铭拧,在Unity中我們可以將其標(biāo)記為 Static,即靜態(tài)物體恃锉,那么在游戲運行時搀菩,Unity就會對使用相同材質(zhì)的靜態(tài)物體的網(wǎng)格進(jìn)行合并。注意:Unity并不是簡單的把所有靜態(tài)物體都合并為一個網(wǎng)格破托。 Unity在靜態(tài)合批時也會考慮到視錐體剔除問題肪跋,參與靜態(tài)合批的物體自身會有一個索引,反過來根據(jù)索引我們也可以找到具體的物體對象土砂,那么就可以動態(tài)的決定該對象是否隱藏(參與渲染)州既。

對于動態(tài)合批:一些頂點數(shù)較小的網(wǎng)格,在運行時Unity會動態(tài)的對它們的網(wǎng)格進(jìn)行合并萝映,因此即使這些物體是動態(tài)的也沒有關(guān)系吴叶。 注意:要使用靜態(tài)合批和動態(tài)合批,首先要在設(shè)置中開啟:

在 PlayerSetting 中開啟靜合批和動態(tài)合批

動態(tài)合批的頂點數(shù)限制的具體定義:

一個網(wǎng)格序臂, 如果 Shader 中使用了 Vertex Position, Normal 和 單個?UV蚌卤,那么只有在頂點數(shù)不超過 300 個時,該網(wǎng)格才能參與動態(tài)合批奥秆。

一個網(wǎng)格逊彭,如果 Shader 中 使用了 Vertex Position, Normal, UV0, UV1和Tangent,那么只有在頂點數(shù)不超過 180 個時构订,該網(wǎng)格才能參與動態(tài)合批侮叮。

還有一些情況會導(dǎo)致無法進(jìn)行動態(tài)合批,如 Shader 有多個Pass悼瘾、材質(zhì)不同的物體無法合批在一起等等囊榜,github.com/Unity-Technologies/BatchBreakingCause 這篇官方文檔介紹了所有導(dǎo)致合批失敗的原因。通過 Unity的 FrameDebuger 我們也可以知道一些合批失敗的原因:

對于原本能合批卻合批失敗的物體亥宿,F(xiàn)rameDebuger會給出原因

動態(tài)合批通常的應(yīng)用場景有兩個:粒子系統(tǒng) 和 UI卸勺。 粒子系統(tǒng)沒什么好說的,要注意的是 UI 的動態(tài)合批:

1箩绍、不同 Canvas 下的 UI 無法動態(tài)合批

2孔庭、不同層級下的UI無法動態(tài)合批(這里的層級可以理解為 一個 UI 其下面墊了幾層的UI,這一塊可以根據(jù) FrameDebuger 的合批結(jié)果來進(jìn)行調(diào)整)

3、alpha = 0圆到,depth = -1 的 UI 無法進(jìn)行合批

4怎抛、depth = x 的 UI,只能與 depth ≤?x 的 UI 進(jìn)行合批

5芽淡、動態(tài)合批本身也是有代價的马绝。 當(dāng)調(diào)用 Canvas.BuildBatch 或者,UI 元素產(chǎn)生變化時 就會重新進(jìn)行 動態(tài)合批挣菲。 因此我們應(yīng)該盡量把經(jīng)常產(chǎn)生變化的 UI 和 不怎么產(chǎn)生變化的靜態(tài)UI 分別放在兩個 Canvas 下富稻,這樣可以降低 UI 動態(tài)合批的復(fù)雜度,加快合批運行的時間白胀。

過多的材質(zhì)椭赋。過多的材質(zhì)與上面的合批基本原因和處理方法是一樣的。場景中有大量的材質(zhì)就會導(dǎo)致收集材質(zhì)信息時變得復(fù)雜或杠。那么對于能夠合批的物體哪怔,合批后它們使用的就是同一個材質(zhì)。 而對于材質(zhì)使用的Shader和屬性都一樣向抢,但貼圖不一樣的情況认境,我們可以試著將貼圖進(jìn)行合并.

復(fù)雜的動畫。Unity是可以對動畫文件進(jìn)行壓縮的挟鸠,對于一些動畫我們不需要太高的精度那么就可以進(jìn)行壓縮叉信,來加快動畫運算的速度和減少動畫文件的體積。并且對于動畫文件中存儲的一些數(shù)值的精度我們可以通過代碼工具來修改艘希,從而進(jìn)行動畫壓縮硼身,例如對于動畫文件里 1.123456789 的數(shù)值,我們可以修改為 1.1234枢冤。并且有的動畫文件中鸠姨,某一幀和它的前一幀和后一幀是沒有變化的,那么該幀就可以刪除淹真,這個也可以用代碼工具來檢測和解決。

2连茧、?CPU向GPU傳遞渲染所需數(shù)據(jù) 階段的性能點

這一部分就是帶寬問題了核蘸。除了壓縮資源就是壓縮資源。當(dāng)然還有一些不在本篇范疇內(nèi)的手段(流式加載啸驯、VirtualTexture 等)

貼圖資源客扎。

壓縮格式:PC端壓縮格式一般保持默認(rèn)就好了。移動端貼圖建議使用ASTC6x6進(jìn)行壓縮罚斗,如果覺得壓縮后效果不行 可以換為 ASTC4x4徙鱼。對于 HDR 貼圖 可以采樣 ASTC HDR 6x6 或 4x4 的壓縮格式。?一些用來保存高精度數(shù)據(jù)的貼圖,如果沒有 Alpha 通道袱吆,可以使用 RGB9e5 32bit Shared Exponent Float 的壓縮格式厌衙,有 Alpha 通道的話那就只能用 RGBAHalf 的格式了。

貼圖大薪嗜蕖:貼圖大小就是盡可能的小婶希,比如先做一個 2048x2048 的貼圖,然后不斷降低尺寸蓬衡,直到效果上發(fā)生明顯變化并且無法接受時喻杈,就得到了最適合的貼圖大小。并且對于一些具有四方連續(xù)特性的細(xì)節(jié)貼圖狰晚,我們可以只取其中的一小部分筒饰,放在一個尺寸很小的貼圖中,然后通過 Tilling And Offset 來采樣得到完整的內(nèi)容壁晒。

Mipmap:對于始終只出現(xiàn)在很遠(yuǎn)處的物體龄砰,其貼圖尺寸我們可以給很小,并且不需要生成 Mipmap讨衣。 同樣對于始終只出現(xiàn)在很近處的物體换棚,我們可以給個較大的貼圖尺寸,并且不需要生成 Mipmap

網(wǎng)格資源

建模時控制好網(wǎng)格的頂點數(shù)

網(wǎng)格 LOD 策略

曲面細(xì)分著色器配合高度圖和區(qū)塊劃分來做到地形LOD

在網(wǎng)格資源設(shè)置中反镇,關(guān)閉不需要導(dǎo)入的東西

可以嘗試開啟 Mesh Compression 對網(wǎng)格進(jìn)行壓縮固蚤,看得到的效果是否可以接受

非靜態(tài)物體(不需要參與烘焙光照貼圖的物體)取消勾選 GenerateLightmapUV

對于一些頂點數(shù)很多,同時體積很大很容易一直出現(xiàn)在視野范圍內(nèi)的物體歹茶∠ν妫可以將其拆分為多個物體。這樣在經(jīng)過視錐體剔除后惊豺,就不需要向GPU傳入太多的頂點數(shù)據(jù)燎孟。

3、CPU發(fā)起DrawCall 階段的性能點

DrawCall 的數(shù)量尸昧,要減小 DrawCall 的數(shù)量揩页,其實就是減少物體和材質(zhì)的數(shù)量,這些在上面的 CPU計算和收集渲染所需數(shù)據(jù)組裝描述符和材質(zhì)階段 部分已經(jīng)介紹了烹俗,這里就不贅述了爆侣。另外對于 DrawCall 數(shù)量的影響就是 Shader 的 Pass 數(shù),和在前向渲染的管線中點光源的數(shù)量幢妄,但這兩方面屬于是那種如果在不降低渲染效果的情況下那么就該是多少就是多少沒辦法減小的問題兔仰,如果非要減小那么就要對渲染管線進(jìn)行改造,插入一些現(xiàn)代的優(yōu)化方案蕉鸳,由于這些方案通常都比較復(fù)雜乎赴,不在本篇范疇類,有機會會專門做一篇進(jìn)行介紹。

DrawCall 的復(fù)雜度榕吼。DrawCall 不單單只是一個指令饿序,一個 DrawCall 中通常包含了多個指令。那么其包含的指令數(shù)的多少也就決定了其本身的復(fù)雜度友题。而 DrawCall 中最常見的指令就是告訴GPU材質(zhì)的屬性:

一個DrawCall中包含了多條指令

對于設(shè)置一個浮點數(shù)的值嗤堰,需要調(diào)用 一次 glUniformf 指令(這里以 OpenGL 為例),而設(shè)置一個浮點向量的值度宦,同樣也只需要調(diào)用 一次 glUniform4fv 指令踢匣。因此我們就可以把 4個浮點數(shù)變量 合并為 1個浮點向量變量。這樣 4條指令就可以合并為 1條指令戈抄。而要做到這樣离唬,我們只需要在編寫Shader時,將4個浮點變量的聲明改為1個浮點向量的聲明划鸽。但是浮點向量在材質(zhì)面板上的顯示方式對于美術(shù)極不友好输莺,調(diào)節(jié)起來很變扭也很不直觀,這里可以使用 ShaderGUI 和 MaterialPropertyDrawer 類來對材質(zhì)面板進(jìn)行定制裸诽,以達(dá)到美術(shù)友好嫂用,這一部分我會放在后面的 騷操作篇進(jìn)行細(xì)說。

4丈冬、GPU進(jìn)行渲染和計算 階段的性能點

Overdraw

對于特效引起的Overdraw嘱函,一定要在特效制作時關(guān)注 "像素填充比" 這一概念:

像素填充比,即在一個特效面片中 alpha不為0 的像素 占整個面片像素的比例埂蕊。在特效制作時往弓,要讓像素填充比盡可能的大。下面給出例子:

對于上面這個特效面片蓄氧,像素填充比就過小函似,會產(chǎn)生大量沒有必要的 Overdraw。此時應(yīng)該改變網(wǎng)格喉童,減低片面網(wǎng)格的高度撇寞,或者將網(wǎng)格做成月牙形。

而對于由于渲染順序不合理導(dǎo)致的 Overdraw泄朴,就只有自己根據(jù)實際情況去調(diào)整渲染隊列了重抖。例如對于一個 有河流、草祖灰、樹木 和 地面的場景,我們應(yīng)該 先渲染草畔规,然后渲染樹木的樹葉局扶、之后是樹木、接著是地面,最后是河流三妈。這樣在渲染地面時畜埋,地面就會有大量像素因為被草和樹木遮擋而沒能通過深度測試,也就沒有被光柵化渲染畴蒲,從而減少了Overdraw悠鞍。而因為河流是一個半透明物體(我們可以透過河流看到河水下面的地面),因此河流需要在地面渲染之后才渲染模燥,這樣才能和地面做半透明混合咖祭。

Shader本身的計算復(fù)雜度

LUT策略。我們可以把Shader中這類計算:其輸入變量的值范圍在0~1或者可以轉(zhuǎn)換為0~1蔫骂,其輸出變量的值范圍也在0~1或者可以轉(zhuǎn)換為0~1么翰,那么我們就可以把0~1范圍的所有輸入都看作一個貼圖的UV值,而0~1的所有輸出都看作一個貼圖的顏色值辽旋。那么我們就可以提前離線的將所有輸入值都進(jìn)行計算得到輸出值浩嫌,并存儲在一個貼圖中。那么 Shader 在 實時計算時补胚,我們只需要拿到輸入變量去采樣貼圖即可码耐,從而避免了復(fù)雜的運算。

合并運算溶其。對于 GPU 來說骚腥,一個浮點數(shù)的運算 和 一個浮點向量的運算使用的指令數(shù)是相同的。因此如果幾個浮點數(shù)需要做相同的運算握联,那么就可以先把這幾個浮點數(shù)合并為幾個浮點向量桦沉,然后再運算。并且金闽,Unity在編譯著色器時纯露,會在一些地方幫我們做出這種優(yōu)化。

在移動端還要注意數(shù)值變量的精度問題代芜。在移動端GPU上埠褪,數(shù)值變量有 fixed、half挤庇、float 的區(qū)分钞速,其數(shù)值精度分別為 8位、16位和32位嫡秕,位數(shù)越高渴语,計算過程就越慢。但在一些GPU上(如蘋果的GPU 和 部分華為手機使用的GPU)昆咽,如果運算結(jié)果超過了其定義的精度范圍驾凶,就會出現(xiàn)渲染異常的情況(渲染結(jié)果出現(xiàn)黑色塊牙甫,或渲染結(jié)果不正確等)。這里我的建議是调违,在聲明變量時窟哺,顏色使用fixed,世界空間下的位置信息使用float技肩,如果采樣的貼圖會用到很大的Tilling那么uv也是用float且轨,否則使用 half,其它的變量都使用half虚婿。

在移動端還要注意GMEM_Load機制問題旋奢。GMEM Load 即 Graphic?Memory Load 在 移動端 GPU 的 TileBase 架構(gòu)下, 其觸發(fā)表明上一幀的 Frame Buffer 在這一幀渲染時被從 GPU 主存加載到了正在渲染的 Tile 內(nèi)存中雳锋。其會引起嚴(yán)重的渲染性能問題黄绩!例如在一款手機上屏幕被分為了30個Tile, 如果觸發(fā)了 GMEM Load 那么在每次渲染一個 Tile 之前都會從 主存 加載 FrameBuffer玷过,而 Frame Buffer占用內(nèi)存比較大爽丹,加載時間會比較慢,并且在加載完畢后 GPU 內(nèi)部還需要一系列調(diào)度才能讓渲染開始進(jìn)行辛蚊,因此 GMEM Load 會很大程度的降低GPU運行的效率粤蝎。 在 Unity 中觸發(fā) GMEM Load 的操作有:

開啟 HDR。在移動端即使開啟了 HDR袋马,顏色緩沖仍然是 RGBA8 格式的初澎,Unity 會創(chuàng)建出一個 RT(RGBA Half 或者 R11G11B10 格式,取決于你的 Graphic Setting)虑凛,渲染結(jié)果先輸出到這個 RT 上碑宴,并做了編碼,之后該 RT 通過解碼和Tonemapping 輸出到顏色緩沖上(相當(dāng)于一個后處理)桑谍,但是 Unity 自己的這個后處理會觸發(fā) GMEM Load

GrabPass延柠。因為 GrabPass 就是直接復(fù)制 Frame Buffer 的顏色緩沖。

相機的 ClearFlag 是 DepthOnly 或者 DontClear (這個在我的記憶中不是那么確定锣披,總之好像確實有可能會導(dǎo)致GMEM Load)

混亂和大量的RT (這里說的混亂和大量是因為通常簡單的使用 RT 是不會導(dǎo)致 GMEM Load 的贞间,但某些情況下會觸發(fā),具體是哪些情況我也說不上來雹仿,因為觸發(fā)時 RT 的管理真的太亂了...)增热。 另外對于不需要 深度/模板緩沖的RT,創(chuàng)建時要把它的 depth 設(shè)為 0胧辽,這樣即使因為 RT 觸發(fā)了 GMEM Load峻仇,由于 GMEM Load Color 和 GMEM Load Depth and Stencil 是兩個分開的操作,所以這樣可以避免 GMEM Load Depth and Stencil邑商,從而做到盡量避免 GMEM Load础浮。

?5帆调、在一些情況下GPU會向CPU回傳數(shù)據(jù) 階段的性能點

沒什么好說的奠骄,這里能引起的只有帶寬問題豆同。通常游戲開發(fā)中不會遇到這一階段。對于這一階段我們只需要留意使用 GPU 做計算功能時含鳞,其結(jié)果應(yīng)該盡可能的是留在GPU的內(nèi)存中影锈,作為GPU后面計算或渲染的輸入,如果一定要把結(jié)果傳給CPU蝉绷,那就要注意結(jié)果的大小鸭廷,避免產(chǎn)生帶寬問題。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末熔吗,一起剝皮案震驚了整個濱河市辆床,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌桅狠,老刑警劉巖讼载,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異中跌,居然都是意外死亡咨堤,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進(jìn)店門漩符,熙熙樓的掌柜王于貴愁眉苦臉地迎上來一喘,“玉大人,你說我怎么就攤上這事嗜暴⊥箍耍” “怎么了?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵闷沥,是天一觀的道長萎战。 經(jīng)常有香客問我,道長狐赡,這世上最難降的妖魔是什么撞鹉? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮颖侄,結(jié)果婚禮上鸟雏,老公的妹妹穿的比我還像新娘。我一直安慰自己览祖,他們只是感情好孝鹊,可當(dāng)我...
    茶點故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著展蒂,像睡著了一般又活。 火紅的嫁衣襯著肌膚如雪苔咪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天柳骄,我揣著相機與錄音团赏,去河邊找鬼。 笑死耐薯,一個胖子當(dāng)著我的面吹牛舔清,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播曲初,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼体谒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了臼婆?” 一聲冷哼從身側(cè)響起抒痒,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎颁褂,沒想到半個月后故响,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡痢虹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年被去,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片奖唯。...
    茶點故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡惨缆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出丰捷,到底是詐尸還是另有隱情坯墨,我是刑警寧澤,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布病往,位于F島的核電站捣染,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏停巷。R本人自食惡果不足惜耍攘,卻給世界環(huán)境...
    茶點故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一翔横、第九天 我趴在偏房一處隱蔽的房頂上張望藏杖。 院中可真熱鬧,春花似錦袱箱、人聲如沸庆揪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至吝羞,卻和暖如春兰伤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背钧排。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工敦腔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人卖氨。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓会烙,卻偏偏與公主長得像,于是被迫代替她去往敵國和親筒捺。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,630評論 2 359

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