Camadas e telas

Camadas e telas são duas primitivas que representam o trabalho de composição e 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 tem um conjunto de propriedades que e como ele interage com outras camadas. As propriedades da camada são descritas na tabela abaixo.

Propriedade Descrição
Posicional Define onde a camada aparece na tela. Inclui informações como as posições das arestas de uma camada e sua ordem Z em relação a outras camadas (se deve estar na frente ou atrás outras camadas).
Conteúdo Define como o conteúdo exibido na camada deve ser apresentado. os limites definidos pelas propriedades posicionais. Inclui informações como como corte (para expandir uma parte do conteúdo e preencher os limites da camada) e transformar (para mostrar conteúdo girado ou invertido).
Composição Define como a camada precisa ser composta com outras camadas. Inclui informações como modo de mistura e um valor alfa em toda a camada para alfa composição.
Otimização Fornece informações que não são estritamente necessárias para compor corretamente a camada, mas que podem ser usadas pelo dispositivo Hardware Composer (HWC) para otimizar a composição. Inclui informações como região visível da camada e qual porção da camada foi atualizados desde o frame anterior.

Telas

Uma exibição é outra unidade importante de composição. Um sistema pode tiver várias telas e telas podem ser adicionadas ou removidas durante as operações normais do sistema. As telas são adicionadas/removidas a pedido do HWC ou do framework. O dispositivo HWC solicita que as telas sejam adicionadas ou removidas quando uma tela externa é conectada ou desconectada do dispositivo, o que é chamado de hotplugging. Os clientes solicitam telas virtuais, que têm o conteúdo são renderizados em um buffer fora da tela, e não em uma exibição física.

Telas virtuais

O SurfaceFlinger oferece suporte a uma tela interna (integrada ao smartphone ou tablet), telas externas (como uma TV conectada por HDMI) e uma ou mais telas virtuais que disponibilizam a saída composta no sistema. As telas virtuais podem ser usadas para gravar a tela ou enviá-la por uma rede. Frames gerados para exibição virtual são gravados em um BufferQueue.

As telas virtuais podem compartilhar o mesmo conjunto de camadas que a tela principal. (pilha de camadas) ou têm um conjunto próprio. Não há VSYNC para uma tela virtual, então o VSYNC para a tela interna aciona a composição para todos é exibido.

Em implementações HWC compatíveis, as telas podem ser compostas com OpenGL ES (GLES), HWC ou com GLES e HWC. Em implementações sem suporte, as telas virtuais são sempre compostas usando GLES.

Estudo de caso: screenrecord

O comando screenrecord permite que o usuário registre tudo o que aparece na tela como um arquivo .mp4 no disco. Para implementar isso, o sistema recebe frames 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, buffers gráficos grandes precisam se mover pelo sistema. Para tornar o desafio mais difícil, o objetivo é gravar vídeos de 60 qps na resolução máxima. A chave para fazer isso funcionar de maneira eficiente é a BufferQueue.

A classe MediaCodec permite que um app forneça dados como bytes brutos em buffers ou por uma superfície. Quando o screenrecord pedir acesso a um vídeo codificador, o processo mediaserver cria um BufferQueue, conecta o lado do produtor de volta para o lado do consumidor screenrecord como superfície.

O utilitário screenrecord pede ao SurfaceFlinger para criar um tela virtual que espelha a tela principal (ou seja, todos os mesmos elementos camadas) e a direciona para enviar a saída para a superfície de origem mediaserver. Nesse caso, o SurfaceFlinger é o produtor de buffers, e não o consumidor.

Depois que a configuração for concluída, screenrecord será acionado quando os dados codificados aparecerem. À medida que os apps são renderizados, os buffers são enviados para o SurfaceFlinger, que os combina em um único buffer enviado diretamente para o codificador de vídeo no processo mediaserver. Os frames completos nunca são identificados pelo processo screenrecord. Internamente, O processo mediaserver tem uma maneira própria de mover buffers também transmite dados por identificador, minimizando a sobrecarga.

Estudo de caso: simular telas secundárias

O WindowManager pode solicitar que o SurfaceFlinger crie uma camada visível para que o SurfaceFlinger atue como consumidor da BufferQueue. Também é possível pedir ao SurfaceFlinger para criar uma tela virtual, para a qual o SurfaceFlinger atua como produtor da BufferQueue.

Se você conectar uma tela virtual a uma camada visível, um loop fechado será criado em que a tela composta aparece em uma janela. Essa janela agora faz parte da saída composta. Assim, na próxima atualização, a imagem composta dentro da janela também mostra o conteúdo da janela. Para conferir isso em ação, ative as Opções do desenvolvedor nas Configurações, selecione Simular telas secundárias e ative uma janela. Para ver telas secundárias em ação, use screenrecord para capturar o ato de ativar a tela e reproduzi-la quadro por quadro.