GLSL - Deklarowanie zmiennych globalnych poza zakresem głównej funkcji

12

Czy pomaga deklarować zmienne poza głównym zakresem funkcji w GLSL? Czy te zmienne faktycznie są ponownie wykorzystywane i czy są bardziej wydajne?

Oto kod, o którym mowa:

varying vec2 vposition;
uniform float seed;
uniform float top;
uniform float bottom;
uniform float phi;
uniform float theta;
uniform float scaledPI;
uniform float yn;
uniform float ym;
uniform float rx;
uniform float ry;
uniform float radius;

const float PI = 3.141592653589793238462643383;

float left;
float right;
float mscaled;
float xn;
float xm;
void main() {
    float t = vposition.y * yn + ym;

    if(t <= 0.0 || t >= PI){
        left = phi - PI;
        right = phi + PI;
    }else{
        mscaled = scaledPI / (1 - abs(Math.cos(theta)));
        mscaled = mscaled < PI ? mscaled : PI;
        left = phi - mscaled;
        right = phi + mscaled;
    }
    xn = (left - right) / ((-rx / 2.0) - (rx / 2.0));
    xm = left - ((-rx/2.0) * xn);
    float p = vposition.x * xn + xm;

    vec3 coords = vec3( sin(p) * sin(t), cos(t), cos(p) * sin(t) );
    float nv = surface( vec4( coords, seed ) );
    gl_FragColor = vec4( vec3( nv, nv, nv ), 1.0 );
}
RodgerDodger
źródło
3
To pytanie jest mylące. GLSL nie ma głównej pętli. Masz na myśli main()funkcję? Czy twoje wartości są w rzeczywistości zmiennymi globalnymi (mundury lub atrybuty w języku GLSL), czy wartościami stałymi?
Sean Middleditch,
Czy możesz zamieścić kod jako przykład tego, o czym mówisz?
Nathan Reed,
Zaktualizowałem pytanie kodem.
RodgerDodger
@ user1286792: To nie zmienia faktu, że GLSL nie ma głównej pętli . Nie jest jasne, o czym mówisz. Co dokładnie myślisz, że zostanie to uratowane?
Nicol Bolas,
@NicolBolas Zaktualizowałem pytanie, aby było bardziej jasne. Mam nadzieję, że przyda się teraz komuś w przyszłości.
RodgerDodger

Odpowiedzi:

33

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 (x86idivna 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 xndo jednego obliczenia, to nigdy nie użyjesz jej ponownie, kompilator może to ustalić, a następnie wiedzieć, że zajmowany przez rejestr xnmoż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.

Sean Middleditch
źródło
Dokładnie o to mi chodziło. Odpowiedziałeś doskonale na moje pytanie, a także lepiej wyjaśniłeś, o co pytałem.
RodgerDodger
1
Właściwie czasami deklarowanie tablic jako const zamiast non-const powoduje spowolnienie całego shadera (DUŻO wolniej). Zauważyłem ten problem na moim GTX 460.
Tara,
Właśnie pozbyłem się dziwnego błędu i mocno podejrzewam, że to GPU Adreno (OpenGL ES 3.1) nie skompilował modułu cieniującego, ponieważ zmienne zostały zadeklarowane poza głównym.
comodoro
Jedna z najdokładniejszych odpowiedzi SO, jakie kiedykolwiek widziałem - dobra robota!
duhaime
Dziś muszę nauczyć się czegoś nowego. Dzisiaj uczę się, że naprawdę nie znam ani nie rozumiem glsl. To, że mogę go używać do tworzenia cylindrycznej geometrii przekształconej w przestrzeń cylindryczną, nie oznacza, że ​​rozumiem, jak to działa.
cmarangu,