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.