Camadas e telas

Camadas e exibições são duas primitivas que representam o trabalho de composição e as 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 tem 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 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 de 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.

Displays

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. 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 , cujos conteúdos são renderizados em um buffer fora da tela em vez de em uma exibição física.

Visores virtuais

O SurfaceFlinger oferece suporte a um monitor interno (embutido no telefone ou tablet), monitores externos (como uma televisão conectada por HDMI) e um ou mais monitores virtuais que disponibilizam a saída composta no sistema. Displays virtuais podem ser usados ​​para gravar a tela ou enviar a tela através de 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.

Em 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 sem suporte, 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 em disco. Para implementar isso, o sistema recebe quadros compostos do SurfaceFlinger, os grava 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 com eficiência é 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 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 para screenrecord como uma superfície.

O utilitário screenrecord pede ao SurfaceFlinger para criar uma exibição virtual que espelhe a exibição 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 em vez do consumidor.

Após a conclusão da configuração, 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 mediaserver . Os quadros completos nunca são vistos pelo processo 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 exibições secundárias

O WindowManager pode pedir ao SurfaceFlinger para criar uma camada visível para a qual o SurfaceFlinger atua como o consumidor BufferQueue. Também é possível pedir ao SurfaceFlinger para criar uma exibição virtual, para a qual o SurfaceFlinger atua como o produtor do BufferQueue.

Se você conectar uma exibição 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 as exibições secundárias em ação, use screenrecord para capturar o ato de habilitar a exibição e, em seguida, reproduza-o quadro a quadro.