本文說明如何使用工具找出並解決 CPU 和 GPU 瓶頸,進而提升遊戲效能。
CPU 最佳化
如果分析結果顯示遊戲受 CPU 限制,請務必進一步調查。 這需要找出造成瓶頸並降低 FPS 的特定執行緒或 API。
一般來說,通用解決方案無法有效最佳化 CPU。而是必須根據遊戲或場景找出最耗資源的工作負載,然後最佳化相關邏輯和函式。
遊戲引擎時間追蹤工具
下列工具可協助進行這項分析:
Unreal 洞察
在 Unreal Engine 專案中,Unreal Insight Tool 可協助分析構成影格的個別執行緒時間追蹤資訊。
舉例來說,GameThread 通常會佔用最大比例的 CPU 時間,主要歸因於 Tick Time。此外,與 FActorComponentTickFunction 相關聯的工作會耗用大量 Tick Time。
如要最佳化 FActorComponentTick,請務必排除計算,並針對位於攝影機視野外的字元和物件實作裁剪。此外,運用 LOD (詳細程度) 型動畫,可進一步提升效能。
Unity Profiler (Unity)
使用 Unity Profiler 進行分析後,發現主執行緒耗用超過 45 毫秒,其中 PostLateUpdate.FinishFrameRendering 佔用 16.23 毫秒,是耗時最長的作業。其中會觀察到多次呼叫 Inl_RenderCameraStack。建議您確認已啟用攝影機的必要性,並據此進行最佳化。
系統層級剖析工具
請使用下列剖析工具:
Perfetto
使用 Perfetto 追蹤記錄,您可以判斷 Android 裝置上每個執行緒的 CPU 核心指派情形和執行詳細資料。您可以分析執行緒執行資料,找出效能瓶頸。
CPU 負荷案例
追蹤記錄指出,GameThread 和 RenderThread 的工作負載會導致 RHI Thread 的 QueuePresent 延遲,進而根據 VSync 造成 CPU 繫結情境。
GPU 負荷過高案例
追蹤記錄指出 GPU 完成時間超過 25 毫秒,這表示是受 GPU 限制的情況。
Simpleperf
如要找出目前 CPU 使用率最高的函式,可以使用 simpleperf。為獲得最佳成效,建議您將這些函式排序,優先處理使用率最高的函式。
Simpleperf 可協助您檢查使用最多 CPU 時間的函式資料。如要最佳化 CPU 使用率,請先從使用最多 CPU 的函式著手。在這個範例中,與動畫相關聯的 USkeletalMeshComponent 使用最多 CPU。ActorComponentTickFunctions
GPU 最佳化
如果分析結果顯示遊戲受到 GPU 限制,就必須進一步調查。這需要使用各種工具和技術,才能最佳化及分析 GPU。
如要最佳化 GPU,請使用影格偵錯工具分析每個場景的轉譯管道和繪圖呼叫。此外,您必須徹底瞭解 GPU 架構和管道行為,才能找出不必要的操作或可最佳化的區域。
以下各節說明 GPU 最佳化的方法和工具。
排除不必要的 RenderPass
為提升轉譯效能並減少 GPU 工作負載,請移除不必要的轉譯通道。包括缺少繪圖呼叫的任何算繪通道,或輸出內容未用於最終影格的通道。
使用 RenderDoc 等 GPU 偵錯工具分析轉譯管道,找出最佳化機會。
沒有繪圖呼叫:檢查算繪通道是否包含任何繪圖呼叫。如果沒有繪製呼叫,請移除憑證。
未使用的輸出內容:檢查後續傳遞是否會存取或顯示算繪傳遞輸出內容,例如顏色或深度。如果沒有,請移除票證。
可合併的票證:找出可合併的票證:
- 相同的 Framebuffer 或附件
- 相容的載入或儲存作業
- 中間沒有依附元件障礙
減少負載或商店作業
載入或儲存作業會使用大量記憶體,因此耗用大量資源。盡量減少不必要的載入/儲存作業。只有在需要 RenderPass 中的附件時,才執行這些動作。否則,請將這些作業替換為 Clear 或 Don't care,以減少負擔。
如何最佳化
使用 RenderDoc 等 GPU 偵錯工具分析轉譯管道,並找出下列最佳化商機:
載入:如果算繪通道附件未採用前一個通道或附件的資料,就不需要載入作業。在這種情況下,使用
Don't care或Clear可減少負擔。儲存:如果目前的算繪通道之後不會使用算繪通道附件,就不需要執行儲存作業。在這種情況下,請使用
Don't care或Clear。取代:判斷目前的載入或儲存設定是否可由
Clear或Don't Care取代,而不影響最終影格。
避免捨棄以啟用 Early-Z
Early-Z 可提升行動平台上的效能。不過,著色器中的 discard
指令會自動停用 Early-Z。如果discard
指令並非必要,請移除。
Early-Z 加速
這項最佳化作業可大幅減少片段著色器作業,並提升 GPU 效能。
如何最佳化
使用 RenderDoc 等 GPU 偵錯工具分析轉譯管道,並找出下列最佳化商機:
在片段著色器中使用
discard:discard關鍵字可防止 GPU 執行早期深度測試,因為系統無法預先得知片段的可見度。修改
gl_FragDepth:動態修改gl_FragDepth會變更片段的深度,導致 Early-Z 最佳化功能停用,因為在處理片段前,系統無法得知最終深度。啟用 Alpha 值到涵蓋範圍:啟用 Alpha 值到涵蓋範圍 (通常用於 MSAA 算繪) 時,片段涵蓋範圍取決於 Alpha 值。這可能會延遲深度測試,並停用 Early-Z。
最佳化紋理格式
選擇最佳紋理格式可減少記憶體用量、提升頻寬效率,並改善算繪效能。採用過於高精確度的格式可能會浪費 GPU 資源,但不會提供視覺優勢。
如何最佳化
使用 RenderDoc 等 GPU 偵錯工具分析轉譯管道,並找出下列最佳化商機:
- 使用
D24S8取代深度樣板緩衝區的D32S8:與D32S8相比,使用深度樣板緩衝區的D24S8可減少 20% 的記憶體消耗量,且大多數應用程式的視覺品質幾乎沒有明顯差異。 - 對彩色紋理使用
ASTC壓縮:與未壓縮格式相比,ASTC壓縮可大幅減少紋理記憶體用量,最多可減少 8 倍,同時維持高視覺品質。 - 改用半浮點格式,而非全浮點格式:使用
R16F或RG16F減少記憶體頻寬和儲存空間用量。這些格式很適合用於後續處理緩衝區。
最佳化幾何圖形複雜度
盡量減少幾何複雜度,可提升算繪效能,特別是 GPU 功能受限的行動裝置。這包括使用較少的頂點和三角形、合併物件以減少繪圖呼叫,以及消除未算繪或不必要的幾何圖形。網格簡化、詳細程度 (LOD) 和視錐體或遮蔽剔除等技術,可大幅降低 GPU 工作負載並提高影格速率。
如何最佳化
使用剖析工具和 GPU 偵錯工具 (例如 RenderDoc、Android GPU 檢查器或其他效能分析器),找出與幾何相關的效能瓶頸。
減少三角形數量:盡量減少多邊形的使用量,尤其是小型或遠處的物件。
使用細節層級 (LOD):系統會根據攝影機的距離,自動使用較簡單的網格。
合併小型網格:整合靜態物件,減少繪圖呼叫和 CPU 負荷。
視錐體和遮蔽剔除:避免算繪視角外的物件,或遭其他元素遮蔽的物件。
移除不必要的附件
即使未使用,算繪通道附件 (例如顏色、深度、模板) 仍會耗用記憶體頻寬和 GPU 資源。移除不必要或重複的附件可提升效能並降低耗電量,尤其是在行動平台。
如何最佳化
使用剖析工具和 GPU 偵錯工具 (例如 RenderDoc、Android GPU Inspector 或其他效能分析器),找出與幾何相關的效能瓶頸。
- 檢查實際用量:是否有任何繪圖呼叫或著色器正在寫入或讀取附件?
- 分析影格輸出內容:使用
RenderDoc或類似公用程式,判斷附件是否會影響最終圖片。 - 考慮使用暫時性或虛擬附件:對於不需要永久儲存的暫時性資料,應使用暫時性附件或「Don't Care」儲存作業。
最佳化著色器精確度
在著色器中使用過高的精確度 (例如 highp 而不是 mediump 或 lowp),會增加 GPU 工作負載、耗電量和暫存器壓力,尤其是在行動 GPU 上。為變數 (例如位置、顏色、UV) 使用最低的適當精確度,即可提升效能,且不會對視覺效果造成明顯影響。
如何最佳化
使用剖析工具和 GPU 偵錯工具 (例如 RenderDoc、Android GPU 檢查器或其他效能分析器),找出與幾何相關的效能瓶頸。
檢查著色器程式碼:評估著色器變數,確認只有在必要時才使用高精確度,例如深度或螢幕空間計算。對於不需要高精度的顏色、UV 座標或值,請使用中或低精度。
使用 GPU 偵錯工具:診斷公用程式 (例如 RenderDoc 或行動 GPU 分析器,如 AGI、Mali/GPU 檢查器) 可找出與精確度問題相關的暫存器使用量偏高或著色器停滯情形。
啟用背面剔除
對於實心物件,通常不需要轉譯背對相機的三角形 (背面)。
如何最佳化
使用 VK_CULL_MODE_NONE 可能會對效能造成負面影響,因為這會強制 GPU 算繪正面和背面,進而增加算繪工作負載。
盡量減少 UI 場景中的過度繪製
消除不必要的繪圖呼叫和算繪傳遞,特別是在 UI 場景中,以提升算繪效能並減少 GPU 工作負載。舉例來說,在 UI 場景中,整個世界會在 UI 疊加在畫面上之前算繪,因此算繪世界會變得多餘。
如何最佳化
使用 RenderDoc 等 GPU 偵錯工具分析轉譯管道,並找出下列最佳化商機:
- 確認沒有多餘的過度繪製。在使用者介面環境中,整個畫面可能會算繪,請確認先前的算繪通道不會不必要地過度繪製。
- 啟用深度測試和剔除功能,盡可能提升效能。
- 請考慮從前到後算繪順序。