Camadas e exibições são duas primitivas que representam trabalho de composição e interações com o hardware de exibição.
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 estã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 deveria 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 a forma 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. |
Exibições
Um display é outra unidade importante 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. As exibições são adicionadas/removidas a pedido do HWC ou a pedido da estrutura. O dispositivo HWC solicita que os monitores sejam adicionados ou removidos quando um monitor externo é conectado ou desconectado do dispositivo, o que é chamado de hotplugging . Os clientes solicitam exibições virtuais , cujo conteúdo é renderizado em um buffer fora da tela, em vez de em uma exibição física.
Exibições virtuais
SurfaceFlinger oferece suporte a um monitor interno (integrado ao telefone ou tablet), monitores externos (como uma televisão conectada via HDMI) e um ou mais monitores virtuais que disponibilizam saída composta no sistema. Exibições virtuais podem ser usadas para gravar a tela ou enviá-la por uma rede. Os quadros gerados para uma exibição virtual são gravados em um BufferQueue.
As exibições virtuais podem compartilhar o mesmo conjunto de camadas que a exibição 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 para todos os displays.
Nas implementações de HWC que os suportam, os displays virtuais podem ser compostos com OpenGL ES (GLES), HWC ou GLES e HWC. Em implementações sem suporte, 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 qps em resolução máxima. A chave para fazer isso funcionar de forma eficiente é BufferQueue.
A classe MediaCodec
permite que um aplicativo forneça dados como bytes brutos em buffers ou por meio de uma superfície. Quando screenrecord
solicita acesso a um codificador de vídeo, o processo mediaserver
cria um BufferQueue, conecta-se ao lado do consumidor e, em seguida, passa o lado do produtor de volta ao screenrecord
como uma superfície.
O utilitário screenrecord
então pede ao SurfaceFlinger para criar um display virtual que espelhe o display principal (ou seja, tem todas as mesmas camadas) e o direciona para enviar a saída para a superfície que veio do processo mediaserver
. Nesse caso, SurfaceFlinger é o produtor de buffers e não o consumidor.
Após a conclusão da configuração, screenrecord
é acionado quando os dados codificados aparecem. À medida que os aplicativos são desenhados, seus buffers viajam para o SurfaceFlinger, que os compõe em um único buffer que é enviado diretamente ao codificador de vídeo no processo mediaserver
. Os quadros completos nunca são vistos pelo processo de screenrecord
. Internamente, o processo mediaserver
tem sua própria maneira de mover buffers, que também passa dados por identificador, minimizando a sobrecarga.
Estudo de caso: simular monitores secundários
O WindowManager pode pedir ao SurfaceFlinger para criar uma camada visível para a qual o SurfaceFlinger atua como consumidor 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 exibição virtual a uma camada visível, um loop fechado será criado onde a tela composta aparecerá 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 monitores secundários e ative uma janela. Para ver exibições secundárias em ação, use screenrecord
para capturar o ato de ativar a exibição e reproduza-o quadro a quadro.