2013-07-25 15 views
5

Apple mówi w swoich sprawdzonych metodach dla shaderów na avoid branching, o ile to możliwe, a zwłaszcza na rozgałęzianie na wartościach obliczonych w module cieniującym. Tak więc zastąpiłem niektóre instrukcje if wbudowaną funkcją clamp(). Moje pytanie brzmi, czy są one bardziej wydajne, czy też są jedynie wygodnymi (tj. Makrami) funkcjami, które po prostu rozszerzają się na bloki if?Praktyki OpenGL ES dla osób warunkowych

Wiem, że odpowiedź może być zależna od implementacji. W każdym razie funkcje są oczywiście czystsze i jasno określają cel, z którym kompilator może coś zrobić.

+2

Myślę, że twoje ostatnie zdanie już na nie dość dobrze odpowiada. Poza tym, że wyglądają na znacznie bardziej uproszczone, są one co najmniej bardziej prawdopodobne, że zostaną zaimplementowane za pomocą szybkich instrukcji sprzętowych niż zwykłe 'if'. Poza tą ogólną sugestią (która powinna już wystarczyć), w praktyce jest całkiem prawdopodobne, że używają specjalnych instrukcji sprzętowych lub warunkowych przypisań, a nie są tylko funkcjami zawijającymi 'if's. –

Odpowiedz

9

Historycznie rzecz biorąc, procesory graficzne obsługują instrukcje dotyczące poszczególnych fragmentów, takie jak MIN i MAX, o wiele dłużej, niż obsługują arbitralne rozgałęzienia warunkowe. Jednym z przykładów tego w OpenGL na pulpicie jest rozszerzenie GL_ARB_fragment_program (obecnie zastąpione przez GLSL), które wyraźnie stwierdza, że ​​nie obsługuje rozgałęzień, ale zapewnia instrukcje dla MIN i MAX, a także kilka innych instrukcji warunkowych.

Byłbym przekonany, że wszystkie procesory graficzne nadal będą miały dedykowany sprzęt do tych operacji, biorąc pod uwagę, jak często są one w modułach cieniujących. Nie jest to gwarantowane przez specyfikację, ponieważ implementacja może zoptymalizować kod, ale uważa, że ​​powinien on pasować, ale w świecie rzeczywistym należy raczej używać wbudowanych funkcji GLSL, a nie własnych.

Jedynym wyjątkiem jest sytuacja, w której zastosowano warunek, aby uniknąć dużej ilości dodatkowego przetwarzania fragmentów. W pewnym momencie koszt oddziału będzie mniejszy niż koszt uruchomienia całego kodu w oddziale, ale saldo będzie w tym przypadku bardzo zależne od sprzętu i będziesz musiał porównać, aby sprawdzić, czy rzeczywiście pomaga w twojej aplikacji docelowy sprzęt. Oto takie rzeczy to znaczy:

void main() { 
    vec3 N = ...; 
    vec3 L = ...; 
    float NDotL = dot(N, L); 
    if (NDotL > 0.0) 
    { 
     // Lots of very intensive code for an awesome shadowing algorithm that we 
     // want to avoid wasting time on if the fragment is facing away from the light 
    } 
} 

Wystarczy pierścieniem NDotL do 0-1, a potem zawsze przetwarza kod cień na każdym fragmencie tylko pomnożyć przez ostatecznego terminu cień przez NDotL jest dużo zmarnowanego wysiłku jeśli NDotL pierwotnie był to < = 0 i teoretycznie możemy uniknąć tego obciążenia z odgałęzieniem. Powodem, dla którego tego typu rzeczy nie zawsze wygrywają wydajność, jest to, że zależy to w dużej mierze od tego, jak sprzęt implementuje rozgałęzianie modułu cieniującego.

+0

Doskonała recenzja. Powinienem zdać sobie sprawę, że 'MIN' i' MAX' mają przed sobą ogólny blok "if" i jestem pewien, że masz rację co do obsługi sprzętu. Wielkie dzięki! –

+0

Myślę, że należy wspomnieć o tym, że niektóre GPU nie respektują standardów i nawet nie wdrażają w ogóle oddziałów. Jedynymi, na które natknąłem się, są seria Samsung Galaxy Tab. Mają tylko cichy trzask bez żadnej wiadomości. –