Camadas e exibições

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.