Jak działa OpenGL na najniższym poziomie? [Zamknięte]

84

Rozumiem, jak pisać programy OpenGL / DirectX i znam matematykę i koncepcje, które się za tym kryją, ale jestem ciekaw, jak działa komunikacja GPU-CPU na niskim poziomie.

Powiedzmy, że mam program OpenGL napisany w C, który wyświetla trójkąt i obraca kamerę o 45 stopni. Kiedy skompiluję ten program, zostanie on zamieniony na serię wywołań ioctl, a sterownik gpu wyśle ​​następnie odpowiednie polecenia do gpu, gdzie cała logika obracania trójkąta i ustawiania odpowiednich pikseli w odpowiednim kolorze jest podłączona w? A może program zostanie skompilowany do postaci „programu GPU”, który jest ładowany do procesora GPU i oblicza rotację itp.? A może coś zupełnie innego?

Edycja : Kilka dni później znalazłem tę serię artykułów, która w zasadzie odpowiada na pytanie: http://fgiesen.wordpress.com/2011/07/01/a-trip-through-the-graphics-pipeline-2011-part- 1 /

Benno
źródło
Specyfikacja OpenGL stwierdza, że ​​polecenia są wysyłane w trybie klient / serwer. Specyfikacja jest zbyt szeroka, aby określić konkretną technologię używaną w implementacjach OpenGL.
Luca

Odpowiedzi:

86

Odpowiedź na to pytanie jest prawie niemożliwa, ponieważ sam OpenGL jest tylko interfejsem API typu front-end i tak długo, jak implementacja jest zgodna ze specyfikacją, a wynik jest zgodny z tym, można to zrobić w dowolny sposób.

Pytanie mogło brzmieć: jak działa sterownik OpenGL na najniższym poziomie. Teraz znowu nie można odpowiedzieć na to ogólnie, ponieważ sterownik jest ściśle powiązany z jakimś sprzętem, który może znowu działać tak, jak zaprojektował go programista.

Zatem pytanie powinno brzmieć: „Jak to średnio wygląda za kulisami OpenGL i systemu graficznego?”. Spójrzmy na to od dołu do góry:

  1. Na najniższym poziomie jest jakieś urządzenie graficzne. W dzisiejszych czasach są to GPU, które zapewniają zestaw rejestrów kontrolujących ich działanie (które dokładnie są zależne od urządzenia), mają trochę pamięci programowej dla shaderów, pamięć masową na dane wejściowe (wierzchołki, tekstury itp.) Oraz kanał I / O dla reszty systemu, przez który odbiera / wysyła strumienie danych i poleceń.

  2. Sterownik karty graficznej śledzi stan procesorów GPU i wszystkie zasoby aplikacji korzystających z GPU. Odpowiada również za konwersję lub jakiekolwiek inne przetwarzanie danych wysyłanych przez aplikacje (konwertowanie tekstur do formatu pikseli obsługiwanego przez GPU, kompilowanie shaderów w kodzie maszynowym GPU). Ponadto zapewnia abstrakcyjny, zależny od sterownika interfejs do programów użytkowych.

  3. Jest też zależna od sterownika biblioteka / sterownik klienta OpenGL. W systemie Windows ładuje się to przez proxy przez opengl32.dll, w systemach Unix znajduje się w dwóch miejscach:

    • Moduł X11 GLX i sterownik GLX zależny od sterownika
    • a /usr/lib/libGL.so może zawierać pewne elementy zależne od sterownika do bezpośredniego renderowania

    W systemie MacOS X jest to „OpenGL Framework”.

    To właśnie ta część tłumaczy wywołania OpenGL, jak to robisz, na wywołania funkcji specyficznych dla sterownika w części sterownika opisanej w (2).

  4. Wreszcie aktualna biblioteka API OpenGL, opengl32.dll w systemie Windows i na Unix /usr/lib/libGL.so; to głównie przekazuje polecenia do właściwej implementacji OpenGL.

Jak przebiega faktyczna komunikacja, nie można uogólniać:

W Uniksie połączenie 3 <-> 4 może się odbywać albo przez Sockets (tak, może i przechodzi przez sieć, jeśli chcesz) lub przez Shared Memory. W systemie Windows biblioteka interfejsów i klient sterownika są ładowane do przestrzeni adresowej procesu, więc to nie tyle komunikacja, ile proste wywołania funkcji i przekazywanie zmiennych / wskaźników. W MacOS X jest to podobne do Windows, tyle że nie ma oddzielenia między interfejsem OpenGL a klientem sterownika (to jest powód, dla którego MacOS X tak wolno nadąża za nowymi wersjami OpenGL, zawsze wymaga pełnej aktualizacji systemu operacyjnego, aby dostarczyć nowy struktura).

Komunikacja między 3 <-> 2 może przechodzić przez ioctl, odczytywać / zapisywać lub poprzez mapowanie pewnej pamięci do przestrzeni adresowej procesu i konfigurowanie MMU tak, aby wyzwalała kod sterownika, gdy tylko zmiany w tej pamięci są wykonywane. Jest to dość podobne w każdym systemie operacyjnym, ponieważ zawsze musisz przekroczyć granicę jądra / obszaru użytkownika: Ostatecznie przechodzisz przez wywołanie systemowe.

Komunikacja między systemem a GPU odbywa się za pośrednictwem magistrali peryferyjnej i definiowanych przez nią metod dostępu, czyli PCI, AGP, PCI-E itp., Które działają przez Port-I / O, Memory Mapped I / O, DMA, IRQ.

datenwolf
źródło
1
Ten opis jest prawdopodobnie zbyt niskopoziomowy i ogólny z bardzo małą ilością szczegółów dotyczących OpenGL. Z grubsza dotyczy każdego komponentu sprzętowego obecnego w komputerze.
przeciwko Shashenko
1
@ v.shashenko: Cóż, oczywiście. Niezależnie od tego, z którym komponentem sprzętowym rozmawiasz, postępuje zgodnie z tym ogólnym schematem. Ale OpenGL nie jest konkretnym oprogramowaniem, to tylko specyfikacja i wszystko , co jest zgodne ze specyfikacją, jest prawidłową implementacją. A ponieważ w końcu implementacja OpenGL komunikuje się z GPU, będzie z grubsza podążać za tym samym skryptem, wzdłuż którego zaimplementowane są interfejsy API skierowane do sprzętu. Nie można być bardziej szczegółowym, ponieważ nie ma implementacji OpenGL „ JEDNEJ ”. A każde wdrożenie jest trochę inne.
datenwolf
1
@ v.shashenko: Jeśli chcesz uzyskać więcej informacji, musisz zapytać o konkretną implementację. Na przykład powiedzmy X11 + GLX + DRI → Mesa / AMDGPU → Linux-KMS + DRM (Direct Rendering Manager). A każdy z tych elementów jest dość złożoną bestią z tak wieloma szczegółami, że można by wypełnić książki szczegółami na temat działania każdego elementu. Ale to by opisało implementację Linux-AMDGPU. Ale Linux + NVidia to zupełnie inna bestia. A w systemie Windows znowu jest inaczej.
datenwolf
Pamiętasz, jak rozmawialiśmy kilka dni temu, chciałem tylko wiedzieć, jak się z tobą skontaktować, jeśli chcę się czegoś dowiedzieć.?
Suraj Jain
To, czego nauczyłeś się tamtego dnia, rozwiało wiele moich wątpliwości, stworzyło też nowe, ale teraz ogólnie nie uważam za magię, że rysujemy okna i ikonę na ekranie.
Suraj Jain
23

Kiedy skompiluję ten program, zostanie on zamieniony na serię wywołań ioctl, a sterownik gpu wyśle ​​następnie odpowiednie polecenia do gpu, gdzie cała logika obracania trójkąta i ustawiania odpowiednich pikseli w odpowiednim kolorze jest podłączona w? A może program zostanie skompilowany do postaci „programu GPU”, który jest ładowany do procesora GPU i oblicza rotację itp.?

Nie jesteś daleko. Twój program wywołuje instalowalny sterownik klienta (który tak naprawdę nie jest sterownikiem, jest to biblioteka współdzielona w przestrzeni użytkownika). Spowoduje to użycie ioctl lub podobnego mechanizmu do przekazywania danych do sterownika jądra.

W następnej części zależy to od sprzętu. Starsze karty graficzne miały tak zwany „potok o ustalonej funkcji”. Na karcie graficznej były dedykowane miejsca w pamięci dla macierzy i dedykowany sprzęt do wyszukiwania tekstur, mieszania itp. Sterownik wideo ładował odpowiednie dane i flagi dla każdej z tych jednostek, a następnie ustawiał DMA do przesyłania danych wierzchołków (pozycja , kolor, współrzędne tekstury itp.).

Nowszy sprzęt ma rdzenie procesorów („shadery”) wewnątrz karty graficznej, które różnią się od procesora tym, że każdy z nich działa znacznie wolniej, ale jest ich znacznie więcej pracujących równolegle. W przypadku tych kart graficznych sterownik przygotowuje pliki binarne programu do działania w modułach cieniujących GPU.

Ben Voigt
źródło
20

Twój program nie jest kompilowany dla żadnego konkretnego GPU; jest po prostu dynamicznie połączony z biblioteką, która zaimplementuje OpenGL. Rzeczywista implementacja może obejmować wysyłanie poleceń OpenGL do GPU, uruchamianie oprogramowania awaryjnego, kompilowanie programów do cieniowania i wysyłanie ich do GPU, a nawet używanie funkcji zastępczych shaderów do poleceń OpenGL. Krajobraz graficzny jest dość skomplikowany. Na szczęście łączenie izoluje cię od większości złożoności sterowników, pozostawiając wykonawcom sterowników swobodę korzystania z dowolnych technik, które uznają za stosowne.

Tobu
źródło
18

Kompilatory / konsolidatory C / C ++ robią dokładnie jedną rzecz: konwertują pliki tekstowe na serię kodów operacyjnych specyficznych dla maszyny, które są uruchamiane na procesorze. OpenGL i Direct3D to po prostu interfejsy API C / C ++; nie mogą magicznie przekształcić twojego kompilatora / linkera C / C ++ w kompilator / linker dla GPU.

Każda linia kodu C / C ++, którą napiszesz, zostanie wykonana na procesorze. Wywołania OpenGL / Direct3D będą wywoływać biblioteki C / C ++, statyczne lub dynamiczne, w zależności od przypadku.

Jedynym miejscem, w którym „program gpu” mógłby wejść do gry, jest sytuacja, gdy twój kod jawnie tworzy shadery. Oznacza to, że jeśli wykonasz wywołania API do OpenGL / D3D, które spowodują kompilację i linkowanie shaderów. Aby to zrobić, (w czasie wykonywania, a nie w C / C ++ kompilacji) generujesz lub ładujesz ciągi znaków, które reprezentują shadery w jakimś języku shaderów. Następnie przepychasz je przez kompilator modułu cieniującego i odzyskujesz obiekt w tym interfejsie API, który reprezentuje ten moduł cieniujący. Następnie zastosujesz jeden lub więcej shaderów do określonego polecenia renderowania. Każdy z tych kroków odbywa się jawnie w kierunku Twojego kodu C / C ++, który, jak wspomniano wcześniej, działa na procesorze.

Wiele języków shaderów używa składni podobnej do C / C ++. Ale to nie czyni ich odpowiednikiem C / C ++.

Nicol Bolas
źródło
Uczyłem się opengl ostatnio i zastanawiałem się, dlaczego widzę te wszystkie "programy shaderów" w kodzie, na które patrzę, zapisane jako łańcuchy liter. Jak powiedziałeś, są one kompilowane w czasie wykonywania. Widziałem kilka przykładów w kodzie Android OpenGL ES. Potem zobaczyłem też kod dla iPhone'a. Wygląda na to, że iPhone ma cztery procesory wektorowe, które są w stanie wykonywać obliczenia zmiennoprzecinkowe znacznie szybciej niż procesor iPhone'a - więc możesz napisać ASM jako dosłowne ciągi, które zostaną skompilowane w czasie wykonywania, aby używać tych procesorów zamiast głównego procesora.
eggie5
1
Większość „potoku funkcji stałych” jest teraz implementowana przez domyślny zestaw programów cieniujących. Nie musisz jawnie żądać modułu cieniującego, aby go uzyskać.
Ben Voigt
1
@Ben Voigt: To prawda, ale gdyby nikt ci nie powiedział, nie byłbyś w stanie dostrzec różnicy.
Nicol Bolas
1
Co mogłoby być rozsądnym podejściem, gdyby nie chodziło o ukryte szczegóły.
Ben Voigt