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 realiza 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 argumentos esperados (largura, altura, formato de pixel), bem como um conjunto de sinalizadores de uso.
Produtores e consumidores de 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 o retorna para a fila chamando queueBuffer()
. Em seguida, o consumidor adquire o buffer com acquireBuffer()
e utiliza o 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 em conjunto 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 tamanho diferente, os buffers antigos serão liberados e 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.
Rastreie BufferQueue com Systrace
Para entender como os buffers gráficos se movimentam, use o Systrace , uma ferramenta que registra a atividade do dispositivo durante 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, habilite 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 chamada SurfaceView informa quantos buffers foram enfileirados em um determinado momento.
O valor aumenta enquanto o aplicativo está ativo, o que aciona a renderização de quadros pelo decodificador MediaCodec. O valor diminui enquanto o SurfaceFlinger está funcionando e consumindo buffers. Ao exibir vídeo a 30 fps, o valor da fila varia de 0 a 1 porque a exibição de ~60 fps pode acompanhar a fonte. O SurfaceFlinger é ativado apenas quando há trabalho a ser feito, e não 60 vezes por segundo. O sistema tenta evitar o trabalho e desabilita o VSYNC se nada estiver atualizando a tela.
Se você mudar para o Play video do Grafika (TextureView) e pegar um novo traço, você verá uma linha chamada com.android.grafika
/ com.android.grafika.PlayMovieActivity
. Esta é a camada principal da UI, que é outro BufferQueue. Como o TextureView é renderizado na camada de UI em vez de em uma camada separada, todas as atualizações baseadas em vídeo são exibidas aqui.
Gralloc
O alocador HAL hardware/libhardware/include/hardware/gralloc.h
Gralloc 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 pelo software (CPU)
- Com que frequência a memória será acessada pelo hardware (GPU)
- Se a memória será usada como 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 pelo software (o que significa que um aplicativo tocará pixels na CPU), Gralloc criará um buffer com 4 bytes por pixel na ordem RGBA. Se, em vez disso, um produtor especificar que seu buffer será acessado apenas pelo 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 de software e especificar RGBA_8888
falha.
O identificador retornado pelo Gralloc pode ser passado entre processos por meio do Binder.
Buffers protegidos
O sinalizador de uso Gralloc GRALLOC_USAGE_PROTECTED
permite que o buffer gráfico seja exibido apenas através 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 só pode ser apresentado em um plano de sobreposição. Os players de vídeo que oferecem suporte a conteúdo protegido devem ser implementados com o SurfaceView. O software executado em hardware desprotegido não consegue ler ou gravar no buffer; 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 .