Vulkan 應用程式管理著色器的方式必須與 OpenGL ES 應用程式不同:OpenGL ES 著色器是構成 GLSL 著色器程式來源文字的一組字串。相反地,Vulkan API 則要求著色器的形式為 SPIR-V 模組中的進入點。
NDK 12 以上版本包含將 GLSL 編譯至 SPIR-V 的執行階段程式庫。這個執行階段程式庫與 Shaderc 開放原始碼專案中的相同,並使用相同的 Glslang GLSL 參照編譯器做為後端。根據預設,Shaderc 版本的編譯器會假設您是進行 Vulkan 編譯作業。檢查程式碼是否適用 Vulkan 後,編譯器就會自動啟用 KHR_vulkan_glsl
擴充功能。Shaderc 版本的編譯器還會產生與 Vulkan 相容的 SPIR-V 程式碼。
您可以選擇在開發過程中將 SPIR-V 模組編譯至 Vulkan 應用程式,這種做法稱為「預先」(即 AOT) 編譯。或者,也可以讓應用程式在執行階段期間視需要編譯這些模組,來源為搭載的著色器或程序產生的著色器。這種做法稱為「執行階段編譯」。 Android Studio 已整合支援功能,可以建構 Vulkan 著色器。
本頁的其他部分將詳細介紹各項做法,並說明如何將著色器編譯項目整合至 Vulkan 應用程式。
AOT 編譯
如以下各節所述,您可以透過兩種方法進行著色器 AOT 編譯。
使用 Android Studio
將著色器放入 app/src/main/shaders/
後,Android Studio 會依副檔名辨識著色器,並完成以下操作:
- 在該目錄下週期性編譯所有著色器檔案。
- 將 .spv 後置字串附加到已編譯的 SPIR-V 著色器檔案。
- 將 SPIRV 著色器封裝至 APK 的
assets/shaders/
目錄。
應用程式執行時會從對應的 assets/shaders/
位置載入已編譯的著色器;已編譯的 spv 著色器檔案結構,與 app/src/main/shaders/
底下應用程式的 GLSL 著色器檔案結構相同:
AAsset* file = AAssetManager_open(assetManager, "shaders/tri.vert.spv", AASSET_MODE_BUFFER); size_t fileLength = AAsset_getLength(file); char* fileContent = new char[fileLength]; AAsset_read(file, fileContent, fileLength);
您可以在 Gradle DSL shaders
區塊中設定 Shaderc 編譯標記,如以下範例所示:
Groovy
android { defaultConfig { shaders { glslcArgs.addAll(['-c', '-g']) scopedArgs.create('lights') { glslcArgs.addAll(['-DLIGHT1=1', '-DLIGHT2=0']) } } } }
Kotlin
android { defaultConfig { shaders { glslcArgs += listOf("-c", "-g") glslcScopedArgs("lights", "-DLIGHT1=1", "-DLIGHT2=0") } } }
glslcArgs
適用於所有著色器編譯;scopedArgs
僅適用於該範圍的編譯作業。上述範例建立的範圍引數 lights
僅適用於 app/src/main/shaders/lights/
目錄下的 GLSL 著色器。如需可用編譯標記的完整清單,請參閱 glslc。請注意,NDK 中的 Shaderc 是 NDK 發布時該 GitHub 存放區中的快照;您可以使用 glslc --help
指令取得對應版本支援的確切標記,詳情請見下一節。
離線指令列編譯
您可以使用 glslc 指令列編譯器,將 GLSL 著色器編譯成不受主要應用程式影響的 SPIR-V。NDK 12 以上版本會將某個版本的預建 glslc 和相關工具封裝至 <android-ndk-dir>/shader-tools/
目錄,以便支援這種使用模式。
您也可以從 Shaderc 專案取得編譯器,請按照相關操作說明建構二進位檔版本。
glslc 為著色器編譯提供了豐富的指令列選項,能夠滿足應用程式的各種需求。
glslc 工具可將單一來源檔案編譯成包含單一著色器進入點的 SPIR-V 模組。根據預設,輸出檔案的名稱與來源檔案的名稱相同,但附加了 .spv
副檔名。
您可以使用檔案名稱副檔名來告知 glslc 工具要編譯的圖形著色器階段,或者指示是否正在編譯某個運算著色器。如要瞭解如何使用這些檔案名稱副檔名,以及這項工具的運用方式,請參閱 glslc 手冊中的著色器階段規格。
執行階段編譯
針對執行階段期間著色器的 JIT 編譯,NDK 提供同時包含 C 和 C++ API 的 Libshaderc 程式庫。
C++ 應用程式應使用 C++ API。我們建議以其他語言編寫的應用程式採用 C API,因為 C ABI 級別較低,穩定性可能更佳。
以下範例說明了如何使用 C++ API:
#include <iostream> #include <string> #include <vector> #include <shaderc/shaderc.hpp> std::vector<uint32_t> compile_file(const std::string& name, shaderc_shader_kind kind, const std::string& data) { shaderc::Compiler compiler; shaderc::CompileOptions options; // Like -DMY_DEFINE=1 options.AddMacroDefinition("MY_DEFINE", "1"); shaderc::SpvCompilationResult module = compiler.CompileGlslToSpv( data.c_str(), data.size(), kind, name.c_str(), options); if (module.GetCompilationStatus() != shaderc_compilation_status_success) { std::cerr << module.GetErrorMessage(); } std::vector<uint32_t> result(module.cbegin(), module.cend()); return result; }
整合至專案
您可以使用專案的 Android.mk
檔案或 Gradle,將 Vulkan 著色器編譯器整合至應用程式。
Android.mk
請執行下列步驟,使用專案的 Android.mk
檔案來整合著色器編譯器。
-
在 Android.mk 檔案中加入下列這幾行程式碼:
include $(CLEAR_VARS) ... LOCAL_STATIC_LIBRARIES := shaderc ... include $(BUILD_SHARED_LIBRARY) $(call import-module, third_party/shaderc)
-
在應用程式的 Application.mk 中,將 APP_STL 設為
c++_static
、c++_shared
、gnustl_static
或gnustl_shared
的之一
Gradle 的 CMake 整合
-
在終端機視窗中,前往
ndk_root/sources/third_party/shaderc/
。 -
執行下列指令來建構 NDK 的 Shaderc。在您使用的每個 NDK 版本中,只需執行這個指令一次:
$ ../../../ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk \ APP_STL:=<stl_version> APP_ABI=all libshaderc_combined
這個指令會將兩個資料夾置於 <ndk_root>/sources/third_party/shaderc/。目錄結構如下:
include/ shaderc/ shaderc.h shaderc.hpp libs/ <stl_version>/ {all of the abis} libshaderc.a
-
按照您平常對類似外部程式庫執行的動作,使用
target_include_directories
和target_link_libraries
新增產生的 include 和 lib。 應用程式的 STL 類型必須與stl_version
中指定的其中一個stl
類型相符。NDK 建議使用c++_shared
或c++_static
,但也支援gnustl_static
和gnustl_shared
。
取得最新版 Shaderc
NDK 中的 Shaderc 來自 Android 來源樹狀結構,它是上游 Shaderc 存放區的快照。 如需最新版 Shaderc,請參閱建構操作說明瞭解詳情。 大致步驟如下:
- 下載最新版 Shaderc:
git clone https://github.com/google/shaderc.git
- 更新依附元件:
./utils/git-sync-deps
- 建構 Shaderc:
<ndk_dir>/ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk \ APP_STL:=c++_static APP_ABI=all libshaderc_combined -j16
- 設定專案,在建構指令碼檔案中使用自己的 Shaderc 版本。