El modelo de capas
Introducción
Para la mayoría de los desarrolladores web, el modelo fundamental de una página web es el DOM. La renderización es el proceso, a menudo oscuro, de convertir esta representación de una página en una imagen en la pantalla. En los últimos años, los navegadores modernos cambiaron la forma en que funciona la renderización para aprovechar las tarjetas gráficas. A menudo, se hace referencia a esto de forma vaga como "aceleración de hardware". Cuando se habla de una página web normal (es decir, no Canvas2D ni WebGL), ¿qué significa realmente ese término? En este artículo, se explica el modelo básico que sustenta la renderización acelerada por hardware del contenido web en Chrome.
Grandes advertencias
Aquí hablamos de WebKit y, más específicamente, del puerto de Chromium de WebKit. En este artículo, se describen los detalles de la implementación de Chrome, no las funciones de la plataforma web. La plataforma web y los estándares no codifican este nivel de detalle de implementación, por lo que no hay garantías de que algo de este artículo se aplique a otros navegadores. Sin embargo, el conocimiento de los elementos internos puede ser útil para la depuración avanzada y el ajuste del rendimiento.
Además, ten en cuenta que en todo este artículo se analiza una parte fundamental de la arquitectura de renderización de Chrome que cambia muy rápido. En este artículo, intentamos abordar solo los aspectos que es poco probable que cambien, pero no garantizamos que todo siga aplicándose dentro de seis meses.
Es importante comprender que Chrome tiene dos rutas de renderización diferentes desde hace un tiempo: la ruta de acceso con aceleración de hardware y la ruta de acceso de software anterior. En el momento de escribir este artículo, todas las páginas siguen la ruta de acceso con aceleración de hardware en Windows, ChromeOS y Chrome para Android. En Mac y Linux, solo las páginas que necesitan composición para parte de su contenido siguen la ruta acelerada (consulta a continuación para obtener más información sobre lo que requeriría composición), pero pronto todas las páginas también seguirán la ruta acelerada.
Por último, observamos el motor de renderización y sus funciones que tienen un gran impacto en el rendimiento. Cuando intentas mejorar el rendimiento de tu propio sitio, puede ser útil comprender el modelo de capas, pero también es fácil cometer errores: las capas son construcciones útiles, pero crear muchas de ellas puede generar sobrecarga en toda la pila de gráficos. Ten en cuenta lo siguiente.
Del DOM a la pantalla
Presentamos las capas
Una vez que se carga y analiza una página, se representa en el navegador como una estructura que muchos desarrolladores web conocen: el DOM. Sin embargo, cuando se renderiza una página, el navegador tiene una serie de representaciones intermedias que no se exponen directamente a los desarrolladores. La más importante de estas estructuras es una capa.
En Chrome, en realidad, hay varios tipos diferentes de capas: RenderLayers, que son responsables de los subárboles del DOM, y GraphicsLayers, que son responsables de los subárboles de RenderLayers. Lo último es lo más interesante para nosotros aquí, ya que las GraphicsLayers son las que se suben a la GPU como texturas. A partir de ahora, diré “capa” para referirme a GraphicsLayer.
Breve comentario sobre la terminología de la GPU: ¿qué es una textura? Piensa en ella como una imagen de mapa de bits que se mueve de la memoria principal (es decir, la RAM) a la memoria de video (es decir, la VRAM, en tu GPU). Una vez que está en la GPU, puedes asignarlo a una geometría de malla. En los videojuegos o los programas de CAD, esta técnica se usa para dar “textura” a los modelos 3D esqueléticos. Chrome usa texturas para obtener fragmentos de contenido de páginas web en la GPU. Las texturas se pueden asignar de forma económica a diferentes posiciones y transformaciones aplicándolas a una malla rectangular muy simple. Así es como funciona el CSS en 3D, y también es excelente para el desplazamiento rápido, pero hablaremos de ambos más adelante.
Veamos algunos ejemplos para ilustrar el concepto de capas.
Una herramienta muy útil cuando se estudian las capas en Chrome es la marca "Mostrar bordes de capas compuestas" en la configuración (es decir, el ícono de engranaje) de Herramientas para desarrolladores, en el encabezado "Renderización". Destaca de forma muy sencilla dónde se encuentran las capas en la pantalla. Vamos a encenderlo. Estas capturas de pantalla y ejemplos se tomaron de la versión más reciente de Chrome Canary, Chrome 27, en el momento de escribir este artículo.
Figura 1: Una página de una sola capa
<!doctype html>
<html>
<body>
<div>I am a strange root.</div>
</body>
</html>

Esta página solo tiene una capa. La cuadrícula azul representa las tarjetas, que puedes considerar como subunidades de una capa que Chrome usa para subir partes de una capa grande a la vez a la GPU. No son realmente importantes aquí.
Figura 2: Un elemento en su propia capa
<!doctype html>
<html>
<body>
<div style="transform: rotateY(30deg) rotateX(-30deg); width: 200px;">
I am a strange root.
</div>
</body>
</html>

Si colocamos una propiedad CSS 3D en el <div>
que lo rota, podemos ver cómo se ve cuando un elemento tiene su propia capa: observa el borde naranja, que define una capa en esta vista.
Criterios para la creación de capas
¿Qué más tiene su propia capa? Las heurísticas de Chrome evolucionaron con el tiempo y siguen evolucionando, pero, actualmente, cualquiera de las siguientes acciones activa la creación de capas:
- Propiedades de CSS de transformación 3D o de perspectiva
- Elementos
<video>
que usan decodificación de video acelerada - Elementos
<canvas>
con un contexto 3D (WebGL) o un contexto 2D acelerado - Complementos compuestos (p.ej., Flash)
- Elementos con animación de CSS para su opacidad o que usan una transformación animada
- Elementos con filtros de CSS acelerados
- El elemento tiene un descendiente que tiene una capa de composición (en otras palabras, si el elemento tiene un elemento secundario que está en su propia capa).
- El elemento tiene un hermano con un índice z más bajo que tiene una capa de composición (en otras palabras, se renderiza sobre una capa compuesta).
Implicaciones prácticas: Animación
También podemos mover las capas, lo que las hace muy útiles para la animación.
Figura 3: Capas animadas
<!doctype html>
<html>
<head>
<style>
div {
animation-duration: 5s;
animation-name: slide;
animation-iteration-count: infinite;
animation-direction: alternate;
width: 200px;
height: 200px;
margin: 100px;
background-color: gray;
}
@keyframes slide {
from {
transform: rotate(0deg);
}
to {
transform: rotate(120deg);
}
}
</style>
</head>
<body>
<div>I am a strange root.</div>
</body>
</html>
Como se mencionó anteriormente, las capas son muy útiles para desplazarse por el contenido web estático. En el caso básico, Chrome pinta el contenido de una capa en un mapa de bits de software antes de subirlo a la GPU como una textura. Si ese contenido no cambia en el futuro, no es necesario volver a pintarlo. Esto es algo bueno: volver a pintar requiere tiempo que se puede dedicar a otras tareas, como ejecutar JavaScript, y si la pintura es larga, causa interrupciones o retrasos en las animaciones.
Por ejemplo, observa esta vista del cronograma de Dev Tools: no hay operaciones de pintura mientras esta capa gira hacia adelante y hacia atrás.

No es válido. Repintado
Sin embargo, si cambia el contenido de la capa, se debe volver a pintar.
Figura 4: Repainting Layers
<!doctype html>
<html>
<head>
<style>
div {
animation-duration: 5s;
animation-name: slide;
animation-iteration-count: infinite;
animation-direction: alternate;
width: 200px;
height: 200px;
margin: 100px;
background-color: gray;
}
@keyframes slide {
from {
transform: rotate(0deg);
}
to {
transform: rotate(120deg);
}
}
</style>
</head>
<body>
<div id="foo">I am a strange root.</div>
<input id="paint" type="button" value="repaint">
<script>
var w = 200;
document.getElementById('paint').onclick = function() {
document.getElementById('foo').style.width = (w++) + 'px';
}
</script>
</body>
</html>
Cada vez que se hace clic en el elemento de entrada, el elemento giratorio se hace 1 px más ancho. Esto provoca que se vuelva a diseñar y pintar todo el elemento, que en este caso es una capa completa.
Una buena manera de ver qué se está pintando es con la herramienta "Show paint rects" en Dev Tools, también en el encabezado "Rendering" de la configuración de Dev Tools. Después de encenderlo, observa que el elemento animado y el botón parpadean en rojo cuando se hace clic en él.

Los eventos de pintura también aparecen en la línea de tiempo de DevTools. Los lectores con ojos avizores pueden notar que hay dos eventos de pintura: uno para la capa y otro para el botón en sí, que se vuelve a pintar cuando cambia a su estado deprimido o viceversa.

Ten en cuenta que Chrome no siempre necesita volver a pintar toda la capa, sino que intenta ser inteligente y solo volver a pintar la parte del DOM que se invalidó. En este caso, el elemento DOM que modificamos es el tamaño de toda la capa. Sin embargo, en muchos otros casos, habrá muchos elementos DOM en una capa.
La siguiente pregunta obvia es qué causa una invalidación y fuerza una nueva pintura. Es difícil responder de forma exhaustiva porque hay muchos casos extremos que pueden forzar invalidaciones. La causa más común es ensuciar el DOM manipulando los estilos de CSS o provocando un nuevo diseño. Tony Gentilcore tiene una excelente entrada de blog sobre los motivos que generan el rediseño, y Stoyan Stefanov tiene un artículo que aborda la pintura con más detalle (pero termina solo con la pintura, no con este material de composición sofisticado).
La mejor manera de saber si afecta algo en lo que estás trabajando es usar las herramientas de Dev Tools Timeline y Show Paint Rects para ver si estás volviendo a pintar cuando no quieres y, luego, intenta identificar dónde ensuciaste el DOM justo antes de ese nuevo diseño o nueva pintura. Si la pintura es inevitable, pero parece tardar demasiado, consulta el artículo de Eberhard Gräther sobre el modo de pintura continua en DevTools.
Cómo combinar todo: del DOM a la pantalla
Entonces, ¿cómo convierte Chrome el DOM en una imagen de pantalla? Conceptualmente, tiene las siguientes características:
- Toma el DOM y lo divide en capas.
- Pinta cada una de estas capas de forma independiente en mapas de bits de software.
- Los sube a la GPU como texturas.
- Combina las diferentes capas en la imagen de pantalla final.
Todo esto debe ocurrir la primera vez que Chrome produce un marco de una página web. Sin embargo, puede tomar algunos atajos para los fotogramas futuros:
- Si cambian ciertas propiedades CSS, no es necesario volver a pintar nada. Chrome solo puede volver a componer las capas existentes que ya están en la GPU como texturas, pero con diferentes propiedades de composición (p. ej., en diferentes posiciones, con diferentes opacidades, etc.).
- Si se invalida parte de una capa, se vuelve a pintar y a subir. Si su contenido permanece igual, pero cambian sus atributos compuestos (p.ej., se traduce o cambia su opacidad), Chrome puede dejarlo en la GPU y volver a componerlo para crear un fotograma nuevo.
Como ya debería estar claro, el modelo de composición basado en capas tiene implicaciones importantes para el rendimiento de la renderización. La composición es relativamente económica cuando no se necesita pintar nada, por lo que evitar volver a pintar capas es un buen objetivo general cuando se intenta depurar el rendimiento de la renderización. Los desarrolladores expertos echarán un vistazo a la lista de activadores de composición anterior y se darán cuenta de que es posible forzar fácilmente la creación de capas. Sin embargo, ten cuidado de no crearlos a ciegas, ya que no son gratuitos: ocupan memoria en la RAM del sistema y en la GPU (especialmente limitada en dispositivos móviles) y tener muchos de ellos puede generar otra sobrecarga en la lógica que realiza un seguimiento de cuáles son visibles. Muchas capas también pueden aumentar el tiempo dedicado a la rasterización si son grandes y se superponen mucho donde no lo hacían antes, lo que a veces se conoce como “superposición”. Por lo tanto, usa tus conocimientos con prudencia.
Eso es todo por ahora. No te pierdas los próximos artículos sobre las implicaciones prácticas del modelo de capas.