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

Veamos 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 se componen de nodos locales y remotos que representan qué documentos web se encuentran en qué proceso de renderización y qué renderizador de Blink.
  • El árbol de fragmentos inmutable representa el resultado (y la entrada) del algoritmo de restricción de diseño.
  • Los árboles de propiedades representan las jerarquías de transformación, recorte, efecto y desplazamiento de un documento web. Se usan en toda la canalización.
  • Las listas de visualización y los fragmentos de pintura son las entradas de los algoritmos de rasterización y de creación de capas.
  • Los fotogramas del compositor encapsulan las superficies, las superficies de renderización y las tarjetas de textura de la GPU que se usan para dibujar con la GPU.

Antes de analizar estas estructuras de datos, el siguiente ejemplo se basa en uno de la revisión de la arquitectura. Este ejemplo se usa en todo este documento con demostraciones de cómo se 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>

Árboles de marco

A veces, Chrome puede elegir renderizar un marco entre orígenes en un proceso de renderización diferente de su marco superior.

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

Un marco superior foo.com que contiene dos iframes

Con el aislamiento de sitios, Chromium usa dos procesos de renderización para renderizar 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 fotogramas que representan los dos procesos de renderización.

Un fotograma renderizado en un proceso diferente se representa como un fotograma remoto. Un marco remoto contiene la información mínima necesaria para actuar como marcador de posición en la renderización, como sus dimensiones, por ejemplo. De lo contrario, el marco remoto no contiene información necesaria para renderizar su contenido real.

En cambio, un fotograma 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 el árbol DOM y los datos de estilo) en algo que se pueda renderizar y mostrar.

La canalización de renderización opera en el nivel de detalle de un fragmento de árbol de fotogramas 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 renderizadores, ahora hay tres fragmentos de árbol de tramas locales, 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 tres fragmentos del árbol de fotogramas.

Para producir un fotograma del compositor para la página web, Visualiza solicita simultáneamente un fotograma del compositor desde el fotograma raíz de cada uno de los tres árboles de fotogramas locales y, luego, los agrega. Consulta también la sección de fotogramas 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 de árbol de marcos locales. Por este motivo, es imposible generar un fotograma del compositor para ambos en una sola actualización. El proceso de renderización no tiene suficiente información para combinar el fotograma del compositor generado para foo.com/other-page directamente en el fotograma del compositor para el fotograma principal foo.com. Por ejemplo, el marco superior bar.com fuera del proceso puede afectar la visualización del iframe foo.com/other-url, ya que transforma el iframe con CSS o ocluye partes del iframe con otros elementos en su DOM.

Cascada de actualización de propiedades visuales

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 locales tiene un objeto de widget asociado. Las actualizaciones de propiedades visuales se envían 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 usa 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. Este proceso evita mezclar fotogramas 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 de la página (sin aplicar transformaciones).

Representación de los fragmentos en cada árbol, con un fragmento marcado como que necesita diseño.

Cada fragmento representa una parte de un elemento 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 más se vuelve a cambiar. Es importante que sepas que también aplicamos algunas restricciones adicionales. No hacemos lo siguiente:

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

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

Por lo general, la mayoría de los diseños son actualizaciones incrementales, por ejemplo, una app web que actualiza una pequeña parte de la IU en respuesta a que el usuario hace clic en un elemento. Lo ideal es que el diseño solo realice tareas proporcionales a lo que realmente cambió en la pantalla. Para lograrlo, podemos reutilizar tantas partes del árbol anterior como sea posible. Esto significa que, por lo general, solo debemos volver a compilar la columna vertebral del árbol.

En el futuro, este diseño inmutable podría permitirnos hacer cosas 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 en paralelo. También nos brinda el potencial del diseño de subprocesos.

Elementos de fragmento intercalados

El contenido intercalado (principalmente, texto con diseño aplicado) 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 beneficio principal es que una representación de lista plana para las intercaladas es rápida, útil para inspeccionar o consultar estructuras de datos intercaladas y eficiente en la 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 fácilmente en la parte más lenta de la canalización, a menos que esté muy optimizada.

La lista plana se crea para cada contexto de formato intercalado en el orden de una búsqueda en profundidad de su subárbol de diseño intercalado. Cada entrada de la lista es una tupla de (objeto, cantidad de descendientes). 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 “Hola” y “hay”.

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 se ve de la siguiente manera:

  • (Line box, 2)
  • (cuadro <span>, 1)
  • (Text "Hola", 0)
  • (cuadro de línea, 3)
  • (cuadro <b>, 1)
  • (Text "there", 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 requisitos diferentes. Estos componentes acceden a la estructura de datos plana a través de un cursor conveniente.

El cursor tiene APIs, como MoveToNext, MoveToNextLine y CursorForChildren. Esta representación del cursor es muy potente para el contenido de texto por varios motivos:

  • La iteración en el orden de búsqueda en profundidad es muy rápida. Se usa con mucha frecuencia porque es similar a los movimientos de corchetes. Como es una lista plana, la búsqueda en profundidad solo incrementa el desplazamiento del array, lo que proporciona iteraciones rápidas y localidad de memoria.
  • Proporciona una búsqueda en amplitud, que es necesaria cuando, por ejemplo, se pinta el fondo de los cuadros de línea y en línea.
  • Conocer la cantidad de elementos secundarios permite pasar al siguiente elemento hermano con rapidez (solo debes incrementar el desplazamiento del array en esa cantidad).

Á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 para el algoritmo de restricción de diseño.
  • Paint: Cómo pintar y rasterizar el elemento (pero no sus descendientes)
  • Visual: Son efectos de rasterización o dibujo que se aplican al subárbol del DOM, como transformaciones, filtros y recortes.
  • Desplazamiento: Recorte de esquinas redondeadas y alineadas con el eje, y desplazamiento del subárbol contenido.

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

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

  • La geometría potencialmente propensa a errores y otros cálculos pueden centralizarse 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 el estado completo del DOM, lo que permite usarlos para muchos casos de uso.
  • Cuantos más casos de uso haya, más beneficios podremos obtener de la caché de geometría compilada en la parte superior, ya que pueden reutilizar las cachés de los demás.

RenderingNG usa árboles de propiedades para muchos fines, incluidos los siguientes:

  • Separación de la composición de la pintura y de la composición del subproceso principal
  • Determinar una estrategia de composición o dibujo óptima
  • Medición de la geometría de IntersectionObserver
  • Evita el trabajo para los elementos fuera de la pantalla y las tarjetas de textura de la GPU.
  • Invalida la pintura y el raster de manera eficiente y precisa.
  • Medir el cambio de diseño y la pintura más grande del contenido en las Métricas web esenciales

Cada documento web tiene cuatro árboles de propiedades independientes: transformación, recorte, efecto y desplazamiento.(*) El árbol de transformación representa las transformaciones y el desplazamiento de CSS. (Una transformación de desplazamiento se representa como una matriz de transformación 2D). El árbol de clips representa los 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 clip-path. El árbol de desplazamiento representa información sobre el desplazamiento, como cómo se encadenan los desplazamientos. Es necesario para realizar el desplazamiento en el subproceso del compositor. Cada nodo de un árbol de propiedades representa un desplazamiento o un efecto visual que aplica un elemento 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 DOM con clips de desbordamiento, entonces habrá tres nodos del árbol de clips, y la estructura del árbol de clips seguirá la relación del bloque contenedor entre los clips de desbordamiento. También hay vínculos entre los árboles. Estos vínculos indican la jerarquía de DOM relativa y, por lo tanto, el orden de aplicación de los nodos. Por ejemplo, si una transformación en un elemento DOM está debajo de otro elemento DOM con un filtro, por supuesto, la transformación se aplica antes del filtro.

Cada elemento DOM tiene un estado del árbol de propiedades, que es un 4-tuplo (transformación, recorte, efecto y desplazamiento) que indica el clip, la transformación y los nodos del árbol de efectos del ancestro más cercano que tienen efecto en ese elemento. Esto es muy conveniente, ya que con esta información sabemos exactamente 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>

En 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 del árbol de propiedades.

Cómo mostrar listas y pintar fragmentos

Un elemento de visualización 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 unos pocos 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 siguiendo el orden de pintura del 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 produciría la siguiente lista de visualización, en la que cada celda es un elemento de visualización:

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

La lista de elementos visibles está ordenada de atrás hacia adelante. En el ejemplo anterior, el div verde está antes del div azul en el orden del DOM, pero el orden de pintura del CSS requiere que el div azul con índice z negativo se pinte antes (paso 3) que el div verde (paso 4.1). Los elementos de visualización corresponden aproximadamente a pasos atómicos de la especificación del orden de pintura del CSS. Un solo elemento DOM puede generar varios elementos de visualización, como el modo en que #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 del CSS, como la intercalación creada por el margen negativo:

Un rectángulo verde, con un cuadro gris superpuesto en parte y las palabras &quot;Hello world&quot;.

<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 produce la siguiente lista de visualización, en la que cada celda es un elemento de visualización:

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

La lista de elementos visibles se almacena y se reutiliza 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: los contextos de apilamiento se pintan de forma atómica. Si no cambió ningún objeto de diseño dentro de un contexto de apilamiento, el recorrido del árbol de pintura omite el contexto de apilamiento y copia toda la secuencia de elementos de visualización 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 de visualización que comparten el mismo estado del árbol de propiedades. Esto se demuestra en el siguiente ejemplo:

Una caja rosada 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 produce la siguiente lista de visualización, en la que cada celda es un elemento de visualización:

Fondo de View #scroll en segundo plano #scroll texto intercalado #orange en segundo plano #orange texto intercalado
drawRect con un tamaño de 800 x 600 y color blanco. drawRect con un tamaño de 100 × 100 en la posición 0,0 y de 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 "I'm falling".

El árbol de propiedades de transformación y los fragmentos de pintura serían los siguientes (simplificados para mayor brevedad):

Una imagen de la tabla anterior, las dos primeras celdas del fragmento 1, la tercera del fragmento 2 y las dos últimas del fragmento 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 división en capas de la canalización de renderización. Toda la lista de fragmentos de pintura se podría combinar en una sola capa compuesta y rasterizar juntos, pero esto requeriría una rasterización costosa cada vez que el usuario se desplaza. Se podría crear una capa compuesta para cada fragmento de pintura y rasterizarla de forma individual para evitar la rasterización, pero eso agotaría rápidamente la memoria de la GPU. El paso de división en capas debe realizar compensaciones entre la memoria de la GPU y la reducción de los costos cuando cambian los elementos. Un buen enfoque general es combinar fragmentos de forma predeterminada y no combinar fragmentos de pintura que tengan estados de árbol de propiedades que se espera que cambien en el subproceso del compositor, como con el desplazamiento del subproceso del compositor o las animaciones de transformación del subproceso del compositor.

En el ejemplo anterior, lo ideal sería que se produjeran dos capas compuestas:

  • Una capa compuesta de 800 × 600 que contiene los siguientes comandos de dibujo:
    1. drawRect con un tamaño de 800 x 600 y color blanco
    2. drawRect con un tamaño de 100 × 100 en la posición 0,0 y de color rosa
  • Una capa compuesta de 144 × 224 que contiene los siguientes 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,0 y de color naranja
    5. drawTextBlob con la posición 0,0 y el texto "I'm falling"

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

En el ejemplo, de la sección anterior sobre árboles de propiedades, hay seis fragmentos de pintura. Junto con los estados del árbol de propiedades (transform, clip, effect, scroll), 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, recorte del documento, desenfoque de #one, desplazamiento del documento.
  • Iframe #one: #one rota, clip de desplazamiento desbordado, desenfoque #one, desplazamiento de div.
  • #two de iframe: Escala de #two, recorte de documentos, raíz y desplazamiento de documentos.

Fotogramas del compositor: superficies, renderización de superficies y tarjetas de textura de la GPU

Los procesos de renderización y navegador administran la rasterización del contenido y, luego, envían fotogramas del compositor al proceso de Viz para que se presenten en la pantalla. Los fotogramas del compositor representan cómo unir el contenido rasterizado y dibujarlo de manera eficiente con la GPU.

Tarjetas

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

En su lugar, el viewport se divide en mosaicos. Una tarjeta de textura de GPU independiente respalda cada tarjeta con los píxeles rasterizados para parte del viewport. Luego, el renderizador puede actualizar tarjetas individuales o incluso cambiar la posición en pantalla de las tarjetas existentes. Por ejemplo, cuando se desplaza un sitio web, la posición de las tarjetas existentes se desplaza hacia arriba y, solo ocasionalmente, se debe rasterizar una tarjeta nueva para el contenido que se encuentra más abajo en la página.

Cuatro tarjetas
Esta imagen muestra un día soleado con cuatro tarjetas. Cuando se produce un desplazamiento, comienza a aparecer una quinta tarjeta. Una de las tarjetas solo tiene un color (azul celeste) y hay un video y un iframe en la parte superior.

Cuadrículas y superficies

Las tarjetas de textura de la GPU son un tipo especial de cuadrángulo, que es solo un nombre elegante para una categoría de textura o para otra. Un cuádruple identifica la textura de entrada y señala cómo transformarla y aplicarle efectos visuales. Por ejemplo, las tarjetas de contenido normales tienen una transformación que indica su posición en X e Y en la cuadrícula de tarjetas.

Mosaicos de texturas de la GPU.

Estas tarjetas rasterizadas se unen en un pase de renderización, que es una lista de cuadrángulos. 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 cuádruple para producir el resultado de píxeles deseado. Hay un cuadrángulo de dibujo para cada tarjeta de textura de la GPU. El compositor de pantalla solo tiene que iterar por la lista de cuádruplos y dibujar 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 cuadrángulos 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 sean aquellos que se asignan directamente a las funciones de la GPU.

Existen otros tipos de cuadrángulos de dibujo además de las tarjetas rasterizadas. Por ejemplo, hay cuadrángulos de dibujo de color sólido que no tienen respaldo de una textura o cuadrángulos de dibujo de textura para texturas que no son de mosaico, como video o lienzo.

También es posible que un fotograma del compositor incorpore otro fotograma del compositor. Por ejemplo, el compositor del navegador produce un marco de 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 logra a través de superficies.

Cuando un compositor envía un fotograma, este se acompaña de un identificador, llamado ID de superficie, que permite que otros fotogramas del compositor lo incorporen por referencia. Viz almacena el fotograma del compositor más reciente que se envió con un ID de superficie en particular. Luego, otro fotograma del compositor puede hacer referencia a él más adelante a través de un cuadrángulo de dibujo de superficie, por lo que Viz sabe qué dibujar. (Ten en cuenta que los cuádruplos de dibujo de la superficie solo contienen IDs 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 en una textura intermedia. Luego, la textura intermedia se dibuja en un búfer de destino en la GPU (o posiblemente en otra textura intermedia) y se aplica el efecto visual al mismo tiempo. Para permitir esto, un fotograma del compositor contiene una lista de pases de renderización. Siempre hay un pase de renderización raíz, que se dibuja al final y cuyo destino corresponde al búfer de trama, y puede haber más.

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

Agregación

Se envían varios fotogramas del compositor a Viz, y se deben dibujar en la pantalla juntos. Esto se logra mediante una fase de agregación que los convierte en un solo marco de compositor agregado. La agregación reemplaza los cuádruplos de dibujo de superficie por los fotogramas del compositor que especifican. También es una oportunidad para optimizar las texturas intermedias innecesarias o el contenido fuera de la pantalla. Por ejemplo, en muchos casos, el fotograma del compositor para un iframe aislado del sitio no necesita su propia textura intermedia y se puede dibujar directamente en el búfer de trama a través de los quads de dibujo adecuados. La fase de agregación determina 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 fotogramas del compositor que representan el ejemplo del comienzo de esta publicación.

  • foo.com/index.html surface: id=0
    • Paso de renderización 0: dibuja en la salida.
      • Render pass draw quad: Dibuja con desenfoque de 3 px y recorta en el pase de renderización 0.
        • Paso de renderización 1:
          • Dibuja cuadrángulos para el contenido de las tarjetas del iframe de #one, con posiciones x e y para cada uno.
      • Cuadrángulo de dibujo de superficie: con el ID 2, dibujado con la transformación de escala y traducción.
  • Plataforma de la IU del navegador: ID=1
    • Paso de renderización 0: dibuja en la salida.
      • Dibuja cuadrángulos para la IU del navegador (también en mosaico)
  • Superficie bar.com/index.html: ID=2
    • Paso de renderización 0: dibuja en la salida.
      • Dibuja cuadrángulos para el contenido del iframe #two, con posiciones x e y para cada uno.

Ilustraciones de Una Kravets.