O Google tem o compromisso de promover a igualdade racial para as comunidades negras. Saiba como.

Implementando Vulkan

Vulkan é um baixo-cima, API plataforma cruzada de alto desempenho gráficos 3D. Como OpenGL ES (GLES) , Vulkan fornece ferramentas para a criação de alta qualidade, gráficos em tempo real em aplicativos. Vantagens do uso de Vulkan incluem reduções na sobrecarga da CPU e suporte para o SPIR-V Binário Intermediate idioma.

Para implementar o Vulkan com sucesso, um dispositivo deve incluir:

  • O carregador Vulkan, fornecido pelo Android.
  • Um controlador de Vulkan, fornecida por SoC, tais como GPU IHV, que implementa o API Vulkan . Para suportar a funcionalidade Vulkan, o dispositivo Android precisa de hardware de GPU compatível com Vulkan e o driver associado. A GPU também deve suportar GLES 3.1 e superior. Consulte o seu fornecedor de SoC para solicitar suporte ao driver.

Se um dispositivo inclui um controlador de Vulkan, as necessidades do dispositivo para declarar FEATURE_VULKAN_HARDWARE_LEVEL e FEATURE_VULKAN_HARDWARE_VERSION recursos do sistema, com versões que refletem com precisão as capacidades do dispositivo. Isso ajuda a garantir que o dispositivo está em conformidade com a definição de compatibilidade Document (CDD).

Carregador Vulkan

O carregador de Vulkan platform/frameworks/native/vulkan é a interface primária entre aplicações Vulkan e condutor Vulkan de um dispositivo. O carregador Vulkan está instalado no /system/lib[64]/libvulkan.so . O carregador fornece os principais pontos de entrada da API Vulkan, bem como os pontos de entrada das extensões exigidas pelo Android CDD. As extensões do Windows System Integration (WSI) são exportadas pelo carregador e implementadas principalmente no carregador, e não no driver. O carregador também oferece suporte para enumerar e carregar camadas que podem expor extensões adicionais e interceptar chamadas de API principais em seu caminho para o driver.

O NDK inclui um esboço libvulkan.so biblioteca para ligando. A biblioteca exporta os mesmos símbolos que o carregador. Aplicativos chamar as funções exportadas do verdadeiro libvulkan.so biblioteca para introduzir funções trampolim no carregador, que expedição para a camada ou driver apropriado com base no seu primeiro argumento. O vkGet*ProcAddr() chamada retorna os ponteiros de função para a qual os trampolins expedição (isto é, a que chama diretamente no código API core). Chamar os ponteiros de função, em vez dos símbolos exportados, é mais eficiente, pois ignora o trampolim e o despacho.

Enumeração e carregamento de driver

Quando a imagem do sistema é criada, o Android espera que o sistema saiba quais GPUs estão disponíveis. O carregador usa o mecanismo HAL existente no hardware.h para descobrir e carregar o driver. Os caminhos preferidos para os drivers Vulkan de 32 e 64 bits são:

/vendor/lib/hw/vulkan.<ro.hardware.vulkan>.so
/vendor/lib/hw/vulkan.<ro.product.platform>.so
/vendor/lib64/hw/vulkan.<ro.hardware.vulkan>.so
/vendor/lib64/hw/vulkan.<ro.product.platform>.so

No Android 7,0 e mais elevado, o Vulkan hw_module_t derivado envolve um único hw_module_t estrutura; apenas um condutor é suportado e a constante de cadeia HWVULKAN_DEVICE_0 é passado para open() .

A Vulkan hw_device_t corresponde derivados de um único condutor que pode suportar vários dispositivos físicos. O hw_device_t estrutura pode estender-se a exportação vkGetGlobalExtensionProperties() , vkCreateInstance() , e vkGetInstanceProcAddr() funções. O carregador pode encontrar todos os outros VkInstance() , VkPhysicalDevice() , e vkGetDeviceProcAddr() funções chamando o hw_device_t da estrutura vkGetInstanceProcAddr() .

Descoberta de camada e carregamento

O carregador Vulkan suporta enumeração e carregamento de camadas que podem expor extensões adicionais e interceptar chamadas de API principais em seu caminho para o driver. O Android não inclui camadas na imagem do sistema; no entanto, os aplicativos podem incluir camadas em seu APK.

Ao usar camadas, lembre-se de que o modelo e as políticas de segurança do Android diferem significativamente de outras plataformas. Em particular, o Android não permite carregar código externo em um processo não depurável em dispositivos de produção (não rooteados), nem permite que código externo inspecione ou controle a memória do processo, estado e assim por diante. Isso inclui a proibição de salvar core dumps, rastreamentos de API e assim por diante no disco para inspeção posterior. Apenas camadas entregues como parte de aplicativos não depuráveis ​​são habilitadas em dispositivos de produção, e os drivers não devem fornecer funcionalidade que viole essas políticas.

Casos de uso para camadas incluem:

  • Camadas de tempo de desenvolvimento - camadas de validação e calços para rastreamento / profiling / ferramentas de depuração não deve ser instalado na imagem do sistema de dispositivos de produção. Camadas de validação e correções para ferramentas de rastreamento / criação de perfil / depuração devem ser atualizáveis ​​sem uma imagem do sistema. Os desenvolvedores que desejam usar uma dessas camadas durante o desenvolvimento podem modificar o pacote do aplicativo, por exemplo, adicionando um arquivo ao diretório de bibliotecas nativas. Os engenheiros de IHV e OEM que desejam diagnosticar falhas no envio de aplicativos não modificáveis ​​devem ter acesso a compilações de não produção (com root) da imagem do sistema, a menos que esses aplicativos sejam depuráveis. Para mais informações consulte camadas de validação Vulkan no Android .
  • Camadas de serviços públicos - Estas camadas expor extensões, como uma camada que implementa um gerenciador de memória para a memória do dispositivo. Os desenvolvedores escolhem camadas e versões dessas camadas para usar em seu aplicativo; aplicativos diferentes que usam a mesma camada ainda podem usar versões diferentes. Os desenvolvedores escolhem qual dessas camadas enviar em seu pacote de aplicativo.
  • Injetados (implícitas) camadas - Inclui camadas, como a taxa de quadros, rede social e jogo lançador de sobreposições fornecido pelo usuário ou algum outro aplicativo sem o conhecimento ou consentimento do aplicativo. Eles violam as políticas de segurança do Android e não são compatíveis.

Para aplicativos nondebuggable, as pesquisas carregador para camadas única no diretório de biblioteca nativa do aplicativo e tenta carregar qualquer biblioteca com um nome que corresponde a um determinado padrão (por exemplo, libVKLayer_foo.so ).

Para aplicativos debuggable, as pesquisas carregador para camadas em /data/local/debug/vulkan e tentativas para carregar qualquer biblioteca correspondentes a um padrão particular.

O Android permite que as camadas sejam portadas com mudanças no ambiente de construção entre o Android e outras plataformas. Para mais detalhes sobre a interface entre camadas e o carregador, consulte Arquitetura dos Vulkan carregador Interfaces . As camadas de validação Kronos conservados estão alojadas em Camadas Vulkan validação .

Versões e recursos da API Vulkan

O Android 9 e superior são compatíveis com a versão 1.1 da API Vulkan. Android 7 a Android 9 é compatível com a versão 1.0 da API Vulkan. Para mais informações sobre a API Vulkan 1.1, consulte a Vulkan especificação 1.1 API .

Visão geral do suporte Vulkan 1.1

Vulkan 1.1 inclui suporte para interoperabilidade de memória / sincronização, que permite aos OEMs oferecer suporte ao Vulkan 1.1 nos dispositivos. Além disso, a interoperabilidade de memória / sincronização permite que os desenvolvedores determinem se o Vulkan 1.1 é compatível com um dispositivo e o usem efetivamente quando for necessário. Vulkan 1.1 tem os mesmos requisitos de hardware do Vulkan 1.0, mas a maior parte da implementação está no driver gráfico específico do SOC, não na estrutura.

Os recursos mais importantes do Vulkan 1.1 para Android são:

  • Suporte para importação e exportação de buffers de memória e objetos de sincronização de fora do Vulkan (para interoperabilidade com câmera, codecs e GLES)
  • Suporte para formatos YCbCr

Vulkan 1.1 também inclui vários recursos menores e aprimoramentos de usabilidade de API.

Implementando Vulkan 1.1

Os dispositivos Android devem oferecer suporte ao Vulkan 1.1 se:

  • Inicie com Android 10.
  • Suporta ABI de 64 bits.
  • Não são pouca memória.

Outros dispositivos podem, opcionalmente, oferecer suporte ao Vulkan 1.1.

Para implementar o Vulkan 1.1:

  1. Adicionar um driver Vulkan que suportes Vulkan 1.1 mais os Android 1.1 adicionais exigências de CDD , ou atualizar o 1.0 motorista Vulkan existente.
  2. Certifique-se que PackageManager#hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, 0x401000) retorna true , adicionando uma regra como a seguinte para um meio adequado device.mk arquivo:
    PRODUCT_COPY_FILES += frameworks/native/data/etc/android.hardware.vulkan.version-1_1.xml:
    $(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.vulkan.version.xml
    

Integração do sistema de janelas (WSI)

Em libvulkan.so , os implementos motorista a seguinte janela Integração de Sistemas (WSI) extensões:

  • VK_KHR_surface
  • VK_KHR_android_surface
  • VK_KHR_swapchain
  • VK_KHR_driver_properties , implementadas para Vulkan 1.1 no Android 10 única
  • VK_GOOGLE_display_timing , implementado em qualquer versão Vulkan em Android 10

Os VkSurfaceKHR e VkSwapchainKHR objetos e todas as interações com ANativeWindow são tratados pela plataforma e não estão expostos aos motoristas. A implementação WSI depende da VK_ANDROID_native_buffer extensão, que deve ser apoiada pelo condutor; esta extensão é usada apenas pela implementação WSI e não é exposta a aplicativos.

Sinalizadores de uso Gralloc

As implementações Vulkan podem precisar que buffers de cadeia de troca sejam alocados com sinalizadores de uso Gralloc privados definidos pela implementação. Ao criar uma cadeia de troca, o Android pede ao driver para traduzir o formato solicitado e os sinalizadores de uso de imagem em sinalizadores de uso Gralloc chamando:

typedef enum VkSwapchainImageUsageFlagBitsANDROID {
    VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID = 0x00000001,
    VK_SWAPCHAIN_IMAGE_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkSwapchainImageUsageFlagBitsANDROID;
typedef VkFlags VkSwapchainImageUsageFlagsANDROID;

VkResult VKAPI vkGetSwapchainGrallocUsage2ANDROID(
    VkDevice                          device,
    VkFormat                          format,
    VkImageUsageFlags                 imageUsage,
    VkSwapchainImageUsageFlagsANDROID swapchainUsage,
    uint64_t*                         grallocConsumerUsage,
    uint64_t*                         grallocProducerUsage
);

Os format e imageUsage parâmetros são retirados do VkSwapchainCreateInfoKHR estrutura. O motorista deve preencher *grallocConsumerUsage e *grallocProducerUsage com as bandeiras de uso Gralloc necessários para o formato e uso. Os sinalizadores de uso retornados pelo driver são combinados com os sinalizadores de uso solicitados pelo consumidor da cadeia de troca ao alocar buffers.

7.x Android chama uma versão anterior do VkSwapchainImageUsageFlagsANDROID() , chamado vkGetSwapchainGrallocUsageANDROID() . Android 8.0 e superior deprecates vkGetSwapchainGrallocUsageANDROID() , mas ainda chama vkGetSwapchainGrallocUsageANDROID() se vkGetSwapchainGrallocUsage2ANDROID() não é fornecido pelo controlador:

VkResult VKAPI vkGetSwapchainGrallocUsageANDROID(
    VkDevice            device,
    VkFormat            format,
    VkImageUsageFlags   imageUsage,
    int*                grallocUsage
);

vkGetSwapchainGrallocUsageANDROID() não suporta bandeiras de uso swapchain ou estendido bandeiras de uso Gralloc.

Imagens apoiadas por Gralloc

VkNativeBufferANDROID é um vkCreateImage estrutura extensão para a criação de uma imagem apoiado por uma Gralloc tampão. VkNativeBufferANDROID é fornecido para vkCreateImage() na VkImageCreateInfo cadeia de estrutura. Chamadas para vkCreateImage() com VkNativeBufferANDROID acontecer durante a chamada para vkCreateSwapchainKHR . Os aloca implementação WSI o número de tampões nativas solicitado para o swapchain, então cria um VkImage para cada um:

typedef struct {
    VkStructureType             sType; // must be VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID
    const void*                 pNext;

    // Buffer handle and stride returned from gralloc alloc()
    buffer_handle_t             handle;
    int                         stride;

    // Gralloc format and usage requested when the buffer was allocated.
    int                         format;
    int                         usage;
    // Beginning in Android 8.0, the usage field above is deprecated and the
    // usage2 struct below was added. The usage field is still filled in for
    // compatibility with Android 7.0 drivers. Drivers for Android 8.0
    // should prefer the usage2 struct, especially if the
    // android.hardware.graphics.allocator HAL uses the extended usage bits.
    struct {
        uint64_t                consumer;
        uint64_t                producer;
    } usage2;
} VkNativeBufferANDROID;

Ao criar uma imagem lastreados em Gralloc, VkImageCreateInfo tem os seguintes dados:

  .sType               = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO
  .pNext               = the above VkNativeBufferANDROID structure
  .imageType           = VK_IMAGE_TYPE_2D
  .format              = a VkFormat matching the format requested for the gralloc buffer
  .extent              = the 2D dimensions requested for the gralloc buffer
  .mipLevels           = 1
  .arraySize           = 1
  .samples             = 1
  .tiling              = VK_IMAGE_TILING_OPTIMAL
  .usage               = VkSwapchainCreateInfoKHR::imageUsage
  .flags               = 0
  .sharingMode         = VkSwapchainCreateInfoKHR::imageSharingMode
  .queueFamilyCount    = VkSwapchainCreateInfoKHR::queueFamilyIndexCount
  .pQueueFamilyIndices = VkSwapchainCreateInfoKHR::pQueueFamilyIndices

No Android 8,0 e superior, a plataforma fornece um VkSwapchainImageCreateInfoKHR estrutura extensão no VkImageCreateInfo corrente fornecida para vkCreateImage quando todas as bandeiras de utilização imagem swapchain são necessários para a swapchain. A estrutura da extensão contém os sinalizadores de uso da imagem da cadeia de troca:

typedef struct {
    VkStructureType                        sType; // must be VK_STRUCTURE_TYPE_SWAPCHAIN_IMAGE_CREATE_INFO_ANDROID
    const void*                            pNext;

    VkSwapchainImageUsageFlagsANDROID      usage;
} VkSwapchainImageCreateInfoANDROID;

Em Android 10 e superior, a plataforma suporta VK_KHR_swapchain v70, então o aplicativo Vulkan é capaz de criar um VkImage apoiado pela memória swapchain. O aplicativo chama primeiro vkCreateImage com um VkImageSwapchainCreateInfoKHR estrutura acorrentado à VkImageCreateInfo estrutura. Em seguida, o aplicativo chama vkBindImageMemory2(KHR) com um VkBindImageMemorySwapchainInfoKHR estrutura acorrentado à VkBindImageMemoryInfo estrutura. O imageIndex especificado no VkBindImageMemorySwapchainInfoKHR estrutura deve ser um índice de imagem swapchain válido. Enquanto isso, a plataforma fornece um VkNativeBufferANDROID estrutura extensão com a correspondente informação Gralloc tampão para o VkBindImageMemoryInfo cadeia, de modo que o controlador sabe que tampão Gralloc para se ligar a VkImage com.

Aquisição de imagens

vkAcquireImageANDROID adquire a propriedade de uma imagem de swapchain e as importações uma cerca nativa sinalizou externamente em ambos um já existente VkSemaphore objeto e um já existente VkFence objeto:

VkResult VKAPI vkAcquireImageANDROID(
    VkDevice            device,
    VkImage             image,
    int                 nativeFenceFd,
    VkSemaphore         semaphore,
    VkFence             fence
);

vkAcquireImageANDROID() é chamado durante vkAcquireNextImageKHR para importar uma cerca nativa no VkSemaphore e VkFence objetos fornecidos pelo aplicativo (no entanto, ambos os objetos de semáforo e cerca são opcionais no presente convite). O driver também pode usar esta oportunidade para reconhecer e tratar quaisquer mudanças externas no estado do buffer Gralloc; muitos drivers não precisarão fazer nada aqui. Esta chamada coloca o VkSemaphore e VkFence no mesmo estado pendente como se sinalizado por vkQueueSubmit , então filas podem esperar o semáforo e o aplicativo pode esperar em cima do muro.

Ambos os objetos são sinalizados quando a cerca nativa subjacente sinaliza; se a cerca nativa já foi sinalizada, então o semáforo está no estado sinalizado quando esta função retorna. O driver assume a propriedade do descritor de arquivo fence e fecha o descritor de arquivo fence quando não for mais necessário. O condutor deve fazê-lo mesmo se nem um semáforo ou objeto vedação é fornecida, ou mesmo se vkAcquireImageANDROID falha e retorna um erro. Se fenceFd é -1, é como se a cerca nativa já foi sinalizado.

Liberando imagens

vkQueueSignalReleaseImageANDROID prepara uma imagem do swapchain para uso externo, cria uma cerca nativa e horários a cerca nativa a ser sinalizado após os semáforos de entrada têm sinalizado:

VkResult VKAPI vkQueueSignalReleaseImageANDROID(
    VkQueue             queue,
    uint32_t            waitSemaphoreCount,
    const VkSemaphore*  pWaitSemaphores,
    VkImage             image,
    int*                pNativeFenceFd
);

vkQueuePresentKHR() chama vkQueueSignalReleaseImageANDROID() sobre a fila fornecida. O condutor deve produzir uma cerca nativa que não sinaliza até que todos os waitSemaphoreCount semáforos em pWaitSemaphores sinalizar, e qualquer trabalho adicional necessário para preparar image de concluída apresentação.

Se os semáforos de espera (se houver) já sinalizou, e queue já está ocioso, o motorista pode definir *pNativeFenceFd para -1 em vez de um descritor de arquivo cerca nativa real, indicando que não há nada para esperar. O chamador é proprietária e fecha o descritor de arquivo retornado em *pNativeFenceFd .

Muitos drivers podem ignorar o parâmetro de imagem, mas alguns podem precisar preparar estruturas de dados do lado da CPU associadas a um buffer Gralloc para uso por consumidores de imagem externos. Preparando conteúdo do buffer para uso por consumidores externos deve ser feito de forma assíncrona, como parte da transição da imagem para VK_IMAGE_LAYOUT_PRESENT_SRC_KHR .

Se a imagem foi criada com VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID , em seguida, o motorista deve permitir vkQueueSignalReleaseImageANDROID() para ser chamado repetidamente sem intervir chamadas para vkAcquireImageANDROID() .

Suporte para imagem apresentável compartilhada

Alguns dispositivos podem compartilhar a propriedade de uma única imagem entre o pipeline de exibição e a implementação do Vulkan para minimizar a latência. Em Android 9 e superior, o carregador condicionalmente anuncia o VK_KHR_shared_presentable_image extensão com base na resposta do motorista para uma chamada para vkGetPhysicalDeviceProperties2 .

Se o condutor não suporta qualquer Vulkan 1.1 ou o VK_KHR_physical_device_properties2 extensão, o carregador não anuncia suporte para imagens apresentável compartilhados. Caso contrário, o carregador consulta as capacidades do driver, chamando vkGetPhysicalDeviceProperties2() e incluindo a seguinte estrutura no VkPhysicalDeviceProperties2::pNext cadeia:

typedef struct {
    VkStructureType sType; // must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENTATION_PROPERTIES_ANDROID
    const void*     pNext;
    VkBool32        sharedImage;
} VkPhysicalDevicePresentationPropertiesANDROID;

Se o motorista pode compartilhar a propriedade de uma imagem com o sistema de exibição, ele define o sharedImage membro a VK_TRUE .

Validação

Os OEMs podem testar sua implementação Vulkan usando CTS, que inclui:

  • Testes Kronos Vulkan Conformidade no CtsDeqpTestCases módulo, que incluem testes de API funcionais para Vulkan 1,0 e 1,1.
  • O CtsGraphicsTestCases módulo, que testa se o dispositivo está configurado correctamente para as capacidades de Vulkan que ele suporta.

Sinalizador de recurso Vulkan

Um dispositivo que suporta Android 11 ou superior e que suporta a API Vulkan é necessária para expor uma bandeira recurso, android.software.vulkan.deqp.level . O valor deste sinalizador de recurso é uma data, codificada como um valor inteiro. Ele especifica a data associada aos testes dEQP Vulkan que o dispositivo afirma ter passado.

Uma data no formato AAAA-MM-DD é codificada como um número inteiro de 32 bits da seguinte maneira:

  • Os bits de 0 a 15 armazenam o ano
  • Os bits 16-23 armazenam o mês
  • Os bits 24-31 armazenam o dia

O valor mínimo permitido para a bandeira característica é 0x07E30301 , que corresponde à data 2019/03/01, que é a data associada com os testes de Vulkan dEQP para Android 10. Se a bandeira característica é, pelo menos, este valor, o dispositivo reivindicações de passar em todos os testes dEQP do Android 10 Vulkan.

Valor 0x07E40301 corresponde à data 2020/03/01, que é a data associada com os testes de Vulkan dEQP para 11. Android Se a bandeira característica é, pelo menos, esse valor, as reivindicações de dispositivo para passar todos os 11 testes Android Vulkan dEQP.

Se o valor da bandeira característica é pelo menos 0x07E30301 mas menos do que 0x07E40301 , isso significa que as reivindicações do dispositivo para passar todos os Android 10 testes Vulkan dEQP mas não é garantido para passar por testes Vulkan dEQP que foram adicionados para Android 11.

Vulkan dEQP faz parte do Android CTS. A partir do Android 11, o componente de teste corredor dEQP de CTS está ciente da android.software.vulkan.deqp.level bandeira recurso, e ignora quaisquer testes Vulkan dEQP que - de acordo com esta bandeira recurso - o dispositivo não tem a pretensão de apoio. Esses testes são relatados como triviais.