A classe BufferQueue conecta componentes que geram buffers de dados gráficos ( produtores ) a componentes que aceitam os dados para exibição ou processamento posterior ( consumidores ). Quase tudo que move buffers de dados gráficos pelo sistema depende do BufferQueue.
O alocador de memória Gralloc executa alocações de buffer e é implementado por meio de duas interfaces HIDL específicas do fornecedor (consulte hardware/interfaces/graphics/allocator/
e hardware/interfaces/graphics/mapper/
). A função allocate()
recebe os argumentos esperados (largura, altura, formato de pixel), bem como um conjunto de sinalizadores de uso.
Produtores e consumidores do BufferQueue
Os consumidores criam e possuem a estrutura de dados BufferQueue e podem existir em processos diferentes dos seus produtores. Quando um produtor precisa de um buffer, ele solicita um buffer livre de BufferQueue chamando dequeueBuffer()
, especificando a largura, altura, formato de pixel e sinalizadores de uso dos buffers. O produtor então preenche o buffer e retorna o buffer para a fila chamando queueBuffer()
. Em seguida, o consumidor adquire o buffer com acquireBuffer()
e faz uso do conteúdo do buffer. Quando o consumidor termina, ele retorna o buffer para a fila chamando releaseBuffer()
. A estrutura de sincronização controla como os buffers se movem pelo pipeline gráfico do Android.
Algumas características do BufferQueue, como o número máximo de buffers que ele pode conter, são determinadas conjuntamente pelo produtor e pelo consumidor. No entanto, o BufferQueue aloca buffers conforme necessário. Os buffers são retidos a menos que as características mudem; por exemplo, se um produtor solicitar buffers com um tamanho diferente, os buffers antigos serão liberados e os novos buffers serão alocados sob demanda.
O conteúdo do buffer nunca é copiado pelo BufferQueue, pois mover tantos dados é ineficiente. Em vez disso, os buffers são sempre passados por um identificador.
Rastreando BufferQueue com Systrace
Para entender como os buffers gráficos se movem, use o Systrace , uma ferramenta que registra a atividade do dispositivo em um curto período de tempo. O código gráfico no nível do sistema é bem instrumentado, assim como grande parte do código da estrutura do aplicativo relevante.
Para usar o Systrace, ative as tags gfx
, view
e sched
. Os objetos BufferQueue são exibidos no rastreamento. Por exemplo, se você fizer um rastreamento enquanto o vídeo Play do Grafika (SurfaceView) estiver em execução, a linha rotulada SurfaceView informará quantos buffers foram enfileirados em um determinado momento.
O valor é incrementado enquanto o aplicativo está ativo, o que aciona a renderização de quadros pelo decodificador MediaCodec. O valor diminui enquanto SurfaceFlinger está trabalhando e consumindo buffers. Ao exibir vídeo a 30 fps, o valor da fila varia de 0 a 1 porque a tela de ~60 fps pode acompanhar a fonte. O SurfaceFlinger acorda apenas quando há trabalho a ser feito, não 60 vezes por segundo. O sistema tenta evitar o trabalho e desabilita o VSYNC se nada estiver atualizando a tela.
Se você alternar para o vídeo Play do Grafika (TextureView) e pegar um novo traço, verá uma linha rotulada com.android.grafika
/ com.android.grafika.PlayMovieActivity
. Esta é a camada principal da interface do usuário, que é outro BufferQueue. Como o TextureView é renderizado na camada da interface do usuário em vez de em uma camada separada, todas as atualizações orientadas por vídeo são exibidas aqui.
Gralloc
O alocador de HAL hardware/libhardware/include/hardware/gralloc.h
executa alocações de buffer por meio de sinalizadores de uso. Os sinalizadores de uso incluem atributos como:
- Com que frequência a memória será acessada a partir do software (CPU)
- Com que frequência a memória será acessada do hardware (GPU)
- Se a memória será usada como uma textura OpenGL ES (GLES)
- Se a memória será usada por um codificador de vídeo
Por exemplo, se o formato de buffer de um produtor especificar RGBA_8888
pixels e o produtor indicar que o buffer será acessado a partir do software (o que significa que um aplicativo tocará em pixels na CPU), Gralloc cria um buffer com 4 bytes por pixel na ordem RGBA. Se, em vez disso, um produtor especificar que seu buffer será acessado apenas do hardware e como uma textura GLES, o Gralloc poderá fazer qualquer coisa que o driver GLES desejar, como ordenação BGRA, layouts swizzled não lineares e formatos de cores alternativos. Permitir que o hardware use seu formato preferido pode melhorar o desempenho.
Alguns valores não podem ser combinados em determinadas plataformas. Por exemplo, o sinalizador do codificador de vídeo pode exigir pixels YUV, portanto, adicionar acesso ao software e especificar RGBA_8888
falhará.
O identificador retornado por Gralloc pode ser passado entre processos por meio do Binder.
Buffers protegidos
O sinalizador de uso GRALLOC_USAGE_PROTECTED
permite que o buffer gráfico seja exibido apenas por meio de um caminho protegido por hardware. Esses planos de sobreposição são a única maneira de exibir conteúdo DRM (buffers protegidos por DRM não podem ser acessados pelo SurfaceFlinger ou pelo driver OpenGL ES).
O vídeo protegido por DRM pode ser apresentado apenas em um plano de sobreposição. Os players de vídeo que oferecem suporte a conteúdo protegido devem ser implementados com SurfaceView. O software executado em hardware desprotegido não pode ler ou gravar o buffer; os caminhos protegidos por hardware devem aparecer na sobreposição do Hardware Composer (ou seja, os vídeos protegidos desaparecem da exibição se o Hardware Composer alternar para a composição OpenGL ES).
Para obter detalhes sobre conteúdo protegido, consulte DRM .