Implementar HAL do compositor de hardware

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

O HWC abstrai objetos, como sobreposições e blitters 2D, para superfícies compostas e se comunica com hardware de composição de janela especializado para janelas compostas. Use o HWC para compor janelas em vez de ter o SurfaceFlinger composto 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/plano de fundo
  • Camadas maiores que a exibição (por exemplo, um papel de parede)
  • Mistura alfa por pixel pré-multiplicada simultânea e mistura alfa por plano
  • Caminho de hardware para reprodução de vídeo protegida
  • Ordem de embalagem RGBA, formatos YUV e propriedades lado a lado, swizzling e passada

Para implementar o HWC:

  1. Implemente um HWC não operacional e envie 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:
    • Selecionando superfícies que maximizam a carga retirada da GPU e enviando-as para o HWC.
    • Detectando se a tela está atualizando. Caso contrário, delegue a composição ao GLES em vez do HWC para economizar energia. Quando a tela for atualizada novamente, continue a descarregar 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 os papéis de parede animados
      • Jogos em tela cheia no modo retrato e paisagem
      • Vídeo em tela cheia com legenda oculta e controle de reprodução
      • Reprodução de vídeo protegida
      • Multijanela em tela dividida

Primitivas de HWC

O HWC fornece duas primitivas, camadas e exibições , para representar o trabalho de composição e sua interação com o hardware de exibição. O HWC também fornece controle sobre VSYNC e um retorno de chamada para SurfaceFlinger para notificá-lo quando ocorrer 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 do Composer HAL do HWC, o Composer HAL aceitará diretamente as chamadas HIDL do SurfaceFlinger. Se os fornecedores fornecerem uma implementação herdada do HWC, o Composer HAL carregará 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 monitor; 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 ou colocar o monitor em um modo de baixo consumo de energia, se suportado.

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 documentação detalhada sobre funções HAL do Composer e funções de passagem de função HWC, consulte composer . Para documentação detalhada sobre ponteiros de função HWC, consulte o hwcomposer2.h .

Alças de camada e exibição

Camadas e exibições são manipuladas por alças geradas 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.

Exibições físicas são criadas por hotplugged. Quando um display físico é hotplug, o HWC cria um identificador e passa o identificador para SurfaceFlinger por meio do retorno de chamada hotplug. As exibições virtuais são criadas pelo SurfaceFlinger chamando createVirtualDisplay() para solicitar uma exibição. Se o HWC oferecer suporte à composição de exibição virtual, ele retornará um identificador. Em seguida, o SurfaceFlinger delega a composição dos displays 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 composição. 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 presente.
  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 do visor.

Para executar 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 seus conteúdos atuais, usando chamadas como setLayerBuffer ou setLayerColor . Depois que todas as camadas são atualizadas, SurfaceFlinger chama validateDisplay , que instrui o HWC a examinar o estado das camadas e determinar como a composição continuará. 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 fallback 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 para a exibição de modo que o buffer possa ser exibido na tela ou ainda composto com camadas que não foram marcadas para composição de SurfaceFlinger. Se nenhuma camada for 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.

Múltiplos 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, existem algumas restrições nã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 relata durante a inicialização. Após o display interno ser conectado, ele não pode ser desconectado.
  • Além do visor interno, qualquer número de visores externos pode ser conectado automaticamente durante a operação normal do dispositivo. A estrutura assume que todos os hotplugs após o primeiro monitor interno são 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 SurfaceFlinger descritas acima sejam executadas por tela, elas são executadas sequencialmente para todas as telas ativas, mesmo se o conteúdo de apenas uma tela for atualizado.

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

// 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 de exibição virtual é semelhante à composição de exibição externa. A diferença entre a composição de exibição virtual e a composição de exibição física é que as exibições 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 o limite de conclusão e envia o buffer para um consumidor (como o codificador de vídeo, GPU, CPU e assim por diante). As exibições 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 — 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 de 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 pode 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, o Gralloc define um formato YCbCr se o consumidor for um codificador de vídeo e o HWC puder gravar o formato com eficiência.

cercas de sincronização

Cercas de sincronização (sync) são um aspecto crucial do sistema gráfico do 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. Essa cerca sinaliza quando a GPU termina de gravar no buffer.

O HWC requer que a GPU termine de gravar os buffers antes que os buffers sejam exibidos. 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 tiver, exibe o buffer.

Para obter mais informações sobre cercas de sincronização, consulte Hardware Composer Integration .