Dlaczego ten moduł cieniujący geometrię tak bardzo spowalnia mój program?


27

Mam program OpenGL i renderuję siatkę terenu. Przesuwam wierzchołki w buforze wierzchołków i tak naprawdę nie pokolorowałem ich w module cieniującym fragmenty. Dodaję moduł cieniujący geometrię po jednej części na raz.

Zanim dodałem moduł cieniujący geometrię, kiedy programowałem kroki cieniowania fragmentów i wierzchołków potoku, uzyskiwałem około 30+ klatek na sekundę. Wystarczająco, że nie zauważyłem żadnej niepewności. Po dodaniu modułu cieniującego geometrię uzyskuję około 5 klatek na sekundę. Czemu? Oto całość modułu cieniującego geometrię:

#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();
}

Czy to nie dokładnie to, co robił OpenGL bez modułu cieniującego geometrię?

Odpowiedzi:


40

Czy to nie dokładnie to, co robił OpenGL bez modułu cieniującego geometrię?

Nie, nie jest. GS jest krokiem opcjonalnym , a nie krokiem domyślnym.

Aby OpenGL mógł wykonać moduł cieniujący geometrię , musi wykonać tak zwane „ prymitywne złożenie ”. Kiedy renderujesz serię trójkątów za pomocą GL_TRIANGLE_STRIP, OpenGL zrobi rzeczy wewnętrzne, aby przekształcić każde 3 sąsiadujące wierzchołki w pojedynczy trójkąt, odpowiednio modyfikując kolejność uzwojenia.

Zwykle, gdy nie używa się GS, proces ten jest wykonywany raz. Jeśli jednak używasz GS, musisz je wykonać przed GS. Ale należy to również wykonać po GS, ponieważ GS może generować zupełnie inny typ pierwotny (np. Quady).

Więc teraz sprawiasz, że system w zasadzie wykonuje wiele dodatkowej pracy za darmo. W końcu OpenGL nie może zakładać, że twój GS nic nie robi (to nierozstrzygalny problem).

Ponadto wiele optymalizacji nie działa już w obecności GS. Rozważ renderowanie indeksowane.

Każdy indeks z bufora tablicy elementów wygeneruje te same dane wyjściowe z modułu cieniującego wierzchołki. Więc GPU często buforować tych wyjść w pamięci podręcznej po T & L . Jeśli zobaczy indeks, który jest już w pamięci podręcznej, VS nie zostanie ponownie uruchomiony; po prostu pobiera dane z pamięci podręcznej.

Co to jest"? „To” to… prymitywna jednostka montażowa . Tak, ta rzecz, która uruchamia się dwa razy, gdy używasz GS. Indeks pamięci podręcznej? Działa tylko w przypadku wejść GS.

Co dzieje się z wynikami GS? To zależy od sprzętu. Ale musi przejść do jakiegoś bufora pamięci. I na tym polega problem: ten bufor w ogóle nie jest indeksowany. To jest jak sytuacja glDrawArrays.

Więc jeśli wyślesz bufor indeksu 0, 1, 2, 0, 2, 3, to przełoży się to na 4 wierzchołki w pamięci podręcznej po T & L. Ale bufor wierzchołków po GS ma teraz 6 wierzchołków. Bufor post-GS zajmuje więcej miejsca. Jeśli więc przejdziecie trud tworzenia właściwych list lub pasków trójkątów zoptymalizowanych po T & L i włączysz GS typu pass-through jak twój, w zasadzie zabiłeś około połowy zysków z tej optymalizacji.

To nie było bezużyteczne, ale boli.

Do tego dochodzi fakt, że wiele procesorów graficznych klasy GL 3.x (aka: DX10) miało raczej małe bufory post-GS. Im mniejszy bufor, tym mniej wywołań GS możesz mieć jednocześnie aktywnych. Twój sprzęt skutecznie wąskie gardła w GS. Ponieważ teselacja jest dużą cechą sprzętu klasy 4.x, większość takiego sprzętu ma bufory wystarczające, aby cięższe użycie GS było opłacalne.

Tak więc użycie GS może sprawić, że przetwarzanie wierzchołków kodu będzie wąskie. Oczywiście zawsze możesz użyć tego na swoją korzyść, czyniąc shadery wierzchołków i fragmentów bardziej złożonymi, ponieważ w tym momencie jest to po prostu darmowa wydajność.

Aby uzyskać więcej informacji na temat spowolnień wywołanych przez GS, przeczytaj ten artykuł .

Oto podstawowa zasada o GS: nigdy nie używaj GS bo myślisz uczyni rendering szybciej . Powinieneś go używać, gdy umożliwia to, co próbujesz zrobić . Jeśli próbujesz zoptymalizować, użyj czegoś innego.

Ogólne wyjątki od tego są następujące:


Próbuję obliczyć nachylenie każdego wielokąta, biorąc jego najwyższą wysokość i odejmując jego najniższą wysokość. Jeśli jednak moduł cieniujący geometrycznie koniecznie spowolni mnie o tę wielkość, myślę, że mógłbym to zrobić kreatywnie w module cieniującym wierzchołki.
Avi

1
@Avi pamiętaj, że najwyższe i najniższe punkty w trójkącie nie dadzą ci stromości; potrzebujesz wszystkich trzech punktów.
sam hocevar

2
Osobiście zawsze uważałem, że instancja jest bardziej przydatna dla sprite'ów punktowych niż GS.
Maximus Minimus

1
Czy wyjątek dla duszków punktowych uogólnia się na shadery layout(points) in;? Czy jest to stały rozmiar wyjściowy? A może jedno i drugie?
Filip
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.