Strutture di dati chiave in 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

Diamo un'occhiata alle strutture principali dei dati, che sono input e output per la pipeline di rendering.

Queste strutture di dati sono:

  • I frame Tree sono composti da nodi locali e remoti che rappresentano i documenti web in cui si trovano il processo di rendering e il renderer Blink.
  • L'albero di frammenti immutabile rappresenta l'output e l'input dell'algoritmo di vincolo di layout.
  • Le alberi delle proprietà rappresentano le gerarchie di trasformazione, clip, effetto e scorrimento di un documento web. e vengono utilizzati in tutta la pipeline.
  • Gli elenchi di visualizzazione e i blocchi di colore sono gli input per gli algoritmi di raster e di stratificazione.
  • I frame del compositore incapsulano superfici, superfici di rendering e riquadri di texture GPU utilizzati per disegnare utilizzando la GPU.

Prima di attraversare queste strutture di dati, l'esempio seguente si basa su una tratta dalla revisione dell'architettura. Questo esempio viene utilizzato in tutto il documento con dimostrazioni dell'applicazione delle strutture di dati.

<!-- 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>

Alberi incorniciati

A volte Chrome può scegliere di eseguire il rendering di un frame multiorigine in un processo di rendering diverso dal frame principale.

Nel codice di esempio, ci sono tre frame totali:

Un frame principale foo.com, contenente due iframe.

Con l'isolamento dei siti, Chromium utilizza due processi di rendering per visualizzare questa pagina web. Ogni processo di rendering ha la propria rappresentazione dell'albero di frame per la pagina web:

Due strutture di frame che rappresentano i due processi di rendering.

Un frame sottoposto a rendering in un processo diverso è rappresentato da un frame remoto. Un frame remoto contiene il minimo di informazioni necessarie per fungere da segnaposto nel rendering, ad esempio le sue dimensioni. In caso contrario, il frame remoto non contiene alcuna informazione necessaria per eseguire il rendering dei suoi contenuti effettivi.

Al contrario, un frame locale rappresenta un frame che passa attraverso la pipeline di rendering standard. Il frame locale contiene tutte le informazioni necessarie per trasformare i dati per quel frame (come l'albero DOM e i dati di stile) in qualcosa che può essere visualizzato e visualizzato.

La pipeline di rendering opera sulla base di un livello di granularità di un frammento di albero di frame locale. Considera un esempio più complicato con foo.com come frame principale:

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

E il seguente frame secondario bar.com:

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

Anche se ci sono ancora solo due renderer, ora sono presenti tre frammenti di frame frame locali, con due nel processo di rendering per foo.com e uno nel processo di rendering per bar.com:

Una rappresentazione dei due rendering e tre frammenti di albero di frame.

Per produrre un frame del compositore per la pagina web, Viz richiede contemporaneamente un frame del compositore dal frame principale di ciascuna delle tre strutture di frame locali e quindi li aggrega. Fai riferimento anche alla sezione relativa ai frame del compositore.

Il frame principale foo.com e il frame secondario foo.com/other-page fanno parte dello stesso albero di frame e vengono visualizzati nello stesso processo. Tuttavia, i due frame hanno ancora cicli di vita dei documenti indipendenti poiché fanno parte di diversi frammenti di frame Tree locali. Per questo motivo, non è possibile generare un frame del compositore per entrambi in un unico aggiornamento. Il processo di rendering non ha informazioni sufficienti per comporre il frame del compositore generato per foo.com/other-page direttamente nel frame del compositore per il frame principale foo.com. Ad esempio, il frame principale bar.com out-of-process potrebbe influire sulla visualizzazione dell'iframe foo.com/other-url, trasformando l'iframe con CSS o nascondendo parti dell'iframe con altri elementi nel suo DOM.

Struttura a cascata dell'aggiornamento delle proprietà visive

Le proprietà visive come il fattore di scala del dispositivo e le dimensioni dell'area visibile influiscono sull'output visualizzato e devono essere sincronizzate tra i frammenti ad albero di frame locali. Alla radice di ogni frammento di albero di frame locale è associato un oggetto widget. Gli aggiornamenti delle proprietà visive vengono inviati al widget del frame principale prima di propagarsi ai widget rimanenti dall'alto verso il basso.

Ad esempio, quando cambiano le dimensioni dell'area visibile:

Diagramma del processo spiegato nel testo precedente.

Questo processo non è istantaneo, quindi le proprietà visive replicate includono anche un token di sincronizzazione. Il compositore Viz utilizza questo token di sincronizzazione per attendere che tutti i frammenti ad albero di frame locali inviino un frame del compositore con il token di sincronizzazione corrente. Questo processo evita la combinazione di frame del compositore con proprietà visive diverse.

L'albero a frammenti immutabile

L'albero di frammenti immutabile è l'output della fase di layout della pipeline di rendering. Rappresenta la posizione e le dimensioni di tutti gli elementi sulla pagina (senza trasformazioni applicate).

Rappresentazione dei frammenti in ogni albero, con un frammento contrassegnato come layout necessario.

Ogni frammento rappresenta una parte di un elemento DOM. In genere è presente un solo frammento per elemento, ma è possibile averne di più se viene suddiviso in diverse pagine durante la stampa o in colonne quando si trova in un contesto a più colonne.

Dopo il layout, ogni frammento diventa immutabile e non viene più modificato. È importante anche applicare alcune limitazioni aggiuntive. Cosa non facciamo:

  • Consenti qualsiasi riferimento "up" nella struttura. (Un asset secondario non può avere un puntatore al relativo elemento principale.)
  • "a bolle" in basso nell'albero (un publisher secondario legge solo le informazioni dai propri figli, non da quelli dell'elemento principale).

Queste restrizioni ci consentono di riutilizzare un frammento per un layout successivo. Senza queste restrizioni, spesso dovremmo rigenerare l'intero albero, il che è costoso.

La maggior parte dei layout è in genere aggiornamenti incrementali, ad esempio un'app web che aggiorna una piccola parte dell'interfaccia utente in risposta al clic dell'utente su un elemento. Idealmente, il layout dovrebbe funzionare proporzionalmente a ciò che è stato effettivamente modificato sullo schermo. Possiamo ottenere questo risultato riutilizzando il maggior numero possibile di parti dell'albero precedente. Ciò significa (in genere) che dobbiamo solo ricostruire la colonna vertebrale dell'albero.

In futuro, questo design immutabile potrebbe consentirci di fare cose interessanti come passare l'albero di frammenti immutabile oltre i confini dei thread se necessario (per eseguire fasi successive su un thread diverso), generare più alberi per un'animazione di layout fluida o eseguire layout speculativi paralleli. Inoltre, ci offre il potenziale del layout multi-threading stesso.

Elementi con frammenti incorporati

I contenuti in linea (prevalenza del testo con stili applicati) utilizzano una rappresentazione leggermente diversa. Anziché una struttura ad albero con caselle e puntatori, rappresentano i contenuti in linea in un elenco semplice che rappresenta l'albero. Il vantaggio principale è che una rappresentazione a elenco fisso per i dati in linea è rapida, utile per ispezionare o eseguire query sulle strutture di dati in linea ed efficiente in termini di memoria. Questo è estremamente importante per le prestazioni di rendering web, dal momento che il rendering del testo è molto complesso e può facilmente diventare la parte più lenta della pipeline se non è molto ottimizzato.

L'elenco semplice viene creato per ogni contesto di formattazione in linea nell'ordine di una ricerca in profondità nella struttura secondaria del layout in linea. Ogni voce dell'elenco è una tupla di (oggetto, numero di discendenti). Ad esempio, considera questo DOM:

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

La proprietà width è impostata su 0 in modo che la linea venga spostata tra "Hi" e "there".

Quando il contesto di formattazione in linea per questa situazione è rappresentato come una struttura ad albero, l'aspetto è il seguente:

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

L'elenco semplice ha il seguente aspetto:

  • (Riquadro a linee, 2)
  • (Box <span>, 1)
  • (Testo "Ciao", 0)
  • (Riquadro a linee, 3)
  • (Riquadro <b>, 1)
  • (Testo "lì", 0)
  • (Testo ".", 0)

Esistono molti consumatori di questa struttura di dati: API di accessibilità e API di geometria come getClientRects e contenteditable. Ognuno ha requisiti diversi. Questi componenti accedono alla struttura dei dati piatti tramite un cursore pratico.

Il cursore ha API quali MoveToNext, MoveToNextLine, CursorForChildren. Questa rappresentazione del cursore è molto efficace per i contenuti testuali per diversi motivi:

  • L'iterazione dell'ordine di ricerca depth-first è molto veloce. Viene usato molto spesso perché è simile ai movimenti del cursore. Poiché si tratta di un elenco semplice, la ricerca depth-first non aumenta l'offset dell'array, fornendo iterazioni rapide e località di memoria.
  • Fornisce una ricerca sull'ampiezza, necessaria quando, ad esempio, dipingi lo sfondo di riquadri in linea e in linea.
  • Conoscere il numero di discendenti consente di passare rapidamente all'elemento di pari livello successivo (basta incrementare l'offset dell'array di quel numero).

Alberi della proprietà

Il DOM è una struttura di elementi (più nodi di testo) e CSS può applicare vari stili agli elementi.

Esistono quattro modi per:

  • Layout: inserisce l'algoritmo del vincolo di layout.
  • Paint: come dipingere e rasterizzare l'elemento (ma non i relativi discendenti).
  • Immagini: effetti di raster/disegno applicati al sottoalbero del DOM, come trasformazioni, filtri e ritaglio.
  • Scorrimento: ritaglio degli angoli arrotondati e allineati all'asse e scorrimento del sottoalbero contenuto.

Gli alberi delle proprietà sono strutture di dati che spiegano come gli effetti visivi e di scorrimento vengono applicati agli elementi DOM. Forniscono i mezzi per rispondere a domande quali: dove, rispetto allo schermo, si trova un determinato elemento DOM, in base alle dimensioni e alla posizione del layout? Infine, quale sequenza di operazioni GPU dovrebbe essere utilizzata per applicare effetti visivi e di scorrimento?

Gli effetti visivi e di scorrimento sul web sono molto complicati nel loro complesso. La cosa più importante che gli alberi di proprietà fanno è tradurre questa complessità in un'unica struttura di dati che ne rappresenti con precisione la struttura e il significato, eliminando al contempo il resto della complessità di DOM e CSS. In questo modo possiamo implementare algoritmi per la composizione e lo scorrimento con maggiore sicurezza. In particolare:

  • La geometria potenzialmente soggetta a errori e altri calcoli possono essere centralizzati in un'unica posizione.
  • La complessità della creazione e dell'aggiornamento degli alberi di proprietà è isolata in una fase della pipeline di rendering.
  • È molto più facile e veloce inviare alberi di proprietà a thread e processi diversi rispetto allo stato DOM completo, rendendo così possibile utilizzarli per molti casi d'uso.
  • Maggiore è il numero di casi d'uso, maggiori sono i risultati che possiamo ottenere dalla memorizzazione nella cache della geometria basata su, in quanto possono riutilizzare le cache reciproche.

RenderingNG utilizza gli alberi di proprietà per molti scopi, tra cui:

  • Separazione della composizione dal disegno e della composizione dal thread principale.
  • Determinare una strategia di composizione / disegno ottimale.
  • Misurazione della geometria IntersectionObserver.
  • Evitando di lavorare per elementi fuori schermo e riquadri di texture GPU.
  • Annullamento di immagini e raster in modo efficiente e preciso.
  • Misurazione della variazione del layout e della visualizzazione più grande con contenuti in Core Web Vitals.

Ogni documento web ha quattro strutture di proprietà separate: transform, clip, effetti e scorrimento.(*) L'albero di trasformazione rappresenta le trasformazioni e lo scorrimento CSS. Una trasformazione di scorrimento è rappresentata come una matrice di trasformazione 2D. La struttura ad albero rappresenta i clip extra. L'albero degli effetti rappresenta tutti gli altri effetti visivi: opacità, filtri, maschere, modalità di fusione e altri tipi di clip come clip-path. L'albero di scorrimento rappresenta le informazioni sullo scorrimento, ad esempio il modo in cui si concatena lo scorrimento; è necessario per eseguire lo scorrimento sul thread del compositore. Ogni nodo in una struttura ad albero delle proprietà rappresenta uno scorrimento o un effetto visivo applicato da un elemento DOM. In caso di effetti multipli, potrebbe esserci più di un nodo dell'albero delle proprietà per lo stesso elemento.

La topologia di ogni albero è come una rappresentazione sparsa del DOM. Ad esempio, se sono presenti tre elementi DOM con clip di overflow, ci saranno tre nodi dell'albero dei clip e la struttura del clip Tree seguirà la relazione di blocco contenitore tra i clip di overflow. Sono inoltre presenti collegamenti tra gli alberi. Questi link indicano la gerarchia DOM relativa e quindi l'ordine di applicazione dei nodi. Ad esempio, se una trasformazione su un elemento DOM si trova al di sotto di un altro elemento DOM con un filtro, ovviamente la trasformazione viene applicata prima del filtro.

Ogni elemento DOM ha uno stato ad albero delle proprietà, ovvero un 4 tuple (trasformazione, clip, effetto, scorrimento) che indica i nodi predecessore, trasformazione e albero degli effetti più vicini che hanno effetto su quell'elemento. Questo è molto pratico, perché con queste informazioni conosciamo esattamente l'elenco di clip, trasformazioni ed effetti applicabili a quell'elemento e in quale ordine. Questo ci indica dove si trova sullo schermo e come disegnarlo.

Esempio

(fonte)

<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>

Nell'esempio precedente (che è leggermente diverso da quello nell'introduzione), ecco gli elementi chiave degli alberi di proprietà generati:

Un esempio dei vari elementi della struttura ad albero delle proprietà.

Visualizza elenchi e blocchi di colore

Un elemento visualizzato contiene comandi di disegno di basso livello (vedi qui) che possono essere rasterizzati con Skia. Gli elementi di visualizzazione sono in genere semplici, con pochi comandi di disegno, ad esempio tracciare un bordo o uno sfondo. L'albero di visualizzazione esegue l'iterazione sull'albero del layout e sui frammenti associati seguendo l'ordine di pittura CSS per produrre un elenco di elementi da visualizzare.

Ad esempio:

Un riquadro blu con la scritta &quot;Hello world&quot; all&#39;interno di un rettangolo 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>

Questo codice HTML e CSS produrrebbe il seguente elenco di visualizzazione, in cui ogni cella è un elemento di visualizzazione:

Sfondo della visualizzazione #blue in background #green in background Testo in linea #green
drawRect con dimensioni 800x600 e colore bianco. drawRect con dimensioni 100 x 100 nella posizione 0,0 e colore blu. drawRect con dimensioni 80 x 18 nella posizione 8,8 e di colore verde. drawTextBlob con posizione 8,8 e testo "Hello world".

L'elenco degli elementi visualizzati viene ordinato in ordine decrescente. Nell'esempio precedente, il div verde precede il div blu nell'ordine DOM, ma l'ordine di colorazione CSS richiede che l'elemento div blu negativo con z-index venga visualizzato prima (passaggio 3) del div verde (passaggio 4.1). Gli elementi visualizzati corrispondono approssimativamente ai passaggi atomici della specifica dell'ordine di colorazione CSS. Un singolo elemento DOM può generare diversi elementi di visualizzazione, ad esempio #green ha un elemento di visualizzazione per lo sfondo e un altro per il testo incorporato. Questa granularità è importante per rappresentare l'intera complessità della specifica dell'ordine di colorazione CSS, ad esempio l'interfoliazione creata da un margine negativo:

Un rettangolo verde con una casella grigia parzialmente sovrapposta e la scritta &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>

Questo produce il seguente elenco di visualizzazione, in cui ogni cella è un elemento di visualizzazione:

Sfondo della visualizzazione #green in background #gray in background Testo in linea #green
drawRect con dimensioni 800x600 e colore bianco. drawRect con dimensioni 80 x 18 nella posizione 8,8 e di colore verde. drawRect con dimensioni 35 x 20 nella posizione 8 e 16 e colore grigio. drawTextBlob con posizione 8,8 e testo "Hello world".

L'elenco degli articoli visualizzati viene archiviato e riutilizzato tramite aggiornamenti successivi. Se un oggetto di layout non ha subito modifiche durante la procedura di colorazione, i relativi elementi di visualizzazione vengono copiati dall'elenco precedente. Un'ulteriore ottimizzazione si basa su una proprietà della specifica dell'ordine di colorazione CSS: l'impilamento dei contesti viene visualizzato a livello atomico. Se nessun oggetto di layout è stato modificato all'interno di un contesto di sovrapposizione, l'operazione di colorazione ad albero salta il contesto di sovrapposizione e copia l'intera sequenza di elementi di visualizzazione dall'elenco precedente.

L'attuale stato della struttura ad albero delle proprietà viene mantenuto durante il percorso e l'elenco degli elementi di visualizzazione viene raggruppato in "blocchi" di elementi di visualizzazione che condividono lo stesso stato della struttura ad albero delle proprietà. Ciò è dimostrato nell'esempio seguente:

Un riquadro rosa con un riquadro arancione inclinato.

<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>

Questo produce il seguente elenco di visualizzazione, in cui ogni cella è un elemento di visualizzazione:

Sfondo della visualizzazione #scroll in background Testo in linea #scroll #orange in background Testo in linea #orange
drawRect con dimensioni 800x600 e colore bianco. drawRect con dimensioni 100 x 100 nella posizione 0,0 e di colore rosa. drawTextBlob con posizione 0,0 e il testo "Hello world". drawRect con dimensioni 75 x 200 nella posizione 0,0 e di colore arancione. drawTextBlob con posizione 0,0 e il testo "Sto scendendo".

L'albero della proprietà di trasformazione e i blocchi di colorazione sarebbero quindi (semplificati per brevità):

Un&#39;immagine della tabella precedente, le prime due celle nel blocco 1, la terza nel blocco 2, le ultime due celle nel blocco 3.

L'elenco ordinato di blocchi di colore, ovvero gruppi di elementi di visualizzazione e uno stato della struttura ad albero delle proprietà, sono gli input per la fase di stratificazione della pipeline di rendering. L'intero elenco di blocchi di colore poteva essere unito in un unico strato composito e rasterizzato insieme, ma richiederebbe una costosa rasterizzazione ogni volta che l'utente scorreva la pagina. È possibile creare uno strato composito per ogni porzione di colore e rasterizzare singolarmente per evitare qualsiasi rirasterizzazione, ma questo esaurirebbe rapidamente la memoria GPU. Il passaggio di stratificazione deve scendere a compromessi tra la memoria GPU e ridurre i costi in caso di cambiamenti. Un buon approccio generale consiste nell'unire i blocchi per impostazione predefinita e non unire i blocchi di colore con stati della struttura ad albero delle proprietà che dovrebbero cambiare nel thread del compositore, ad esempio con lo scorrimento del thread compositore o con le animazioni di trasformazione del thread compositore.

L'esempio precedente dovrebbe idealmente produrre due strati compositi:

  • Un livello composito 800 x 600 contenente i comandi di disegno:
    1. drawRect con dimensioni 800 x 600 e colore bianco
    2. drawRect con dimensioni 100 x 100 nella posizione 0,0 e di colore rosa
  • Un livello composito 144 x 224 contenente i comandi di disegno:
    1. drawTextBlob con posizione 0,0 e il testo "Hello world"
    2. traduci 0,18
    3. rotateZ(25deg)
    4. drawRect con dimensioni 75 x 200 nella posizione 0,0 e di colore arancione
    5. drawTextBlob con posizione 0,0 e il testo "Sto scendendo"

Se l'utente scorre #scroll, il secondo livello composito viene spostato, ma non è necessaria la rasterizzazione.

Ad esempio, nella sezione precedente sugli alberi di proprietà, sono presenti sei porzioni di colore. Insieme agli stati dell'albero delle proprietà (trasformazione, clip, effetto, scorrimento), sono:

  • Sfondo documento: scorrimento documento, clip documento, radice, scorrimento documento.
  • Angolo orizzontale, verticale e di scorrimento per div (tre blocchi di colore separati): scorrimento documento, clip documento, sfocatura #one, scorrimento documento.
  • iframe #one: rotazione di #one, clip di scorrimento extra, sfocatura #one, scorrimento div.
  • iframe #two: scala #two, clip documento, radice, scorrimento documento.

Frame del compositore: superfici, superfici di rendering e riquadri di texture GPU

I processi del browser e di rendering gestiscono la rasterizzazione dei contenuti, quindi inviano i frame di composizione al processo Viz per la presentazione sullo schermo. I frame del compositore rappresentano come unire i contenuti rasterizzati e come disegnarli in modo efficiente utilizzando la GPU.

Riquadri

In teoria, un processo di rendering o un compositore di processi del browser potrebbe rasterizzare i pixel in una singola texture a grandezza naturale dell'area visibile del renderer e inviare questa texture a Viz. Per visualizzarla, il compositore display deve semplicemente copiare i pixel di quella singola texture nella posizione appropriata nel buffer del frame (ad esempio, lo schermo). Tuttavia, se il compositore volesse aggiornare anche un solo pixel, dovrebbe rirasterizzare l'area visibile completa e inviare una nuova texture a Viz.

L'area visibile viene invece suddivisa in riquadri. Un riquadro di texture GPU separato fa retromarcia ogni riquadro con i pixel rasterizzati per parte dell'area visibile. Può quindi aggiornare singoli riquadri o anche solo cambiare la posizione dei riquadri esistenti sullo schermo. Ad esempio, quando si scorre un sito web, la posizione dei riquadri esistenti viene spostata verso l'alto e solo occasionalmente un nuovo riquadro deve essere rasterizzato per i contenuti più in basso nella pagina.

Quattro riquadri.
Questa immagine mostra l'immagine di una giornata di sole, con quattro riquadri. Quando si scorre, inizia a visualizzare un quinto riquadro. Uno dei riquadri ha un solo colore (azzurro cielo) e nella parte superiore ci sono un video e un iframe.

Quad e piattaforme

I riquadri di texture GPU sono un tipo speciale di quad, che è solo un nome sofisticato per una categoria di texture o un'altra. Un quad identifica la texture di input e indica come trasformarla e applicarvi effetti visivi. Ad esempio, i riquadri di contenuti normali presentano una trasformazione che indica la posizione x e y nella griglia dei riquadri.

Riquadri texture GPU.

Questi riquadri rasterizzati vengono avvolti in un pass di rendering, che è un elenco di quad. Il passaggio di rendering non contiene informazioni sui pixel, ma ha istruzioni su dove e come disegnare ogni quad per produrre l'output dei pixel desiderato. È presente un quad di disegno per ogni riquadro di texture GPU. Il compositore display deve solo ripetere l'elenco di quad, disegnandole con gli effetti visivi specificati, per produrre l'output dei pixel desiderato per il passaggio di rendering. La composizione di quattro quad per un rendering può essere eseguita in modo efficiente sulla GPU, perché gli effetti visivi consentiti vengono scelti con cura in modo che siano mappati direttamente alle funzionalità della GPU.

Oltre ai riquadri rasterizzati, esistono altri tipi di quadricipiti. Ad esempio, esistono quadri di disegno a colori a tinta unita non supportati da alcuna texture o quadri per disegnare con texture per texture senza riquadri come video o canvas.

È anche possibile che un frame del compositore incorpora un altro frame del compositore. Ad esempio, il compositore del browser produce un frame del compositore con l'interfaccia utente del browser e un rettangolo vuoto in cui verranno incorporati i contenuti del compositore di rendering. Un altro esempio sono gli iframe isolati per i siti. L'incorporamento viene realizzato tramite le superfici.

Quando un compositore invia un frame del compositore, è accompagnato da un identificatore, chiamato surface ID, che consente agli altri frame del compositore di incorporarlo per riferimento. Il frame del compositore più recente inviato con un particolare ID di superficie viene archiviato da Viz. Un altro frame del compositore può quindi farvi riferimento in seguito tramite un quad di disegno di superficie e pertanto Viz sa cosa disegnare. Tieni presente che i quadricipiti contengono solo gli ID superficie e non le texture.

Pass di rendering intermedi

Alcuni effetti visivi, come molti filtri o modalità di fusione avanzate, richiedono che due o più quadri siano disegnati su una texture intermedia. La texture intermedia viene poi inserita in un buffer di destinazione sulla GPU (o eventualmente in un'altra texture intermedia), applicando contemporaneamente l'effetto visivo. Per consentire ciò, un frame del compositore contiene in realtà un elenco di passaggi di rendering. C'è sempre un passaggio di rendering principale, che viene disegnato per ultimo e la cui destinazione corrisponde al buffer del frame e ce ne potrebbero essere altri.

La possibilità di avere più passaggi di rendering spiega il nome "render pass". Ogni passaggio deve essere eseguito in sequenza sulla GPU, in più "pass", mentre un singolo passaggio può essere completato in un singolo calcolo GPU molto parallelo.

Aggregazione

Vengono inviati a Viz più frame del compositore che devono essere tracciati insieme sullo schermo. Ciò è possibile grazie a una fase di aggregazione che li converte in un singolo frame compositore aggregato. L'aggregazione sostituisce i quadricipiti di superficie da parte dei frame del compositore specificati. È anche un'opportunità per eliminare texture intermedie non necessarie o contenuti fuori schermo. Ad esempio, in molti casi il frame del compositore per un iframe isolato in un sito non ha bisogno di una propria texture intermedia e può essere disegnato direttamente nel buffer del frame tramite quad di disegno appropriati. La fase di aggregazione determina queste ottimizzazioni e le applica sulla base di conoscenze globali non accessibili ai singoli compositori di rendering.

Esempio

Questi sono i frame del compositore che rappresentano l'esempio dall'inizio di questo post.

  • Superficie foo.com/index.html: id=0
    • Passaggio 0 del rendering: disegna nell'output.
      • Quadratura di disegno del passaggio del rendering: disegna con una sfocatura di 3 px e posiziona il clip nel passaggio di rendering pari a 0.
        • Pass di rendering 1:
          • Disegna quad per i contenuti dei riquadri dell'iframe #one, con posizioni x e y per ciascuno.
      • Quadruplo di disegno della superficie: con ID 2, disegnato con la trasformazione in scala e trasla.
  • Piattaforma UI del browser: ID=1
    • Passaggio 0 del rendering: disegna nell'output.
      • Disegna quadricipiti per l'interfaccia utente del browser (anche affiancati)
  • Piattaforma bar.com/index.html: ID=2
    • Passaggio 0 del rendering: disegna nell'output.
      • Disegna dei quad per i contenuti dell'iframe #two, specificando le posizioni x e y per ciascuno.

Illustrazioni di Una Kravets.