2013-03-17 10 views
7

Na przykład, jeśli mogę użyć cieniowania wierzchołków, jak następuje:Czy GLSL naprawdę robi niepotrzebne obliczenia z jednolitymi wartościami (nie na jeden wierzchołek)?

#version 400 core 

uniform mat4 projM; 
uniform mat4 viewM; 
uniform mat4 modelM; 

in vec4 in_Position; 

out vec4 pass_position_model; 

void main(void) { 
    gl_Position = projM * viewM * modelM * in_Position; 
    pass_position_model = modelM * in_Position; 
} 

to zrobi projM * viewM * modelM Mnożenie macierzy dla każdego wierzchołka, czy to wystarczy, inteligentny, aby obliczyć jeśli raz i nie przeliczyć aż jednolite zmienne są zmieniane? Jeśli nie jest "wystarczająco inteligentny", to czy istnieje sposób na jego optymalizację, poza obliczaniem wszystkich wartości zależnych od siebie w jednostce centralnej i przesłaniem ich jako zmiennych jednolitych do procesora graficznego?
Interesują mnie również rozwiązania, które później można bez problemu przenieść do OpenGL ES 2.0.

Odpowiedz

10

Więc, jak rozumiem, nie ma ogólnej odpowiedzi. Zrobiłem jednak kilka testów na moim sprzęcie. Mam 2 GPU w moim ekwipunku, Intel HD Graphics 3000 i NVidia GeForce GT 555M. Testowałem swój program (sam program jest napisany w języku Java/scala) z mnożeniem macierzy w module cieniującym wierzchołków, a następnie przenoszono mnożenie do programu CPU i testowałem ponownie.

(sphereN - to stale obracająca się kula z 2 * N^2 quadami, narysowana za pomocą glDrawElements (GL_QUADS, ...) Z 1 tekstury i bez oświetlenia/inne efekty) mnożenie

matrycy w werteksach: mnożenie

intel: 
    sphere400: 57.17552887364208 fps 
    sphere40: 128.1394156842645 fps 
nvidia: 
    sphere400: 134.9527665317139 fps 
    sphere40: 242.0135527589545 fps 

Matrix procesora:

intel: 
    sphere400: 57.37234652897303 fps 
    sphere40: 128.2051282051282 fps 
nvidia: 
    sphere400: 142.28799089356858 fps 
    sphere40: 247.1576866040534 fps 

Testy wykazują, że multiplicating (jednolite) macierze w vertex shaderze to zły pomysł, przynajmniej na tym sprzęcie. Zasadniczo nie można polegać na odpowiedniej optymalizacji kompilatora GLSL.

+0

Awsome. Będę o tym pamiętać. –

+0

+1 dla wysiłku profilowania (i przy użyciu dwóch posiadanych kart graficznych). – GraphicsMuncher

+0

+1. Ale jak oceniłeś wyniki? Wydaje się, że różnica jest prawie nieistotna. Sugeruję uruchomienie obu symulacji przez 60 sekund i rozważenie najlepszego odczytu FPS (ponieważ jest to najlepsza wydajność, jaką może wykonać procesor/GPU). – Calmarius

3

to zrobi projM * Viewm * modelM Mnożenie macierzy dla każdego wierzchołka, czy to wystarczy, inteligentny, aby obliczyć jeśli raz i nie przeliczyć aż jednolite zmienne są zmieniane?

Zapytaj programistę o implementację OpenGL. Specyfikacja OpenGL nie ma nic do powiedzenia na ten temat, ale twórcy kompilatorów sterowników i GLSL mogli zaimplementować w tym celu optymalizacje.

Jeśli to nie jest „wystarczająco inteligentny”, a następnie czy istnieje sposób, aby zoptymalizować go inne niż obliczanie wartości wszystkich jednolitych zależna od procesora i wysłać je jako jednolitych zmiennych GPU?

Nie. Musisz samodzielnie wykonać nogę.

+0

Jeśli interesuje mnie tylko sytuacja kilku dzisiejszych wiodących dostawców, na przykład NVidia, AMD, PoverVR, pytanie może być łatwiejsze? –

+0

@SargeBorsch: Nie jest łatwiej odpowiedzieć, ponieważ takie optymalizacje są zwykle przechowywane w tajemnicy handlowej. Przynajmniej dla kierowców open source projektu Mesa można zobaczyć, co robią. Ale przy zamkniętych sterownikach źródłowych od NVidii, AMD i Imaginona niemożliwe jest sformułowanie jednoznacznego stwierdzenia. – datenwolf

1

Wszystkie optymalizacje OpenGL i GLSL zależą od dostawcy. Trudno powiedzieć, jaki jest ostateczny wynik z kompilatora glsl.

Możesz zajrzeć tutaj szczegółowych informacji dostawcy: http://renderingpipeline.com/graphics-literature/low-level-gpu-documentation/

Dla kodzie zawsze możesz macierze „opakowania” w nowych mundurach: matModelViewProjection, pomnożyć ją we wniosku i przesłania go do vertex shader.

0

Wszystko zależy od kierowcy. OpenGL to specyfikacja, jeśli zapłacisz im za prawo do wprowadzenia w błąd, które dadzą Ci próbną implementację, ale to wszystko.

Oprócz tego należy wziąć pod uwagę ograniczenia związane z multiplikacją matrycy, ponieważ wykonanie projM * viewM * modelM * vertex nie jest tym samym, co wykonanie vertex * projM * viewM * modelM. Dzieje się tak, ponieważ macierze są mnożone od prawej do lewej, a kolejność ma znaczenie. Tak więc moduł cieniujący nie mógł wstępnie obliczyć wartości projM * viewM * modelM w celu dzielenia między wierzchołkami, ponieważ dałoby to fałszywe wyniki.

+0

Czy jesteś pewien? 'projM * viewM * modelM * in_Position' jest równy' (projM * viewM * modelM) * in_Position' (przynajmniej daje nierozróżnialne ramki w moim programie, gdzie wszystkie 3 macierze nie są trywialne). Ale macierze są rzeczywiście rozmnażane od prawej do lewej. –

+0

Naprawdę? dziwny. Aby wykonać test, używając komputera, możesz stworzyć prosty program, który oblicza macierz 'projM * viewM * modelM' na CPU i ** następnie przekazuje ją do modułu cieniującego. Ponadto powinieneś być w stanie zobaczyć, co to koniec jest z "glGetShaderSource", aby sprawdzić, czy robi coś dziwnego z kodem przed kompilacją. –

+0

Niedawno przeczytałem o tym w Internecie, o tym, że jest to ważna optymalizacja, aby zmienić 'M1 * M2 * v' na' M1 * (M2 * v) ', więc można to zrobić także wstecz, jeśli M1 * M2 jest wstępnie obliczony. Niestety, nie mogę znaleźć linka do niego :( –

Powiązane problemy