Myślę, że rozumiem o co próbujesz zapytać. Zakładam, że twoim głównym problemem są zmienne niejednolite zdefiniowane poza main()
:
float left;
float right;
float mscaled;
float xn;
float xm;
Rzućmy okiem na działanie GPU i GLSL. Procesor graficzny nie ma stosu ani rekordów aktywacji połączenia. Nie ma sposobu na symulację zasięgu lub lokalnych zmiennych w GLSL, jak kompilator C może zrobić na większości procesorów. Wszystko, co istnieje, to rejestry, które są albo rejestrami jednorodnymi, wejściowymi etapami modułu cieniującego, wyjściami i plikiem rejestru lokalnego unikalnym dla tego wywołania modułu cieniującego.
Innymi słowy, ponieważ nie ma czegoś takiego jak funkcja, stos lub sterta, wszystkie zmienne zadeklarowane w dowolnym miejscu znajdują się w rejestrze. Nie ma znaczenia, czy są one lokalne w pewnym zakresie w GLSL, czy globalne dla całego pliku. To tylko rejestry.
Jednak alokator rejestru nie jest częścią standardu GLSL. Różne implementacje OpenGL mogą mieć różne poziomy jakości, jeśli chodzi o konwersję wysokopoziomowego kodu GLSL na niskopoziomowy kod maszynowy, który GPU rozumie. Jedną z bardziej skomplikowanych części kompilatora (GLSL lub innej) jest alokacja rejestru . Jest to część kompilatora, która określa, które rejestry zajmuje dana zmienna. C ma to trochę trudniejsze, ponieważ zwykle ma do czynienia z bardzo małymi plikami rejestrów (szczególnie na x86) i ma do czynienia z rozlewaniem rejestrów (przenoszenie zmiennych na stos) i aliasingiem (zapisywanie zmiennych z powrotem do pamięci RAM przed wywołaniem funkcji) i nieparzyste instrukcje, które wymagają, aby dane wyjściowe znajdowały się w określonym rejestrze (x86idiv
na przykład). Procesory graficzne mają duży plik rejestru z powodu braku stosu lub sterty, dzięki czemu alokator może być prostszy.
Plik rejestru nie jest jednak nieskończony. Jeśli masz więcej zmiennych niż rejestrów obsługiwanych przez twój sprzęt, kompilator będzie musiał spróbować dopasować wszystkie zmienne do rejestrów. Zwykle wymaga to pewnej formy sprawdzania zasięgu działania . Oznacza to, że jeśli użyjesz zmiennej xn
do jednego obliczenia, to nigdy nie użyjesz jej ponownie, kompilator może to ustalić, a następnie wiedzieć, że zajmowany przez rejestr xn
może być później użyty przez inną zmienną, umożliwiając w ten sposób więcej zmiennych niż rejestrów (tak długo ponieważ jednocześnie nie ma zbyt wielu zmiennych na żywo).
Kompilator może jednak tego nie zrobić. Nie ma Lub może to zrobić tylko w niektórych przypadkach. W zakresach, w których prostsze kompilatory są znacznie łatwiejsze do rozwiązania. Wszystkie rejestry przypisane do lokalnych zmiennych funkcji mogą być ponownie użyte po wyjściu z tej funkcji, ponieważ wiadomo, że zmienne są martwe. Zmienne globalne nie mają tak łatwej gwarancji. W związku z tym niektóre mniej wydajne kompilatory mogą również nie optymalizować ich żywotności, a zmienne globalne zawsze będą zajmować rejestr. Nie spowolni to niczego, ale może w niektórych sterownikach ograniczyć rozmiar shadera, który możesz napisać.
Zasadniczo zdecydowanie zaleciłbym lokalizację wszystkich zmiennych. Zachowaj definicję tak blisko użycia zmiennej, jak to ma sens. Dotyczy to wszystkich języków programowania, nie tylko GLSL. Poleciłbym również ustawienie każdej stałej „zmiennej” w każdym możliwym przypadku. Ponownie może to być wskazówka dla niektórych mniej zdolnych kompilatorów, że pewne optymalizacje są możliwe, a co ważniejsze, sprawia, że twój kod jest bardziej samo dokumentujący i łatwy w utrzymaniu.
I oczywiście, oto Twój obowiązkowy „po prostu profil, aby przetestować i znaleźć na pewno” porady. Napisz swój shader z globalsami i bez nich i profiluj go. Wszelkie porady dotyczące wydajności online powinny być nieufne i zakładać, że są przesiąknięte przypuszczeniami lub nieaktualne.
main()
funkcję? Czy twoje wartości są w rzeczywistości zmiennymi globalnymi (mundury lub atrybuty w języku GLSL), czy wartościami stałymi?