Google se compromete a impulsar la igualdad racial para las comunidades afrodescendientes. Obtén información al respecto.

Marco de sincronización

El marco de sincronización describe explícitamente las dependencias entre diferentes operaciones asincrónicas en el sistema de gráficos de Android. El marco proporciona una API que permite que los componentes indiquen cuándo se liberan los búferes. El marco también permite que las primitivas de sincronización se pasen entre los controladores del kernel al espacio de usuario y entre los propios procesos del espacio de usuario.

Por ejemplo, una aplicación puede poner en cola el trabajo que se realizará en la GPU. La GPU comienza a dibujar esa imagen. Aunque la imagen aún no se ha dibujado en la memoria, el puntero del búfer se pasa al compositor de la ventana junto con una valla que indica cuándo finalizará el trabajo de la GPU. El compositor de ventanas comienza a procesar con anticipación y pasa el trabajo al controlador de pantalla. De manera similar, el trabajo de la CPU se realiza con anticipación. Una vez que finaliza la GPU, el controlador de pantalla muestra inmediatamente la imagen.

El marco de sincronización también permite a los implementadores aprovechar los recursos de sincronización en sus propios componentes de hardware. Por último, el marco proporciona visibilidad de la canalización de gráficos para ayudar con la depuración.

Sincronización explícita

La sincronización explícita permite a los productores y consumidores de búferes gráficos señalar cuando terminan de usar un búfer. La sincronización explícita se implementa en el espacio del kernel.

Los beneficios de la sincronización explícita incluyen:

  • Menor variación de comportamiento entre dispositivos
  • Mejor soporte de depuración
  • Métricas de prueba mejoradas

El marco de sincronización tiene tres tipos de objetos:

  • sync_timeline
  • sync_pt
  • sync_fence

sync_timeline

sync_timeline es una línea de tiempo monótona creciente que los proveedores deben poner en práctica para cada instancia conductor, tal como un contexto GL, controlador de pantalla, o blitter 2D. sync_timeline empleos recuentos enviadas al núcleo de una determinada pieza de hardware. sync_timeline ofrece garantías acerca de la orden de operaciones y permite implementaciones de hardware específicos.

Siga estas directrices al implementar sync_timeline :

  • Proporcione nombres útiles para todos los controladores, líneas de tiempo y vallas para simplificar la depuración.
  • Implementar el timeline_value_str y pt_value_str operadores de líneas de tiempo para hacer una salida de operación más legible.
  • Aplicar el relleno driver_data para dar el espacio de usuario bibliotecas, tales como la biblioteca GL, el acceso a los datos privados de línea de tiempo, si lo desea. data_driver permite vendedores pasan información sobre el inmutable sync_fence y sync_pts a las líneas de comando de generación basados en ellos.
  • No permita que el espacio de usuario cree o señale explícitamente una valla. La creación explícita de señales / vallas da como resultado un ataque de denegación de servicio que detiene la funcionalidad de la canalización.
  • No acceda a sync_timeline , sync_pt o sync_fence elementos de forma explícita. La API proporciona todas las funciones necesarias.

sync_pt

sync_pt es un solo valor o punto en un sync_timeline . Un punto tiene tres estados: activo, señalado y error. Los puntos comienzan en el estado activo y pasan a los estados señalizados o de error. Por ejemplo, cuando un consumidor de imagen ya no necesita un tampón, un sync_pt se señaliza por lo que un productor de imagen sabe que está bien para escribir en el búfer de nuevo.

sync_fence

sync_fence es una colección de sync_pt valores que a menudo tienen diferentes sync_timeline padres (tales como para el controlador de pantalla y GPU). sync_fence , sync_pt y sync_timeline son los principales primitivas que los conductores y el uso de espacio de usuario para comunicar sus dependencias. Cuando se señala una valla, se garantiza que todos los comandos emitidos antes de la valla están completos porque el controlador del kernel o el bloque de hardware ejecuta los comandos en orden.

El marco de sincronización permite que varios consumidores o productores señalen cuando terminan de usar un búfer, comunicando la información de dependencia con un parámetro de función. Las cercas están respaldadas por un descriptor de archivo y se pasan del espacio del kernel al espacio de usuario. Por ejemplo, una valla puede contener dos sync_pt valores que significan cuando dos consumidores de imagen separados se realizan la lectura de un búfer. Cuando se señala la valla, los productores de imágenes saben que ambos consumidores han terminado de consumir.

Vallas, como sync_pt valores, empiezan estado activo y el cambio basado en el estado de sus puntos. Si todos sync_pt valores se señalicen, la sync_fence se convierte en una señal. Si uno sync_pt cae en un estado de error, todo el sync_fence tiene un estado de error.

La pertenencia a un sync_fence es inmutable después de crear la valla. Para obtener más de un punto en una cerca, se lleva a cabo una fusión donde los puntos de dos cercas distintas se agregan a una tercera cerca. Si uno de esos puntos fue señalado en la valla de origen y el otro no, la tercera valla tampoco estará en un estado señalado.

Para implementar la sincronización explícita, proporcione lo siguiente:

  • Un subsistema de espacio de kernel que implementa el marco de sincronización para un controlador de hardware en particular. Los controladores que deben ser conscientes de la cerca son generalmente cualquier cosa que acceda o se comunique con el Compositor de hardware. Los archivos clave incluyen:
    • Implementación básica:
      • kernel/common/include/linux/sync.h
      • kernel/common/drivers/base/sync.c
    • Documentación en kernel/common/Documentation/sync.txt
    • Biblioteca para comunicarse con el espacio del núcleo de platform/system/core/libsync
  • El vendedor debe proporcionar las vallas de sincronización apropiadas como parámetros a la validateDisplay() y presentDisplay() funciona de la HAL.
  • Dos extensiones relacionadas con la cerca-GL ( EGL_ANDROID_native_fence_sync y EGL_ANDROID_wait_sync ) y el apoyo valla en el controlador de gráficos.

Estudio de caso: implementación de un controlador de pantalla

Para utilizar la API que admite la función de sincronización, desarrolle un controlador de pantalla que tenga una función de búfer de pantalla. Antes de que existiera el marco de sincronización, esta función podría recibir dma-buf objetos, puso esas memorias intermedias en la pantalla, y el bloque mientras que el tampón era visible. Por ejemplo:

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

Con el marco de sincronización, el display_buffer función es más compleja. Al poner un búfer en exhibición, el búfer se asocia con un cercado que indica cuándo estará listo el búfer. Puede hacer cola e iniciar el trabajo después de que se despeje la cerca.

Hacer cola e iniciar el trabajo después de que se despeje la cerca no bloquea nada. Inmediatamente devuelve su propia valla, lo que garantiza cuando el búfer estará fuera de la pantalla. A medida que pone en cola los búferes, el kernel enumera las dependencias con el marco de sincronización:

/*
 * 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);

Integración sincronizada

Esta sección explica cómo integrar el marco de sincronización del espacio del kernel con las partes del espacio de usuario del marco de Android y los controladores que deben comunicarse entre sí. Los objetos del espacio del núcleo se representan como descriptores de archivo en el espacio de usuario.

Convenciones de integración

Siga las convenciones de la interfaz de Android HAL:

  • Si la API proporciona un descriptor de archivo que se refiere a un sync_pt , el conductor del vendedor o el HAL mediante la API deben cerrar el descriptor de archivo.
  • Si el controlador del proveedor o el HAL pasa un descriptor de archivo que contiene un sync_pt a una función API, el conductor del vendedor o el HAL no está cerca es necesario que el descriptor de archivo.
  • Para continuar usando el descriptor de archivo de valla, el controlador del proveedor o el HAL deben duplicar el descriptor.

Un objeto de valla cambia de nombre cada vez que pasa por BufferQueue. Apoyo cerca del núcleo permite vallas tengan cadenas de los nombres, por lo que el marco de sincronización utiliza el nombre de la ventana y el búfer de índice que está siendo puesto en cola para nombrar la valla, como SurfaceView:0 . Esto es útil en la depuración para identificar la fuente de un punto muerto como los nombres aparecen en la salida de la /d/sync y corrección de informes.

Integración ANativeWindow

ANativeWindow es consciente de la valla. dequeueBuffer , queueBuffer y cancelBuffer tienen parámetros de la cerca.

Integración OpenGL ES

La integración de sincronización de OpenGL ES se basa en dos extensiones EGL:

  • EGL_ANDROID_native_fence_sync proporciona una manera de envolver o crear descriptores de archivo valla nativas de Android en EGLSyncKHR objetos.
  • EGL_ANDROID_wait_sync permite a la GPU en lugar de puestos de lado a lado de la CPU, lo que hace que la espera GPU para EGLSyncKHR . El EGL_ANDROID_wait_sync extensión es el mismo que el EGL_KHR_wait_sync extensión.

Para utilizar estas extensiones de forma independiente, poner en práctica el EGL_ANDROID_native_fence_sync extensión junto con el soporte en el núcleo asociado. A continuación, active la EGL_ANDROID_wait_sync extensión de su conductor. El EGL_ANDROID_native_fence_sync extensión consta de un nativo valla distinta EGLSyncKHR tipo de objeto. Como resultado, las extensiones existentes que se aplican a EGLSyncKHR tipos de objetos no se aplican necesariamente a EGL_ANDROID_native_fence objetos, evitar interacciones no deseadas.

El EGL_ANDROID_native_fence_sync extensión emplea un atributo de descriptor de archivo nativo correspondiente valla que se puede ajustar sólo en tiempo de creación y no se puede consultar directamente en adelante a partir de un objeto de sincronización existente. Este atributo se puede establecer en uno de dos modos:

  • Un descriptor de archivo válido valla envuelve un descriptor de archivo nativo de Android existente valla en un EGLSyncKHR objeto.
  • -1 crea un descriptor de archivo nativo de Android valla de una EGLSyncKHR objeto.

Usar la DupNativeFenceFD() llamada a la función de extraer el EGLSyncKHR objeto desde el descriptor de archivo valla de Android nativo. Esto tiene el mismo resultado que consultar el atributo set, pero se adhiere a la convención de que el destinatario cierra la cerca (de ahí la operación duplicada). Por último, la destrucción de la EGLSyncKHR objeto cierra el atributo valla interna.

Integración de Hardware Composer

Hardware Composer maneja tres tipos de vallas de sincronización:

  • Adquirir vallas se pasan junto con tampones de entrada a los setLayerBuffer y setClientTarget llamadas. Estos representan una escritura pendiente en el búfer y deben señalar antes de que SurfaceFlinger o el HWC intenten leer del búfer asociado para realizar la composición.
  • Vallas de liberación se recuperan después de la llamada a presentDisplay utilizando el getReleaseFences llamada. Estos representan una lectura pendiente del búfer anterior en la misma capa. Una barrera de liberación señala cuando el HWC ya no está usando el búfer anterior porque el búfer actual ha reemplazado al búfer anterior en la pantalla. Las vallas de liberación se devuelven a la aplicación junto con los búferes anteriores que se reemplazarán durante la composición actual. La aplicación debe esperar hasta que se indique una valla de liberación antes de escribir nuevos contenidos en el búfer que se les devolvió.
  • Vallas presentes son devueltos, una por cada frame, como parte de la llamada a presentDisplay . Las vallas actuales representan cuando la composición de este marco se ha completado, o alternativamente, cuando el resultado de la composición del marco anterior ya no es necesario. Para las pantallas físicas, presentDisplay devuelve presentes cercas cuando aparece el cuadro actual en la pantalla. Una vez que se devuelven las cercas actuales, es seguro volver a escribir en el búfer de destino SurfaceFlinger, si corresponde. Para las pantallas virtuales, las vallas actuales se devuelven cuando es seguro leer desde el búfer de salida.