Migrar do RenderScript

As APIs do RenderScript foram suspensas desde o Android 12. Elas continuarão funcionando, mas esperamos que os fabricantes de dispositivos e componentes parem de oferecer compatibilidade com a aceleração de hardware ao longo do tempo. Para aproveitar ao máximo a aceleração de GPU, recomendamos migrar seus scripts para o Vulkan ou usar nosso kit de ferramentas de substituição para migrar dos intrínsecos.

Após a descontinuação do RenderScript na Plataforma Android, também estamos removendo o suporte para ele no Plug-in do Android para Gradle (AGP, na sigla em inglês). A partir da versão 7.2 do AGP, as APIs do RenderScript foram descontinuadas. Elas ainda funcionarão, mas invocarão avisos e serão completamente removidas em versões futuras do AGP. Este guia explica como migrar do RenderScript.

Migrar dos intrínsecos

As funções intrínsecas do RenderScript continuarão funcionando após a suspensão do RenderScript, contudo, elas poderão ser executadas apenas na CPU e não na GPU.

Caso seu aplicativo use intrínsecos, você poderá usar a biblioteca de substituição independente. Nossos testes indicam que isso é mais rápido do que usar a implementação de CPU já existente do RenderScript.

O kit de ferramentas inclui as seguintes funções:

  • Mesclar
  • Desfocar
  • Matriz de cores
  • Convolução
  • Histograma e histogramDot
  • Tabela de consulta (LUT) e LUT 3D
  • Redimensionar
  • YUV para RGB

Para ver todos os detalhes e as limitações, consulte os arquivos README.md e Toolkit.kt (links em inglês) do kit de ferramentas.

Siga estas etapas para fazer o download, adicionar e usar a biblioteca:

  1. Faça o download do projeto (link em inglês) no GitHub.

  2. Localize e crie o renderscript-toolkit module.

  3. Adicione a biblioteca ao projeto do Android Studio modificando o arquivo build.gradle do app.

  4. Invoque o método adequado do kit de ferramentas.

Exemplo: migrar da função ScriptIntrinsicBlur

Para substituir a função ScriptIntrinsicBlur:

  • Para desfocar um bitmap, chame Toolkit.blur.

    var blurredBitmap = Toolkit.blur(myBitmap, radius)
    
  • Se você quiser desfocar uma imagem representada por uma matriz de bytes, especifique a largura, a altura e o número de bytes por pixel.

    val outArray = Toolkit.blur(inputArray, bytesPerPixel, width, height, radius)
    

Para o Android 12 (nível 31 da API) e versões mais recentes, considere usar a classe RenderEffect em vez de Toolkit.blur().

Migrar dos scripts

Para aproveitar ao máximo a aceleração de GPU, recomendamos migrar os scripts do RenderScript para a API multiplataforma do Vulkan. Os scripts continuarão a ser executados mesmo que você não faça a migração, mas poderão ser executados apenas na CPU em vez da GPU, dependendo da disponibilidade dos drivers.

Para entender melhor como migrar as funções, consulte o app de exemplo (link em inglês). O exemplo mostra como desfocar um bitmap e fazer a conversão de uma matriz de cores no RenderScript e tem o código equivalente do Vulkan.

Se o app precisar ser compatível com várias versões, use o RenderScript para dispositivos com o Android 9 (nível 28 da API) ou versões anteriores e o Vulkan para o Android 10 (nível 29 da API) ou versões mais recentes.

O Vulkan não fornece APIs Kotlin ou Java e, portanto, não há um mapeamento direto do RenderScript para o Vulkan. Você precisará desenvolver o código do Vulkan usando o NDK e criar as funções JNI para acessar esse código no Kotlin ou Java.

As seções a seguir abordam aspectos da migração do RenderScript. O app de exemplo implementa quase todas essas considerações. Para entender melhor, compare o RenderScript e o código equivalente do Vulkan.

Inicialização

Em vez de criar um objeto de contexto do RenderScript em Kotlin ou Java, siga as próximas etapas para criar um contexto do Vulkan usando o NDK.

  1. Crie uma instância do Vulkan.

  2. Escolha um dispositivo físico Vulkan compatível com uma fila de computação.

  3. Crie um dispositivo lógico Vulkan e acesse a fila de computação.

Como alternativa, você pode configurar as camadas de validação do Vulkan no Android para acelerar o desenvolvimento de apps Vulkan.

O app de exemplo demonstra como inicializar o contexto do Vulkan em VulkanContext.h (link em inglês). Para saber mais, consulte as seções Inicialização e Dispositivos e filas (links em inglês) da especificação do Vulkan.

Alocações

É possível migrar uma alocação do RenderScript para uma imagem de armazenamento do Vulkan ou um buffer de armazenamento do Vulkan (links em inglês). Para melhorar o desempenho com imagens somente leitura, use uma imagem de exemplo com operações de busca, seja como um sampler de imagem combinada ou com vinculações distintas de sampler e de exemplos de imagem.

Os recursos do Vulkan são alocados nele. Para evitar a sobrecarga de cópia da memória ao interagir com outros componentes do Android, use a extensão VK_ANDROID_external_memory_android_hardware_buffer (link em inglês) para importar um objeto AHardwareBuffer do Android para o Vulkan. Essa extensão está disponível em todos os dispositivos Android compatíveis com o Vulkan 1.1. Para ver mais informações, consulte FEATURE_VULKAN_HARDWARE_VERSION.

O app de exemplo demonstra como criar recursos do Vulkan em VulkanResources.h (link em inglês). Para saber mais, consulte as seções de criação de recursos e descritores de recursos (links em inglês) da especificação do Vulkan.

Scripts

Os scripts do RenderScript precisam ser convertidos em sombreadores de computação do Vulkan. Talvez também seja necessário adaptar seu código, dependendo do uso de elementos globais do RenderScript.

Criar um sombreador de computação do Vulkan

Um sombreador de computação do Vulkan é geralmente programado usando a OpenGL Shading Language (GLSL) e, em seguida, compilado para o formato Standard Portable Intermediate Representation-V (SPIR-V) (links em inglês).

Para ver informações e instruções detalhadas sobre como integrar sombreadores no app, consulte Compiladores de sombreador do Vulkan no Android.

Adaptação de scripts globais

Com base nas características dos scripts globais, recomendamos usar constantes de especialização, constantes de push ou objetos de buffer uniformes para globais que não sejam modificados no sombreador:

  • Constantes de especialização (link em inglês): são recomendadas para scripts globais que são mais consistentes entre as invocações do kernel. Alterar o valor das constantes de especialização exigirá a recriação do pipeline de computação.
  • Constantes de push (link em inglês): são recomendadas para scripts globais com alterações frequentes e menores que maxPushConstantsSize (com um mínimo de 128 bytes garantido).
  • Buffer uniforme (link em inglês): é recomendado para scripts globais com alterações frequentes e maiores que o limite da constante de push.

Para globais que são alterados no sombreador, você pode usar a imagem de armazenamento do Vulkan ou o buffer de armazenamento do Vulkan (links em inglês).

Cálculos

Será necessário criar um pipeline de computação do Vulkan para que a GPU execute o sombreador de computação.

Criar um pipeline de computação do Vulkan

O arquivo ComputePipeline.h (link em inglês) no app de exemplo demonstra como criar o pipeline de computação do Vulkan.

Para usar um sombreador SPIR-V compilado no Vulkan, crie um pipeline de computação do Vulkan desta forma:

  1. Crie um módulo de sombreador usando o sombreador SPIR-V compilado.
  2. Crie um layout de conjunto de descritor especificando as vinculações de recursos. Consulte Alocações para mais detalhes.
  3. Crie um conjunto de descritor com base no layout dele.
  4. Crie um layout de pipeline com base no layout do conjunto de descritor.
  5. Crie um pipeline de computação usando o módulo do sombreador e o layout do pipeline.

Para mais informações, consulte a seção Pipelines de computação (link em inglês) na especificação do Vulkan.

Iniciar um cálculo

Para iniciar o cálculo usando um pipeline de computação:

  1. Atualize o conjunto de descritor usando os recursos do Vulkan.
  2. Crie um buffer de comando do Vulkan e registre os seguintes comandos:
    1. Vincule o pipeline e o conjunto do descritor.
    2. Envie grupos de trabalho de computação.
  3. Envie o buffer de comando para a fila de computação.
  4. Aguarde o resultado da fila ou, como opção, retorne um limite de sincronização.

Para encadear vários kernels (por exemplo, para migrar códigos usando um ScriptGroup), grave-os em um único buffer de comando e sincronize-os com as barreiras de memória.

O app de exemplo (link em inglês) demonstra duas tarefas de computação:

  • Rotação HUE: uma tarefa de computação simples com um único sombreador de computação. Consulte ImageProcessor::rotateHue para ver o exemplo de código.
  • Desfoque: uma tarefa de computação mais complexa que executa dois sombreadores de computação em sequência. Consulte ImageProcessor::blur para ver o exemplo de código.

Para saber mais sobre buffers de comando ou barreiras de memória, consulte as seções Buffers de comando e Barreiras de memória (links em inglês) na especificação do Vulkan.