本文章整合了《Real-Time Rendering 3rd》第十五章“Pipeline Optimization”和《GPU Gem I》第28章“Graphics Pipeline Performance”,整合《Unity Shader入門精要》第十六章 渲染最佳化,同時,還有使用各種工具來分析專案中存在的效能問題的方法介紹。

一、渲染管線的瓶頸定位策略

正確定位到了瓶頸,最佳化工作就已完成了一半,因為可以針對管線上真正需要最佳化的地方有的放矢 。

提到瓶頸定位,很多人都會想到Profiler工具。Profiler工具可以提供API呼叫耗時的詳細資訊,由此可以知道哪些API呼叫是昂貴費時的,但不一定能準確地確定管道中哪些階段正在減慢其餘部分的速度。

確定瓶頸的方法除了用Profiler檢視呼叫耗時的詳細資訊這種眾所周知的方法外,也可以採用基於工作量變化的控制變數法。

設定一系列測試,其中每個測試減少特定階段執行的工作量。如果其中一個測試導致每秒幀數增加,則已經找到瓶頸階段。

Real-Time Rendering筆記(11):渲染最佳化之從瓶頸定位到最佳化策略

整個確認瓶頸的過程從渲染管線的尾端,光柵化階段開始,經過幀緩衝區的操作(也稱光柵操作),終於CPU(應用程式階段)。

下文將按照按照最佳化定位的一般順序(即上述圖中的流程),按光柵化階段、幾何階段、應用程式階段的的順序來依次介紹瓶頸定位的方法與要點。

Real-Time Rendering筆記(11):渲染最佳化之從瓶頸定位到最佳化策略

關於渲染管線整個流程的詳細解讀:

https://

blog。csdn。net/qq8263644

10/article/details/88389349

1。 光柵化階段的瓶頸定位

眾所周知,光柵化階段由四個的階段組成: 三角形設定,三角形遍歷,片元著色器,片元操作(光柵化操作)。

其中三角形設定和遍歷階段幾乎不會是瓶頸,因為它只是將頂點連線成三角形。

1。1 光柵化操作的瓶頸定位

光柵化操作的瓶頸主要與幀緩衝頻寬(Frame-Buffer Bandwidth)相關

。眾所周知,位於管線末端的光柵化操作(Raster Operations,常被簡稱為ROP),用於深度緩衝區和模板緩衝區的讀寫、比較,顏色緩衝區讀寫顏色,以及進行alpha 混合和測試。光柵化操作中許多負載都加重了幀緩衝頻寬負載。

測試幀緩衝頻寬是否是瓶頸所在,比較好的辦法是改變顏色緩衝的位深度,或深度緩衝的位深度(也可以同時改變兩者)

。如果此操作(比如將顏色緩衝或深度緩衝的位深度從32位減少到16位)明顯地提高了效能,那麼幀緩衝頻寬必然是瓶頸所在。

另外,幀緩衝頻寬也與GPU視訊記憶體頻率(GPU memory clock)有關,因此,修改該頻率也可以幫助識別瓶頸。

補充:位深度

示例:8位顏色的圖,位深度就是8,用2的8次冪表示,它含有256種顏色 ( 或256種灰度等級 )。

更通俗的講,8位顏色的圖,每儲存1個畫素一般需要8位二進位制。也就是8個01進行排列組合,排列組合的結果有2的8次冪=256種顏色。我們把每個畫素可表示顏色的2的冪指數稱為深度。

1。2 片元著色器的瓶頸定位

片元著色關係到產生一個片元的實際開銷,與顏色和深度值有關。這就是執行”畫素著色器(Pixel Shader )“或”片元著色器(Fragment Shader )“的開銷。片元著色(Fragment shading)和幀緩衝頻寬(Frame-Buffer Bandwidth)由於填充率(Fill Rate)的關係,經常在一起考慮,因為他們都與螢幕解析度相關。儘管它們在管線中位於兩個截然不同的階段,區分兩者的差別對有效最佳化至關重要。

片元著色器的是否是瓶頸所在可以透過改變螢幕解析度來測試

。如果較低的螢幕解析度導致幀速率明顯上升,片元著色器則是瓶頸,至少在某些時候會是這樣。當然,如果是渲染的是LOD系統,就需斟酌一下是否瓶頸確實是片元著色器了。

片元著色的速度與GPU核心頻率有關。

1。3 紋理頻寬的瓶頸定位

在記憶體中出現紋理讀取請求時,就會消耗紋理頻寬(Texture Bandwidth)。

過程:

從視訊記憶體讀取紋理到GPU的紋理高速緩衝區

儘管現代GPU的紋理快取記憶體設計旨在減少多餘的記憶體請求,但紋理的存取依然會消耗大量的記憶體頻寬。

縮小紋理尺寸,改變紋理過濾方式,如果此修改顯著地改善效能,則意味著紋理頻寬是瓶頸限制。

紋理頻寬也與GPU視訊記憶體頻率相關。

2。 幾何階段的瓶頸定位

幾何階段是最難進行瓶頸定位的階段。這是因為如果在這個階段的工作負載發生了變化,那麼其他階段的一個或兩個階段的工作量也常常發生變化。為了避免這個問題,Cebenoyan 提出了一系列的試驗工作從光柵化階段後的管線開始進行瓶頸定位。

在幾何階段有兩個主要區域可能出現瓶頸:頂點與索引傳輸( Vertex and Index Transfer)和頂點著色器。

2。1 頂點著色器的瓶頸定位

渲染管線中的

頂點著色器,主要工作是座標變換,逐頂點光照和輸出後續階段所需的資料

輸入一組頂點屬性(如模型空間位置、頂點法線、紋理座標等等),輸出一組適合裁剪和光柵化的屬性(如齊次裁剪空間位置,頂點光照結果(正向渲染),紋理座標等等)。當然,這個階段的效能與每個頂點完成的工作,以及正在處理的頂點數量有關。

如果減少頂點著色器的指令數量,幀率有明顯變化,則說明瓶頸在頂點著色器,這種情況一般不會出現。

如果減少頂點數量,幀率有明顯變化,則說明瓶頸可能在頂點過多,或頂點AGP傳輸限制,此時可能透過模型LOD來解決問題。

另外需要注意,頂點處理的速度與GPU核心頻率有關。

2。2 頂點與索引傳輸的瓶頸定位

GPU渲染管線的第一步,是讓GPU獲取頂點和索引。而GPU獲取頂點和索引的操作效能取決於頂點和索引的實際位置。其位置通常是在系統記憶體中(透過AGP或PCI Express匯流排傳送到GPU),或在區域性幀緩衝記憶體中。

如果在頂點著色器中訪問紋理會比較慢,瓶頸可能在頂點著色器(Shader Model 3.0)。

3。 應用程式階段的瓶頸定位

使用各種工具來分析專案中存在的效能問題,最常用的工具有:

Unity引擎提供很多測試工具包括Unity Profiler,Unity Memory Profiler,Unity Frame Debugger等,

在ios平臺下,XCode Instrument 也包含了很多工具,其中最常用的有Time Profiler,Allocation以及Capture GPU Frame。

在android平臺下,最常用的工具有AdrenoProfiler和SnapdragonProfiler,這兩個工具都是用來進行GPU效能分析的。

Unity Profiler

Real-Time Rendering筆記(11):渲染最佳化之從瓶頸定位到最佳化策略

Unity Profiler中最常檢查的內容是CPU Usage,其中GC Alloc和Time ms最為重要。GC Alloc展示了每幀在Mono堆上進行記憶體分配的程式碼,過於頻繁的在堆上分配記憶體會導致Mono定期觸發GC。Collect操作,進而導致遊戲卡頓。

因此我們建議對單幀2K以上的記憶體分配,以及每幀20B以上的記憶體分配進行排查。

如果能把堆記憶體的分配降到最低是最好的。Time ms展示了每一幀CPU耗時最高的函式,透過這項可以找到耗時不合理的程式碼,然後進一步對程式碼進行最佳化。

Unity Memory Profiler

Real-Time Rendering筆記(11):渲染最佳化之從瓶頸定位到最佳化策略

Unity為5。3以上的版本提供了一個新的Memory Profiler工具。這個工具透過圖形的方式展示了工程中佔用記憶體最高的資源型別,因此可以很方便的進行資源記憶體的最佳化。另外還可以在遊戲的不同時間點抓取多個快照,透過比較記憶體佔用的不同,來發現某些資源記憶體洩漏的情況。

Unity Frame Debug

Real-Time Rendering筆記(11):渲染最佳化之從瓶頸定位到最佳化策略

透過Enable按鈕可以抓取當前渲染幀的全部資料。 瞭解不能合批的原因,DrawCall過多的原因。例如,同一張圖集,為什麼會多一個DrawCall,因為物件的材質不同。

XCode Instrument – Time Profiler

Real-Time Rendering筆記(11):渲染最佳化之從瓶頸定位到最佳化策略

左上角是Instrument的Time Profiler工具,右下角是Unity Profiler,可以發現它們非常像。

區別在於Time Profiler可以分析一段時間範圍內不同函式的時間消耗,而Unity Profiler只能分析一幀內程式碼的時間消耗。

另外Time Profiler可以顯示引擎底層耗時高的程式碼堆疊,非常方便從底層去理解效能問題的原因。Unity Profiler只能顯示引擎程式碼中新增標籤的函式耗時,因此往往在Instrument Time Profiler中可以看到更多有用的資料。

XCode Instrument – Allocation

Real-Time Rendering筆記(11):渲染最佳化之從瓶頸定位到最佳化策略

Allocation是用於分析記憶體分配的工具。預設情況下,它會開啟Created & Persistent選項,這代表

它會記錄一段時間內分配出來但是沒有釋放的記憶體。

因為有了這個功能,我們可以很方便的檢查遊戲中存在的記憶體洩露。

一般的使用方法是在遊戲主選單介面開啟Allocation檢測,進入戰鬥場景測試一段時間再回到主選單介面,然後檢查有哪些記憶體分配但是沒有被釋放。這部分記憶體就可能包含存在洩漏的記憶體。

Capture GPU Frame

Real-Time Rendering筆記(11):渲染最佳化之從瓶頸定位到最佳化策略

從XCode內啟動遊戲在真機執行,透過XCode內的Capture按鈕可以抓取當前渲染幀的全部資料

。介面左邊展示了所有的Drawcall列表,中間上方是當前Drawcall渲染出的畫面,下方是當前Drawcall的相關資料,右上方是當前Drawcall用到的紋理資料。這個工具

可以顯示每個Drawcall的耗時,因此可以用來檢查哪些物件渲染耗時太高。進而分析是Shader原因,還是網格體太複雜等等。

使用Profiler精確定位效能熱點的最佳化技巧:

https://

blog。csdn。net/qq8263644

10/article/details/81292973

SnapdragonProfiler抓取遊戲紋理和shader:

https://

blog。csdn。net/qq8263644

10/article/details/88555278

AdrenoProfiler抓取遊戲紋理和shader:

https://

blog。csdn。net/qq8263644

10/article/details/88553830

二、渲染管線的最佳化策略

一旦確定了瓶頸位置,就可以對瓶頸所處階段進行最佳化,以改善我們遊戲的效能。主要分為下面兩個大方向的最佳化:

對CPU的最佳化策略

對GPU的最佳化策略

對記憶體的最佳化策略

2。1 對CPU的最佳化策略

使用批處理技術減少DrawCall數目。批處理技術原理是減少每幀需要的DrawCall數目,即每次呼叫DrawCall時儘可能的處理多個物體。

2。1。1 動態批處理(Unity引擎)

Unity每一幀都會重新合併一次網格,再把合併好的模型資料傳遞給GPU,然後使用同一種材質對其渲染。

經過動態批處理的物體仍然可以移動,這是因為每幀Unity都會重新合併一次網格。

動態批處理條件限制:

(1)進行批處理的網格頂點屬性規模要小於900,如果Shader有三個屬性,那麼頂點數目不能超過300個。

(2)多Pass的Shader會中斷批處理。在前向渲染中,我們有時需要使用額外的Pass來為模型新增更多的光照效果,這樣一來,模型就不會被動態批處理了。

(3)批在一起的所有的模型應用同樣的縮放值

(4)使用相同的材質

(5)相同的一張lightmap

(6)不能接收陰影

2。1。2 靜態批處理

在執行開始的階段,把需要進行靜態批處理的模型合併到一個新的網格中,這意味著模型不能再執行時被移動。往往需要佔用更多的記憶體來儲存合併後的網格結構。應用靜態批處理後,VBO(Vertex Buffer Object)頂點緩衝物件的數目變大了。

無論是動態批處理還是靜態批處理,都要求模型之間需要共享同一個材質。如果兩個材質之間只是使用的紋理不同,可以把這些紋理合併到一張更大的紋理中,這張更大的紋理叫做圖集(atlas)。

補充:

DrawCall:

DrawCall是CPU透過底層影象程式設計介面發出的渲染命令,GPU讀取渲染命令執行渲染操作。

過多的DrawCall影響繪製的原因:

主要是每次繪製時,CPU透過底層影象程式設計介面發出渲染命令DrawCall,而每個DrawCall需要很多準備工作,檢測渲染狀態、提交渲染資料、提交渲染狀態,而GPU本身可以很快處理完渲染任務。DrawCall過多,CPU負載過多,而GPU效能閒置。

渲染狀態:

渲染狀態定義場景中的網格是怎樣被渲染出來的

例如使用哪個頂點著色器、哪個片元著色器、光源屬性、材質等。如果沒有更改渲染狀態,所有的網格將使用同一種渲染狀態。

CPU傳送DrawCall需要完成的操作:

CPU可以向GPU傳送命令以將多個已知的變數統一地轉換為渲染狀態。此命令稱為SetPass呼叫

。SetPass呼叫告訴GPU用於渲染下一個網格的設定。僅當要渲染的下一個網格需要從前一個網格更改渲染狀態時,才會傳送SetPass呼叫。

CPU將繪圖呼叫傳送到GPU。繪圖呼叫指示GPU使用最近的SetPass呼叫中定義的設定呈現指定的網格。

在某些情況下,一個批次可能有多次Pass。對於批次中的每個Pass,CPU必須傳送新的SetPass呼叫,然後必須再次傳送DrawCall。

同時,GPU執行以下工作:

GPU按照發送順序處理來自CPU的任務。

如果當前任務是SetPass呼叫,則GPU更新渲染狀態。

如果當前任務是DrawCall,則GPU渲染網格。這是分階段發生的,由著色器程式碼的不同部分定義。渲染的這一部分很複雜,我們不會詳細介紹它,但是我們理解一段稱為頂點著色器的程式碼告訴GPU如何處理網格的頂點,然後是一段程式碼稱為片段著色器告訴GPU如何繪製單個畫素。

重複此過程,直到GPU處理完所有從CPU傳送的任務為止。

2。2 對GPU的最佳化策略

2。2。1 減少需要的頂點數目

(1)最佳化模型,儘可能的減少三角形的面數,移除不必要的硬邊及紋理銜接,避免邊界平滑和紋理分離。

邊界平滑(smoothing splits,一個頂點可能會對應多個法線資訊或切線資訊

,在Unity匯入模型時,有一個Smoothing Angles(光滑組)的設定,當Smoothing Angles的值為0時,就沒有共用的頂點,拆分出更多新的頂點,可以展示更多細節。當這個值越來越大,共用頂點越多,細節就更少一些。)

紋理分離(uv splits,一個頂點可能有多個紋理座標

。面與面的交界處使用的一些相同頂點,在不同面上,同一個頂點的紋理座標可能並不相同 ,GPU會把這個頂點拆分成多個具有不同紋理座標的頂點)。

(2)使用模型的LOD技術

LOD允許當模型逐漸遠離攝像機時,減少模型上的面片數量,從而提高效能。

(3)使用遮擋剔除技術

消除在其他物體後面看不到的物體,也就不會渲染這個看不到的頂點,從而提高效能。注意:在移動平臺,遮擋剔除開銷太大,不建議使用。

(4)Camera.layerCullDistances

相機跟每一層的剔除距離。比如,在視野中有很多npc,可以把npc設定到npc層,並在程式碼中為npc層設定較小的layerCullDistances剔除距離,這樣就可以只渲染npc層剔除距離內的npc,減少效能開銷。

(5)視椎體越小越好,注意遠裁減面的距離

,頂點數量最多80k-100k之間

(6)Culling Mask ,剔除不需要渲染的層,減少效能開銷

(7)使用視椎體檢測,裁剪場景中不需要渲染的特效。

場景的中特效,在攝像機看不到的地方也在渲染,就會造成不必要的效能開銷。

2。2。2 最佳化光照計算

考慮光照的影響可以每頂點,每畫素的進行計算,光照計算可以透過多種方式進行最佳化:

實時光源越少越好,甚至不用實時光

利用離線烘焙,light mapping

Spotlight(聚光燈)開銷很大,少用

限制畫素光的數量

Culling Mask ,取消不需要進行光照計算的層

謹慎使用實時陰影

儘量用Hard Shadow

減少Shadow Distance

不用Shadow Castcade

補充:

Shadow Castcade

Shadow Castcade,就是遠處的陰影用解析度比較小的貼圖,近處的陰影用解析度比較大的貼圖,提升了近處陰影的質量,但增加了效能開銷。

Real-Time Rendering筆記(11):渲染最佳化之從瓶頸定位到最佳化策略

Shadow Distance

超出此距離的物體(來自相機)不投射陰影,因為遠處的物件不需要渲染到陰影貼圖中。將陰影距離設定的儘可能低,可以提高渲染效能。

2。2。3 加速片元著色

如果你正在使用長而複雜的片元著色器,那麼往往瓶頸就處於片元著色器中。若果真如此,那麼可以試試如下這些建議:

優先渲染深度。

在渲染主要著色通道(Pass)前,先進行僅含深度的通道(depth-only (no-color) pass)的渲染,能顯著地提高效能,尤其是在高深度複雜性的場景中。因為這樣可以減少需要執行的片元著色量,以及幀緩衝儲存器的存取量,從而提高效能。而為了發揮僅含深度的通道的全部優勢,僅僅禁用顏色寫入幀緩衝是遠遠不夠的,同時也應該禁用所有片元的著色,甚至禁用影響到深度以及顏色的著色(比如 alpha test)。

幫助early-z最佳化(即Z緩衝最佳化),來避免多餘片元處理 。

現代GPU配有設計良好的晶片,以避免對被遮擋片元的著色,但是這些最佳化依賴場景知識。而以粗略地從前向後的順序進行渲染,可以明顯提高效能。以及,先在單獨的pass中先渲染深度,透過將著色深度複雜度減少到1,可以有效地幫助之後的pass(主要的昂貴的shader計算的位置)進行加速。

把紋理作為查詢表( lookup tables),儲存資料。

其實非常好用,而且可以無消耗地過濾它們的結果。一個典型例子便是單位立方體貼圖,它僅允許以一個單一紋理查詢的代價來高精度地對任意向量進行標準化。

將更多每片元的工作移到頂點著色器。

對於最佳化的大方向而言,正如頂點著色器中的每個物體的計算量工作應該儘可能地移到CPU中一樣,每頂點的計算也應該儘量被移到頂點著色器(連同在螢幕空間中線性插值計算)。常見的例子包括計算向量和座標系之間的變換向量。

使用必需的最低精度。

諸如DirectX之類的API允許我們在著色器程式碼中指定精度,以減少精度高所帶來的額外計算量。很多GPU都可以利用這些提示來減少內部精度以及提高效能。

避免過度歸一化(Normalization)

。在寫shader時,對每個步驟的每個向量都進行歸一化的習慣,常常被調侃為“以歸一化為樂(Normalization-Happy)”。這個習慣通常來說其實是不太好的習慣。我們應該意識到不改變長度的變換(例如標準正交基上的變換)和不依賴向量長度的計算(例如正方體貼圖的查詢)是完全沒必要進行歸一化後再進行的。

考慮使用片元著色器的LOD層次細節。

雖然片元著色器的層次細節不像頂點著色器的層次細節影響那麼大(由於投射,在遠處物體本身的層次細節自然與畫素處理有關),但是減少遠處著色器的複雜性和表面的通道數,可以減少片元處理的負載。

在不必要的地方禁用三線性過濾。

在現代GPU結構的片元著色器中計算三線性過濾(Trilinear filtering),即使不消耗額外的紋理頻寬,也要消耗額外的迴圈。在mip級別轉換不容易辨別的紋理上,關掉三線性過濾,可以節省填充率。

補充:

LUT(Look Up Table)指的是“顏色查詢表”,是原始顏色透過LUT的顏色查詢表對映到新的色彩上去。是單獨針對色彩空間的一種管理和轉換。

2。2。4 最佳化幀緩衝頻寬

管線的最後階段,

片元操作或光柵化操作,與幀緩衝儲存器直接銜接,是消耗幀緩衝頻寬的主要階段

。因此如果頻寬出了問題,經常會追蹤到光柵化操作。下面幾條技巧將講到如何最佳化幀緩衝頻寬。

首先渲染深度。

這個步驟不但減少片元著色的開銷,也會減少幀緩衝頻寬的消耗。

減少Alpha混合,儘量不要使用Alpha測試。

當alpha混合的目標混合因子非0時,則要求對幀緩衝區進行讀取和寫入操作,因此可能消耗雙倍的頻寬。所以只有在必要時才進行alpha混合,並且要防止高深度級別的alpha混合複雜性。

在移動平臺,渲染透明物體,Alpha混合性能比Alpha測試更好。

儘可能關閉深度寫入。

深度寫入會消耗額外的頻寬,應該在多通道的渲染中被禁用(且多通道渲染中的最終深度已經在深度緩衝區中了)。比如在渲染alpha混合效果(例如粒子)時,也比如將物體渲染進陰影對映時,都應該關閉深度寫入。另外,渲染進基於顏色的陰影對映也可以關閉深度讀取。

避免無關的顏色緩衝區清除。

如果每個畫素在緩衝區都要被重寫,那麼就不必清除顏色緩衝區,因為清除顏色緩衝區的操作會消耗昂貴的頻寬。但是,只要是可能就應該清除深度和模板緩衝區,這是因為許多早期z值最佳化都依賴被清空的深度緩衝區的內容。

預設大致上從前向後進行渲染。

除了上文提到的片元著色器會從預設大致上從前向後進行渲染這個方法中受益外,幀緩衝區頻寬也會得到類似的好處。早期z值硬體最佳化能去掉無關的幀緩衝區讀出和寫入。實際上,沒有最佳化功能的老硬體也會從此方法中受益。因為通不過深度測試的片元越多,需要寫入幀緩衝區的顏色和深度就越少。

最佳化天空盒的渲染。

天空盒經常是幀緩衝頻寬的瓶頸,因此必須決定如何對其進行最佳化,以下有兩種策略:

(1)最後渲染天空盒,讀取深度,但不寫入深度,而且允許和一般的深度緩衝一起進行早期early-z最佳化,以節省頻寬。(2)首先渲染天空盒,而且禁用所有深度讀取和寫入。

以上兩種策略,究竟哪一種會節省更多開銷,取決於目標硬體的功能和在最終幀中有多大部分的天空盒可見。如果大部分的天空盒被遮擋,那麼策略(1)更好,否則,策略(2)可以節省更多頻寬。

僅在必要時使用浮點幀緩衝區。

顯然,這種格式比起較小的整數格式來說,會消耗更多的頻寬,所以,能不用就不用。對多渲染目標( Multiple Render Targets,MRT)也同樣如此。

儘可能使用16位的深度緩衝區。

深度處理會消耗大量頻寬,因此使用16位代替32位是極有好處的,且16位對於小規模、不需要模板操作的室內場景往往就足夠了。對於需要深度的紋理效果,16位深度緩衝區也常常足夠渲染,如動態的立方體貼圖。

儘可能使用16位的顏色。

這個建議尤其適用於對紋理的渲染效果,因為這些工作的大多數,用16位的顏色能工作得很好,例如動態立方體貼圖和彩色投射陰影貼圖。

2。2。5 減少計算複雜度

(1)使用Shader的LOD技術

Shader的LOD技術可以控制使用的Shader等級。原理是隻有Shader的LOD值小於某個設定值,這個Shader才會被使用。在某些情況下,我們可能需要去掉一些使用複雜計算的Shader渲染。這時,我們可以使用Shader。maximumLOD或Shader。globalMaximumLOD來設定允許的最大LOD值。

(2)程式碼方面的最佳化

儘可能使用低精度的浮點值進行計算。

使用插值暫存器把資料從頂點著色器傳遞給下一個階段時,應該使用盡可能少的插值變數。

儘量不要使用全屏的屏幕後處理效果,如果真的需要使用,儘量使用低精度計算,高精度計算可以使用查詢表(LUT)或者轉移到頂點著色器中進行處理。

儘可能不要使用分支或迴圈語句。

儘可能避免使用類似sin、tan、pow、log等較為複雜的數學計算,請考慮使用查詢紋理(lookup texture, LUT)作為複雜數學計算的替代方法。

2。3 對記憶體的最佳化策略

節省記憶體頻寬

(1)減少紋理大小,考慮目標解析度和紋理座標,長寬值最好是2的整數冪。這樣很多最佳化策略才可以發揮最大效用。

(2)針對不同平臺,採用壓縮紋理來減少紋理大小,可以加快載入速度,減少記憶體佔用,顯著提高渲染效能。

在不同移動GPU平臺下選擇GPU支援的壓縮紋理,就可以在不需要CPU解壓的情況下直接被GPU取樣,節省CPU記憶體和頻寬,也可以節省儲存的體積。如果目標平臺不支援設定的壓縮格式,紋理將解壓為RGBA32或者RGB24,浪費CPU時間和記憶體。

(3)利用Mip Maps,始終為3D場景中使用的紋理啟用Mip Maps。但此規則例外的是:UI元素或2D遊戲中,不要使用。

Mip Maps(多級漸遠紋理),根據攝像機遠近不同而生成對應的八個貼圖,執行會載入到記憶體中。遠離相機時,使用較模糊的紋理。使用Mip maps需要使用33%以上的記憶體,但不使用它會導致巨大的效能損失。

優點:最佳化視訊記憶體頻寬,用來減少渲染。因為可以根據距離攝像機遠近,選擇適合的貼圖來渲染。

利用Mip maps,對處理鋸齒和閃爍的很有用。

(3)對於特定機型進行解析度縮放,Screen.SetResolution,過高的螢幕解析度是造成效能下降的原因之一,尤其對於很多低端手機。

根據不同的硬體平臺,設定不同的配置,控制特效顯示,解析度大小設定等等。