Capas y pantallas

Las capas y las pantallas son dos elementos primitivos que representan el trabajo de composición y las interacciones con el hardware de la pantalla.

Capas

Una capa es la unidad de composición más importante. Una capa es una combinación de una superficie y una instancia de SurfaceControl. Cada capa tiene un conjunto de propiedades que definen cómo interactúa con otras capas. Las propiedades de la capa se describen en la siguiente tabla:

Propiedad Descripción
Posicional Define dónde aparece la capa en la pantalla. Incluye información, como las posiciones de los bordes de una capa y su orden Z en relación con otras capas (si debe estar delante o detrás de otras capas).
Contenido Define cómo se debe presentar el contenido que se muestra en la capa dentro de los límites definidos por las propiedades de posición. Incluye información como el recorte (para expandir una parte del contenido y llenar los límites de la capa) y la transformación (para mostrar contenido rotado o volteado).
Composición Define cómo se debe componer la capa con otras capas. Incluye información como el modo de combinación y un valor alfa para toda la capa para la composición alfa.
Optimización Proporciona información que no es estrictamente necesaria para componer correctamente la capa, pero que el dispositivo Hardware Composer (HWC) puede usar para optimizar la forma en que realiza la composición. Incluye información como la región visible de la capa y qué parte de la capa se actualizó desde el cuadro anterior.

Displays

Una pantalla es otra unidad de composición importante. Un sistema puede tener varias pantallas, y se pueden agregar o quitar pantallas durante las operaciones normales del sistema. Las pantallas se agregan o quitan a solicitud del HWC o del framework. El dispositivo HWC solicita que se agreguen o quiten pantallas cuando se conecta o desconecta una pantalla externa del dispositivo, lo que se denomina conexión en caliente. Los clientes solicitan pantallas virtuales, cuyo contenido se renderiza en un búfer fuera de la pantalla en lugar de en una pantalla física.

Pantallas virtuales

SurfaceFlinger admite una pantalla interna (integrada en el teléfono o la tablet), pantallas externas (como un televisor conectado a través de HDMI) y una o más pantallas virtuales que hacen que la salida compuesta esté disponible dentro del sistema. Las pantallas virtuales se pueden usar para grabar la pantalla o enviarla a través de una red. Los fotogramas generados para una pantalla virtual se escriben en un BufferQueue.

Las pantallas virtuales pueden compartir el mismo conjunto de capas que la pantalla principal (la pila de capas) o tener su propio conjunto. No hay VSync para una pantalla virtual, por lo que la VSync de la pantalla interna activa la composición para todas las pantallas.

En las implementaciones de HWC que los admiten, los dispositivos virtuales se pueden componer con OpenGL ES (GLES), HWC o ambos. En las implementaciones no compatibles, las pantallas virtuales siempre se componen con GLES.

Caso de éxito: screenrecord

El comando screenrecord permite que el usuario grabe todo lo que aparece en la pantalla como un archivo MP4 en el disco. Para implementar esto, el sistema recibe fotogramas compuestos de SurfaceFlinger, los escribe en el codificador de video y, luego, escribe los datos de video codificados en un archivo. Los códecs de video se administran mediante un proceso independiente (mediaserver), por lo que los búferes de gráficos grandes deben moverse por el sistema. Para que sea más difícil, el objetivo es grabar videos a 60 FPS y en resolución completa. La clave para que esto funcione de manera eficiente es BufferQueue.

La clase MediaCodec permite que una app proporcione datos como bytes sin procesar en búferes o a través de una superficie. Cuando screenrecord solicita acceso a un codificador de video, el proceso mediaserver crea un BufferQueue, se conecta al lado del consumidor y, luego, pasa el lado del productor a screenrecord como una superficie.

Luego, la utilidad screenrecord le solicita a SurfaceFlinger que cree una pantalla virtual que refleje la pantalla principal (es decir, que tenga todas las mismas capas) y le indica que envíe la salida a la superficie que proviene del proceso mediaserver. En este caso, SurfaceFlinger es el productor de búferes, no el consumidor.

Una vez que se complete la configuración, screenrecord se activará cuando aparezcan los datos codificados. A medida que las apps dibujan, sus búferes viajan a SurfaceFlinger, que los compone en un solo búfer que se envía directamente al codificador de video en el proceso mediaserver. El proceso de screenrecord nunca ve los fotogramas completos. Internamente, el proceso mediaserver tiene su propia forma de mover búferes que también pasa datos por identificador, lo que minimiza la sobrecarga.

Caso de éxito: Simula pantallas secundarias

WindowManager puede solicitar a SurfaceFlinger que cree una capa visible para la que SurfaceFlinger actúa como consumidor de BufferQueue. También es posible solicitarle a SurfaceFlinger que cree una pantalla virtual, para la cual SurfaceFlinger actúa como productor de BufferQueue.

Si conectas una pantalla virtual a una capa visible, se crea un bucle cerrado en el que la pantalla compuesta aparece en una ventana. Esa ventana ahora forma parte del resultado compuesto, por lo que, en la siguiente actualización, la imagen compuesta dentro de la ventana también mostrará el contenido de la ventana. Para ver esto en acción, habilita Opciones para desarrolladores en Configuración, selecciona Simular pantallas secundarias y habilita una ventana. Para ver las pantallas secundarias en acción, usa screenrecord para capturar el acto de habilitar la pantalla y, luego, reproducirla fotograma por fotograma.