SRP Batcher: Beschleunigen Sie Ihr Rendering

ARNAUD CARRÉ / UNITY TECHNOLOGIESContributor
Feb 28, 2019|12 Min.
SRP Batcher: Beschleunigen Sie Ihr Rendering
Diese Website wurde aus praktischen Gründen für Sie maschinell übersetzt. Die Richtigkeit und Zuverlässigkeit des übersetzten Inhalts kann von uns nicht gewährleistet werden. Sollten Sie Zweifel an der Richtigkeit des übersetzten Inhalts haben, schauen Sie sich bitte die offizielle englische Version der Website an.

2018 haben wir eine hochgradig anpassbare Rendering-Technologie eingeführt, die wir Scriptable Render Pipeline (SRP) nennen. Ein Teil davon ist eine neue Low-Level-Engine-Rendering-Schleife namens SRP Batcher, die Ihre CPU während des Renderns um das 1,2- bis 4-fache beschleunigen kann, je nach Szene. Sehen wir uns an, wie Sie diese Funktion am besten nutzen können!

Dieses Video zeigt das Worst-Case-Szenario für Unity: Jedes Objekt ist dynamisch und verwendet ein anderes Material (Farbe, Textur). Diese Szene zeigt viele ähnliche Meshes, aber sie würde mit einem unterschiedlichen Mesh pro Objekt genauso laufen (so dass GPU-Instanzierung nicht verwendet werden kann). Die Beschleunigung beträgt etwa 4x auf der PlayStation 4 (dieses Video ist für PC, Dx11).

HINWEIS: Wenn wir von x4-Beschleunigung sprechen, meinen wir den CPU-Rendering-Code (die Profiler-Marker "RenderLoop.Draw" und "ShadowLoop.Draw"). Wir sprechen hier nicht über die globale Framerate (FPS)).

Unity und Materialien

Der Unity-Editor verfügt über eine sehr flexible Rendering-Engine. Sie können jede Materialeigenschaft jederzeit während eines Rahmens ändern. Unity Plus wurde historisch gesehen für nicht-konstante Puffer entwickelt und unterstützt Grafik-APIs wie DirectX9. Allerdings haben diese schönen Funktionen auch einige Nachteile. Es gibt zum Beispiel viel zu tun, wenn ein DrawCall ein neues Material verwendet. Je mehr Materialien Sie also in einer Szene haben, desto mehr CPU wird für die Einrichtung der GPU-Daten benötigt.

Standard Unity Rendering Arbeitsablauf
Standard Unity Rendering Arbeitsablauf

Während der inneren Rendering-Schleife, wenn ein neues Material erkannt wird, sammelt die CPU alle Eigenschaften und richtet verschiedene konstante Puffer im GPU-Speicher ein. Die Anzahl der GPU-Puffer hängt davon ab, wie der Shader seine CBUFFERs deklariert.

So funktioniert SRP Batcher

Als wir die SRP-Technologie entwickelt haben, mussten wir einige Teile der Low-Level-Engine neu schreiben. Wir sahen eine große Chance, einige neue Paradigmen, wie die GPU-Datenpersistenz, nativ zu integrieren. Unser Ziel war es, den allgemeinen Fall zu beschleunigen, in dem eine Szene viele verschiedene Materialien, aber nur wenige Shader-Varianten verwendet.

Jetzt können Low-Level-Renderschleifen Materialdaten im GPU-Speicher persistent machen. Wenn sich der Inhalt des Materials nicht ändert, müssen Sie den Puffer nicht einrichten und auf die GPU hochladen. Außerdem verwenden wir einen speziellen Codepfad, um die Eigenschaften der eingebauten Engine in einem großen GPU-Puffer schnell zu aktualisieren. Das neue Flussdiagramm sieht nun wie folgt aus:

SRP Batcher Rendering-Arbeitsablauf.
SRP Batcher Rendering-Arbeitsablauf.

Hier bearbeitet die CPU nur die eingebauten Eigenschaften der Engine, die als Objektmatrix-Transformation bezeichnet werden. Alle Materialien verfügen über persistente CBUFFERs, die sich im GPU-Speicher befinden und zur Verwendung bereit sind. Zusammenfassend lässt sich sagen, dass der Geschwindigkeitszuwachs auf zwei verschiedene Dinge zurückzuführen ist:

  • Jeder materielle Inhalt ist jetzt im GPU-Speicher persistent
  • Ein spezieller Code verwaltet einen großen GPU-CBUFFER "pro Objekt
So aktivieren Sie SRP Batcher

Ihr Projekt muss entweder die Lightweight Render Pipeline (LWRP), die High Definition Render Pipeline (HDRP) oder Ihre eigene SRP verwenden. Um den SRP Batcher in HDRP oder LWRP zu aktivieren, verwenden Sie einfach das Kontrollkästchen im SRP Asset Inspector.

SRP Batcher einschalten
SRP Batcher einschalten

Wenn Sie SRP Batcher zur Laufzeit aktivieren/deaktivieren möchten, um die Leistungsvorteile zu testen, können Sie diese globale Variable auch mit C#-Code umschalten:

GraphicsSettings.useScriptableRenderPipelineBatching = true;

SRP Batcher Kompatibilität

Damit ein Objekt über den SRP Batcher-Codepfad gerendert werden kann, gibt es zwei Voraussetzungen:

1. Das Objekt muss sich in einem Netz befinden. Es kann kein Partikel oder ein Mesh mit Haut sein.

2. Sie müssen einen Shader verwenden, der mit dem SRP Batcher kompatibel ist. Alle beleuchteten und unbeleuchteten Shader in HDRP und LWRP erfüllen diese Anforderung.

Damit ein Shader mit SRP kompatibel ist:

  • Alle eingebauten Eigenschaften der Engine müssen in einem einzigen CBUFFER namens "UnityPerDraw" deklariert werden. For example, unity_ObjectToWorld, or unity_SHAr.
  • Alle Materialeigenschaften müssen in einem einzigen CBUFFER namens "UnityPerMaterial" deklariert werden.

Sie können den Kompatibilitätsstatus eines Shaders im Inspektorfenster sehen. Dieser Abschnitt zur Kompatibilität wird nur angezeigt, wenn Ihr Projekt auf SRP basiert.

SRP Batcher-Kompatibilität
SRP Batcher-Kompatibilität

In einer bestimmten Szene sind einige Objekte mit SRP Batcher kompatibel, andere nicht. Aber die Szene wird immer noch richtig gerendert. Kompatible Objekte verwenden den SRP Batcher-Codepfad, während andere weiterhin den Standard-SRP-Codepfad verwenden.

SRP Batcher-Kompatibilität
Die Kunst des Profilierens
SRPBatcherProfiler.cs

Wenn Sie die Geschwindigkeitssteigerung mit SRP Batcher in Ihrer spezifischen Szene messen möchten, können Sie das C#-Skript SRPBatcherProfiler.cs verwenden. Fügen Sie das Skript einfach in Ihre Scene ein. Wenn dieses Skript ausgeführt wird, können Sie die Overlay-Anzeige mit der Taste F8 umschalten. Sie können den SRP Batcher auch während des Spiels mit der Taste F9 ein- und ausschalten. Wenn Sie das Overlay im Modus WIEDERGABE (F8) aktivieren, sollten Sie eine Menge nützlicher Informationen sehen:

SRP Batcher Profiler

Hier wird die Zeit in Millisekunden (ms) gemessen. Diese Zeitmessungen zeigen den CPU-Verbrauch in Unity SRP-Rendering-Schleifen.

HINWEIS: Mit Timing ist die kumulierte Zeit aller "RenderLoop.Draw" und "Shadows.Draw" Marker gemeint , die während eines Frames aufgerufen werden, unabhängig vom Eigentümer des Threads. Wenn Sie "1,31ms SRP Batcher code path" sehen, werden vielleicht 0,31ms auf main thread verbraucht, und 1ms verteilt sich auf alle Grafikaufträge.

Overlay-Informationen

In dieser Tabelle finden Sie eine Beschreibung der einzelnen Einstellungen im Overlay, das im Modus WIEDERGABE sichtbar ist, von oben nach unten:

Spezifikationen

HINWEIS: Wir zögern, FPS am unteren Ende des Overlays hinzuzufügen, da Sie bei der Optimierung sehr vorsichtig mit FPS-Metriken sein sollten. Erstens ist die FPS nicht linear. Wenn Sie also sehen, dass die FPS um 20% steigen, sagt Ihnen das nicht sofort, wie sehr Sie Ihre Szene optimiert haben. Zweitens: FPS ist global über das gesamte Bild. FPS (oder globales Frame-Timing) hängt von vielen anderen Dingen als dem Rendering ab, wie C# Gameplay, Physik, Culling usw.

Sie können SRPBatcherProfiler.cs von einer SRP Batcher-Projektvorlage auf GitHub erhalten.

Verschiedene Szenen Benchmark

Hier sind einige Aufnahmen von Unity-Szenen mit ausgeschaltetem und eingeschaltetem SRP Batcher, um die Geschwindigkeitssteigerung in verschiedenen Situationen zu sehen.

BOTD

Book of the Dead, HDRP, PlayStation 4. x1.47 beschleunigen. Bitte beachten Sie, dass sich die FPS nicht ändern, da diese Szene GPU-gebunden ist. Es bleiben 12 ms übrig, um andere Dinge auf der CPU-Seite zu erledigen. Die Geschwindigkeit ist auf dem PC fast die gleiche.

FPS Probe

FPS Sample, HDRP, PC DirectX 11. X1.23 Geschwindigkeit erhöhen. Bitte beachten Sie, dass aufgrund der Inkompatibilität des SRP-Batchers immer noch 1,67 ms auf den Standard-Codepfad entfallen. In diesem Fall handelt es sich um gehäutete Meshes und einige Partikel, die mit Material Property Blocks gerendert wurden.

Bootsangriff

Boat Attack, LWRP, PlayStation 4. Geschwindigkeit erhöhen x2.13.

Unterstützte Plattformen

SRP Batcher funktioniert auf fast allen Plattformen. Hier finden Sie eine Tabelle mit der Plattform und der minimal erforderlichen Unity-Version. Unity 2019.2 befindet sich derzeit in der offenen Alpha-Phase.

Unterstützte Plattformen
Einige Worte über VR

SRP Batcher fast code path wird in VR nur im Modus "SinglePassInstanced" unterstützt. Durch die Aktivierung von VR wird keine zusätzliche CPU-Zeit benötigt (dank des SinglePassInstanced-Modus).

Allgemeine Fragen

Wie kann ich sicher sein, dass ich SRP Batcher optimal nutze?

Verwenden Sie SRPBatcherProfiler.cs und überprüfen Sie zunächst, ob SRP Batcher eingeschaltet ist. Schauen Sie sich dann das Timing des "Standard-Codepfads" an. Dieser Wert sollte nahe bei 0 liegen, und die gesamte Zeit sollte im "SRP Batcher code path" verbracht werden. Manchmal ist es normal, dass etwas Zeit im Standard-Codepfad verbracht wird, wenn Ihre Szene ein paar gehäutete Meshes oder Partikel verwendet. Sehen Sie sich unser SRP Batcher Benchmark-Projekt auf GitHub an.

SRPBatcherProfiler zeigt ein ähnliches Timing, unabhängig davon, ob SRP Batcher ein- oder ausgeschaltet ist. Und warum?

Zunächst sollten Sie überprüfen, ob fast die gesamte Rendering-Zeit über den neuen Code-Pfad läuft (siehe oben). Wenn dies der Fall ist und die Zahlen immer noch ähnlich sind, dann sehen Sie sich die "Flush"-Nummer an. Diese "Flush"-Nummer sollte stark abnehmen, wenn der SRP Batcher eingeschaltet ist. Als Faustregel gilt: geteilt durch 10 ist wirklich gut, durch 2 ist fast gut. Wenn die Anzahl der Flushs nicht stark abnimmt, bedeutet dies, dass Sie immer noch viele Shader-Varianten haben. Versuchen Sie, die Anzahl der Shader-Varianten zu reduzieren. Wenn Sie viele verschiedene Shader erstellt haben, versuchen Sie, einen "Super"-Shader mit mehr Parametern zu erstellen. Sie haben dann tonnenweise verschiedene Materialparameter zur Verfügung.

Die globalen FPS änderten sich nicht, als ich den SRP Batcher aktivierte. Und warum?

Überprüfen Sie die beiden obigen Fragen. Wenn SRPBatcherProfiler anzeigt, dass die "CPU-Rendering-Zeit" doppelt so schnell ist und sich die FPS nicht verändert haben, dann ist der CPU-Rendering-Teil nicht Ihr Engpass. Es bedeutet nicht, dass Sie nicht an die CPU gebunden sind - stattdessen verwenden Sie vielleicht zu viel C# Gameplay oder zu viele Physikelemente. Wie auch immer, wenn die "CPU-Rendering-Zeit" doppelt so schnell ist, ist das immer noch positiv. Sie haben wahrscheinlich im oberen Video bemerkt, dass die Szene selbst bei 3,5-facher Beschleunigung immer noch mit 60 FPS läuft. Das liegt daran, dass wir VSYNC eingeschaltet haben. SRP Batcher hat wirklich 6,8 ms auf der CPU-Seite eingespart. Diese Millisekunden könnten für eine andere Aufgabe verwendet werden. Es kann auch einfach etwas Akkulaufzeit auf dem Handy sparen.

Wie Sie die Effizienz von SRP Batcher überprüfen

Es ist wichtig zu verstehen, was ein "Stapel" im Zusammenhang mit SRP Batcher ist. Traditionell neigt man dazu, die Anzahl der DrawCalls zu reduzieren, um die CPU-Renderingkosten zu optimieren. Der eigentliche Grund dafür ist, dass die Maschine eine Menge Dinge einrichten muss, bevor sie die Auslosung vornimmt. Und die wirklichen CPU-Kosten entstehen durch diese Einrichtung, nicht durch den GPU DrawCall selbst (das sind nur einige Bytes, die in den GPU-Befehlspuffer geschoben werden müssen). SRP Batcher reduziert nicht die Anzahl der DrawCalls. Es reduziert lediglich die Kosten für die GPU-Einrichtung zwischen DrawCalls.

Das können Sie auf dem folgenden Workflow sehen:

ShaderPass Arbeitsabläufe

Auf der linken Seite sehen Sie die Standard-SRP-Rendering-Schleife. Rechts ist die SRP Batcher-Schleife zu sehen. Im SRP Batcher-Kontext ist ein "Stapel" einfach eine Abfolge von "Binden", "Zeichnen", "Binden", "Zeichnen"... GPU-Befehle.

Im Standard-SRP wird das langsame SetShaderPass für jedes neue Material aufgerufen. Im SRP Batcher-Kontext wird der SetShaderPass für jede neue Shader-Variante aufgerufen.

Um eine maximale Leistung zu erzielen, müssen Sie diese Chargen so groß wie möglich halten. Sie müssen also jede Änderung der Shader-Variante vermeiden, aber Sie können eine beliebige Anzahl verschiedener Materialien verwenden, wenn diese denselben Shader verwenden.

Sie können den Unity Frame Debugger verwenden, um die Länge der SRP Batcher "Batches" zu überprüfen. Jeder Stapel ist ein Ereignis im Frame-Debugger mit der Bezeichnung "SRP-Stapel", wie Sie hier sehen können:

Frame Debugger

Siehe das Ereignis SRP Batch auf der linken Seite. Siehe auch die Größe des Stapels, d.h. die Anzahl der Zeichnungsaufrufe (hier 109). Das ist eine ziemlich effiziente Charge. Sie sehen auch den Grund, warum der vorherige Stapel kaputt war ("Node use different shader keywords"). Das bedeutet, dass die für diesen Stapel verwendeten Shader-Schlüsselwörter sich von den Schlüsselwörtern im vorherigen Stapel unterscheiden. Das bedeutet, dass sich die Shader-Variante geändert hat und wir den Stapel abbrechen müssen.

In manchen Szenen kann die Stapelgröße sehr gering sein, wie in dieser:

Frame Debugger

Die Chargengröße beträgt nur 2. Es bedeutet wahrscheinlich, dass Sie zu viele verschiedene Shader-Varianten haben. Wenn Sie Ihren eigenen SRP erstellen, versuchen Sie, einen generischen "Super"-Shader mit einem Minimum an Schlüsselwörtern zu schreiben. Sie müssen sich keine Gedanken darüber machen, wie viele Materialparameter Sie in den Abschnitt "Eigenschaften" eingeben.

HINWEIS: SRP Batcher-Informationen im Frame Debugger erfordern Unity 2018.3 oder höher.

Schreiben Sie Ihr eigenes SRP mit kompatiblem Shader

Anmerkung: Dieser Abschnitt ist für fortgeschrittene Benutzer gedacht, die ihre eigene skriptfähige Renderschleife und Shader-Bibliothek schreiben. LWRP- oder HDRP-Benutzer können diesen Abschnitt überspringen, da alle Shader, die wir anbieten, bereits mit SRP Batcher kompatibel sind.

Wenn Sie Ihre eigene Rendering-Schleife schreiben, müssen Ihre Shader einigen Regeln folgen, um den SRP Batcher-Codepfad zu durchlaufen.

"Pro Material" Variablen

Zunächst sollten alle "pro Material"-Daten in einem einzigen CBUFFER namens "UnityPerMaterial" deklariert werden. Was sind "Pro-Material"-Daten? Normalerweise alle Variablen, die Sie im Abschnitt "Shader-Eigenschaften" deklariert haben. Das sind alles Variablen, die Ihr Künstler mit dem GUI-Inspektor für Materialien verändern kann. Betrachten wir zum Beispiel einen einfachen Shader wie:

Properties

{

  _Color1 ("Color 1", Color) = (1,1,1,1)

  _Color2 ("Color 2", Color) = (1,1,1,1)

}

float4 _Color1;

float4 _Color2;

Wenn Sie diesen Shader kompilieren, wird Ihnen das Shader-Inspektionsfenster angezeigt:

Pro Materialien

Um das zu beheben, deklarieren Sie einfach alle Ihre "pro Material"-Daten so:

CBUFFER_START(UnityPerMaterial)

float4 _Color1;

float4 _Color2;

CBUFFER_END
"Pro Objekt"-Variablen

SRP Batcher benötigt außerdem einen ganz speziellen CBUFFER namens "UnityPerDraw". Dieser CBUFFER sollte alle in Unity eingebauten Engine-Variablen enthalten.

Die Reihenfolge der Variablendeklarationen innerhalb des CBUFFERs "UnityPerDraw" ist ebenfalls wichtig. Alle Variablen sollten ein bestimmtes Layout einhalten, das wir "Block Feature" nennen. Zum Beispiel sollte das "Blockmerkmal Raumposition" all diese Variablen in dieser Reihenfolge enthalten:

float4x4 unity_ObjectToWorld;

float4x4 unity_WorldToObject;

float4 unity_LODFade;

float4 unity_WorldTransformParams;

Sie brauchen einige dieser Blockfunktionen nicht zu deklarieren, wenn Sie sie nicht benötigen. Alle eingebauten Engine-Variablen in "UnityPerDraw" sollten float4 oder float4x4 sein. Auf Mobiltelefonen kann es sinnvoll sein, real4 (16 Bit kodierte Fließkommazahlen) zu verwenden, um GPU-Bandbreite zu sparen. Nicht alle UnityPerDraw-Variablen können "real4" verwenden. Bitte beachten Sie die Spalte "Könnte echt sein4".

Hier finden Sie eine Tabelle, die alle möglichen Blockfunktionen beschreibt, die Sie im CBUFFER "UnityPerDraw" verwenden können:

Pro Objekt

HINWEIS: Wenn eine der Variablen eines Merkmalsblocks als real4 ( half ) deklariert ist, dann sollten auch alle anderen potentiellen Variablen dieses Merkmalsblocks als real4 deklariert werden.

TIPP 1: Überprüfen Sie immer den Kompatibilitätsstatus eines neuen Shaders im Inspektor. Wir überprüfen mehrere mögliche Fehler (UnityPerDraw-Layout-Deklaration, usw.) und zeigen an, warum es nicht kompatibel ist.

HINT 2: Wenn Sie Ihren eigenen SRP-Shader schreiben, können Sie sich vom LWRP- oder HDRP-Paket inspirieren lassen, indem Sie sich deren UnityPerDraw CBUFFER-Deklaration ansehen.

Future

Wir arbeiten weiterhin an der Verbesserung von SRP Batcher, indem wir die Stapelgröße in einigen Rendering-Durchläufen (insbesondere Schatten und Tiefe) erhöhen.

Wir arbeiten auch daran, die automatische Nutzung von GPU-Instanzen mit SRP Batcher hinzuzufügen. Wir haben mit dem neuen DOTS-Renderer begonnen, der in unserer MegaCity-Demo verwendet wird. Der Geschwindigkeitszuwachs im Unity-Editor ist beeindruckend: von 10 auf 50 FPS.

MegaCity In-Editor mit SRP Batcher & DOTS Renderer. Der Leistungsunterschied ist so groß, dass sich sogar die globale Bildrate um den Faktor fünf erhöht.

HINWEIS: Um genau zu sein, ist dieser massive Geschwindigkeitszuwachs bei der Aktivierung des SRP-Batchers nur im Editor möglich, da der Editor derzeit keine Grafikaufträge verwendet. Die Beschleunigung im Standalone-Spielermodus beträgt etwa x2.

MegaCity im Editor. Wenn Sie das Video mit 60hz abspielen könnten, würden Sie den Geschwindigkeitszuwachs spüren, wenn Sie SRP Batcher aktivieren.

HINWEIS: SRP Batcher mit DOTS Renderer ist noch experimentell und in aktiver Entwicklung.