Um app Vulkan precisa gerenciar sombreadores de forma diferente da que é usada por um app com OpenGL ES. No OpenGL ES, você fornece um sombreador como um conjunto de strings que formam o texto de origem de um programa de sombreador GLSL. Por outro lado, a API Vulkan exige que você forneça um sombreador na forma de um ponto de entrada em um módulo SPIR-V (link em inglês).
A versão 12 do NDK e versões mais recentes contém uma biblioteca de ambiente de execução para compilar GLSL em SPIR-V.
A biblioteca de ambiente de execução é a mesma que a presente no
projeto de código aberto Shaderc e usa o mesmo
compilador de referência Glslang GLSL como
back-end (links em inglês). Por padrão, a versão Shaderc do compilador considera que você está compilando para Vulkan. Depois de verificar se o código é válido para Vulkan, o compilador ativa a extensão KHR_vulkan_glsl
automaticamente. A versão Shaderc do compilador também gera código SPIR-V compatível com Vulkan.
É possível optar por compilar módulos SPIR-V no seu app Vulkan durante o desenvolvimento, uma prática chamada de compilação antecipada (AOT, na sigla em inglês). Ou você pode fazer o app compilá-los a partir da origem do sombreador enviada ou gerada de forma processual quando necessário durante o tempo de execução. Essa prática é chamada de compilação em tempo de execução. O Android Studio oferece compatibilidade integrada com a criação de sombreadores Vulkan.
O restante desta página fornece mais detalhes sobre cada prática e explica como integrar a compilação de sombreador ao app Vulkan.
Compilação AOT
Há duas formas de fazer a compilação AOT de sombreador, que são descritas nas seções a seguir.
Usar o Android Studio
Ao colocar sombreadores em app/src/main/shaders/
, o Android Studio os reconhece pelas
extensões de arquivo deles e realiza as seguintes ações:
- Compila todos os arquivos de sombreador recursivamente nesse diretório.
- Anexar o sufixo .spv aos arquivos de sombreador SPIR-V compilados.
- Empacotar os sombreadores SPIRV no diretório
assets/shaders/
do APK.
O app carregaria os sombreadores compilados do local assets/shaders/
correspondente no momento da execução. A estrutura do arquivo de sombreador spv compilado é a mesma que a do arquivo de sombreador GLSL do app em 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);
As sinalizações de compilação do Shaderc podem ser configuradas dentro do bloco shaders
da DSL do gradle, conforme mostrado no exemplo a seguir:
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
se aplica a todas as compilações de sombreador. scopedArgs
se aplica somente ao compilar
para esse escopo. O exemplo acima cria um argumento de escopo lights
, que só se aplica a sombreadores GLSL do diretório app/src/main/shaders/lights/
. Consulte o glslc (link em inglês) para ver a lista completa de sinalizações de compilação disponíveis. O Shaderc no NDK é um instantâneo desse repositório do GitHub no
momento do lançamento do NDK. É possível ver as sinalizações exatas compatíveis com essa versão usando o comando
glslc --help
, conforme descrito na próxima seção.
Compilação off-line na linha de comando
Os sombreadores GLSL podem ser compilados para SPIR-V de forma independente do app principal, usando o compilador da linha de comando glslc. As versões 12 e mais recentes do NDK empacotam uma versão do glslc pré-compilada
e ferramentas relacionadas no diretório <android-ndk-dir>/shader-tools/
para oferecer compatibilidade com o uso desse modelo.
O compilador também está disponível no projeto Shaderc. Siga as instruções dele para criar uma versão binária.
O glslc fornece um conjunto vasto de opções da linha de comando (link em inglês) para compilação de sombreador de modo a atender diversos requisitos para um app.
A ferramenta glslc compila um arquivo de origem única para um módulo SPIR-V com um único ponto de entrada de sombreador. Por padrão, o arquivo de saída tem o mesmo nome do arquivo de origem,
mas com a extensão .spv
anexada.
Use as extensões de nome de arquivo para informar à ferramenta glslc qual estágio de sombreador gráfico será compilado ou se o sombreador de computação está sendo compilado. Para saber mais sobre como usar essas extensões de nome de arquivo e as opções que podem ser usadas com a ferramenta, consulte Especificação do estágio do sombreador no manual do glslc (links em inglês).
Compilação em tempo de execução
Para a compilação JIT de sombreadores no tempo de execução, o NDK oferece a biblioteca libshaderc, que tem APIs C e C++.
Os aplicativos em C++ precisam usar a API C++. Recomendamos que os aplicativos em outras linguagens usem a API C, porque ela tem nível inferior e provavelmente fornecerá mais estabilidade.
O exemplo a seguir mostra como usar a 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; }
Integrar aos seus projetos
Para integrar o compilador de sombreadores Vulkan ao seu app, use o arquivo Android.mk
do projeto ou o Gradle.
Android.mk
Siga as etapas abaixo para usar o arquivo Android.mk
do projeto e integrar o compilador de sombreador.
-
Inclua as seguintes linhas no arquivo Android.mk:
include $(CLEAR_VARS) ... LOCAL_STATIC_LIBRARIES := shaderc ... include $(BUILD_SHARED_LIBRARY) $(call import-module, third_party/shaderc)
-
Defina APP_STL como
c++_static
,c++_shared
,gnustl_static
ougnustl_shared
no arquivo Application.mk do app.
Integração CMake do Gradle
-
Em uma janela do terminal, acesse
ndk_root/sources/third_party/shaderc/
. -
Execute o comando a seguir para criar o Shaderc do NDK. Você só precisa executar este comando uma vez em cada versão do NDK usada:
$ ../../../ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk \ APP_STL:=<stl_version> APP_ABI=all libshaderc_combined
Esse comando coloca duas pastas em <ndk_root>/sources/third_party/shaderc/. A estrutura do diretório é a seguinte:
include/ shaderc/ shaderc.h shaderc.hpp libs/ <stl_version>/ {all of the abis} libshaderc.a
-
Adicione includes e libs geradas usando
target_include_directories
etarget_link_libraries
, como normalmente é feito com bibliotecas externas semelhantes (links em inglês). O tipo de STL do seu app precisa corresponder a um dos tipos destl
especificados emstl_version
. O NDK recomenda o uso dec++_shared
ouc++_static
, emboragnustl_static
egnustl_shared
também sejam compatíveis.
Fazer o download do Shaderc mais recente
O Shaderc no NDK vem da árvore de origem do Android, que é um instantâneo do repositório Shaderc ascendente (links em inglês). Se você precisar do Shaderc mais recente, consulte instrução de compilação (link em inglês) para ver detalhes. As etapas gerais são as seguintes:
- Fazer o download do Shaderc mais recente:
git clone https://github.com/google/shaderc.git
- Atualizar dependências:
./utils/git-sync-deps
- Compilar o Shaderc:
<ndk_dir>/ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk \ APP_STL:=c++_static APP_ABI=all libshaderc_combined -j16
- Configurar seu projeto para usar o próprio build do Shaderc no arquivo de script de compilação.