Implementar HAL do compositor de hardware

O Hardware Composer (HWC) HAL compõe as camadas recebidas do SurfaceFlinger, reduzindo a quantidade de composição do OpenGL ES (GLES) e o desempenho da GPU.

O HWC abstrai objetos, como sobreposições e blitters 2D, para superfícies compostas e se comunica com hardware especializado de composição de janelas para janelas compostas. Use o HWC para compor janelas em vez de compor o SurfaceFlinger com a GPU. A maioria das GPUs não é otimizada para composição e, quando a GPU compõe camadas do SurfaceFlinger, os aplicativos não podem usar a GPU para sua própria renderização.

As implementações de HWC devem suportar:

  • Pelo menos quatro sobreposições:
    • Barra de status
    • Barra do sistema
    • Aplicativo
    • Papel de parede/fundo
  • Camadas maiores que a tela (por exemplo, um papel de parede)
  • Combinação alfa pré-multiplicada por pixel e combinação alfa por plano simultâneas
  • Caminho de hardware para reprodução de vídeo protegida
  • Ordem de embalagem RGBA, formatos YUV e propriedades de ladrilho, swizzling e passada

Para implementar o HWC:

  1. Implementar um HWC não operacional e enviar todo o trabalho de composição para o GLES.
  2. Implemente um algoritmo para delegar a composição ao HWC de forma incremental. Por exemplo, delegue apenas as primeiras três ou quatro superfícies ao hardware de sobreposição do HWC.
  3. Otimize o HWC. Isso pode incluir:
    • Selecionar superfícies que maximizem a carga retirada da GPU e enviá-las ao HWC.
    • Detectando se a tela está sendo atualizada. Caso contrário, delegue a composição ao GLES em vez do HWC para economizar energia. Quando a tela for atualizada novamente, continue a transferir a composição para o HWC.
    • Preparando-se para casos de uso comuns, como:
      • A tela inicial, que inclui a barra de status, a barra do sistema, a janela do aplicativo e papéis de parede animados
      • Jogos em tela cheia no modo retrato e paisagem
      • Vídeo em tela cheia com legendas ocultas e controle de reprodução
      • Reprodução de vídeo protegida
      • Janela múltipla em tela dividida

Primitivos HWC

O HWC fornece duas primitivas, camadas e displays , para representar o trabalho de composição e sua interação com o hardware do display. O HWC também fornece controle sobre VSYNC e um retorno de chamada para SurfaceFlinger para notificá-lo quando ocorre um evento VSYNC.

Interface HIDL

O Android 8.0 e superior usa uma interface HIDL chamada Composer HAL para IPC vinculado entre o HWC e o SurfaceFlinger. O Composer HAL substitui a interface herdada hwcomposer2.h . Se os fornecedores fornecerem uma implementação Composer HAL do HWC, o Composer HAL aceitará diretamente chamadas HIDL do SurfaceFlinger. Se os fornecedores fornecerem uma implementação legada do HWC, o Composer HAL carrega ponteiros de função de hwcomposer2.h , encaminhando chamadas HIDL para chamadas de ponteiro de função.

O HWC fornece funções para determinar as propriedades de um determinado display; para alternar entre diferentes configurações de exibição (como resolução 4k ou 1080p) e modos de cor (como cor nativa ou sRGB verdadeiro); e para ligar, desligar a tela ou colocá-la em modo de baixo consumo de energia, se compatível.

Ponteiros de função

Se os fornecedores implementarem o Composer HAL diretamente, o SurfaceFlinger chamará suas funções por meio do HIDL IPC. Por exemplo, para criar uma camada, SurfaceFlinger chama createLayer() no Composer HAL.

Se os fornecedores implementarem a interface hwcomposer2.h , o Composer HAL chama os ponteiros de função hwcomposer2.h . Nos comentários hwcomposer2.h , as funções da interface HWC são referidas por nomes lowerCamelCase que não existem na interface como campos nomeados. Quase todas as funções são carregadas solicitando um ponteiro de função usando getFunction fornecido por hwc2_device_t . Por exemplo, a função createLayer é um ponteiro de função do tipo HWC2_PFN_CREATE_LAYER , que é retornado quando o valor enumerado HWC2_FUNCTION_CREATE_LAYER é passado para getFunction .

Para obter documentação detalhada sobre funções HAL do Composer e funções de passagem de função HWC, consulte composer . Para obter documentação detalhada sobre ponteiros de função HWC, consulte hwcomposer2.h .

Alças de camada e exibição

Camadas e exibições são manipuladas por identificadores gerados pelo HWC. As alças são opacas para SurfaceFlinger.

Quando SurfaceFlinger cria uma nova camada, ele chama createLayer , que retorna do tipo Layer para implementações diretas ou hwc2_layer_t para implementações de passagem. Quando SurfaceFlinger modifica uma propriedade dessa camada, SurfaceFlinger passa o valor hwc2_layer_t para a função de modificação apropriada junto com qualquer outra informação necessária para fazer a modificação. O tipo hwc2_layer_t é grande o suficiente para conter um ponteiro ou um índice.

Os monitores físicos são criados por meio de hotplug. Quando um monitor físico é hotplug, o HWC cria um identificador e passa o identificador para o SurfaceFlinger por meio do retorno de chamada do hotplug. Os displays virtuais são criados pelo SurfaceFlinger chamando createVirtualDisplay() para solicitar um display. Se o HWC suportar composição de exibição virtual, ele retornará um identificador. Em seguida, o SurfaceFlinger delega a composição dos monitores ao HWC. Se o HWC não oferecer suporte à composição de exibição virtual, o SurfaceFlinger criará o identificador e comporá a exibição.

Exibir operações de composição

Uma vez por VSYNC, o SurfaceFlinger é ativado se tiver novo conteúdo para compor. Esse novo conteúdo pode ser novos buffers de imagem de aplicativos ou uma alteração nas propriedades de uma ou mais camadas. Quando o SurfaceFlinger o ativa:

  1. Lida com transações, se houver.
  2. Trava novos buffers gráficos, se presentes.
  3. Executa uma nova composição, se a etapa 1 ou 2 resultar em uma alteração no conteúdo da tela.

Para realizar uma nova composição, o SurfaceFlinger cria e destrói camadas ou modifica os estados das camadas, conforme aplicável. Ele também atualiza as camadas com seu conteúdo atual, usando chamadas como setLayerBuffer ou setLayerColor . Depois que todas as camadas forem atualizadas, o SurfaceFlinger chama validateDisplay , que instrui o HWC a examinar o estado das camadas e determinar como a composição prosseguirá. Por padrão, o SurfaceFlinger tenta configurar cada camada de forma que a camada seja composta pelo HWC; embora em algumas circunstâncias, o SurfaceFlinger componha camadas por meio do substituto da GPU.

Após a chamada para validateDisplay , SurfaceFlinger chama getChangedCompositionTypes para ver se o HWC deseja que algum dos tipos de composição de camada seja alterado antes de executar a composição. Para aceitar as alterações, SurfaceFlinger chama acceptDisplayChanges .

Se alguma camada estiver marcada para composição do SurfaceFlinger, o SurfaceFlinger as compõe no buffer de destino. SurfaceFlinger então chama setClientTarget para fornecer o buffer à exibição para que o buffer possa ser exibido na tela ou posteriormente composto com camadas que não foram marcadas para a composição do SurfaceFlinger. Se nenhuma camada estiver marcada para a composição do SurfaceFlinger, o SurfaceFlinger ignorará a etapa de composição.

Por fim, SurfaceFlinger chama presentDisplay para informar ao HWC para concluir o processo de composição e exibir o resultado final.

Vários monitores

O Android 10 oferece suporte a vários monitores físicos. Ao projetar uma implementação de HWC destinada ao uso no Android 7.0 e superior, há algumas restrições que não estão presentes na definição de HWC:

  • Presume-se que haja exatamente um display interno . A exibição interna é a exibição que o hotplug inicial reporta durante a inicialização. Depois que o display interno for conectado a quente, ele não poderá ser desconectado.
  • Além do monitor interno, qualquer número de monitores externos pode ser conectado durante a operação normal do dispositivo. A estrutura pressupõe que todos os hotplugs após o primeiro monitor interno sejam monitores externos, portanto, se mais monitores internos forem adicionados, eles serão categorizados incorretamente como Display.TYPE_HDMI em vez de Display.TYPE_BUILT_IN .

Embora as operações do SurfaceFlinger descritas acima sejam executadas por monitor, elas são executadas sequencialmente para todos os monitores ativos, mesmo que o conteúdo de apenas um monitor seja atualizado.

Por exemplo, se o display externo for atualizado, a sequência será:

// In Android 9 and lower:

// Update state for internal display
// Update state for external display
validateDisplay(<internal display>)
validateDisplay(<external display>)
presentDisplay(<internal display>)
presentDisplay(<external display>)

// In Android 10 and higher:

// Update state for internal display
// Update state for external display
validateInternal(<internal display>)
presentInternal(<internal display>)
validateExternal(<external display>)
presentExternal(<external display>)

Composição de exibição virtual

A composição do display virtual é semelhante à composição do display externo. A diferença entre a composição do display virtual e a composição do display físico é que os displays virtuais enviam a saída para um buffer Gralloc em vez de para a tela. O Hardware Composer (HWC) grava a saída em um buffer, fornece a barreira de conclusão e envia o buffer para um consumidor (como o codificador de vídeo, GPU, CPU e assim por diante). Os monitores virtuais podem usar 2D/blitter ou sobreposições se o pipeline de exibição gravar na memória.

Modos

Cada quadro está em um dos três modos depois que SurfaceFlinger chama o método validateDisplay() HWC:

  • GLES — A GPU compõe todas as camadas, gravando diretamente no buffer de saída. O HWC não está envolvido na composição.
  • MIXED — A GPU compõe algumas camadas no framebuffer e o HWC compõe o framebuffer e as camadas restantes, gravando diretamente no buffer de saída.
  • HWC — o HWC compõe todas as camadas e grava diretamente no buffer de saída.

Formato de saída

Os formatos de saída do buffer de exibição virtual dependem do seu modo:

  • Modo GLES — O driver EGL define o formato do buffer de saída em dequeueBuffer() , normalmente RGBA_8888 . O consumidor deve ser capaz de aceitar o formato de saída definido pelo driver ou o buffer não poderá ser lido.
  • Modos MIXED e HWC — Se o consumidor precisar de acesso à CPU, o consumidor define o formato. Caso contrário, o formato é IMPLEMENTATION_DEFINED e Gralloc define o melhor formato com base nos sinalizadores de uso. Por exemplo, Gralloc define um formato YCbCr se o consumidor for um codificador de vídeo e o HWC puder escrever o formato com eficiência.

Cercas de sincronização

As cercas de sincronização (sincronização) são um aspecto crucial do sistema gráfico Android. As cercas permitem que o trabalho da CPU prossiga independentemente do trabalho simultâneo da GPU, bloqueando apenas quando há uma dependência real.

Por exemplo, quando um aplicativo envia um buffer que está sendo produzido na GPU, ele também envia um objeto de limite de sincronização. Esta cerca sinaliza quando a GPU termina de escrever no buffer.

O HWC exige que a GPU termine de gravar os buffers antes que os buffers sejam exibidos. As cercas de sincronização são passadas pelo pipeline gráfico com buffers e sinalizam quando os buffers são gravados. Antes de um buffer ser exibido, o HWC verifica se o limite de sincronização sinalizou e, se sim, exibe o buffer.

Para obter mais informações sobre limites de sincronização, consulte Integração do Hardware Composer .