Implementa la HAL de Hardware Composer

La HAL de Hardware Composer (HWC) compone las capas que recibe de SurfaceFlinger, lo que reduce la cantidad de composición que realizan OpenGL ES (GLES) y la GPU.

El HWC abstrae objetos, como superposiciones y blitters 2D, para componer superficies y se comunica con hardware especializado de composición de ventanas para componer ventanas. Usar el HWC para componer ventanas en lugar de que SurfaceFlinger realice la composición con la GPU La mayoría de las GPUs no están optimizadas para la composición, y cuando la GPU compone capas de SurfaceFlinger, las apps no pueden usar la GPU para su propia renderización.

Las implementaciones de HWC deben admitir lo siguiente:

  • Al menos cuatro superposiciones:
    • Barra de estado
    • Barra del sistema
    • App
    • Fondo de pantalla o fondo
  • Capas más grandes que la pantalla (por ejemplo, un fondo de pantalla)
  • Composición alfa simultánea premultiplicada por píxel y por plano
  • Ruta de hardware para la reproducción de video protegido
  • Orden de empaquetado RGBA, formatos YUV y propiedades de mosaicos, swizzling y stride

Para implementar el HWC, haz lo siguiente:

  1. Implementa un HWC no operativo y envía todo el trabajo de composición a GLES.
  2. Implementa un algoritmo para delegar la composición en el HWC de forma incremental. Por ejemplo, delega solo las primeras tres o cuatro superficies al hardware de superposición del HWC.
  3. Optimiza el HWC. Esto puede incluir lo siguiente:
    • Seleccionar las superficies que maximizan la carga que se quita de la GPU y enviarlas al HWC
    • Detectar si la pantalla se está actualizando De lo contrario, delega la composición a GLES en lugar de a HWC para ahorrar energía. Cuando la pantalla se actualice de nuevo, continúa con la descarga de la composición en el HWC.
    • Preparación para casos de uso comunes, como los siguientes:
      • La pantalla principal, que incluye la barra de estado, la barra del sistema, la ventana de la app y los fondos de pantalla animados
      • Juegos en pantalla completa en modo horizontal y vertical
      • Video en pantalla completa con subtítulos y control de reproducción
      • Reproducción de videos protegidos
      • Multiventana en pantalla dividida

Primitivas de HWC

El HWC proporciona dos elementos primitivos, capas y pantallas, para representar el trabajo de composición y su interacción con el hardware de la pantalla. El HWC también proporciona control sobre VSync y una devolución de llamada a SurfaceFlinger para notificarlo cuando se produce un evento de VSync.

Interfaz de HIDL

Android 8.0 y versiones posteriores usan una interfaz de HIDL llamada HAL de Composer para la IPC vinculada entre HWC y SurfaceFlinger. El HAL de Composer reemplaza la interfaz hwcomposer2.h heredada. Si los proveedores proporcionan una implementación de la HAL de Composer del HWC, la HAL de Composer acepta directamente las llamadas de HIDL desde SurfaceFlinger. Si los proveedores proporcionan una implementación heredada del HWC, el HAL de Composer carga punteros de función desde hwcomposer2.h y reenvía las llamadas a HIDL a llamadas de punteros de función.

El HWC proporciona funciones para determinar las propiedades de una pantalla determinada, cambiar entre diferentes configuraciones de pantalla (como la resolución 4K o 1080p) y modos de color (como el color nativo o sRGB verdadero), y encender, apagar o poner en modo de bajo consumo la pantalla si es compatible.

Punteros de función

Si los proveedores implementan el HAL de Composer directamente, SurfaceFlinger llama a sus funciones a través de la IPC de HIDL. Por ejemplo, para crear una capa, SurfaceFlinger llama a createLayer() en el HAL de Composer.

Si los proveedores implementan la interfaz hwcomposer2.h, el HAL de Composer llama a los punteros de función hwcomposer2.h. En los comentarios de hwcomposer2.h, se hace referencia a las funciones de la interfaz de HWC con nombres en lowerCamelCase que no existen en la interfaz como campos con nombre. Casi todas las funciones se cargan solicitando un puntero de función con getFunction proporcionado por hwc2_device_t. Por ejemplo, la función createLayer es un puntero de función de tipo HWC2_PFN_CREATE_LAYER, que se devuelve cuando el valor enumerado HWC2_FUNCTION_CREATE_LAYER se pasa a getFunction.

Para obtener documentación detallada sobre las funciones de la HAL de Composer y las funciones de transferencia de la función HWC, consulta composer. Para obtener documentación detallada sobre los punteros de funciones de HWC, consulta hwcomposer2.h.

Manijas de capas y visualización

Las capas y las pantallas se manipulan con identificadores generados por el HWC. Los identificadores son opacos para SurfaceFlinger.

Cuando SurfaceFlinger crea una capa nueva, llama a createLayer, que devuelve el tipo Layer para implementaciones directas o hwc2_layer_t para implementaciones de transferencia. Cuando SurfaceFlinger modifica una propiedad de esa capa, pasa el valor hwc2_layer_t a la función de modificación adecuada junto con cualquier otra información necesaria para realizar la modificación. El tipo hwc2_layer_t es lo suficientemente grande como para contener un puntero o un índice.

Las pantallas físicas se crean mediante la conexión en caliente. Cuando se conecta un monitor físico en caliente, el HWC crea un identificador y se lo pasa a SurfaceFlinger a través de la devolución de llamada de conexión en caliente. SurfaceFlinger crea pantallas virtuales llamando a createVirtualDisplay() para solicitar una pantalla. Si el HWC admite la composición de pantallas virtuales, devuelve un identificador. Luego, SurfaceFlinger delega la composición de las pantallas al HWC. Si el HWC no admite la composición de pantallas virtuales, SurfaceFlinger crea el identificador y compone la pantalla.

Operaciones de composición de la pantalla

Una vez por VSync, SurfaceFlinger se activa si tiene contenido nuevo para componer. Este contenido nuevo puede ser un búfer de imagen nuevo de las apps o un cambio en las propiedades de una o más capas. Cuando SurfaceFlinger lo activa, ocurre lo siguiente:

  1. Controla las transacciones, si están presentes.
  2. Se conecta a nuevos búferes gráficos, si están presentes.
  3. Realiza una nueva composición si el paso 1 o 2 generaron un cambio en el contenido de la pantalla.

Para realizar una composición nueva, SurfaceFlinger crea y destruye capas, o bien modifica los estados de las capas, según corresponda. También actualiza las capas con su contenido actual, mediante llamadas como setLayerBuffer o setLayerColor. Después de que se actualizan todas las capas, SurfaceFlinger llama a validateDisplay, que le indica al HWC que examine el estado de las capas y determine cómo se realizará la composición. De forma predeterminada, SurfaceFlinger intenta configurar cada capa de modo que el HWC la componga. Sin embargo, en algunas circunstancias, SurfaceFlinger compone capas a través de la GPU de respaldo.

Después de la llamada a validateDisplay, SurfaceFlinger llama a getChangedCompositionTypes para ver si el HWC desea que se cambie alguno de los tipos de composición de capas antes de realizar la composición. Para aceptar los cambios, SurfaceFlinger llama a acceptDisplayChanges.

Si alguna capa está marcada para la composición de SurfaceFlinger, SurfaceFlinger las compone en el búfer de destino. Luego, SurfaceFlinger llama a setClientTarget para darle el búfer a la pantalla, de modo que se pueda mostrar en ella o componer aún más con capas que no se hayan marcado para la composición de SurfaceFlinger. Si no se marca ninguna capa para la composición de SurfaceFlinger, SurfaceFlinger omite el paso de composición.

Por último, SurfaceFlinger llama a presentDisplay para indicarle al HWC que complete el proceso de composición y muestre el resultado final.

Varios anuncios gráficos

Android 10 admite varias pantallas físicas. Cuando diseñes una implementación de HWC para usar en Android 7.0 y versiones posteriores, ten en cuenta algunas restricciones que no están presentes en la definición de HWC:

  • Se supone que hay exactamente una pantalla interna. La pantalla interna es la que informa el hotplug inicial durante el arranque. Después de conectar la pantalla interna en caliente, no se puede desconectar.
  • Además de la pantalla interna, se puede conectar en caliente cualquier cantidad de pantallas externas durante el funcionamiento normal del dispositivo. El framework supone que todas las conexiones en caliente después de la primera pantalla interna son pantallas externas, por lo que, si se agregan más pantallas internas, se categorizan de forma incorrecta como Display.TYPE_HDMI en lugar de Display.TYPE_BUILT_IN.

Si bien las operaciones de SurfaceFlinger descritas anteriormente se realizan por pantalla, se ejecutan de forma secuencial para todas las pantallas activas, incluso si solo se actualiza el contenido de una pantalla.

Por ejemplo, si se actualiza la pantalla externa, la secuencia es la siguiente:

// In Android 9 and lower:

// Update state for internal display
// Update state for external display
validateDisplay(<internal display>)
validateDisplay(<external display>)
presentDisplay(<internal display>)
presentDisplay(<external display>)

// In Android 10 and higher:

// Update state for internal display
// Update state for external display
validateInternal(<internal display>)
presentInternal(<internal display>)
validateExternal(<external display>)
presentExternal(<external display>)

Composición de pantalla virtual

La composición de la pantalla virtual es similar a la composición de la pantalla externa. La diferencia entre la composición de pantallas virtuales y la composición de pantallas físicas es que las pantallas virtuales envían la salida a un búfer de Gralloc en lugar de a la pantalla. El Hardware Composer (HWC) escribe el resultado en un búfer, proporciona la barrera de finalización y envía el búfer a un consumidor (como el codificador de video, la GPU, la CPU, etcétera). Las pantallas virtuales pueden usar 2D/blitter o superposiciones si la canalización de pantalla escribe en la memoria.

Modos

Cada fotograma se encuentra en uno de los tres modos después de que SurfaceFlinger llama al método validateDisplay() de HWC:

  • GLES: La GPU compone todas las capas y escribe directamente en el búfer de salida. La HWC no participa en la composición.
  • MIXED: La GPU compone algunas capas en el búfer de fotogramas, y el HWC compone el búfer de fotogramas y las capas restantes, y escribe directamente en el búfer de salida.
  • HWC: HWC compone todas las capas y escribe directamente en el búfer de salida.

Formato de salida

Los formatos de salida del búfer de pantalla virtual dependen de su modo:

  • Modo GLES: El controlador de EGL establece el formato del búfer de salida en dequeueBuffer(), por lo general, RGBA_8888. El consumidor debe poder aceptar el formato de salida que establece el controlador, o no se podrá leer el búfer.
  • Modos MIXED y HWC: Si el consumidor necesita acceso a la CPU, establece el formato. De lo contrario, el formato es IMPLEMENTATION_DEFINED, y Gralloc establece el mejor formato según las marcas de uso. Por ejemplo, Gralloc establece un formato YCbCr si el consumidor es un codificador de video y HWC puede escribir el formato de manera eficiente.

Barreras de sincronización

Las barreras de sincronización (sync) son un aspecto fundamental del sistema de gráficos de Android. Las barreras permiten que el trabajo de la CPU continúe independientemente del trabajo simultáneo de la GPU, y solo se bloquean cuando hay una dependencia real.

Por ejemplo, cuando una app envía un búfer que se está produciendo en la GPU, también envía un objeto de barrera de sincronización. Esta barrera indica cuándo la GPU terminó de escribir en el búfer.

El HWC requiere que la GPU termine de escribir los búferes antes de que se muestren. Las barreras de sincronización se pasan a través de la canalización de gráficos con búferes y señales cuando se escriben los búferes. Antes de mostrar un búfer, el HWC verifica si la barrera de sincronización envió una señal y, si lo hizo, muestra el búfer.

Para obtener más información sobre las barreras de sincronización, consulta Integración de Hardware Composer.