Pisząc nietrywialne programy cieniujące (tak jak piszą każdy inny nietrywialny kod), ludzie popełniają błędy. [potrzebne źródło] Nie mogę jednak po prostu debugować go jak każdy inny kod - w końcu nie możesz po prostu dołączyć gdb lub debugera Visual Studio. Nie można nawet debugować printf, ponieważ nie ma żadnej formy wyjścia konsoli. To, co zwykle robię, to renderowanie danych, na które chcę patrzeć, jako kolorów, ale jest to bardzo podstawowe i amatorskie rozwiązanie. Jestem pewien, że ludzie wymyślili lepsze rozwiązania.
Więc jak mogę faktycznie debugować moduł cieniujący? Czy istnieje sposób na przejście przez moduł cieniujący? Czy mogę spojrzeć na wykonanie modułu cieniującego na określonym wierzchołku / prymitywie / fragmencie?
(To pytanie dotyczy w szczególności debugowania kodu modułu cieniującego podobnego do sposobu debugowania „normalnego” kodu, a nie debugowania takich rzeczy jak zmiany stanu).
Odpowiedzi:
O ile wiem, nie ma narzędzi, które pozwalają ci przechodzić przez kod w module cieniującym (również w takim przypadku musiałbyś być w stanie wybrać tylko piksel / wierzchołek, który chcesz "debugować", wykonanie prawdopodobnie różnią się w zależności od tego).
To, co robię osobiście, to bardzo hackerskie „kolorowe debugowanie”. Posypuję więc kilka dynamicznych gałęzi
#if DEBUG / #endif
strażnikami, którzy w zasadzie to mówiąW ten sposób możesz „obserwować” informacje debugowania. Zazwyczaj robię różne sztuczki, takie jak przeszukiwanie lub mieszanie różnych „kodów kolorów”, aby przetestować różne bardziej złożone zdarzenia lub rzeczy niebinarne.
W tym „frameworku” przydatny jest także zestaw ustalonych konwencji dla typowych przypadków, aby jeśli nie musiałem ciągle wracać i sprawdzać, z jakim kolorem skojarzyłem się z czym. Ważne jest, aby mieć dobre wsparcie w ponownym ładowaniu kodu modułu cieniującego, dzięki czemu możesz prawie interaktywnie zmieniać śledzone dane / zdarzenia i łatwo włączać / wyłączać wizualizację debugowania.
Jeśli potrzebujesz debugować coś, czego nie można łatwo wyświetlić na ekranie, zawsze możesz zrobić to samo i użyć jednego narzędzia do analizy klatek, aby sprawdzić wyniki. Wymieniłem kilka z nich jako odpowiedź na to drugie pytanie.
Oczywiste jest, że jeśli nie „debuguję” modułu cieniującego piksele lub modułu obliczeniowego, przekazuję tę informację „debugColor” przez potok bez interpolacji (w GLSL ze
flat
słowem kluczowym)Ponownie jest to bardzo zuchwałe i dalekie od prawidłowego debugowania, ale utknąłem w tym, że nie znam żadnej właściwej alternatywy.
źródło
Istnieje również GLSL-Debugger . Jest to debugger znany jako „GLSL Devil”.
Sam debugger jest bardzo przydatny nie tylko dla kodu GLSL, ale także dla samego OpenGL. Możesz przeskakiwać między losowaniami i przerywać przełączniki Shader. Pokazuje również komunikaty o błędach przekazywane przez OpenGL z powrotem do samej aplikacji.
źródło
Istnieje kilka ofert dostawców GPU, takich jak CodeXL AMD lub debuger NVIDIA nSight / Linux GFX, które umożliwiają przechodzenie przez moduły cieniujące, ale są powiązane ze sprzętem danego dostawcy.
Pragnę zauważyć, że chociaż są one dostępne pod Linuksem, zawsze miałem bardzo mały sukces z ich użyciem. Nie mogę komentować sytuacji w systemie Windows.
Opcją, z której ostatnio korzystałem, jest modularyzacja mojego kodu modułu cieniującego
#includes
i ograniczenie dołączonego kodu do wspólnego podzbioru GLSL i C ++ i glm .Kiedy napotykam problem, próbuję go odtworzyć na innym urządzeniu, aby sprawdzić, czy problem jest taki sam, co wskazuje na błąd logiczny (zamiast problemu ze sterownikiem / nieokreślonego zachowania). Istnieje również szansa na przekazanie niewłaściwych danych do GPU (np. Przez niepoprawnie powiązane bufory itp.), Co zwykle wykluczam albo przez debugowanie danych wyjściowych jak w odpowiedzi CIFZ lub przez kontrolę danych za pomocą apitrace .
Gdy jest to błąd logiczny, próbuję odbudować sytuację z GPU na CPU, wywołując dołączony kod na CPU z tymi samymi danymi. Następnie mogę przejść przez procesor.
Opierając się na modułowości kodu, możesz także spróbować napisać dla niego najbardziej nieprzystosowany i porównać wyniki między uruchomieniem GPU a uruchomieniem procesora. Należy jednak pamiętać, że istnieją przypadki narożne, w których C ++ może zachowywać się inaczej niż GLSL, co daje fałszywe pozytywne wyniki w tych porównaniach.
Wreszcie, gdy nie możesz odtworzyć problemu na innym urządzeniu, możesz zacząć kopać, skąd bierze się różnica. Unittests może pomóc ci zawęzić miejsce, w którym to się dzieje, ale ostatecznie prawdopodobnie będziesz musiał napisać dodatkowe informacje debugowania z modułu cieniującego, jak w odpowiedzi CIFZ .
Aby dać ci przegląd tutaj, jest schemat blokowy mojego procesu debugowania:
Podsumowując, oto lista losowych zalet i wad:
zawodowiec
kon
źródło
Chociaż wydaje się, że nie jest możliwe przejście przez moduł cieniujący OpenGL, możliwe jest uzyskanie wyników kompilacji.
Poniższe dane pochodzą z próbki kartonu Android .
Jeśli Twój kod kompiluje się poprawnie, nie masz innego wyjścia, jak wypróbować inny sposób komunikowania Ci stanu programu. Można zasygnalizować, że część kodu została osiągnięta, na przykład poprzez zmianę koloru wierzchołka lub użycie innej tekstury. Co jest niezręczne, ale na razie wydaje się to jedyną drogą.
EDYCJA: W przypadku WebGL patrzę na ten projekt , ale dopiero go znalazłem ... nie mogę za niego ręczyć.
źródło
To jest kopia-wklej mojej odpowiedzi na to samo pytanie na StackOverflow .
Na dole tej odpowiedzi znajduje się przykład kodu GLSL, który pozwala na wyświetlenie pełnej
float
wartości w kolorze, kodując IEEE 754binary32
. Używam go w następujący sposób (ten fragment podajeyy
komponent macierzy widoku modelu):Po wyświetleniu tego na ekranie możesz po prostu wybrać dowolny próbnik kolorów, sformatować kolor jako HTML (dołączając
00
dorgb
wartości, jeśli nie potrzebujesz większej precyzji, i wykonując drugi krok, aby uzyskać niższy bajt, jeśli to zrobisz), i otrzymasz szesnastkową reprezentacjęfloat
jako IEEE 754binary32
.Oto faktyczna realizacja
toColor()
:źródło
Rozwiązaniem, które działało dla mnie, jest kompilacja kodu modułu cieniującego do C ++ - jak wspomniał Nobody. Udowodnił, że jest bardzo wydajny podczas pracy nad złożonym kodem, mimo że wymaga nieco konfiguracji.
Pracuję głównie z HLSL Compute Shaders, dla których opracowałem bibliotekę proof-of-concept dostępną tutaj:
https://github.com/cezbloch/shaderator
Pokazuje on na module obliczeniowym z próbek SDK DirectX, jak włączyć C ++ jak debugowanie HLSL i jak skonfigurować testy jednostkowe.
Kompilacja modułu cieniującego GLSL do C ++ wygląda łatwiej niż HLSL. Głównie z powodu konstrukcji składni w HLSL. Dodałem trywialny przykład wykonywalnego testu jednostkowego na ray tracerze GLSL Compute Shader, który można również znaleźć w źródłach projektu Shaderator pod linkiem powyżej.
źródło