Estructuras de datos clave en RenderingNG

Chris Harrelson
Chris Harrelson
Daniel Cheng
Daniel Cheng
Philip Rogers
Philip Rogers
Koji Ishi
Koji Ishi
Ian Kilpatrick
Ian Kilpatrick
Kyle Charbonneau
Kyle Charbonneau

Observemos las estructuras de datos clave, que son entradas y salidas de la canalización de renderización.

Estas estructuras de datos son las siguientes:

  • Los árboles de marcos constan de nodos locales y remotos que representan qué documentos web se encuentran en qué proceso de renderización y en qué procesador de Blink.
  • El árbol de fragmentos inmutable representa la salida del algoritmo de restricción de diseño y la entrada correspondiente.
  • Los árboles de propiedades representan las jerarquías de transformación, recorte, efecto y desplazamiento de un documento web. Estos se usan en toda la canalización.
  • Las listas de visualización y los fragmentos de pintura son las entradas a los algoritmos de trama y de creación de capas.
  • Los marcos del compositor encapsulan las superficies, las superficies de renderización y los mosaicos de texturas de la GPU que se usan para dibujar con la GPU.

Antes de analizar estas estructuras de datos, el siguiente ejemplo se basa en una de la revisión de arquitectura. Este ejemplo se usa en todo este documento con demostraciones de cómo se le aplican las estructuras de datos.

<!-- Example code -->
<html>
  <div style="overflow: hidden; width: 100px; height: 100px;">
    <iframe style="filter: blur(3px);
      transform: rotateZ(1deg);
      width: 100px; height: 300px"
      id="one" src="foo.com/etc"></iframe>
  </div>
  <iframe style="top:200px;
    transform: scale(1.1) translateX(200px)"
    id="two" src="bar.com"></iframe>
</html>

Enmarcar árboles

En ocasiones, Chrome puede elegir renderizar un marco de origen cruzado en un proceso de renderización diferente al de su marco superior.

En el código de ejemplo, hay tres marcos en total:

Un marco superior foo.com que contiene dos iframes.

Con el aislamiento de sitios, Chromium usa dos procesos de renderización para procesar esta página web. Cada proceso de renderización tiene su propia representación del árbol de marcos de esa página web:

Dos árboles de marcos que representan los dos procesos de renderización.

Una trama renderizada en un proceso diferente se representa como una trama remota. Un fotograma remoto contiene la información mínima necesaria para actuar como marcador de posición en la renderización, como sus dimensiones. De lo contrario, la trama remota no contendrá ninguna información necesaria para representar su contenido real.

Por el contrario, un marco local representa un fotograma que pasa por la canalización de renderización estándar. El marco local contiene toda la información necesaria para convertir los datos de ese marco (como los datos de estilo y del árbol del DOM) en algo que se pueda renderizar y mostrar.

La canalización de renderización opera con el nivel de detalle de un fragmento del árbol de marcos local. Considera un ejemplo más complicado con foo.com como marco principal:

<iframe src="bar.com"></iframe>

Y el siguiente submarco bar.com:

<iframe src="foo.com/etc"></iframe>

Aunque todavía solo hay dos procesadores, ahora hay tres fragmentos de árbol de marcos locales, con dos en el proceso de renderización de foo.com y uno en el proceso de renderización de bar.com:

Representación de las dos renderizaciones y los tres fragmentos del árbol de fotogramas

Para producir un marco del compositor para la página web, la visualización solicita simultáneamente un marco del compositor desde el marco raíz de cada uno de los tres árboles de fotogramas locales y, luego, los agrega. Consulta también la sección de marcos del compositor.

El marco principal foo.com y el submarco foo.com/other-page forman parte del mismo árbol de marcos y se renderizan en el mismo proceso. Sin embargo, los dos marcos aún tienen ciclos de vida de documentos independientes, ya que forman parte de diferentes fragmentos locales del árbol de marcos. Por este motivo, es imposible generar un marco del compositor para ambos en una sola actualización. El proceso de renderización no tiene suficiente información para componer el marco del compositor generado para foo.com/other-page directamente en el marco del compositor del marco principal foo.com. Por ejemplo, el marco superior bar.com fuera del proceso puede afectar la visualización del iframe de foo.com/other-url, ya que transforma el iframe con CSS, o bien oculta partes del iframe con otros elementos de su DOM.

Cascada de actualización de la propiedad visual

Las propiedades visuales, como el factor de escala del dispositivo y el tamaño del viewport, afectan el resultado renderizado y deben sincronizarse entre los fragmentos del árbol de marcos locales. La raíz de cada fragmento del árbol de marcos local tiene un objeto de widget asociado. Las actualizaciones de propiedades visuales van al widget del marco principal antes de propagarse a los widgets restantes de arriba abajo.

Por ejemplo, cuando cambia el tamaño del viewport:

Diagrama del proceso que se explica en el texto anterior.

Este proceso no es instantáneo, por lo que las propiedades visuales replicadas también incluyen un token de sincronización. El compositor de Viz utiliza este token de sincronización para esperar a que todos los fragmentos del árbol de fotogramas locales envíen un fotograma del compositor con el token de sincronización actual. Con este proceso, se evita mezclar marcos del compositor con diferentes propiedades visuales.

El árbol de fragmentos inmutable

El árbol de fragmentos inmutable es el resultado de la etapa de diseño de la canalización de renderización. Representa la posición y el tamaño de todos los elementos en la página (sin transformaciones aplicadas).

Representación de los fragmentos en cada árbol; uno de ellos se marca como que necesita diseño.

Cada fragmento representa una parte de un elemento del DOM. Por lo general, solo hay un fragmento por elemento, pero puede haber más si se divide en diferentes páginas cuando se imprime o en columnas cuando se encuentra en un contexto de varias columnas.

Después del diseño, cada fragmento se vuelve inmutable y nunca se vuelve a cambiar. Es importante destacar que también imponemos algunas restricciones adicionales. No:

  • Permite cualquier referencia "hacia arriba" en el árbol. (Un elemento secundario no puede tener un puntero hacia su elemento superior).
  • "burbuja" de datos hacia abajo por el árbol (un elemento secundario solo lee información de sus elementos secundarios, no de sus elementos superiores).

Esas restricciones nos permiten reutilizar un fragmento para un diseño posterior. Sin estas restricciones, a menudo tendríamos que volver a generar todo el árbol, lo cual es costoso.

La mayoría de los diseños suelen ser actualizaciones incrementales, por ejemplo, una app web que actualiza una pequeña parte de la IU cuando el usuario hace clic en un elemento. Idealmente, el diseño solo debería funcionar de manera proporcional a lo que en realidad cambió en pantalla. Para lograrlo, podemos reutilizar tantas partes del árbol anterior como sea posible. Esto significa que, por lo general, solo necesitamos reconstruir la columna vertebral del árbol.

En el futuro, este diseño inmutable podría permitirnos realizar acciones interesantes, como pasar el árbol de fragmentos inmutable a través de los límites de subprocesos si es necesario (para realizar fases posteriores en un subproceso diferente), generar varios árboles para una animación de diseño fluida o realizar diseños especulativos paralelos. Además, nos brinda el potencial del diseño multisubproceso en sí.

Elementos de fragmentos intercalados

El contenido intercalado (texto con estilo predominantemente) usa una representación ligeramente diferente. En lugar de una estructura de árbol con cuadros y punteros, representamos el contenido intercalado en una lista plana que representa el árbol. El principal beneficio es que una representación de lista plana para intercaladas es rápida, útil a la hora de inspeccionar o consultar estructuras de datos intercaladas, y es eficiente en términos de memoria. Esto es muy importante para el rendimiento de la renderización web, ya que la renderización de texto es muy compleja y puede convertirse con facilidad en la parte más lenta de la canalización, a menos que esté altamente optimizada.

La lista plana se crea para cada contexto de formato intercalado en el orden de una búsqueda que prioriza la profundidad del subárbol de diseño intercalado. Cada entrada de la lista es una tupla de (objeto, número de elementos subordinados). Por ejemplo, considera este DOM:

<div style="width: 0;">
  <span style="color: blue; position: relative;">Hi</span> <b>there</b>.
</div>

La propiedad width se establece en 0 para que la línea se ajuste entre "Hi" y "there".

Cuando el contexto de formato intercalado para esta situación se representa como un árbol, se ve de la siguiente manera:

{
  "Line box": {
    "Box <span>": {
      "Text": "Hi"
    }
  },
  "Line box": {
    "Box <b>": {
      "Text": "There"
    }
  },
  {
    "Text": "."
  }
}

La lista plana tiene el siguiente aspecto:

  • (Cuadro de línea, 2)
  • (Casilla <span>, 1)
  • (Texto “Hola”, 0)
  • (Cuadro de línea, 3)
  • (Casilla <b>, 1)
  • (Texto "allí", 0)
  • (Texto ".", 0)

Hay muchos consumidores de esta estructura de datos: APIs de accesibilidad y APIs de geometría, como getClientRects y contenteditable. Cada uno tiene diferentes requisitos. Estos componentes acceden a la estructura plana de datos a través de un cursor de conveniencia.

El cursor tiene APIs, como MoveToNext, MoveToNextLine y CursorForChildren. Esta representación de cursor es muy poderosa para el contenido de texto por varias razones:

  • Iterar en el orden de búsqueda que prioriza la profundidad es muy rápido. Se usa con mucha frecuencia porque es similar a los movimientos de acento circunflejo. Como es una lista plana, la búsqueda que prioriza la profundidad solo aumenta el desplazamiento del array, lo que proporciona iteraciones rápidas y localidad de la memoria.
  • Proporciona una búsqueda más amplia, que es necesaria cuando, por ejemplo, se pinta el fondo de líneas y cuadros intercalados.
  • Conocer la cantidad de elementos subordinados hace que avanzar al siguiente elemento del mismo nivel sea rápido (solo aumenta el desplazamiento del array según ese número).

Árboles de propiedades

El DOM es un árbol de elementos (más nodos de texto), y CSS puede aplicar varios estilos a los elementos.

Esto aparece de cuatro maneras:

  • Diseño: Entradas al algoritmo de restricción de diseño.
  • Paint: cómo pintar y generar tramas del elemento (pero no sus elementos subordinados)
  • Elementos visuales: Efectos de trama o dibujos aplicados al subárbol del DOM, como transformaciones, filtros y recortes.
  • Desplazamiento: recorte y desplazamiento de esquinas redondeadas alineado con ejes y del subárbol contenido contenido.

Los árboles de propiedades son estructuras de datos que explican cómo se aplican los efectos visuales y de desplazamiento a los elementos del DOM. Proporcionan los medios para responder preguntas como: ¿dónde, en relación con la pantalla, se encuentra un elemento del DOM determinado, dado su tamaño y posición de diseño? ¿Qué secuencia de operaciones de la GPU se debería usar para aplicar efectos visuales y de desplazamiento?

Los efectos visuales y de desplazamiento en la Web son muy complicados en todo su esplendor. Por lo tanto, lo más importante que hacen los árboles de propiedades es traducir esa complejidad a una sola estructura de datos que represente con precisión su estructura y significado, y que, al mismo tiempo, quite el resto de la complejidad del DOM y la CSS. Esto nos permite implementar algoritmos de composición y desplazamiento con mucha más confianza. En particular, considera lo siguiente:

  • La geometría potencialmente propensa a errores y otros cálculos se pueden centralizar en un solo lugar.
  • La complejidad de compilar y actualizar árboles de propiedades se aísla en una etapa de canalización de renderización.
  • Es mucho más fácil y rápido enviar árboles de propiedades a diferentes subprocesos y procesos que a estado completo del DOM, lo que permite usarlos para muchos casos de uso.
  • Cuantos más casos de uso haya, más beneficios obtendremos del almacenamiento en caché de geometría compilado sobre la parte superior, ya que pueden reutilizar las cachés de los demás.

RenderingNG usa árboles de propiedades para muchos propósitos, incluidos los siguientes:

  • Separa la composición de la pintura, y la composición del subproceso principal.
  • Determinar una estrategia óptima de composición o dibujo
  • Medir la geometría de IntersectionObserver
  • Se evita el trabajo con elementos fuera de pantalla y mosaicos de texturas de GPU.
  • Invalidación de pintura y trama de forma eficiente y precisa
  • Mide el cambio de diseño y el procesamiento de imagen con contenido más grande en las Métricas web esenciales.

Cada documento web tiene cuatro árboles de propiedades separados: transformación, recorte, efecto y desplazamiento.(*) El árbol de transformación representa las transformaciones CSS y el desplazamiento. (Una transformación de desplazamiento se representa como una matriz de transformación 2D). El árbol de clips representa clips de desbordamiento. El árbol de efectos representa todos los demás efectos visuales: opacidad, filtros, máscaras, modos de combinación y otros tipos de clips, como la ruta de recorte. El árbol de desplazamiento representa información sobre el desplazamiento, como la forma en que se desplazan las cadenas entre sí; es necesario para realizar el desplazamiento en el subproceso compositor. Cada nodo de un árbol de propiedades representa un desplazamiento o un efecto visual aplicado por un elemento del DOM. Si tiene varios efectos, puede haber más de un nodo del árbol de propiedades en cada árbol para el mismo elemento.

La topología de cada árbol es como una representación dispersa del DOM. Por ejemplo, si hay tres elementos del DOM con clips de desbordamiento, habrá tres nodos del árbol de clips, y la estructura del árbol de clips seguirá la relación de bloque contenedor entre los clips de desbordamiento. También hay eslabones entre los árboles. Estos vínculos indican la jerarquía relativa del DOM y, por lo tanto, el orden de aplicación de los nodos. Por ejemplo, si una transformación en un elemento del DOM se encuentra debajo de otro elemento del DOM con un filtro, entonces, por supuesto, la transformación se aplica antes que el filtro.

Cada elemento del DOM tiene un estado de árbol de propiedades, que es una tupla de 4 tuplas (transformación, recorte, efecto, desplazamiento) que indica el recorte, la transformación y los nodos del árbol de efectos principales más cercanos que se aplican en ese elemento. Esto es muy conveniente, ya que, con esta información, conocemos con exactitud la lista de clips, transformaciones y efectos que se aplican a ese elemento, y en qué orden. Esto nos indica dónde está en la pantalla y cómo dibujarlo.

Ejemplo

(fuente).

<html>
  <div style="overflow: scroll; width: 100px; height: 100px;">
    <iframe style="filter: blur(3px);
      transform: rotateZ(1deg);
      width: 100px; height: 300px"
  id="one" srcdoc="iframe one"></iframe>
  </div>
  <iframe style="top:200px;
      transform: scale(1.1) translateX(200px)" id=two
      srcdoc="iframe two"></iframe>
</html>

Para el ejemplo anterior (que es ligeramente diferente al de la introducción), estos son los elementos clave de los árboles de propiedades generados:

Ejemplo de los diversos elementos en el árbol de propiedades.

Muestra listas y fragmentos de pintura

Un elemento de la pantalla contiene comandos de dibujo de bajo nivel (consulta aquí) que se pueden rasterizar con Skia. Los elementos de visualización suelen ser simples, con solo algunos comandos de dibujo, como dibujar un borde o un fondo. El recorrido del árbol de pintura itera en el árbol de diseño y los fragmentos asociados según el orden de pintura de CSS para producir una lista de elementos de visualización.

Por ejemplo:

Un cuadro azul con las palabras &quot;Hello World&quot; dentro de un rectángulo verde.

<div id="green" style="background:green; width:80px;">
    Hello world
</div>
<div id="blue" style="width:100px;
  height:100px; background:blue;
  position:absolute;
  top:0; left:0; z-index:-1;">
</div>

Este código HTML y CSS generaría la siguiente lista de visualización, en la que cada celda sería un elemento de visualización:

Fondo de la vista #blue en segundo plano #green en segundo plano Texto intercalado de #green
drawRect con un tamaño de 800 x 600 y color blanco. drawRect con un tamaño de 100 x 100 en la posición 0.0 y de color azul. drawRect con un tamaño de 80 x 18 en la posición 8 y 8 y de color verde. drawTextBlob con la posición 8,8 y el texto "Hello World".

La lista de elementos de visualización está ordenada de atrás hacia adelante. En el ejemplo anterior, el div verde aparece antes del div azul en el orden del DOM, pero el orden de pintura de CSS requiere que el div azul del índice z negativo pinte antes del div verde (paso 3) (paso 4.1). Los elementos de visualización corresponden, en términos generales, a los pasos atómicos de la especificación del orden de pintura de CSS. Un solo elemento del DOM puede generar varios elementos de la pantalla, por ejemplo, cómo #green tiene un elemento de visualización para el fondo y otro para el texto intercalado. Este nivel de detalle es importante para representar la complejidad total de la especificación del orden de pintura de CSS, como la intercalación creada por el margen negativo:

Un rectángulo verde con un cuadro gris parcialmente superpuesto y las palabras “Hello World”.

<div id="green" style="background:green; width:80px;">
    Hello world
</div>
<div id="gray" style="width:35px; height:20px;
  background:gray;margin-top:-10px;"></div>

Esto genera la siguiente lista de visualización, en la que cada celda es un elemento de visualización:

Fondo de la vista #green en segundo plano #gray en segundo plano Texto intercalado de #green
drawRect con un tamaño de 800 x 600 y color blanco. drawRect con un tamaño de 80 x 18 en la posición 8 y 8 y de color verde. drawRect con un tamaño de 35 x 20 en la posición 8 y 16,y de color gris. drawTextBlob con la posición 8,8 y el texto "Hello World".

La lista de artículos que se muestra se almacena y se vuelve a usar en actualizaciones posteriores. Si un objeto de diseño no cambió durante el recorrido del árbol de pintura, sus elementos de visualización se copian de la lista anterior. Una optimización adicional se basa en una propiedad de la especificación del orden de pintura de CSS: la pila de contextos de pintura de forma atómica. Si ningún objeto de diseño cambió dentro de un contexto de pila, el recorrido del árbol de pintura omite el contexto de apilado y copia toda la secuencia de elementos de la pantalla de la lista anterior.

El estado actual del árbol de propiedades se mantiene durante el recorrido del árbol de pintura y la lista de elementos de visualización se agrupa en "fragmentos" de elementos que comparten el mismo estado de árbol de propiedades. Esto se demuestra en el siguiente ejemplo:

Una caja rosa con una caja naranja inclinada.

<div id="scroll" style="background:pink; width:100px;
   height:100px; overflow:scroll;
   position:absolute; top:0; left:0;">
    Hello world
    <div id="orange" style="width:75px; height:200px;
      background:orange; transform:rotateZ(25deg);">
        I'm falling
    </div>
</div>

Esto genera la siguiente lista de visualización, en la que cada celda es un elemento de visualización:

Fondo de la vista #scroll en segundo plano Texto intercalado de #scroll #orange en segundo plano Texto intercalado de #orange
drawRect con un tamaño de 800 x 600 y color blanco. drawRect con un tamaño de 100 x 100 en la posición 0,0 y color rosa. drawTextBlob con la posición 0,0 y el texto "Hello World". drawRect con un tamaño de 75 x 200 en la posición 0.0 y de color naranja. drawTextBlob con la posición 0,0 y el texto "Estoy cayendo".

Entonces, el árbol de propiedades de la transformación y los fragmentos de pintura serían (simplificado para mayor brevedad):

Una imagen de la tabla anterior, las dos primeras celdas del bloque 1, la tercera en el bloque 2 y las últimas dos celdas del bloque 3.

La lista ordenada de fragmentos de pintura, que son grupos de elementos de visualización y un estado de árbol de propiedades, son las entradas del paso de creación de capas de la canalización de renderización. La lista completa de fragmentos de pintura se podría combinar en una sola capa compuesta y se podría rasterizar juntos, pero esto requeriría una rasterización costosa cada vez que el usuario se desplazara. Podría crearse una capa compuesta para cada fragmento de pintura y rasterizarse de manera individual para evitar que se vuelva a rasterizar, pero eso agotaría rápidamente la memoria de la GPU. El paso de creación de capas debe compensar la memoria de la GPU y reducir los costos cuando la situación cambia. Un buen enfoque general consiste en combinar los fragmentos de forma predeterminada y no fusionar los fragmentos de pintura con estados de árbol de propiedades que se espera que cambien en el subproceso del compositor, como con el desplazamiento de subproceso del compositor o las animaciones de transformación del subproceso del compositor.

Lo ideal sería que el ejemplo anterior produzca dos capas compuestas:

  • Una capa compuesta de 800 x 600 que contiene los comandos de dibujo:
    1. drawRect con un tamaño de 800 x 600 y color blanco
    2. drawRect con un tamaño de 100 x 100 en la posición 0,0 y color rosa
  • Una capa compuesta de 144 x 224 que contiene los comandos de dibujo:
    1. drawTextBlob con la posición 0,0 y el texto "Hello World"
    2. traducir 0,18
    3. rotateZ(25deg)
    4. drawRect con un tamaño de 75 x 200 en la posición 0 y color naranja
    5. drawTextBlob con la posición 0,0 y el texto "Me estoy cayendo"

Si el usuario se desplaza por #scroll, se mueve la segunda capa compuesta, pero no se necesita la rasterización.

Para el ejemplo, de la sección anterior sobre árboles de propiedades, hay seis trozos de pintura. Junto con los estados del árbol de propiedades (transformar, recortar, efecto, desplazarse) son los siguientes:

  • Fondo del documento: Desplazamiento del documento, clip del documento, raíz, desplazamiento del documento.
  • Esquina horizontal, vertical y de desplazamiento para div (tres fragmentos de pintura separados): Desplazamiento del documento, clip del documento, desenfoque #one y desplazamiento del documento.
  • Iframe #one: rotación de #one, clip de desplazamiento de desbordamiento, #one desenfoque, desplazamiento de div.
  • Iframe #two: escala #two, clip de documento, raíz, desplazamiento de documentos.

Marcos del compositor: superficies, superficies de renderización y mosaicos de texturas de GPU

El navegador y los procesos de renderización administran la rasterización del contenido y, luego, envían marcos del compositor al proceso de Viz para su presentación en la pantalla. Los fotogramas del compositor representan cómo unir contenido de trama y dibujarlo de manera eficiente con la GPU.

Tarjetas

En teoría, un proceso de renderización o un compositor de procesos del navegador podría rasterizar los píxeles en una sola textura del tamaño completo del viewport del procesador y enviar esa textura a Viz. Para mostrarla, el compositor de pantallas solo tendría que copiar los píxeles de esa textura única a la posición adecuada en el búfer de fotogramas (por ejemplo, la pantalla). Sin embargo, si ese compositor quisiera actualizar incluso un píxel, tendría que volver a rasterizar el viewport completo y enviar una textura nueva a Viz.

En cambio, el viewport se divide en mosaicos. Un mosaico de textura de GPU separado respalda cada mosaico con los píxeles rasterizados que forman parte del viewport. Luego, el procesador puede actualizar mosaicos individuales o solo cambiar la posición en la pantalla de los mosaicos existentes. Por ejemplo, cuando te desplazas por un sitio web, la posición de los mosaicos existentes cambiaría hacia arriba y solo ocasionalmente podría ser necesario rasterizar un nuevo mosaico para el contenido que se encuentra más abajo en la página.

Cuatro tarjetas.
En esta imagen, se muestra un día soleado con cuatro mosaicos. Cuando se produce un desplazamiento, comienza a aparecer un quinto mosaico. Uno de los mosaicos solo tiene un color (celeste) y hay un video y un iframe en la parte superior.

Cuatriciclos y superficies

Las tarjetas de textura de GPU son un tipo especial de quad, que es solo un nombre elegante para una categoría u otra de textura. Un cuadrante identifica la textura de entrada e indica cómo transformarla y aplicarle efectos visuales. Por ejemplo, las tarjetas de contenido normales tienen una transformación que indica su posición x e y en la cuadrícula de mosaicos.

Mosaicos de texturas de GPU.

Estos mosaicos rasterizados se unen en un pase de renderización, que es una lista de cuádruplos. El pase de renderización no contiene información de píxeles. En su lugar, tiene instrucciones sobre dónde y cómo dibujar cada cuadrante para producir la salida de píxeles deseada. Hay un cuadro de dibujo para cada tarjeta de textura de la GPU. El compositor de pantallas solo tiene que iterar a través de la lista de cuádruplos, dibujando cada uno con los efectos visuales especificados para producir el resultado de píxeles deseado para el pase de renderización. La composición de cuadrantes de dibujo para un pase de renderización se puede realizar de manera eficiente en la GPU, ya que los efectos visuales permitidos se eligen cuidadosamente para que se asignen directamente a los atributos de la GPU.

Existen otros tipos de cuádruplos de dibujo más allá de las tarjetas en trama. Por ejemplo, hay cuadros de dibujo de color sólido que no están respaldados por una textura, o cuadros de dibujo de texturas para texturas que no son de mosaicos, como video o lienzo.

También es posible que un marco del compositor incorpore otro marco del compositor. Por ejemplo, el compositor del navegador produce un marco del compositor con la IU del navegador y un rectángulo vacío en el que se incorporará el contenido del compositor de renderización. Otro ejemplo son los iframes aislados del sitio. Esta incorporación se realiza a través de plataformas.

Cuando un compositor envía un marco del compositor, se ve acompañado de un identificador, llamado ID de superficie, que permite que otros marcos del compositor lo incorporen como referencia. Viz almacena el fotograma del compositor más reciente enviado con un ID de superficie particular. Luego, otro fotograma del compositor puede hacer referencia a él más tarde a través de un cuadro de dibujo de superficie y, por lo tanto, Viz sabe qué dibujar. (Ten en cuenta que los cuadrantes de dibujo de superficie solo contienen ID de superficie, no texturas).

Pases de renderización intermedios

Algunos efectos visuales, como muchos filtros o modos de combinación avanzados, requieren que se dibujen dos o más cuádruplos para una textura intermedia. Luego, la textura intermedia se dibuja en un búfer de destino en la GPU (o posiblemente otra textura intermedia), y se aplica el efecto visual al mismo tiempo. Para permitir esto, un marco del compositor contiene una lista de pases de renderización. Siempre hay un pase de renderización de raíz, que se dibuja en último lugar y cuyo destino corresponde al búfer de fotogramas, y puede haber más.

La posibilidad de varios pases de renderización explica el nombre "pase de renderización". Cada pase debe ejecutarse de manera secuencial en la GPU, en varios “apases”, mientras que un solo pase se puede completar en un solo procesamiento de GPU masivamente paralelo.

Agregación

Se envían múltiples marcos del compositor a Viz y deben dibujarse juntos en la pantalla. Esto se logra mediante una fase de agregación que los convierte en un solo marco del compositor agregado. La agregación reemplaza los cuadrantes de dibujo de superficie por los marcos del compositor que especifiquen. También es una oportunidad para optimizar las texturas intermedias innecesarias o el contenido que está fuera de la pantalla. Por ejemplo, en muchos casos, el marco del compositor de un iframe aislado de sitio no necesita su propia textura intermedia, y se puede dibujar directamente en el búfer de fotogramas mediante los cuadrantes de dibujo adecuados. La fase de agregación descifra esas optimizaciones y las aplica en función del conocimiento global al que no pueden acceder los compositores de renderización individuales.

Ejemplo

Estos son los marcos del compositor que representan el ejemplo del principio de esta entrada.

  • Plataforma de foo.com/index.html: id=0
    • Pase de renderización 0: Dibuja para el resultado.
      • Pase de renderización para dibujar cuadrantes: dibuja con un desenfoque de 3 px y recorta en el pase de renderización 0.
        • Pase de renderización 1:
          • Dibuja cuádruplos para el contenido de tarjetas del iframe de #one, con posiciones "x" e "y" para cada uno.
      • Cuadrante de dibujo de superficie: con ID 2, dibujado con la transformación de escala y traducción.
  • Plataforma de la IU del navegador: ID=1
    • Pase de renderización 0: Dibuja para el resultado.
      • Dibuja cuadrantes para la IU del navegador (también se muestran en mosaico)
  • Plataforma de bar.com/index.html: ID=2
    • Pase de renderización 0: Dibuja para el resultado.
      • Dibuja cuádruplos para el contenido del iframe #two, con las posiciones "x" e "y" para cada uno.

Ilustraciones de Una Kravets.