2013-09-01 9 views
8

Mój 9600GT mnie nienawidzi.Moduł cieniujący GLSL nie rozwija pętli w razie potrzeby

Fragment shader:

#version 130 

uint aa[33] = uint[33](
    0,0,0,0,0,0,0,0,0,0, 
    0,0,0,0,0,0,0,0,0,0, 
    0,0,0,0,0,0,0,0,0,0, 
    0,0,0 
); 

void main() { 
    int i=0; 
    int a=26; 

    for (i=0; i<a; i++) aa[i]=aa[i+1]; 

    gl_FragColor=vec4(1.0,0.0,0.0,1.0); 

} 

Jeśli a=25 program działa z prędkością 3000 klatek na sekundę.
Jeśli program a=26 działa z prędkością 20 klatek na sekundę.
Jeśli rozmiar aa < = 32 problem nie pojawia się.
Rozmiar rzutni to 1000x1000.
Problem występuje tylko wtedy, gdy rozmiar aa wynosi> 32.
Wartość a jako wartość progowa zmienia się w zależności od wywołania tablicy wewnątrz pętli (aa[i]=aa[i+1]+aa[i-1] podaje inny termin).
Wiem, że gl_FragColor jest przestarzałe. Ale to nie jest problem.

Domyślam się, że GLSL nie rozwija automatycznie pętli, jeśli a> 25 i rozmiar (aa)> 32. Czemu. Powód, dla którego zależy to od wielkości tablicy, jest nieznany ludzkości.

Dość podobne zachowanie wyjaśnione tutaj:
http://www.gamedev.net/topic/519511-glsl-for-loops/

odwijania pętla ręcznie nie rozwiązuje problemu (3000 fps), nawet jeśli aa wielkość wynosi> 32:

aa[0]=aa[1]; 
    aa[1]=aa[2]; 
    aa[2]=aa[3]; 
    aa[3]=aa[4]; 
    aa[4]=aa[5]; 
    aa[5]=aa[6]; 
    aa[6]=aa[7]; 
    aa[7]=aa[8]; 
    aa[8]=aa[9]; 
    aa[9]=aa[10]; 
    aa[10]=aa[11]; 
    aa[11]=aa[12]; 
    aa[12]=aa[13]; 
    aa[13]=aa[14]; 
    aa[14]=aa[15]; 
    aa[15]=aa[16]; 
    aa[16]=aa[17]; 
    aa[17]=aa[18]; 
    aa[18]=aa[19]; 
    aa[19]=aa[20]; 
    aa[20]=aa[21]; 
    aa[21]=aa[22]; 
    aa[22]=aa[23]; 
    aa[23]=aa[24]; 
    aa[24]=aa[25]; 
    aa[25]=aa[26]; 
    aa[26]=aa[27]; 
    aa[27]=aa[28]; 
    aa[28]=aa[29]; 
    aa[29]=aa[30]; 
    aa[30]=aa[31]; 
    aa[31]=aa[32]; 
    aa[32]=aa[33]; 
+0

Więc ... jakie jest twoje pytanie? –

+1

@NicolBolas Dlaczego, gdy drastycznie spada a = 26 framerate? – user2464424

+1

Jedyną osobą, która mogłaby to wiedzieć, jest osoba, która zaimplementowała twój kompilator OpenGL. –

Odpowiedz

5

jestem tylko wprowadzenie w podsumowującej odpowiedzi na komentarze tutaj, więc to nie pojawia się już jako bez odpowiedzi.

"#pragma optionNV (rozwiń całość)"

rozwiązuje problem na natychmiastowe NVIDIA.

Ogólnie rzecz biorąc, kompilatory GLSL są zależne od implementacji. Powód, dla którego liczba kropli wynosi dokładnie 32, można łatwo wyjaśnić, wybierając heurystyczny kompilator, np. "Nie rozwijaj pętli dłuższych niż 32". Również ogromna różnica prędkości może pochodzić z rozwiniętej pętli używającej stałych, podczas gdy dynamiczna pętla będzie wymagać adresowalnej pamięci tablicy. Innym powodem może być to, że po rozwinięciu eliminacji martwego kodu, ciągłe rzucanie kopnięć redukuje całą pętlę do zera.

Najbardziej przenośną metodą naprawy jest ręczne rozwijanie, a nawet lepsze ręczne składanie na stałe. Zawsze wątpliwe jest obliczanie stałych w module cieniującym, który można obliczyć na zewnątrz. Niektórzy kierowcy mogą go złapać w niektórych przypadkach, ale lepiej nie polegać na tym.

+1

Podkreślę, że długość pętli to 26, a nie 32. 32 to wielkość tablicy. Zasadniczo jest to piekielnie skrajny przypadek. Istnieją co najmniej 3 czynniki będące ze sobą w konflikcie: 1) kompilator usuwa martwy kod tylko w przypadku rozwinięcia pętli. 2) stała tablica zmieniająca się w tablicę przydzieloną VRAM po 32 floatach. 3) próg długości pętli przed jej rozwinięciem automatycznie zależy od typów zmiennych związanych z samą pętlą. Wniosek: w tym przypadku nikt nie powinien się zdarzyć, ponieważ napisany przeze mnie kod jest bardzo złą praktyką i nigdy nie powinien być stosowany w żadnym realnym scenariuszu. – user2464424

Powiązane problemy