Die teuersten Render-Passes ermitteln

Mit dem AGI Frame Profiler können Sie einzelne Rendering-Durchläufe untersuchen, die zum Erstellen eines einzelnen Frames Ihrer App verwendet werden. Dazu werden alle für die Ausführung der einzelnen Grafik-API-Aufrufe erforderlichen Status abgefangen und aufgezeichnet. Unter Vulkan erfolgt dies nativ über das Layering-System von Vulkan. Bei OpenGL werden Befehle mit ANGLE abgefangen, das OpenGL-Befehle in Vulkan-Aufrufe konvertiert, damit sie auf der Hardware ausgeführt werden können.

Adreno-Geräte

Um die teuren Render-Passes zu ermitteln, sehen Sie sich zuerst die Zeitachse von AGI oben im Fenster an. Hier werden alle Render-Passes, aus denen sich die Komposition eines bestimmten Frames zusammensetzt, chronologisch angezeigt. Es ist dieselbe Ansicht, die Sie im Systemprofiler sehen würden, wenn Sie Informationen zur GPU-Warteschlange hätten. Außerdem werden grundlegende Informationen zum Render-Pass angezeigt, z. B. die Auflösung der Framebuffer, in die gerendert wird. So lässt sich nachvollziehen, was im Render-Pass passiert.

Frame-Zeitachse
Abbildung 1. Frame-Zeitachse

Das erste Kriterium, mit dem Sie Ihre Render-Passes untersuchen können, ist die benötigte Zeit. Der längste Rendering-Vorgang bietet wahrscheinlich das größte Optimierungspotenzial. Beginnen Sie also damit, ihn sich anzusehen.

Längsten Rendering-Pass in der Ansicht „Frame-Zeitachse“ identifizieren
Abbildung 2. Längsten Renderdurchlauf in der Frame-Zeitachse identifizieren

Der GPU-Abschnitt für den relevanten Rendering-Pass enthält bereits einige Informationen dazu, was im Rendering-Pass passiert:

  1. Binning: Hier werden Eckpunkte in Bins platziert, je nachdem, wo sie auf dem Bildschirm landen.
  2. Rendering: Hier werden Pixel oder Fragmente schattiert.
  3. GMEM-Laden/Speichern: Wenn der Inhalt eines Framebuffers aus dem internen GPU-Speicher in den Hauptspeicher geladen oder dort gespeichert wird

Sie können sich ein gutes Bild davon machen, wo potenzielle Engpässe auftreten könnten, indem Sie sich ansehen, wie viel Zeit für die einzelnen Schritte im Render-Pass benötigt wird. Beispiel:

  • Wenn das Binning einen großen Teil der Zeit in Anspruch nimmt, deutet dies auf einen Engpass bei den Vertex-Daten hin, der auf zu viele oder zu große Vertices oder andere Probleme im Zusammenhang mit Vertices zurückzuführen ist.
  • Wenn das Rendern den Großteil der Zeit in Anspruch nimmt, deutet dies darauf hin, dass die Schattierung der Engpass ist. Mögliche Ursachen sind komplexe Shader, zu viele Texturabrufe, das Rendern in einem hochauflösenden Framebuffer, wenn dies nicht erforderlich ist, oder andere ähnliche Probleme.

Auch die GMEM-Ladevorgänge und ‑Speichervorgänge sollten berücksichtigt werden. Das Verschieben von Daten aus dem Grafikspeicher in den Hauptspeicher ist teuer. Wenn Sie die Anzahl der Lade- oder Speichervorgänge minimieren, können Sie die Leistung verbessern. Ein häufiges Beispiel dafür ist das Speichern von Tiefe/Stencil in GMEM, wodurch der Tiefe/Stencil-Puffer in den Hauptspeicher geschrieben wird. Wenn Sie diesen Puffer in zukünftigen Rendering-Durchläufen nicht verwenden, kann dieser Speichervorgang eliminiert werden. Dadurch sparen Sie Frame-Zeit und Speicherbandbreite.

GMEM-Lade- und Speicheroperationen identifizieren
Abbildung 3. GMEM-Ladevorgänge und ‑Speicherorte identifizieren

Untersuchung großer Renderdurchgänge

So sehen Sie alle einzelnen Zeichenbefehle, die während des Renderings ausgegeben wurden:

  1. Klicken Sie in der Zeitachse auf den Render-Pass. Dadurch wird der Rendering-Pass in der Hierarchie im Bereich Befehle des Frame Profiler geöffnet.

  2. Klicken Sie auf das Menü des Render-Passes. Dort werden alle einzelnen Zeichenbefehle angezeigt, die während des Render-Passes ausgegeben wurden. Wenn es sich um eine OpenGL-Anwendung handelt, können Sie noch genauer nachsehen und die von ANGLE ausgegebenen Vulkan-Befehle aufrufen.

Bereich „Befehle“
Abbildung 4. Bereich „Befehle“

Wählen Sie einen der Zeichenaufrufe aus. Dadurch wird der Bereich Framebuffer geöffnet. Dort sehen Sie alle Framebuffer-Anhänge, die während dieses Draw-Vorgangs gebunden wurden, sowie das Endergebnis des Draw-Vorgangs im angehängten Framebuffer. Hier können Sie auch AGI verwenden, um sowohl den vorherigen als auch den nächsten Draw-Aufruf zu öffnen und die Unterschiede zwischen den beiden zu vergleichen. Wenn sie visuell fast identisch sind, kann möglicherweise ein Draw-Aufruf entfernt werden, der nicht zum endgültigen Bild beiträgt.

Einzelne Zeichenaufrufe im Bereich „Befehle“ auswählen
Abbildung 5. Einzelne Draw-Aufrufe im Bereich „Befehle“ auswählen

Wenn Sie das Pipeline-Fenster für diesen Draw öffnen, sehen Sie den Zustand, der von der Grafikpipeline zum Ausführen dieses Draw-Aufrufs verwendet wird.

Pipeline-Bereich
Abbildung 6. Pipeline-Bereich

Der Input Assembler (Eingabe-Assembler) enthält Informationen dazu, wie Vertex-Daten an diesen Draw gebunden wurden. Dieser Bereich ist hilfreich, wenn Sie feststellen, dass das Binning einen großen Teil der Zeit Ihres Renderings in Anspruch nimmt. Hier finden Sie Informationen zum Vertex-Format, zur Anzahl der gezeichneten Eckpunkte und dazu, wie Eckpunkte im Speicher angeordnet sind. Weitere Informationen finden Sie unter Vertex-Formate analysieren.

Bereich „Input Assembler“ im Bereich „Pipeline“
Abbildung 7. Abschnitt „Input Assembler“ im Bereich „Pipeline“

Im Abschnitt Vertex Shader finden Sie Informationen zum Vertex-Shader, den Sie bei diesem Draw verwendet haben. Er kann auch ein guter Ausgangspunkt für die Untersuchung sein, wenn Binning als Problem identifiziert wurde. Sie können das SPIR-V und das dekompilierte GLSL des verwendeten Shaders sehen und die gebundenen Uniform Buffers für diesen Aufruf untersuchen. Weitere Informationen finden Sie unter Shader-Leistung analysieren.

Abschnitt „Vertex Shader“ im Bereich „Pipeline“
Abbildung 8. Bereich „Vertex Shader“ im Bereich „Pipeline“

Im Bereich Rasterizer finden Sie Informationen zur Einrichtung der Pipeline mit fester Funktion. Er kann eher für das Debugging von Status mit fester Funktion wie Viewport, Schere, Tiefenstatus und Polygonmodus verwendet werden.

Bereich „Rasterizer“ im Bereich „Pipeline“
Abbildung 9. Rasterizer-Abschnitt im Bereich „Pipeline“

Der Abschnitt Fragment Shader enthält viele der Informationen, die auch im Abschnitt Vertex Shader zu finden sind, aber speziell für den Fragment Shader. In diesem Fall können Sie sehen, welche Texturen gebunden werden, und sie untersuchen, indem Sie auf das Handle klicken.

Bereich „Fragment Shader“ im Bereich „Pipeline“
Abbildung 10. Bereich „Fragment Shader“ im Bereich „Pipeline“

Untersuchung kleinerer Renderdurchgänge

Ein weiteres Kriterium, mit dem Sie die GPU-Leistung verbessern können, ist die Betrachtung von Gruppen kleinerer Render-Passes. Im Allgemeinen sollten Sie die Anzahl der Rendering-Durchläufe so weit wie möglich minimieren, da es Zeit braucht, bis die GPU den Status von einem Rendering-Durchlauf zum nächsten aktualisiert. Diese kleineren Render-Passes werden in der Regel verwendet, um beispielsweise Schattenkarten zu erstellen, Gaußsche Unschärfe anzuwenden, die Leuchtdichte zu schätzen, Nachbearbeitungseffekte zu erzielen oder die Benutzeroberfläche zu rendern. Einige dieser Durchgänge können möglicherweise in einem einzigen Rendering-Durchgang zusammengefasst oder sogar ganz entfernt werden, wenn sie das Gesamtbild nicht so stark beeinflussen, dass sich der Aufwand lohnt.

Kleinere Render-Passes zum Herunterskalieren des Puffers mit nativer Auflösung
Abbildung 11. Kleinere Render-Passes zum Herunterstufen des Puffers mit der nativen Auflösung