El framework de sincronización describe de forma explícita las dependencias entre diferentes operaciones asíncronas en el sistema de gráficos de Android. El marco de trabajo proporciona una API que habilita a los componentes para indicar cuándo se liberan los búferes. El framework también permite pasar las primitivas de sincronización entre los controladores del kernel al espacio del usuario y entre los procesos de este espacio.
Por ejemplo, una aplicación puede poner en cola el trabajo que se ejecutará en la GPU. La GPU comenzará a dibujar esa imagen. Aunque la imagen no se dibujó en la memoria, el puntero del búfer se pasa a la ventana junto con una valla que indique cuándo se realizará para finalizar. El compositor de ventanas comienza a procesar con anticipación pasa el trabajo al controlador de la pantalla. De manera similar, la CPU funciona se hace con anticipación. Una vez que la GPU finaliza, el controlador de pantalla muestra la imagen de inmediato.
El framework de sincronización también permite a los implementadores aprovechar de sincronización en sus propios componentes de hardware. Por último, la proporciona visibilidad de la canalización de los gráficos para ayudar con la depuración.
Sincronización explícita
La sincronización explícita permite que los productores y consumidores de búferes de gráficos para indicar que terminan de usar un búfer. La sincronización explícita es implementadas en el espacio del kernel.
Entre los beneficios de la sincronización explícita, se incluyen los siguientes:
- Menos variación de comportamiento entre dispositivos
- Mejor compatibilidad con la depuración
- Métricas de prueba mejoradas
El framework de sincronización tiene tres tipos de objetos:
sync_timeline
sync_pt
sync_fence
sincronización_línea
sync_timeline
es un cronograma que aumenta monótonamente y que
los proveedores deben implementar para cada instancia de controlador, como un contexto de GL,
controlador de pantalla o blitter 2D. sync_timeline
recuentos
trabajos enviados al kernel para una pieza concreta de hardware.
sync_timeline
ofrece garantías sobre el orden de las operaciones.
y habilita implementaciones específicas de hardware.
Sigue estos lineamientos cuando implementes sync_timeline
:
- Proporciona nombres útiles para todos los conductores, los cronogramas y las cercas para simplificar el proceso la depuración.
- Implementa
timeline_value_str
ypt_value_str
. en cronogramas para que los resultados de depuración sean más legibles. - Implementa el
driver_data
de relleno para otorgar bibliotecas de espacio de usuario. como la biblioteca GL, y acceso a datos privados de la línea de tiempo, si así lo desean.data_driver
permite que los proveedores pasen información sobre el modelo inmutablesync_fence
ysync_pts
para compilar líneas de comandos en función de ellos. - No permitas que el espacio del usuario cree explícitamente una valla ni la indique. Explícitamente crear señales o vallas da como resultado un ataque de denegación del servicio detiene la funcionalidad de canalización.
- No acceder a
sync_timeline
,sync_pt
nisync_fence
de forma explícita. La API proporciona todos los funciones.
sincronización_pt
sync_pt
es un valor o punto único en un
sync_timeline
Un punto
tiene tres estados: activo, señalizado y error. Los puntos comienzan en el estado activo
y hacer la transición a los estados
indicado o de error. Por ejemplo, cuando una imagen
el consumidor ya no necesita un búfer, se indica sync_pt
para que el productor de imágenes sepa
que puede volver a escribir en el búfer.
protección_sincronización
sync_fence
es una colección de valores sync_pt
que a menudo
tener diferentes sync_timeline
superiores (por ejemplo, para la pantalla
controlador y GPU). sync_fence
, sync_pt
y
sync_timeline
son las principales primitivas que usan los controladores y el espacio del usuario
usan para comunicar sus dependencias. Cuando se señala una cerca, todo
comandos emitidos antes de la valla están garantizados, ya que el
el controlador de kernel o el bloque de hardware ejecutan comandos en orden.
El marco de sincronización permite que
varios consumidores o productores
Terminé de usar un búfer, se comunica la información de la dependencia con una función
parámetro. Las vallas están respaldadas por un descriptor de archivo y se pasan desde
espacio de kernel al espacio del usuario. Por ejemplo, una valla puede contener dos
Valores sync_pt
que indican cuando dos consumidores de imágenes diferentes terminan
leer un búfer. Cuando se indica el cerco, los productores de imágenes saben que ambos
los consumidores terminan de consumir.
Las cercas, como los valores de sync_pt
, comienzan activas y cambian el estado según
el estado de sus puntos. Si se indican todos los valores de sync_pt
, el
Se indicará sync_fence
. Si cae un sync_pt
a un estado de error, toda la sync_fence
tiene un estado de error.
La membresía en un sync_fence
es inmutable después de que se establece la valla.
crear. Para obtener más de un punto en una valla, se debe realizar una combinación
donde se agregan puntos de dos vallas distintas a una tercera.
Si uno de esos puntos se señaló en la cerca de origen y el otro no,
la tercera barrera tampoco
estará en estado indicado.
Para implementar la sincronización explícita, proporciona lo siguiente:
- Un subsistema de espacio de kernel que implementa el framework de sincronización.
para un controlador de hardware específico. Los conductores que deben estar atentos
generalmente cualquier cosa que acceda o se comunique con Hardware Composer.
Entre los archivos clave, se incluyen los siguientes:
- Implementación principal:
kernel/common/include/linux/sync.h
kernel/common/drivers/base/sync.c
- Documentación en
kernel/common/Documentation/sync.txt
- para comunicarse con el espacio del kernel en
platform/system/core/libsync
- Implementación principal:
- El proveedor debe proporcionar la sincronización adecuada
vallas como parámetros a
validateDisplay()
y FuncionespresentDisplay()
en la HAL - Dos extensiones de GL relacionadas con vallas (
EGL_ANDROID_native_fence_sync
) yEGL_ANDROID_wait_sync
) y vallas en los gráficos controlador.
Caso de éxito: Implementa un controlador de pantalla
Para usar la API que admite la función de sincronización,
desarrollar un controlador de pantalla que tenga una función de búfer de pantalla Antes del
de sincronización existente, esta función recibiría dma-buf
coloca esos búferes en la pantalla y realiza el bloqueo mientras el búfer estaba 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 framework de sincronización, la función display_buffer
es más complejo. Cuando se muestra un búfer en pantalla, este se asocia
con una valla que indique
cuándo estará listo el búfer. Puedes agregar a la fila
e iniciar el trabajo
después de que se despegue la cerca.
Iniciar el trabajo y poner en cola el trabajo después de que se despeja la barrera no bloquea nada. Debes devolver inmediatamente tu propia valla, que garantiza que el búfer quedará fuera de la pantalla. Cuando pones en cola los búferes, el kernel enumera dependencias con el framework 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 de sincronización
Esta sección explica cómo integrar el framework de sincronización del espacio del kernel con del espacio del usuario del framework de Android y los controladores que se deben comunicar entre sí. Los objetos de espacio de kernel se representan como descriptores de archivos en el espacio de usuario.
Convenciones de integración
Sigue las convenciones de la interfaz de la HAL de Android:
- Si la API proporciona un descriptor de archivo que hace referencia a un
sync_pt
, el controlador del proveedor o la HAL que usa la API debe cerrar el descriptor de archivos. - Si el controlador del proveedor o la HAL pasan un descriptor de archivos que contiene
un
sync_pt
a una función de API, el controlador del proveedor o la HAL no deben cierra el descriptor de archivo. - Para seguir usando el descriptor de archivos de valla, el controlador del proveedor o el La HAL debe duplicar el descriptor.
Se cambia el nombre de un objeto de valla cada vez que pasa por BufferQueue.
La compatibilidad con vallas de kernel permite
que las vallas tengan cadenas para nombres.
usa el nombre de la ventana y el índice del búfer que se pone en cola para nombrar
la valla, como SurfaceView:0
. Esta
es útil en la depuración para identificar la fuente de un interbloqueo cuando aparecen los nombres
en el resultado de /d/sync
y los informes de errores
Integración de ANativeWindow
ANativeWindow admite vallas. dequeueBuffer
,
queueBuffer
y cancelBuffer
tienen parámetros de valla.
Integración de OpenGL ES
La integración de la sincronización de OpenGL ES se basa en dos extensiones EGL:
EGL_ANDROID_native_fence_sync
proporciona una forma de unir o crear descriptores de archivos de valla nativos de Android enEGLSyncKHR
.EGL_ANDROID_wait_sync
permite los bloqueos en la GPU. en lugar de en la CPU, lo que hace que la GPU espereEGLSyncKHR
. El La extensiónEGL_ANDROID_wait_sync
es igual a laEGL_KHR_wait_sync
.
Para usar estas extensiones de forma independiente, implementa la
EGL_ANDROID_native_fence_sync
junto con la extensión
compatibilidad con el kernel. A continuación, habilita el EGL_ANDROID_wait_sync
en tu controlador. El EGL_ANDROID_native_fence_sync
La extensión consta de un objeto EGLSyncKHR
de valla nativo distinto
el tipo de letra. Por lo tanto, las extensiones que se aplican a EGLSyncKHR
existentes
los tipos de objeto no se aplican necesariamente a EGL_ANDROID_native_fence
de objetos, lo que evita interacciones no deseadas.
La extensión EGL_ANDROID_native_fence_sync
usa un código nativo correspondiente
del descriptor de archivo de valla que se puede configurar solo en el momento de la creación y
no se pueden consultar en adelante directamente desde un objeto de sincronización existente. Este atributo
se puede establecer en uno de dos modos:
- Un descriptor de archivo de valla válido une un nativo existente
Descriptor de archivos de valla de Android en un objeto
EGLSyncKHR
. - -1 crea un descriptor de archivo de valla nativo de Android a partir de un
Objeto
EGLSyncKHR
.
Usa la llamada a función DupNativeFenceFD()
para extraer el
Es un objeto EGLSyncKHR
del descriptor de archivos de valla nativo de Android.
Esto produce el mismo resultado que la consulta del atributo set, pero cumple con
la convención de que el destinatario cierra la barrera (de ahí el
una sola operación). Por último, la destrucción del objeto EGLSyncKHR
se cierra
el atributo de valla interna.
Integración de Hardware Composer
Hardware Composer controla tres tipos de vallas de sincronización:
- Las vallas de adquisición se pasan junto con los búferes de entrada para
a las llamadas
setLayerBuffer
ysetClientTarget
. Representan una escritura pendiente en el búfer y deben indicarse antes de la SurfaceFlinger o HWC intenta leer desde el búfer asociado para realizar una composición. - Las vallas de liberación se recuperan después de la llamada a
presentDisplay
mediante la llamadagetReleaseFences
Estas representan una lectura pendiente del búfer anterior en la misma capa. R La valla de liberación señala cuando el HWC ya no usa el búfer anterior porque el búfer actual reemplazó al anterior en la pantalla. Las vallas de liberación se devuelven a la app junto con los búferes anteriores se reemplazará durante la composición actual. La aplicación debe esperar hasta que de protección y liberación de vallas antes de escribir contenido nuevo en el búfer que y cómo se les devolvió. - Se muestran cercos actuales, uno por fotograma, como parte del
la llamada a
presentDisplay
. Las vallas de presencia representan cuándo se la composición de este marco se complete, o alternativamente, cuando la el resultado de la composición del fotograma anterior ya no es necesario. Para dispositivos físicospresentDisplay
muestra las vallas actuales cuando la el marco actual en la pantalla. Después de que se devuelvan las vallas actuales, es seguro volver a escribir en el búfer de destino que corresponda. Para las pantallas virtuales, se devuelven las vallas actuales cuando se y seguro leer desde el búfer de salida.