O Google tem o compromisso de promover a igualdade racial para as comunidades negras. Saiba como.

Estrutura de sincronização

A estrutura de sincronização descreve explicitamente as dependências entre diferentes operações assíncronas no sistema gráfico Android. A estrutura fornece uma API que permite aos componentes indicar quando os buffers são liberados. A estrutura também permite que os primitivos de sincronização sejam passados ​​entre os drivers do kernel para o espaço do usuário e entre os próprios processos do espaço do usuário.

Por exemplo, um aplicativo pode enfileirar o trabalho a ser executado na GPU. A GPU começa a desenhar essa imagem. Embora a imagem não tenha sido desenhada na memória ainda, o ponteiro do buffer é passado para o compositor da janela junto com uma cerca que indica quando o trabalho da GPU terminará. O compositor da janela começa o processamento antecipadamente e passa o trabalho para o controlador de exibição. De maneira semelhante, o trabalho da CPU é feito com antecedência. Assim que a GPU termina, o controlador de vídeo exibe imediatamente a imagem.

A estrutura de sincronização também permite que os implementadores aproveitem os recursos de sincronização em seus próprios componentes de hardware. Por fim, a estrutura fornece visibilidade do pipeline de gráficos para ajudar na depuração.

Sincronização explícita

A sincronização explícita permite que produtores e consumidores de buffers gráficos sinalizem quando terminarem de usar um buffer. A sincronização explícita é implementada no espaço do kernel.

Os benefícios da sincronização explícita incluem:

  • Menor variação de comportamento entre dispositivos
  • Melhor suporte de depuração
  • Métricas de teste aprimoradas

A estrutura de sincronização tem três tipos de objeto:

  • sync_timeline
  • sync_pt
  • sync_fence

sync_timeline

sync_timeline é um cronograma monotonicamente crescentes de que os fornecedores devem implementar para cada instância do controlador, tal como um contexto GL, controlador de visualização, ou blitter 2D. sync_timeline empregos contagens submetido ao kernel para uma determinada peça de hardware. sync_timeline fornece garantias sobre a ordem das operações e permite implementações específicas do hardware.

Siga estas diretrizes ao implementar sync_timeline :

  • Fornece nomes úteis para todos os drivers, cronogramas e cercas para simplificar a depuração.
  • Implementar o timeline_value_str e pt_value_str operadores em cronogramas para fazer a depuração de saída mais legível.
  • Implementar o preenchimento driver_data para dar espaço do usuário bibliotecas, como a biblioteca GL, o acesso aos dados cronograma privadas, se desejado. data_driver permite que fornecedores de passar informações sobre o imutável sync_fence e sync_pts a linhas de comando de compilação com base nelas.
  • Não permita que o espaço do usuário crie ou sinalize explicitamente uma cerca. A criação explícita de sinais / cercas resulta em um ataque de negação de serviço que interrompe a funcionalidade do pipeline.
  • Não acesse sync_timeline , sync_pt , ou sync_fence elementos explicitamente. A API fornece todas as funções necessárias.

sync_pt

sync_pt é um valor único ou ponto em um sync_timeline . Um ponto tem três estados: ativo, sinalizado e erro. Os pontos começam no estado ativo e fazem a transição para os estados sinalizado ou de erro. Por exemplo, quando um consumidor imagem já não precisa de um tampão, um sync_pt é sinalizado por isso um produtor de imagem sabe que não há problema em escrever para o buffer novamente.

sync_fence

sync_fence é uma coleção de sync_pt valores que muitas vezes têm diferentes sync_timeline pais (como para o controlador de vídeo e GPU). sync_fence , sync_pt e sync_timeline são os principais primitivas que os motoristas e utilização do espaço do usuário para se comunicar suas dependências. Quando um fence torna-se sinalizado, todos os comandos emitidos antes do fence são garantidos como completos porque o driver do kernel ou bloco de hardware executa os comandos em ordem.

A estrutura de sincronização permite que vários consumidores ou produtores sinalizem quando terminarem de usar um buffer, comunicando as informações de dependência com um parâmetro de função. Fences são apoiados por um descritor de arquivo e são passados ​​do espaço do kernel para o espaço do usuário. Por exemplo, uma cerca pode conter dois sync_pt valores significam que quando dois consumidores de imagens separadas são feitas lendo um tampão. Quando a cerca é sinalizada, os produtores de imagens sabem que os dois consumidores já estão consumindo.

Cercas, como sync_pt valores, comece estado ativo e mudança com base no estado de seus pontos. Se todos os sync_pt valores tornam-se sinalizado, o sync_fence se torna sinalizado. Se um sync_pt cai em um estado de erro, toda a sync_fence tem um estado de erro.

Participação em um sync_fence é imutável depois da cerca é criado. Para obter mais de um ponto em uma cerca, uma fusão é conduzida onde pontos de duas cercas distintas são adicionados a uma terceira cerca. Se um desses pontos foi sinalizado na cerca de origem e o outro não, a terceira cerca também não estará em um estado sinalizado.

Para implementar a sincronização explícita, forneça o seguinte:

  • Um subsistema de espaço do kernel que implementa a estrutura de sincronização para um driver de hardware específico. Os drivers que precisam estar cientes de cerca geralmente são qualquer coisa que acessa ou se comunica com o Hardware Composer. Os arquivos principais incluem:
    • Implementação central:
      • kernel/common/include/linux/sync.h
      • kernel/common/drivers/base/sync.c
    • Documentação no kernel/common/Documentation/sync.txt
    • Biblioteca para se comunicar com o espaço de kernel na platform/system/core/libsync
  • O vendedor deve fornecer as cercas de sincronização apropriados como parâmetros para a validateDisplay() e presentDisplay() funções no HAL.
  • Duas extensões relacionadas com cerca GL ( EGL_ANDROID_native_fence_sync e EGL_ANDROID_wait_sync ) e apoio a cerca no driver gráfico.

Estudo de caso: Implementando um driver de vídeo

Para usar a API que suporta a função de sincronização, desenvolva um driver de vídeo que tenha uma função de buffer de vídeo. Antes existia a estrutura de sincronização, esta função receberia dma-buf objetos, colocar os buffers no visor, e bloco enquanto o tampão era visível. Por exemplo:

/*
 * assumes buffer is ready to be displayed.  returns when buffer is no longer on
 * screen.
 */
void display_buffer(struct dma_buf *buffer);

Com o quadro de sincronização, o display_buffer função é mais complexa. Ao colocar um buffer em exibição, o buffer é associado a uma cerca que indica quando o buffer estará pronto. Você pode fazer fila e iniciar o trabalho depois que a cerca for limpa.

Enfileirar e iniciar o trabalho depois que a cerca for limpa não bloqueia nada. Você imediatamente devolve sua própria cerca, o que garante quando o buffer estará fora da tela. Conforme você enfileira os buffers, o kernel lista as dependências com a estrutura de sincronização:

/*
 * displays buffer when fence is signaled.  returns immediately with a fence
 * that signals when buffer is no longer displayed.
 */
struct sync_fence* display_buffer(struct dma_buf *buffer, struct sync_fence
*fence);

Integração de sincronização

Esta seção explica como integrar a estrutura de sincronização do espaço do kernel com as partes do espaço do usuário da estrutura do Android e os drivers que devem se comunicar uns com os outros. Os objetos do espaço do kernel são representados como descritores de arquivo no espaço do usuário.

Convenções de integração

Siga as convenções de interface do Android HAL:

  • Se a API fornece um descritor de arquivo que se refere a um sync_pt , motorista do fornecedor ou o HAL usando a API deve fechar o descritor de arquivo.
  • Se o motorista fornecedor ou o HAL passa um descritor de arquivo que contém um sync_pt para uma função API, o motorista fornecedor ou o HAL não perto deve o descritor de arquivo.
  • Para continuar usando o descritor de arquivo fence, o driver do fornecedor ou o HAL deve duplicar o descritor.

Um objeto fence é renomeado toda vez que passa por BufferQueue. Apoio cerca Kernel permite cercas de ter cordas para nomes, de modo que o Sync Framework usa o nome da janela e buffer de índice que está sendo enfileiradas para nomear o cerca, como SurfaceView:0 . Isso é útil na depuração para identificar a origem de um impasse como os nomes aparecem na saída de /d/sync relatórios e bugs.

Integração ANativeWindow

ANativeWindow está ciente da cerca. dequeueBuffer , queueBuffer e cancelBuffer ter parâmetros da cerca.

Integração OpenGL ES

A integração de sincronização do OpenGL ES depende de duas extensões EGL:

  • EGL_ANDROID_native_fence_sync fornece uma maneira de envolver ou criar descritores de arquivos cerca Android nativas em EGLSyncKHR objetos.
  • EGL_ANDROID_wait_sync permite GPU-side bancas ao invés de CPU-side, tornando a espera GPU para EGLSyncKHR . O EGL_ANDROID_wait_sync extensão é o mesmo que o EGL_KHR_wait_sync extensão.

Para usar essas extensões de forma independente, implementar o EGL_ANDROID_native_fence_sync extensão juntamente com o suporte do kernel associado. Em seguida, permitir que o EGL_ANDROID_wait_sync extensão no seu driver. O EGL_ANDROID_native_fence_sync extensão consiste num nativa distinta cerca EGLSyncKHR tipo de objecto. Como resultado, as extensões que se aplicam aos existentes EGLSyncKHR tipos de objetos não se aplicam necessariamente a EGL_ANDROID_native_fence objetos, evitando interações indesejáveis.

O EGL_ANDROID_native_fence_sync extensão emprega um atributo de descritor de arquivo cerca nativa correspondente que pode ser definido apenas no momento da criação e não pode ser directamente consultado a frente de um objeto de sincronização existente. Este atributo pode ser definido para um dos dois modos:

  • Um descritor de arquivo de cerca válido envolve um descritor de arquivo cerca existente nativo Android em uma EGLSyncKHR objeto.
  • -1 cria um descritor de arquivo cerca Android nativo de um EGLSyncKHR objeto.

Use o DupNativeFenceFD() chamada de função para extrair o EGLSyncKHR objeto do descritor de arquivo cerca Android nativo. Isso tem o mesmo resultado que consultar o atributo definido, mas segue a convenção de que o destinatário fecha a cerca (daí a operação duplicada). Finalmente, destruindo o EGLSyncKHR objecto fecha o atributo cerca interno.

Integração do Hardware Composer

O Hardware Composer lida com três tipos de barreiras de sincronização:

  • Cercas Adquirir são transmitidos juntamente com tampões de entrada para os setLayerBuffer e setClientTarget chamadas. Eles representam uma gravação pendente no buffer e devem sinalizar antes que o SurfaceFlinger ou o HWC tente ler do buffer associado para realizar a composição.
  • Cercas de libertação são recuperados após a chamada para presentDisplay usando o getReleaseFences chamada. Eles representam uma leitura pendente do buffer anterior na mesma camada. Um limite de liberação sinaliza quando o HWC não está mais usando o buffer anterior porque o buffer atual substituiu o buffer anterior na tela. As barreiras de liberação são passadas de volta ao aplicativo junto com os buffers anteriores que serão substituídos durante a composição atual. O aplicativo deve esperar até que um limite de liberação sinalize antes de gravar novos conteúdos no buffer que foi retornado a eles.
  • Cercas presentes são devolvidos, um por quadro, como parte da chamada para presentDisplay . As cercas atuais representam quando a composição deste quadro foi concluída, ou alternativamente, quando o resultado da composição do quadro anterior não é mais necessário. Para demonstrações físicas, presentDisplay retorna cercas presentes quando o quadro atual é exibida na tela. Depois que os limites atuais forem retornados, é seguro gravar no buffer de destino do SurfaceFlinger novamente, se aplicável. Para monitores virtuais, as barreiras presentes são retornadas quando é seguro ler do buffer de saída.