Приложение 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 в файле сценария сборки.