BufferQueue e Gralloc

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 .