總覽
Godot Engine 是一款熱門的多平台開放原始碼遊戲引擎,可提供完善的 Android 支援。Godot 可用於製作幾乎所有類型的遊戲,且支援 2D 和 3D 圖形。Godot 4 版推出了新的算繪系統,內含高保真度圖形的進階功能。Godot 4 轉譯器專為 Vulkan 等新型圖形 API 而設計。
Godot Foundation 聘請 The Forge Interactive 的圖像最佳化專家,並與 Google 合作,分析並進一步改善 Godot 4 Vulkan 轉譯器,並將這些最佳化結果合併回專案存放區。這些最佳化功能可協助開發人員改善 Android 上的自訂 Vulkan 轉譯器。
最佳化方法和結果
最佳化程序使用 Godot 中的兩個不同的 3D 場景做為基準測試目標。在每次最佳化迴圈中,我們會在多部裝置上測量場景的算繪時間。為了符合納入資格,您必須至少在部分測試裝置上顯示轉譯器的效能改善情形,且不得在任何裝置上引入效能回退。
測試中使用了多種熱門的 Android GPU 架構。雖然許多最佳化作業可帶來一般改善效果,但某些最佳化作業對特定 GPU 架構的影響更大。所有最佳化工作的總和,可讓 GPU 影格時間一般減少 10% 至 20%。
一般 Vulkan 最佳化
Forge 在 Godot Vulkan 算繪後端上執行一般架構重構作業,以改善效能,並因應內容算繪需求增加,協助後端擴大規模。這些最佳化功能並非專為行動硬體設計,而是適用於所有 Godot Vulkan 平台。
支援動態 UBO 偏移
繫結包含動態統一緩衝區物件 (UBO) 的描述元集時,Vulkan 會允許在繫結參數中指定 UBO 的動態偏移量。這項功能可用於將多個轉譯作業的資料封裝至單一 UBO,並使用不同的動態偏移重新繫結描述元集,以便為著色器選取適當的資料。Godot Vulkan 轉譯器已更新,可使用動態偏移,而非一律將偏移初始化為零。這項改善可讓我們日後進行效率最佳化。
線性描述元集池
先前,Godot Vulkan 轉譯器的預設行為是使用 VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT
標記建立所有描述符集區,這表示描述符集區的配置可以釋回至集區,並從集區進行重新配置。與僅允許線性配置,然後完全重設集區的描述元組集集區相比,這個模式會額外增加額外負擔。
在可行情況下,描述元集集區現在會以線性集區的形式建立,而不需要設定 VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT
。在需要時,線性資源池會整體重設。這項工作還包括在可行情況下,對批次描述詞集繫結進行額外最佳化,以減少對 vkCmdBindDescriptorSets()
的獨立呼叫次數。
支援不可變動的取樣器
含有取樣設定資料的取樣器物件,通常會綁定為描述元組合資料的一部分。這個方法可讓取樣器物件在描述元組合資料中動態交換。Vulkan 也支援不可變動的取樣器,可將取樣器資料直接編碼至描述元組合版面配置。此取樣器設定會在建立描述元組合和管道狀態時繫結,且無法在建立後變更。
不可變動的取樣器會犧牲彈性,因為您不再需要管理及繫結不連續的取樣器物件。Godot Vulkan 轉譯器已更新,以便支援使用不可變動的取樣器;取樣器用法已變更為在可行情況下使用不可變動的取樣器。
以行動裝置為主軸的最佳化
我們也實作了其他最佳化功能,專門改善行動圖像硬體的算繪效能。由於架構設計不同,這些最佳化措施通常與桌上型電腦級圖形硬體無關。
這些最佳化措施包括:
- 取代大型推送常數的使用
- 延遲緩衝區分配
- 支援持久緩衝區
- ASTC 解碼模式變更
- 螢幕預先旋轉
取代大型推送常數的使用
推送常數是一項功能,可讓您將有效著色器程式的常數值注入指令緩衝區。推送常數很方便,因為不需要建立和填入緩衝區,也不會與描述符繫結。不過,推送常數的最大大小有限,可能會對行動硬體的效能造成負面影響。
在 Android 裝置上進行測試時,我們使用統一緩衝區取代超過 16 個位元組的推送常數用量,藉此提升效能。使用 16 個位元組或更少常數資料的著色器,在使用推送常數時效能更佳。除了效能考量外,某些圖形硬體的統一緩衝區至少有 64 個位元組的對齊方式,這會導致記憶體效率降低,因為與使用推送常數相比,未使用的填充會造成記憶體效率降低。
延遲緩衝區分配
大多數行動圖形硬體都使用以區塊為基礎的延遲算繪 (TBDR) 架構。使用 TBDR 的 GPU 會將較大的螢幕區域分割成較小圖塊的格狀區塊,並依個別圖塊進行算繪。每個圖塊都會備有少量高速 RAM,供 GPU 在轉譯圖塊時使用。有了 TBDR,在渲染通道以外的其他目標從未對渲染目標進行取樣的情況下,渲染目標就能有效地完全保留在平鋪 RAM 中,且不需要主記憶體備援儲存空間的緩衝區。
VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT
是在建立適當的轉譯目標 (例如主要顏色和深度目標) 時新增,以免分配從未使用的緩衝區記憶體。在測試中,在範例場景中使用延後配置記憶體的節省量高達約 50 MB 的 RAM。
支援持久緩衝區
行動硬體使用統一記憶體架構 (UMA),而非在主 RAM 和圖形 RAM 之間進行硬體區分。當主 RAM 和圖形 RAM 分開時,資料必須從主 RAM 轉移至圖形 RAM,才能供 GPU 使用。Godot 已透過使用暫存緩衝區,在其 Vulkan 轉譯器中實作這項轉移程序。在 UMA 硬體上,許多類型的資料都不需要暫存緩衝區;CPU 和 GPU 都可以使用記憶體。Forge 已在支援的硬體上實作持續性共用緩衝區支援功能,以盡可能消除階段作業。
ASTC 解碼模式變更
自動調整可擴充紋理壓縮 (ASTC) 是行動裝置硬體上偏好的現代紋理壓縮格式。在解壓縮期間,GPU 可能會將像素解碼為中間值,而中間值的精確度會高於視覺保真度所需的精確度,導致紋理效率降低。如果目標硬體支援,則在解碼時會使用 VK_EXT_astc_decode_mode
擴充功能,指定每個元件的 8 位元未規格化值,而非 16 位元浮點值。
螢幕預先旋轉
為了在 Android 上使用 Vulkan 時享有最佳效能,遊戲必須將螢幕的裝置方向與算繪介面方向調和。這項程序稱為預旋轉。如果未執行預先旋轉,Android OS 就必須新增合成器通道,以便手動旋轉圖片,因此可能會導致效能降低。在 Godot 轉譯器中新增 Android 上的預旋轉支援功能。
偵錯功能改善
除了進行效能最佳化,The Forge 也改善了 Godot 轉譯器中圖形問題的偵錯體驗,新增了以下功能:
- 裝置故障擴充功能
- 導覽標記
- 偵錯標記
裝置故障擴充功能
如果 GPU 在算繪作業期間遇到問題,Vulkan 驅動程式可以從 Vulkan API 呼叫傳回 VK_ERROR_DEVICE_LOST
結果。根據預設,系統不會提供額外的背景資訊,說明為何驅動程式會傳回 VK_ERROR_DEVICE_LOST
。VK_EXT_device_fault
擴充功能提供機制,讓驅動程式提供錯誤性質的其他資訊。Godot 新增了支援功能,可啟用裝置錯誤擴充功能 (如有),並回報由驅動程式傳回的資訊。
導覽標記
偵錯 GPU 當機或執行停滯問題可能相當困難。為協助您找出在錯誤發生時可能已算繪的圖形內容,我們已在 Godot 算繪器中加入導覽標記支援功能。麵包屑是使用者定義的值,可附加至轉譯圖表中繪圖清單的內容。在開始新的轉譯通道之前,系統會先寫入麵包屑資料。如果發生當機或執行停滯情形,您可以使用目前的麵包屑值,判斷哪些資料可能導致問題。
偵錯標記
當驅動程式支援時,偵錯標記可用於命名資源。這樣一來,使用者就能在使用 RenderDoc 等圖像工具時,將可供使用者閱讀的字串與算繪通道等作業,以及緩衝區和紋理等資源建立關聯。已在 Godot Vulkan 轉譯器中新增偵錯標記註解支援功能。
其他連結
Godot Engine 網誌 - 與 Google 和 The Forge 合作的最新消息