A HAL do Hardware Composer (HWC) compõe as camadas recebidas do SurfaceFlinger, reduzindo a quantidade de composição OpenGL ES (GLES) e a performance da GPU.
O HWC abstrai objetos, como sobreposições e blitters 2D, para compor superfícies e se comunicar com hardware especializado de composição de janelas para compor janelas. Use o HWC para compor janelas em vez de ter composição do SurfaceFlinger com a GPU. A maioria das GPUs não é otimizada para composição. Quando a GPU compõe camadas do SurfaceFlinger, os apps não podem usar a GPU para a própria renderização.
As implementações de HWC precisam oferecer suporte a:
- Pelo menos quatro sobreposições:
- Barra de status
- Barra de sistema
- App
- Plano de fundo/papel de parede
- Camadas maiores que a tela (por exemplo, um plano de fundo)
- Mistura Alfa pré-multiplicada por pixel e por plano simultânea
- Caminho de hardware para reprodução de vídeo protegida
- Ordem de compactação RGBA, formatos YUV e propriedades de ladrilhos, swizzling e stride
Para implementar o HWC:
- Implemente um HWC não operacional e envie todo o trabalho de composição para GLES.
- Implemente um algoritmo para delegar a composição ao HWC de forma incremental. Por exemplo, delegue apenas as três ou quatro primeiras superfícies para o hardware de sobreposição do HWC.
- Otimize o HWC. Isso pode incluir:
- Selecionar superfícies que maximizam a carga retirada da GPU e enviá-las para o HWC.
- Detectar se a tela está sendo atualizada. Caso contrário, delegue a composição para o GLES em vez do HWC para economizar energia. Quando a tela for atualizada novamente, continue a transferir a composição para o HWC.
- Preparar-se para casos de uso comuns, como:
- A tela inicial, que inclui a barra de status, a barra do sistema, a janela do app e os papéis de parede animados
- Jogos em tela cheia no modo retrato e paisagem
- Vídeo em tela cheia com legendas e controle de reprodução
- Reprodução de vídeo protegida
- Janela dividida em várias telas
Primitivos de HWC
O HWC fornece duas primitivas, layers e displays, para representar o trabalho de composição e a interação com o hardware de exibição. O HWC também oferece controle sobre VSYNC e um callback para SurfaceFlinger para notificá-lo quando um evento VSYNC ocorre.
Interface HIDL
O Android 8.0 e versões mais recentes usam uma
interface HIDL chamada HAL do Composer para
IPC vinculado entre o HWC e o SurfaceFlinger. O HAL do Composer substitui a
interface hwcomposer2.h
legada. Se os fornecedores fornecerem uma implementação de HAL do
Composer para o HWC, a HAL do Composer vai aceitar diretamente as chamadas HIDL do
SurfaceFlinger. Se os fornecedores fornecerem uma implementação legada do HWC, o HAL
do Composer vai 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 uma determinada tela, alternar entre diferentes configurações de tela (como resolução 4K ou 1080p) e modos de cor (como cor nativa ou sRGB verdadeiro) e ativar, desativar ou colocar a tela em modo de baixo consumo, se houver suporte.
Ponteiros de função
Se os fornecedores implementarem o HAL do Composer diretamente, o SurfaceFlinger vai chamar as funções
pelo IPC do HIDL. Por exemplo, para criar uma camada, o SurfaceFlinger chama
createLayer()
no HAL do Composer.
Se os fornecedores implementarem a interface hwcomposer2.h
, o HAL do Composer
vai chamar ponteiros de função hwcomposer2.h
. Nos comentários hwcomposer2.h
,
as funções da interface HWC são
referidas por nomes em 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
é
transmitido para getFunction
.
Para conferir uma documentação detalhada sobre as funções HAL do Composer e as funções de passagem de função HWC, consulte composer
. Para conferir uma documentação detalhada sobre
ponteiros de função de HWC, consulte o
hwcomposer2.h
.
Manipuladores de camadas e exibição
As camadas e telas são manipuladas por identificadores gerados pelo HWC. Os identificadores são opacos para o SurfaceFlinger.
Quando o 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
o SurfaceFlinger modifica uma propriedade dessa camada, ele transmite
o valor hwc2_layer_t
para a função de modificação adequada
com todas as outras informações necessárias para fazer a modificação. O
tipo hwc2_layer_t
é grande o suficiente para conter um ponteiro ou um
índice.
As telas físicas são criadas por hotplug. Quando uma tela física é
conectada, o HWC cria um handle e o transmite para o SurfaceFlinger
por meio do callback de hotplug. As telas virtuais são criadas pelo SurfaceFlinger
chamando createVirtualDisplay()
para solicitar uma tela. Se o HWC
oferecer suporte à composição de exibição virtual, ele retornará um identificador. Em seguida, o SurfaceFlinger
delega a composição das telas para o HWC. Se o HWC não oferecer suporte à composição
de tela virtual, o SurfaceFlinger vai criar o gerenciador e compor a tela.
Mostrar operações de composição
Uma vez por VSYNC, o SurfaceFlinger é ativado se tiver um novo conteúdo para compor. Esse novo conteúdo pode ser novos buffers de imagem de apps ou uma mudança nas propriedades de uma ou mais camadas. Quando o SurfaceFlinger acorda:
- Processa transações, se houver.
- Trava novos buffers gráficos, se presentes.
- Executa uma nova composição se a etapa 1 ou 2 resultar em uma mudança 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
camadas com o conteúdo atual, usando chamadas como
setLayerBuffer
ou setLayerColor
. Depois que todas as camadas são
atualizadas, o SurfaceFlinger chama validateDisplay
, que instrui
o HWC a examinar o estado das camadas e determinar como a composição vai
prosseguir. Por padrão, o SurfaceFlinger tenta configurar todas as camadas
para que sejam compostas pelo HWC. No entanto, em algumas
circunstâncias, o SurfaceFlinger compõe camadas pelo substituto da GPU.
Após a chamada para validateDisplay
, o SurfaceFlinger chama
getChangedCompositionTypes
para saber se o HWC
quer que algum dos tipos de composição de camada seja alterado antes de realizar a
composição. Para aceitar as mudanças, o SurfaceFlinger chama
acceptDisplayChanges
.
Se alguma camada for marcada para composição do SurfaceFlinger, ele
a vai compor no buffer de destino. O SurfaceFlinger chama
setClientTarget
para fornecer o buffer à tela, para que o
buffer possa ser mostrado na tela ou composto com camadas que
não foram marcadas para a composição do SurfaceFlinger. Se nenhuma camada for marcada para
composição do SurfaceFlinger, o SurfaceFlinger vai ignorar a etapa de composição.
Por fim, o SurfaceFlinger chama presentDisplay
para informar
ao HWC que ele precisa concluir o processo de composição e mostrar o resultado final.
Várias telas
O Android 10 oferece suporte a várias telas físicas. Ao projetar uma implementação de HWC destinada ao uso no Android 7.0 e versões mais recentes, há algumas restrições que não estão presentes na definição de HWC:
- Supõe-se que há exatamente uma tela interna. A tela interna é a que o hotplug inicial informa durante a inicialização. Depois que a tela interna é conectada, ela não pode ser desconectada.
- Além da tela interna, qualquer número de telas externas pode ser conectado e desconectado
durante a operação normal do dispositivo. O framework pressupõe que todos
os hotplugs após a primeira tela interna são externos. Portanto, se mais
telas internas forem adicionadas, elas serão categorizadas incorretamente como
Display.TYPE_HDMI
em vez deDisplay.TYPE_BUILT_IN
.
Embora as operações do SurfaceFlinger descritas acima sejam realizadas por tela, elas são realizadas sequencialmente para todas as telas ativas, mesmo que o conteúdo de apenas uma tela seja atualizado.
Por exemplo, se a tela externa for atualizada, 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 tela virtual
A composição de tela virtual é semelhante à composição de tela externa. A diferença entre a composição de tela virtual e a composição de tela física é que as telas virtuais enviam a saída para um buffer Gralloc em vez de para a tela. O compositor de hardware (HWC) grava a saída em um buffer, fornece a cerca de conclusão e envia o buffer para um consumidor, como o codificador de vídeo, a GPU, a CPU etc. As telas virtuais podem usar 2D/blitter ou sobreposições se o pipeline de exibição for gravado na memória.
Modos
Cada frame está em um dos três modos depois que o SurfaceFlinger chama o
método HWC validateDisplay()
:
- GLES: a GPU combina 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 modo:
- Modo GLES: o driver EGL define o formato do buffer de saída
em
dequeueBuffer()
, geralmenteRGBA_8888
. O consumidor precisa 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, ele definirá o formato. Caso contrário, o formato é
IMPLEMENTATION_DEFINED
, e o Gralloc define o melhor formato com base nas flags 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 de maneira eficiente.
Cercas de sincronização
As 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 de forma independente do trabalho da GPU simultâneo, bloqueando apenas quando há uma dependência real.
Por exemplo, quando um app envia um buffer que está sendo produzido na GPU, ele também envia um objeto de cerca de sincronização. Essa cerca sinaliza quando a GPU terminou de gravar no buffer.
O HWC exige que a GPU termine de gravar buffers antes que eles sejam exibidos. As cercas de sincronização são transmitidas pelo pipeline gráfico com buffers e sinalizam quando os buffers são gravados. Antes que um buffer seja mostrado, o HWC verifica se a cerca de sincronização sinalizou e, se sim, exibe o buffer.
Para mais informações sobre limites de sincronização, consulte Integração do Hardware Composer.