Приложение Vulkan должно управлять шейдерами иначе, чем приложение OpenGL ES: в OpenGL ES вы предоставляете шейдер в виде набора строк, образующих исходный текст программы шейдера GLSL. Напротив, API Vulkan требует от вас предоставления шейдера в виде точки входа в модуль SPIR-V .
Версия NDK 12 и более поздние версии включают библиотеку времени выполнения для компиляции GLSL в SPIR-V. Библиотека времени выполнения такая же, как в проекте с открытым исходным кодом Shaderc , и использует тот же эталонный компилятор Glslang GLSL в качестве внутренней части. По умолчанию версия компилятора Shaderc предполагает, что вы компилируете для Vulkan. После проверки корректности вашего кода для Vulkan компилятор автоматически включает расширение KHR_vulkan_glsl . Версия компилятора Shaderc также генерирует код SPIR-V, совместимый с Vulkan.
Вы можете скомпилировать модули SPIR-V в свое приложение Vulkan во время разработки. Эта практика называется предварительной компиляцией или AOT . Кроме того, вы можете заставить свое приложение скомпилировать их из поставляемого или процедурно созданного источника шейдеров, когда это необходимо во время выполнения. Эта практика называется компиляцией во время выполнения . В Android Studio встроена поддержка создания шейдеров Vulkan.
Остальная часть этой страницы содержит более подробную информацию о каждом методе, а затем объясняет, как интегрировать компиляцию шейдеров в ваше приложение Vulkan.
AOT-компиляция
Существует два способа добиться AOT-компиляции шейдера, описанные в следующих разделах.
Используйте Android-студию
Поместив шейдеры в app/src/main/shaders/ , Android Studio распознает шейдеры по расширениям файлов и выполнит следующие действия:
- Рекурсивно скомпилируйте все файлы шейдеров в этом каталоге.
- Добавьте суффикс .spv к скомпилированным файлам шейдеров SPIR-V.
- Упакуйте SPIRV-шейдеры в каталог
assets/shaders/APK.
Приложение будет загружать скомпилированные шейдеры из соответствующих assets/shaders/ расположения во время выполнения; скомпилированная файловая структура шейдера spv такая же, как файловая структура шейдера GLSL приложения в app/src/main/shaders/ :
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);
Флаги компиляции Shaderc можно настроить внутри блока shaders gradle DSL, как показано в следующем примере:
классный
android {
defaultConfig {
shaders {
glslcArgs.addAll(['-c', '-g'])
scopedArgs.create('lights') {
glslcArgs.addAll(['-DLIGHT1=1', '-DLIGHT2=0'])
}
}
}
}Котлин
android {
defaultConfig {
shaders {
glslcArgs += listOf("-c", "-g")
glslcScopedArgs("lights", "-DLIGHT1=1", "-DLIGHT2=0")
}
}
}
glslcArgs применяется ко всем компиляциям шейдеров; scopedArgs применяется только при компиляции для этой области. В приведенном выше примере создается аргумент области lights , который будет применяться только к шейдерам GLSL в каталоге app/src/main/shaders/lights/ . Обратитесь к glslc для получения полного списка доступных флагов компиляции. Обратите внимание, что Shaderc внутри NDK — это снимок из репозитория GitHub во время выпуска NDK; вы можете получить точные поддерживаемые флаги для этой версии с помощью команды glslc --help , как описано в следующем разделе.
Автономная компиляция из командной строки
Шейдеры GLSL можно скомпилировать в SPIR-V независимо от основного приложения с помощью компилятора командной строки glslc . Версия NDK 12 и более поздние версии содержат версию предварительно созданного glslc и связанных с ним инструментов в каталоге <android-ndk-dir>/shader-tools/ для поддержки этой модели использования.
Компилятор также доступен в проекте Shaderc ; следуйте инструкциям, чтобы создать двоичную версию.
glslc предоставляет богатый набор параметров командной строки для компиляции шейдеров, отвечающих различным требованиям приложения.
Инструмент glslc компилирует файл с одним исходным кодом в модуль SPIR-V с одной точкой входа в шейдер. По умолчанию выходной файл имеет то же имя, что и исходный файл, но с добавленным расширением .spv .
Вы используете расширения имен файлов, чтобы сообщить инструменту glslc, какой этап графического шейдера компилировать или компилируется ли вычислительный шейдер. Информацию о том, как использовать эти расширения имен файлов и параметры, которые можно использовать с этим инструментом, см. в разделе Спецификация этапа шейдера в руководстве glslc .
Компиляция времени выполнения
Для JIT-компиляции шейдеров во время выполнения NDK предоставляет библиотеку libshaderc, которая имеет API C и C++.
Приложения C++ должны использовать API C++. Мы рекомендуем приложениям на других языках использовать API C, поскольку C ABI находится на более низком уровне и, вероятно, обеспечит лучшую стабильность.
В следующем примере показано, как использовать API C++:
#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;
}
Интегрируйте в свои проекты
Вы можете интегрировать компилятор шейдеров Vulkan в свое приложение, используя файл Android.mk проекта или Gradle.
Android.mk
Выполните следующие шаги, чтобы использовать файл Android.mk вашего проекта для интеграции компилятора шейдеров.
- Включите следующие строки в файл Android.mk:
include $(CLEAR_VARS) ... LOCAL_STATIC_LIBRARIES := shaderc ... include $(BUILD_SHARED_LIBRARY) $(call import-module, third_party/shaderc) - Установите для APP_STL одно из
c++_static,c++_shared,gnustl_staticилиgnustl_sharedв Application.mk приложения.
Интеграция Gradle с CMake
- В окне терминала перейдите к
ndk_root/sources/third_party/shaderc/. - Запустите следующую команду, чтобы собрать Shaderc NDK. Вам нужно запустить эту команду только один раз для каждой используемой вами версии 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, как вы обычно делаете для подобных внешних библиотек . Тип STL вашего приложения должен соответствовать одному из типовstl, указанных вstl_version. NDK рекомендует использоватьc++_sharedилиc++_static, хотяgnustl_staticиgnustl_sharedтакже поддерживаются.
Получите последнюю версию Shaderc
Shaderc в NDK берется из дерева исходного кода Android , которое представляет собой снимок исходного репозитория Shaderc . Если вам нужна последняя версия Shaderc, подробности см. в инструкции по сборке . Шаги высокого уровня заключаются в следующем:
- Загрузите последнюю версию Shaderc:
git clone https://github.com/google/shaderc.git
- Обновить зависимости:
./utils/git-sync-deps
- Сборка шейдерка:
<ndk_dir>/ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk \ APP_STL:=c++_static APP_ABI=all libshaderc_combined -j16 - Настройте свой проект для использования собственной сборки Shaderc в файле сценария сборки.