Perché questo shader di geometria rallenta così tanto il mio programma?


27

Ho un programma OpenGL e sto eseguendo il rendering di una mesh del terreno. Sposto i vertici nel buffer dei vertici e non li coloro ancora nello shader di frammenti. Sto aggiungendo uno shader di geometria una parte alla volta.

Prima di aggiungere lo shader della geometria, mentre stavo solo programmando le fasi di ombreggiatura dei frammenti e dei vertici della pipeline, ottenevo framerate di circa 30+. Abbastanza che non potevo notare alcuna increspatura. Dopo aver aggiunto lo shader della geometria, ottengo circa 5 fotogrammi al secondo. Perché? Questa è l'intera geometria shader:

#version 420

layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;

void main()
{
    for (int i = 0; i < gl_in.length(); i++)
    {
        gl_Position = gl_in[i].gl_Position;
        EmitVertex();
    }
    EndPrimitive();
}

Non è esattamente ciò che OpenGL stava facendo senza lo shader della geometria?

Risposte:


40

Non è esattamente ciò che OpenGL stava facendo senza lo shader della geometria?

No, non lo è. GS è un passaggio facoltativo , non un passaggio con un valore predefinito.

Affinché OpenGL esegua uno shader di geometria , deve eseguire quello che è noto come " assembly primitivo ". Quando si GL_TRIANGLE_STRIPesegue il rendering di una serie di triangoli tramite , OpenGL eseguirà operazioni interne per convertire ogni 3 vertici adiacenti in un singolo triangolo, modificando l'ordine di avvolgimento in modo appropriato.

Normalmente, quando non si utilizza un GS, questo processo viene eseguito una volta. Quando si utilizza un GS, tuttavia, deve essere eseguito prima dell'esecuzione di GS. Ma deve anche essere eseguito dopo il GS, perché un GS può produrre un tipo primitivo completamente diverso (ad es. Quad).

Quindi ora stai facendo praticamente al sistema un sacco di lavoro extra per niente. Dopotutto, OpenGL non può presumere che il tuo GS non stia facendo nulla (questo è un problema indecidibile).

Inoltre, una serie di ottimizzazioni non funzionano più in presenza di un GS. Prendi in considerazione il rendering indicizzato.

Ogni indice da un buffer di array di elementi produrrà gli stessi output da uno shader di vertici. Così la GPU sarà spesso nella cache queste uscite in una cache post-T & L . Se vede un indice che è già nella cache, il VS non viene eseguito di nuovo; recupera solo i dati dalla cache.

Che cos'è"? "It" è ... l' unità di assemblaggio primitiva . Sì, quella cosa che viene eseguita due volte quando usi un GS. L'indice memorizza nella cache? Funziona solo per gli ingressi del GS.

Quindi cosa succede alle uscite della GS? Bene, dipende dall'hardware. Ma deve andare in una sorta di buffer di memoria. E qui sta il problema: quel buffer non è affatto indicizzato. È come una situazione glDrawArrays.

Quindi, se si invia un buffer di indice di 0, 1, 2, 0, 2, 3, questo si tradurrebbe in 4 vertici nella cache post-T & L. Ma il buffer dei vertici post-GS ora contiene 6 vertici. Il buffer post-GS utilizza più spazio. Quindi, se hai il problema di creare elenchi di triangoli o strisce correttamente ottimizzati post-T & L, e capovolgi una GS pass-through come la tua, fondamentalmente hai ucciso circa la metà dei tuoi guadagni in termini di prestazioni da tale ottimizzazione.

Non era inutile, ma fa male.

A ciò si aggiunge il fatto che molte GPU di classe GL 3.x (aka: DX10) avevano buffer post-GS piuttosto piccoli. Più piccolo è il buffer, meno invocazioni GS puoi avere attivo contemporaneamente. In questo modo il tuo hardware si colloca efficacemente sul GS. Poiché la tassellatura è una grande caratteristica dell'hardware di classe 4.x, la maggior parte di tali hardware ha buffer sufficienti per rendere praticabile l'utilizzo di GS più pesante.

Quindi l'uso di un GS ha maggiori probabilità di rallentare l'elaborazione del vertice del codice. Ovviamente, puoi sempre usarlo a tuo vantaggio rendendo i tuoi shader di vertici e frammenti più complessi, dal momento che sono solo prestazioni gratuite a quel punto.

Per ulteriori informazioni sui rallentamenti indotti da GS, leggi questo articolo .

Ecco una regola empirica di base sui GS: non usare mai un GS perché pensi che renderà il rendering più veloce . Dovresti usarlo quando rende possibile ciò che stai cercando di fare . Se quello che stai cercando di fare è un'ottimizzazione, usa qualcos'altro.

Le eccezioni generali a questo sono:


Sto cercando di calcolare la pendenza di ciascun poligono prendendo la sua altezza più alta e sottraendo la sua altezza più bassa. Tuttavia, se uno shader di geometria mi rallenta necessariamente di questa quantità, penso che potrei essere in grado di farlo in modo creativo nello shader di vertice.
Avi,

1
@Avi nota che i punti più alti e più bassi in un triangolo non ti daranno la sua pendenza; hai bisogno di tutti e tre i punti.
Sam Hocevar,

2
Personalmente ho sempre trovato l'istancing più utile per gli sprite di punti rispetto a un GS.
Maximus Minimus

1
L'eccezione per gli sprite di punti si generalizza agli shader di layout(points) in;? O è la dimensione di uscita fissa? O forse entrambi?
Philip
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.