Capas y pantallas

Las capas y las pantallas son dos primitivas 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 define 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 su visualización. Incluye información como las posiciones de los bordes de una capa y su orden en Z con respecto a otras capas (si deben 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 que ocupe todo el límite de la capa) y la transformación (para mostrar contenido girado o invertido).
Composición Define cómo se debe combinar la capa con otras. 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 combinar 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 marco 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 pedido 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 una televisión conectada a través de HDMI) y una o más pantallas virtuales que ponen a disposición del sistema la salida compuesta. 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 las admiten, las pantallas virtuales se pueden componer con OpenGL ES (GLES), HWC o ambos. En las implementaciones que no son compatibles, las pantallas virtuales siempre se combinan con GLES.

Caso de éxito: Screenrecord

El comando screenrecord permite al usuario grabar 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 desafiante, el objetivo es grabar videos a 60 fps con resolución completa. La clave para hacer este trabajo de forma 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 una BufferQueue, se conecta con el lado del consumidor y, luego, pasa el lado del productor de vuelta 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 indique que envíe el resultado a la superficie que proviene del proceso mediaserver. En este caso, SurfaceFlinger es el productor de búferes en lugar del consumidor.

Una vez que se completa la configuración, screenrecord se activa cuando aparecen los datos codificados. A medida que las apps se dibujan, sus búferes se envían 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 screenrecord nunca ve los fotogramas completos. De forma interna, 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 pedirle a SurfaceFlinger que cree una capa visible para la que SurfaceFlinger actúa como consumidor de BufferQueue. También es posible pedirle 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 próxima actualización, la imagen compuesta dentro de la ventana también mostrará su contenido. 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, reprodúcela fotograma por fotograma.