2011-02-05 14 views
6

Obecnie uczę się tworzyć shadery w GLSL dla silnika gry, nad którym pracuję, i mam pytanie dotyczące języka, który mnie zastanawia. Nauczyłem się, że w wersjach modułów cieniujących niższych niż 3.0 nie można używać jednolitych zmiennych w warunkach pętli. Na przykład poniższy kod nie działa w wersjach modułu cieniującego starszych niż 3.0.Komenda przerwania GLSL

for (int i = 0; i < uNumLights; i++) 
{ 
    ............... 
} 

Ale nie jest to możliwe, aby zastąpić tę z pętlą ze stałą ilością powtórzeń, ale zawierające stwierdzenie warunkowe, które przerwać pętlę jeśli w tym przypadku, jest większa niż uNumLights ?. Np .:

for (int i = 0; i < MAX_LIGHTS; i++) 
{ 
    if(i >= uNumLights) 
     break; 
    .............. 
} 

Czy nie są one równoważne? Czy te ostatnie powinny działać w starszych wersjach GLSL? A jeśli tak, to czy nie jest to bardziej wydajne i łatwiejsze do wdrożenia niż inne techniki, o których czytałem, np. Używanie innej wersji shadera dla różnych ilości świateł?
Wiem, że to może być głupie pytanie, ale jestem początkującym i nie mogę znaleźć powodu, dla którego to nie powinno zadziałać.

Odpowiedz

11

GLSL może być mylące ile for() sugeruje ci, że musi istnieć rozgałęzienia warunkowe, nawet gdy nie ma dlatego, że sprzęt jest w stanie zrobić to w ogóle (co dotyczy if() w ten sam sposób).

Co naprawdę dzieje się na sprzęcie pre-SM3 jest to, że HAL wewnątrz implementacji OpenGL będzie całkowicie rozwinąć swoją pętlę, więc faktycznie nie ma skok więcej. I to tłumaczy, dlaczego ma trudności z nietrwałymi.

Mimo że technicznie możliwe jest to zrobić za pomocą niestałych i tak, implementacja będzie musiała przekompilować moduł cieniujący za każdym razem, gdy zmieni się ten uniform, i może działać wbrew maksymalnej liczbie instrukcji, jeśli tylko dostarczy się jakiekolwiek przypadkowe numer.

To jest problem, ponieważ ... co wtedy? To zła sytuacja.

Jeśli podasz zbyt dużą stałą, spowoduje to błąd kompilatora "zbyt wielu instrukcji" podczas budowania modułu cieniującego. Teraz, jeśli podasz głupią liczbę w mundurze, a HAL musi w związku z tym stworzyć nowy kod i działa wbrew temu limitowi, co może zrobić OpenGL?
Najprawdopodobniej sprawdziłeś swój program po kompilacji i łączeniu, a najprawdopodobniej zapytałeś dziennik informacji o module cieniującym, a OpenGL mówił ci, że wszystko było w porządku. Jest to, w pewnym sensie, wiążąca obietnica, nie może po prostu nagle zdecydować inaczej. Dlatego musi upewnić się, że taka sytuacja nie może powstać, a jedynym praktycznym rozwiązaniem jest nie dopuszczanie uniformów w warunkach generacji sprzętu, które nie obsługują dynamicznego rozgałęziania.
W przeciwnym razie musi istnieć jakaś forma sprawdzania poprawności wewnątrz glUniform, która odrzuca błędne wartości. Ponieważ jednak zależy to od udanej (lub nieudanej) ponownej kompilacji shaderów, oznaczałoby to, że musiałaby ona działać synchronicznie, co czyni go podejściem "nie iść".Weź również pod uwagę, że GL_ARB_uniform_buffer_object jest narażony na niektóre urządzenia SM2 (na przykład GeForce FX), co oznacza, że ​​możesz rzucić obiekt buforowy z nieprzewidywalną zawartością w OpenGL i nadal oczekiwać, że zadziała jakoś! Wdrożenie będzie musiało skanować pamięć bufora pod kątem nieprawidłowych wartości po odjęciu go, co jest szalone.

Podobnie jak w przypadku pętli, instrukcja if() nie rozgałęzia się na sprzęcie SM2, nawet jeśli wygląda na to. Zamiast tego obliczy obie gałęzie i wykona ruch warunkowy.

2

(Zakładam, że mówisz o cieniowania pikseli).
Drugi wariant będzie działać tylko na GPU, który obsługuje Shader Model> = 3. Ponieważ dynamiczny rozgałęzienia (takich jak wprowadzenie o zmiennym uNumLights do IF warunek) nie jest obsługiwana przez GPU modelu cieniowania < 3 albo.

Here można porównać to, co jest i nie jest obsługiwane między różnymi modelami cieniowania.

+0

Obecnie piszę shadery na starej karcie graficznej, która obsługuje tylko model cieniowania 2.0. Dziwne jest to, że drugi wariant rzeczywiście działa, a przynajmniej kompiluje się bez błędu. Jeśli chodzi o funkcjonalność, nie jestem jeszcze pewien, czy zatrzyma się po uruchomieniu polecenia break. Pierwszy oczywiście się nie kompiluje. –

+0

Ale jako wyjaśniony @ dm.skt drugi wariant nie jest skuteczny z powodu wysokiego ryzyka ponownego kompilacji shaderów. Nie zależałbym zatem od konstruktów składni, które są obsługiwane tylko w HAL (ale nie w sprzęcie) z wydajnościami :-) –