Fluxo Completo de Distribuição e Escuta do VSYNC
O VSYNC pode ser gerado pelo Hardware Composer (HWC) ou por software, com uma thread emitiendo sinais em intervalos regulares (por exemplo, a cada 16 milissegundos). Desvios são usados para permitir trabalho assíncrono entre SurfaceFlinger (SF) e aplicativos, implementando um pipeline em dois estágios.
Aplicativos solicitam VSYNC ao EventThread, indicando necessidade, e entram em dormência. Quando o EventThread recebe o sinal de hardware ou software, notifica o aplicativo, que inicia a renderização de uma nova interface. SF funciona de maneira similar, iniciando a composição após receber o sinal.
Se o tempo de renderização do aplicativo for longo, normalmente ele solicita o próximo VSYNC ao SF após concluir, garantindo que o conteúdo renderizado seja exibido no próximmo frame, mesmo que não se enquadre no atual.
Estruturas de Dados
// Exemplo simplificado de estruturas para VSYNC
struct SinalVSync {
int64_t timestamp;
int contador;
};
class GerenciadorEventos {
private:
std::vector<conexao_ptr> conexoes;
std::mutex trava;
public:
void adicionarConexao(conexao_ptr con);
void distribuirSinal(SinalVSync sinal);
};
</conexao_ptr>
Inicialização do VSYNC
// Inicialização principal
1. Criação do SurfaceFlinger (SF)
- Em SurfaceFlinger.cpp: onFirstRef() inicializa a fila de mensagens.
- MessageQueue.cpp: cria Looper e Handler.
2. SF->init()
- Cria threads para app e SF usando DispSyncSource.
- Exemplo: mFonteThreadApp = nova FonteDispSync(DispSync, "app");
- Cria EventThread para gerenciar mudanças: mThreadEventos = nova EventThread(mFonteThreadApp.get(), "threadEventosApp");
- Similar para SF: mFonteThreadSF = nova FonteDispSync(DispSync, "sf");
- Estabelece conexões via MessageQueue.cpp, adicionando descritores de arquivo para comunicação com Looper.
- Cria HWComposer para gerenciar VSYNC.
3. SF->run()
- Loop principal: waitForEvent() aguarda sinais, usando mFilaEventos->esperarMensagem().
4. HWC vs. HWC2
- HWC1 usado em versões anteriores ao Android 9; HWC2 nas versões recentes.
- VSyncThread (para HWC1): thread dedicada para gerar VSYNC de software.
- HwcVsync: cria thread via pthread_create para gerar sinais.
5. Inicialização do EventThread
- Inicia thread com std::thread(&EventThread::principalThread, this).
Uso do VSYNC pelo SurfaceFlinger
1. Aplicativo notifica SF para atualização
- Em BufferLayer.cpp: mCompositor->sinalizarAtualizacaoCamada();
- MessageQueue.cpp: mFilaEventos->invalidar(); solicita próximo VSYNC.
- EventThread.cpp: mThreadEventos->solicitarProximoVSync(this); acorda thread.
- SF->run() chama waitForEvent(), que usa mLooper->pollOnce(-1) para aguardar.
- Quando Looper dispara, callback cb_receptorEvento é chamado, levando a despacho de invalidação e tratamento em SurfaceFlinger.cpp.
2. Loop principal do EventThread
- Em EventThread.cpp: threadPrincipal() aguarda eventos, distribuindo para conexões registradas.
- Usa mCanal para enviar sinais via descritor de arquivo, acordando SF.
3. Loop do DispSync
- DispSync.cpp: calcula próximo evento, coleta callbacks, e dispara notificações.
- SurfaceFlinger.cpp recebe callbacks e acorda EventThread.
4. Recebimento de VSYNC do HWC
- SurfaceFlinger::aoReceberVSync() é chamado quando HWC gera sinal.
- HWComposer.cpp consulta VSYNC e atualiza modelo em DispSync, acordando thread.
Processamento de VSYNC pelo SurfaceFlinger
Transações Processadas
SF gerencia camadas (adição, atualização de conteúdo, mudanças de propriedades) e displays (adição ou remoção).
Estruturas de Dados Importantes
1. SurfaceFlinger
- Contém estados: mCurrentEstado e mDesenhoEstado, cada um com vetores de camadas e estados de display.
2. DisplayDeviceState
- Estrutura para estado do display, incluindo ID, tipo e superfície de buffer.
3. Camada
- Classe com estado interno, como layerStack para identificar display associado.
Funções de Processamento Principais
1. Ponto de entrada: aoReceberMensagem() em SurfaceFlinger.cpp.
- Sinaliza atualização de camada se frame perdido.
- Processa transações, invalidações e refresh.
2. ProcessarTransacoes()
- Coleta flags de transação, atualiza regiões visíveis, e comete mudanças.
3. ProcessarInvalidacao()
- Prepara novos dados de buffer: camadas enfileiradas são verificadas, buffers travados e atualizados via consumidores de buffer.
4. SinalizarRefresh()
- Envia mensagem de refresh para síntese final.
Introdução a Regiões
Em SurfaceFlinger, uma região representa uma área composta por retângulos (Rects), usada para otimizar síntese. Propriedades incluem opaca, transparente ou translúcida. Operações como interseção e subtração combinam retângulos.
// Exemplo de operações em regiões
enum Operacao {
op_nand = operador_regiao<rect>::op_nand,
op_and = operador_regiao<rect>::op_and,
op_or = operador_regiao<rect>::op_or,
op_xor = operador_regiao<rect>::op_xor
};
class Regiao {
private:
std::vector<rect> armazenamento;
public:
Regiao intersecao(const Rect& rhs) const;
Regiao subtrair(const Rect& rhs) const;
};
</rect></rect></rect></rect></rect>
T-Junctions são artefatos gráficos tratados por funções como criarRegiaoSemJuncaoT().
reconstruirPilhasCamadas
Esta função reconstrói a lista de camadas visíveis por display, determinando visibilidade e ordem para síntese. É acionada quando mRegioesSujas é definido devido a mudanças em camadas ou displays.
// Pseudo-código
reconstruirPilhasCamadas() {
Regiao regiaoOpaca;
Regiao regiaoSujas;
for (display : displaysValidos) {
computarRegioesVisiveis(display, regiaoSujas, regiaoOpaca);
// Atualiza lista ordenada de camadas visíveis
// Destroi camadas invisíveis se necessário
}
// Define regiões no display para uso posterior
}
O algoritmo percorre camadas de cima para baixo, calculando regiões visíveis, opacas, cobertas e sujas para otimizar a síntese, minimizando área de redenho.