Camadas e telas são duas primitivas que representam o trabalho de composição e as interações com o hardware da tela.
Camadas
Uma camada é a unidade de composição mais importante. Uma camada é uma combinação de uma superfície e uma instância de SurfaceControl
. Cada camada possui um conjunto de propriedades que definem como ela interage com outras camadas. As propriedades da camada são descritas na tabela abaixo.
Propriedade | Descrição |
---|---|
Posicional | Define onde a camada aparece em sua exibição. Inclui informações como as posições das bordas de uma camada e sua ordem Z em relação a outras camadas (se deve estar na frente ou atrás de outras camadas). |
Contente | Define como o conteúdo exibido na camada deve ser apresentado dentro dos limites definidos pelas propriedades posicionais. Inclui informações como cortar (para expandir uma parte do conteúdo para preencher os limites da camada) e transformar (para mostrar o conteúdo girado ou invertido). |
Composição | Define como a camada deve ser composta com outras camadas. Inclui informações como modo de mesclagem e um valor alfa em toda a camada para composição alfa . |
Otimização | Fornece informações não estritamente necessárias para compor corretamente a camada, mas que podem ser usadas pelo dispositivo Hardware Composer (HWC) para otimizar como ele executa a composição. Inclui informações como a região visível da camada e qual parte da camada foi atualizada desde o quadro anterior. |
Exibe
Um display é outra importante unidade de composição. Um sistema pode ter vários monitores e os monitores podem ser adicionados ou removidos durante as operações normais do sistema. Os displays são adicionados/removidos a pedido do HWC ou a pedido da estrutura. O dispositivo HWC solicita que os displays sejam adicionados ou removidos quando um display externo é conectado ou desconectado do dispositivo, o que é chamado de hotplugging . Os clientes solicitam exibições virtuais , cujos conteúdos são renderizados em um buffer fora da tela em vez de em uma exibição física.
Exibições virtuais
O SurfaceFlinger suporta um monitor interno (integrado no telefone ou tablet), monitores externos (como uma televisão conectada através de HDMI) e um ou mais monitores virtuais que disponibilizam a saída composta no sistema. Os monitores virtuais podem ser usados para gravar a tela ou enviar a tela por uma rede. Os quadros gerados para uma exibição virtual são gravados em um BufferQueue.
As telas virtuais podem compartilhar o mesmo conjunto de camadas da tela principal (a pilha de camadas) ou ter seu próprio conjunto. Não há VSYNC para um display virtual, então o VSYNC para o display interno aciona a composição de todos os displays.
Nas implementações de HWC que os suportam, as exibições virtuais podem ser compostas com OpenGL ES (GLES), HWC ou GLES e HWC. Em implementações não compatíveis, as exibições virtuais são sempre compostas usando GLES.
Estudo de caso: registro de tela
O comando screenrecord
permite ao usuário gravar tudo o que aparece na tela como um arquivo .mp4
no disco. Para implementar isso, o sistema recebe quadros compostos do SurfaceFlinger, grava-os no codificador de vídeo e, em seguida, grava os dados de vídeo codificados em um arquivo. Os codecs de vídeo são gerenciados por um processo separado ( mediaserver
), portanto, grandes buffers gráficos precisam se mover pelo sistema. Para torná-lo mais desafiador, o objetivo é gravar vídeo de 60 fps em resolução máxima. A chave para fazer isso funcionar de forma eficiente é o BufferQueue.
A classe MediaCodec
permite que um aplicativo forneça dados como bytes brutos em buffers ou por meio de uma superfície. Quando o screenrecord
solicita acesso a um codificador de vídeo, o processo mediaserver
cria um BufferQueue, conecta-se ao lado do consumidor e passa o lado do produtor de volta ao screenrecord
como uma superfície.
O utilitário screenrecord
então pede ao SurfaceFlinger para criar uma tela virtual que espelhe a tela principal (ou seja, tem todas as mesmas camadas) e a direciona para enviar saída para a superfície que veio do processo mediaserver
. Nesse caso, o SurfaceFlinger é o produtor de buffers e não o consumidor.
Após a conclusão da configuração, o registro de screenrecord
é acionado quando os dados codificados aparecem. À medida que os aplicativos desenham, seus buffers viajam para o SurfaceFlinger, que os compõe em um único buffer que é enviado diretamente ao codificador de vídeo no processo do mediaserver
de mídia. Os quadros completos nunca são vistos pelo processo de screenrecord
de tela. Internamente, o processo mediaserver
tem sua própria maneira de mover buffers que também passa dados por handle, minimizando a sobrecarga.
Estudo de caso: simular telas secundárias
O WindowManager pode pedir ao SurfaceFlinger para criar uma camada visível para a qual o SurfaceFlinger atua como consumidor do BufferQueue. Também é possível pedir ao SurfaceFlinger para criar um display virtual, para o qual o SurfaceFlinger atua como produtor do BufferQueue.
Se você conectar uma tela virtual a uma camada visível, um loop fechado será criado onde a tela composta aparece em uma janela. Essa janela agora faz parte da saída composta, portanto, na próxima atualização, a imagem composta dentro da janela também mostra o conteúdo da janela. Para ver isso em ação, ative as opções do desenvolvedor em Configurações , selecione Simular exibições secundárias e ative uma janela. Para ver os monitores secundários em ação, use o screenrecord
de tela para capturar o ato de habilitar o monitor e reproduzi-lo quadro a quadro.