Popularne jest renderowanie treści proceduralnych w GPU, np. W wersji demonstracyjnej (rysowanie pojedynczego kwadratu, aby wypełnić ekran i pozwalanie GPU na obliczenie pikseli).
Marsz Ray jest popularny:
Oznacza to, że GPU wykonuje nieznaną liczbę iteracji pętli na piksel (chociaż możesz mieć górną granicę jak maxIterations
).
Jak posiadanie pętli o zmiennej długości wpływa na wydajność modułu cieniującego?
Wyobraź sobie prosty kod psuedokodu:
t = 0.f;
while(t < maxDist) {
p = rayStart + rayDir * t;
d = DistanceFunc(p);
t += d;
if(d < epsilon) {
... emit p
return;
}
}
Jak wpływa to na różne główne rodziny GPU (Nvidia, ATI, PowerVR, Mali, Intel itp.)? Shadery wierzchołków, a szczególnie fragmentatory?
Jak można to zoptymalizować?
opengl
glsl
opengl-es2
raytracing
Będzie
źródło
źródło
Odpowiedzi:
Na GDC 2012 odbyła się miła rozmowa na temat marszu promiennego na odległość GPU (i innych tematów): http://directtovideo.wordpress.com/2012/03/15/get-my-slides-from-gdc2012/
Jeśli chodzi o wydajność, najnowsze karty graficzne (klasy DX11) wykonują shadery na urządzeniach SIMD, które działają w trybie „wątków” 32 (NVIDIA) lub 64 (AMD). Grupy te są różnie znane jako osnowy lub fronty fal. W przypadku jednostek cieniujących piksel każdy wątek jest równy jednemu pikselowi, więc spodziewałbym się, że jednostka SIMD przetwarza coś w rodzaju bloku pikseli 8x4 (NVIDIA) lub 8x8 (AMD). Rozgałęzianie i kontrola przepływu są wykonywane dla poszczególnych fal, więc wszystkie wątki w falach muszą zapętlać tyle razy, ile najgłębszy pojedynczy piksel w tej fali. Maski linii SIMD wyłączą wykonywanie piksli, które już się zakończyły, ale nadal muszą dyskretnie przestrzegać ogólnej kontroli frontu falowego. Oznacza to oczywiście, że system jest znacznie bardziej wydajny, gdy rozgałęzienie jest spójne,
Z mojego doświadczenia wynika, że obciążenie gałęzi jest wciąż dość wysokie, nawet jeśli wszystkie wątki w gałęzi wavefront działają w ten sam sposób. Widziałem wzrost wydajności w niektórych przypadkach poprzez rozwinięcie pętli w celu amortyzacji części obciążenia oddziału. Oczywiście zależy to od tego, ile pracy wykonujesz w każdej iteracji pętli. Jeśli w korpusie pętli jest wystarczająco dużo „rzeczy”, rozwinięcie nie będzie wygrane.
źródło
Sugeruję przeczytanie Uruchamianie kodu w Teraflop: Jak działają rdzenie shaderów GPU (pdf) z SIGGRAPH 2008: Poza programowalnym cieniowaniem . Mówi o dynamicznym rozgałęzianiu.
źródło
W odniesieniu do dynamicznego rozgałęziania, jedna dodatkowa uwaga (może być oczywista, ale nadal warta uwagi dla niektórych osób): może poważnie wpłynąć na wydajność rozwiniętych pętli (oczywiście nie można rozwinąć pętli, jeśli liczba ciągów jest nie stała) .
źródło
int s = 0;
teraz dla (int k = 1; k <= n; k ++) {s + = k;} jest taki sam jak s = n * (n + 1) / 2
więc ogólnie nie jest to prawdą: D
źródło