Wie debuggen Entwickler von Grafik-Engines ihren 3D-Grafikcode?


7

Ich versuche gerade, eine Amateur-Game-Engine zu erstellen, und stoße häufig auf sehr grundlegende Fehler (z. B. ändere ich den Code der Knotenhierarchie und plötzlich wird nichts mehr angezeigt). Einige der Methoden, die ich verwenden werde, umfassen:

  • Verwenden Sie den Debugger meiner IDE und viele printfAufrufe, um zu sehen, was sich im Speicher befindet.

  • Führen Sie viele Tests mit unterschiedlichen Parametern durch und platzieren Sie die Kamera an verschiedenen Positionen, um ein besseres Gefühl dafür zu bekommen, was der Code tut.

  • Zwingen Sie sich einfach brutal durch, indem Sie jede Codezeile erneut lesen, bis ich die finde, die sich schlecht benimmt.

Diese Methoden erscheinen mir alle träge und ineffizient. Das Problem ist, dass das 3D-Rendering viele unintuitive Vorgänge umfasst, bei denen außer dem endgültigen "Produkt" nicht viel zu visualisieren ist. Wenn ich auf einen Fehler stoße (insbesondere auf Fehler, bei denen "nichts angezeigt wird"), habe ich oft das Gefühl, blind herumzufummeln.


Damit.

Angenommen, Sie arbeiten als Entwickler an Unity, Godot oder einer anderen 3D-Engine und haben nur einige Schritte in Ihrer Rendering-Pipeline geändert. Aus irgendeinem Grund zeigt der Wireframe-Renderer jetzt inkohärente Ergebnisse an, wenn die Entitäts-Stapelverarbeitung aktiviert ist. Die "Drähte" kreuzen sich auf dem gesamten Bildschirm, anstatt die Kanten der Dreiecke der gestapelten Entität darzustellen.

Wie können Sie diesen Fehler finden und beheben? Haben Sie einen bestimmten Workflow? Verwenden Sie eine Art GPU-Analysetool? Oder fummeln Sie einfach blind herum?

Mit anderen Worten, welche Methoden, Tools und Best Practices können Engine-Entwickler (nicht Engine-Benutzer) verwenden, um die Daten und das Verhalten ihres 3D-Grafikcodes (nicht nur dessen Leistung) zu analysieren , um Fehler und Bugs effizient zu beheben?


Es gibt spezielle Debugger für Grafiken wie Nvidia Nsight oder sogar die integrierten Visual Studios mit vielen Funktionen. Die meisten haben die Möglichkeit, Screenshots zu machen, Pixel auszuwählen und einen detaillierten Verlauf des Weges anzuzeigen.
Andrew Wilson

Antworten:


5

Ich programmiere hauptsächlich in OpenGL. In diesem Fall richte ich als erstes die Erweiterung KHR_debug ein . Es bietet eine Möglichkeit, von GL-Treibern generierte Nachrichten zu abonnieren - von Fehlern über Warnungen bis hin zu detaillierten Informationen darüber, was der Treiber tut. Insbesondere Open Source Linux-Treiber (Mesa) generieren viele nützliche Nachrichten.

Wenn es um Werkzeuge geht, ist ApiTrace normalerweise meine erste Wahl. Sie können eine Ablaufverfolgung aller Rendering-API-Aufrufe aufzeichnen und diese dann wiedergeben und den Status zu jedem Zeitpunkt überprüfen (dies schließt den Inhalt von Puffern, Rendering-Zielen usw. ein). Außerdem können Sie eine Ablaufverfolgung mit anderen Personen teilen, was bei der Arbeit in einem Team hilfreich ist. Dann gibt es andere Tools wie RenderDoc, NVIDIA Tegra Graphics Debugger, Xcodes Grafikdebugger und einige andere. Was auch immer Sie gewählt haben, es wird Ihre Arbeit erheblich verbessern.

Eine andere Sache ist das Testen. Eine Sache ist das Erstellen einer Sammlung einfacher Szenen, in denen einzelne Funktionen der Engine ausgeführt werden (z. B. unterschiedliche Materialeinstellungen, unterschiedliche Animationstechniken usw.). Wenn ein Fehler in die Codebasis eingeführt wird, hilft dies beim Debuggen (da Sie einfach zu analysierende Testfälle zur Verfügung haben) und beim Überprüfen, ob ein Fix nicht versehentlich etwas anderes beschädigt. Ich denke, es ist ziemlich üblich, etwas zu tun. Unity3D-Entwickler tun dies beispielsweise.

Sie können dies erweitern und automatisieren, indem Sie ein Testkabel erstellen, mit dem alle Tests regelmäßig erstellt und ausgeführt werden, und sicherstellen, dass keine Regressionen aufgetreten sind. Wenn Sie viele Testszenarien haben, ist dies möglicherweise möglich, obwohl offensichtlich zusätzliche Investitionen in die Infrastruktur erforderlich sind.

Dann gibt es mehr "Standard" -Einheitstests. Ein Bereich, in dem ich sie angewendet habe, ist das knotenbasierte Materialsystem, das auf verschiedene Rendering-Techniken (vorwärts, verzögert, was auch immer) und APIs abzielen kann. Ich näherte mich dem, indem ich Unit-Tests schrieb, die Shader-Code aus Material und anderen Einstellungen generierten, ihn kompilierten und einen einfachen Draw-Aufruf mit bestimmten Eingaben (Pixel-Shader-Eingaben) ausgaben. Ausgaben werden in ein Renderziel geschrieben und zum Vergleich mit erwarteten Werten abgerufen. IMHO ist dies eine schöne Sache, wenn Sie ein komplexes Materialsystem haben, insb. mit Shader-Code-Generierung.

Schließlich können "traditionellere" Ansätze auf Bereiche angewendet werden, die vom Rendern getrennt werden können. Dinge wie Geodatenstrukturen, Laden von Assets und ähnliches können je nach Einzelfall auf Einheit / Integration getestet werden.

Bearbeiten: Hier ist ein Beitrag des Unity3D-Entwicklers, in dem beschrieben wird, wie Grafikcode getestet wird.


Betreff: Szenentests, ich verwende derzeit glTF-Beispielszenen, um meine Engine zu testen. Ich könnte irgendwann komplexere Szenen erstellen, um zu testen, was besser läuft.
Narrateur du Chaos

Ich habe einen Link vergessen, den ich einfügen wollte, über den Ansatz von Unity3D - ich habe meine Antwort so bearbeitet, dass sie ihn enthält.
Joe_chip

4

Normalerweise bevorzuge ich RenderDoc , um einen Frame zu debuggen. Gibt Ihnen genügend Informationen zu einem bestimmten Frame, der direkt von Vertex zu Pixel gerendert wurde. Es gibt andere ebenso nützliche Tools wie Nvidia Nsight

Schließlich gibt es immer eine Farbcodierung, die beim visuellen Debuggen von Shadern hilfreich sein kann. Das Zerlegen von Shader-Ausgaben in separate Farben kann ebenfalls hilfreich sein. Ich bin mir jedoch nicht sicher, ob Ihr Fall dies erfordert.

Hoffe das hilft.


Ich werde dann in RenderDoc schauen. Betreff: Shader, gibt es ein Tool, mit dem Sie leistungsfähiger debuggen können (z. B. die Werte von Zwischenvariablen), oder ist farbbasiertes Debuggen der Standard?
Narrateur du Chaos

2
Ich habe gerade 1 Stunde mit RenderDoc verbracht und kann dessen Nützlichkeit bereits bestätigen. Es machte das, was ein Amalgam mysteriöser, nicht auffindbarer Fehler war, lächerlich leicht zu verstehen. Vielen Dank!
Narrateur du Chaos

3

Ich arbeite hauptsächlich unter MacOS, wo die OpenGL-Tools fast nicht vorhanden sind. (Ich fange an, mich mit Metal zu beschäftigen, wo die Werkzeuge besser sind.) Also fühle ich deinen Schmerz.

Das erste, was ich mache, ist, häufig kleine Commits meines Codes für die Quellcodeverwaltung vorzunehmen. Dies ist nicht immer möglich, aber normalerweise ist es so. Wenn dies andere stören könnte, arbeiten Sie an einem Zweig. Auf diese Weise kann ich, wenn etwas schrecklich schief geht, den aktuellen Code schnell gegen HEAD oder Trunk austauschen und das Problem nur auf den Code in den Diffs beschränken.

Als nächstes versuche ich zu analysieren, wo das Problem liegt. In Ihrem Beispiel, in dem Geometrie, die zuvor funktioniert hat, plötzlich die falschen Formen zeichnet, würde ich über die Situationen nachdenken, die dies verursachen können:

  1. Senden eines falschen Zeigers an glBufferData()
  2. Beginnen Sie mit dem falschen Byte meines Puffers, indem Sie einen Attributzeiger / Offset falsch setzen

Es gibt zahlreiche Ursachen für allgemeine Symptome wie den gefürchteten schwarzen Bildschirm. Es gibt eine Reihe von Techniken, denen die Grafik entsprichtprintf(). Ich fange an zu brechen, was funktioniert und was nicht. Ich beginne mit wirklich breiten Strichen. Geht meine Zeichnung zum richtigen FBO? Stellen Sie die klare Farbe des FBO auf etwas Grelles wie RGB = (1, 0,5, 0) oder (0, 1, 1) ein und prüfen Sie, ob der Bildschirm orange oder magenta wird. Sie können für jeden FBO, den Sie normalerweise verwenden, eine andere Debug-Farbe auswählen, damit Sie auf einen Blick erkennen können, welche Anzeige auf einem bestimmten Render angezeigt wird. Wenn das funktioniert, überprüfe ich Dinge wie das Ausschneiden von Ebenen - habe ich die gesamte Geometrie ausgeschnitten? Beleuchtung prüfen - habe ich Licht an? Sende ich die richtigen Beleuchtungsinformationen an die Shader? Sind die Texturen korrekt? Es kann hilfreich sein, einige Testtexturen mit Dingen wie Gittern zu haben, oder wenn Sie es mit Würfelkarten zu tun haben, Texturen mit Gesichtsnamen. Wenn Sie Shader-Probleme haben, Sie können beispielsweise die Texturkoordinaten an jedem Punkt als rot und grün (und blau, wenn es sich um eine 3D-Textur handelt) ausgeben, um sicherzustellen, dass sie gültig sind. Gleiches gilt für Normalen - normalisieren Sie sie und geben Sie die ausx, yUnd zin den r, gund bKanälen.

Wenn Sie mehr davon tun, lernen Sie solche Tricks, um die Daten anzuzeigen und Ihre Annahmen zu überprüfen. Das schnelle und einfache Zurückrollen ist enorm hilfreich. Und natürlich nicht vergessen glGetError(). Die geringe Anzahl von Fehlern, die zurückgegeben werden, ist frustrierend, kann Sie jedoch häufig darauf hinweisen, wo ein Problem liegt.

Wenn Sie ein Tool erhalten, das Ihnen zeigt, was sich vom Standard-OpenGL-Status unterscheidet, kann es auch festlegen, wo Sie Ihre Anstrengungen unternehmen sollen. Unter macOS gibt es OpenGL Profiler. Sie können für jede OpenGL-Funktion einen Haltepunkt festlegen und die gesamte Zustandsmaschine untersuchen. Es werden Unterschiede zu den Standardeinstellungen oder Unterschiede zum letzten Stopp oder beides hervorgehoben.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.