Jump to content
Unity Insider Forum

SetPass calls und Batches - Unterschied/Erklärung?


Tiwaz

Recommended Posts

Moin Leute,

 

ich hab mal ne eher Anfängerfrage, weil ich bisher einfach noch nie wirklich Probleme hatte bzw. darauf geachtet hab..

Bin jetzt grade im Statfenster drüber gestolpert und ich frage mich was der Unterschied zwischen "SetPass calls" und "Batches" ist bzw. was von den beiden Werten gibt die Draw Calls an? Bisher lebte ich ja in dem Glauben, dass Batches = Draw Calls sind aber was sind dann SetPass calls? ^^

 

Laut Scripting Reference sind Batches und SetPass Calls folgendes:

Batches:

“Batching†is where the engine attempts to combine the rendering of multiple objects into a chunk of memory in order to reduce CPU overhead due to resources switching.

 

SetPass:

The number of rendering passes. Each pass requires Unity runtime to bind a new shader which may introduce CPU overhead.

Und jetzt bin ich verwirrt :D

Wenn Batches nur die Versuche sind mehrere Objekte zusammen zu fassen, dann haben die ja zunächst erst mal überhaupt nichts mit den Draw Calls am Ende zu tun? (Natürlich schon, weil dadurch die Draw Calls reduziert werden könnten, wenn der Batch erfolgreich war, aber erst mal ist es nur der Versuch richtig?)

Dann sind ja die SetPass die Draw Calls oder nicht?

 

Bitte um Aufklärung :D

 

Grüße,

Tiwaz

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hm.. naja irgendwie nicht so wirklich ^^

Dort wird ja quasi ebenfalls behauptet, dass Batches und Draw Calls identisch sind (wobei sie es ja lt. einiger Postes nicht sind).

 

Außerdem finden Batches nur bei MeshRenderern statt

Currently, only Mesh Renderers are batched. This means that skinned meshes, cloth, trail renderers and other types of rendering components are not batched.

D.h. ja, dass GUI Elemente auch nicht gebatcht werden, allerdings gehen auch die Batches nach oben, wenn man viele GUI Elemente hat, die entweder unterschiedliche Atlanten bzw. keine Atlanten benutzen oder sich gegenseitig überlappen.

 

Der verlinkte Thread hat mich tatsächlich nur noch mehr verwirrt ._.

 

@edit:

Ebenfalls wird dort zitiert:

Draw calls are often seen as expensive, with the graphics API doing significant work for every draw call, causing performance overhead on the CPU side. However this is not the case. The expensive part is the changing of the resources accessed by the GPU between the draw calls as it triggers a graphics driver validation each time. The emphasis should be on reducing the batch count, rather than the draw call count.

Wobei ich das irgendwie nicht verstehe... ^^

Wenn mit einem Draw Call ein State Change und somit eine driver validation einhergeht, was den größten Overhead verursacht.. Wieso sollte man sich dann nicht auf die Draw Calls konzentrieren?

Wenn die Draw Calls sinken würden ebenfalls automatisch die graphics driver validation seltener getriggert, was den Overhead reduziert?

Und wie spielen da jetzt die Batches mit rein?

 

Und was gibt eigentlich der Batch Count genau an? Das sind ja erst mal nur die Versuche Objekte zusammen zu fassen richtig? D.h. ein hoher Batch Count heißt, dass Unity bei vielen Objekten versucht hat sie zusammen zu fassen, um diese in einen Draw Call rendern zu lassen, jedoch gescheitert ist.

Ist "Saved by batching" dann die Anzahl der Draw Calls die nicht eingespart wurden, weil das Batching bei manchen Objekten erfolgreich war?

 

Fragen über Fragen, sry ^^

Link zu diesem Kommentar
Auf anderen Seiten teilen

Also, ich hab mal hier und da ein bisschen recherchiert und die Quellen widersprechen sich hier und da.

 

Fangen wir mal am Anfang an.

Ein Draw Call ist, wenn die CPU zur GPU geht und ihr sagt, sie solle doch bitte ein bekanntes Modell mit einem bekannten Shader und bekannten Texturen zeichnen. "Bekannt" heißt hierbei, das der Kram schon im VRAM bereit liegt. Dazu gegeben werden nur aktuelle Matrizen, also quasi die Transformation relativ zur Kamera, und vielleicht ein paar Floats hier und da.

 

Der Draw Call muss dabei über zwei Busse und die North Bridge geleitet werden (Grafikkarte ist links, heutzutage meist an PCI Express):

370px-Motherboard_diagram.svg.png

 

Die CPU haut jetzt gerne mal weniger schnell Draw Calls raus als die GPU rendern kann. Ein Draw Call kostet die CPU relativ konstante Zeit, und je weniger Vertices dein Mesh hat, desto schneller ist die Grafikkarte.

Hat dein Mesh allerdings so viele Vertices, dass das Rendern ungefähr so lange dauert wie das Losschicken des Draw Calls, erübrigt sich das mehr oder weniger.

 

Ohne Batching wird für jedes Material auf jedem 3D-Objekt ein Draw Call losgeschickt, egal, wie komplex das Mesh ist.

Static Batching nutzt jetzt die static-Flags auf deinen Objekten um zu wissen, dass die Objekte sich nie relativ zueinander bewegen werden. Haben zwei statische Meshes jetzt dasselbe Material, könnten sie genauso gut ein Mesh sein. Also werden sie zu einem zusammengefügt und auch als eines gerendert. Anstatt also zwei Mal einen Draw Call von der CPU abzuwarten, wird nur noch ein Draw Call geschickt. Die Grafikkarte arbeitet genauso lange - der Unterschied ist nur, dass sie weniger lange auf den nächsten Draw Call wartet, weil sie an dem größeren Mesh länger zu knabbern hat.

Packst du also zwei komplexe Meshes mit vielen Vertices nebeneinander, können sie noch so statisch sein und das gleiche Material haben; da passiert kein Batching. Wird der Batch nämlich zu groß, muss die CPU auf die Grafikkarte warten, und das wäre genauso schlimm wie das Gegenteil.

Static Batching lädt das zusammengefügte Mesh gleich als ein Mesh in den VRAM, es ist also zur Laufzeit so, als würde gar kein Batching passieren.

 

Dynamic Batching dagegen ist für dynamische Objekte (wer hätt's gedacht), die deshalb nicht zu einem Mesh zusammengefügt werden können. Stattdessen wird ein Batch-Draw Call an die GPU geschickt, der anweist, mehrere Meshes mit ähnlichen Eigenschaften (gleicher Shader usw.) direkt hintereinander zu zeichnen, während sich die CPU den nächsten Draw Call überlegt. Einen solchen Draw Call zusammenzustellen, kostet die CPU natürlich etwas Zeit, aber das gleicht sich oft durch die reduzierte Idle Time der GPU aus.

 

Zusammenfassend also: Man sollte versuchen, dass die GPU so viel leistet, wie sie kann. Muss die GPU auf die CPU warten, ist das verschwendete Zeit. Wenn man aber durch Batching pro Draw Call der GPU so viel Arbeit aufhalst, dass sie gerade so fertig ist, wenn der nächste von der CPU kommt, nutzt man die Möglichkeiten der Grafikkarte gut aus.

 

Ich denke, da kann man sich einig sein.

Was dein Zitat sagt, ist, dass bei jedem Draw Call (oder Batch-Draw Call!), den die GPU kriegt, Dinge passieren, die Zeit kosten.

So steht ja im Draw Call "Zeichne Mesh an Adresse 0x11d4blub mit Shader an Adresse 0xf13cblub mit Textur 0xbla" und so weiter.

Dass die Zeiger auf diese Adressen gesetzt werden und daraufhin offenbar die Daten an jener Adresse validiert werden, kostet wohl Zeit. Man sollte also möglichst selten diese Daten raussuchen und damit validieren lassen.

Kommt während eines Frames mehrere Male ein Draw Call für denselben Mesh oder denselben Shader, hat das natürlich überflüssiges Rumvalidieren zur Folge.

Zu sagen, dass man deswegen den Batch Count reduzieren soll, halte ich aber für sehr kritisch. Batches sollten schon nach dem oben genannten so viele Vertices wie möglich beinhalten (unter Berücksichtigung der Tatsache, dass die Komplexität des Shaders bei der Bearbeitungsdauer des Batches eine Rolle spielt).

Um den Batch Count zu reduzieren, müsste man die Batches größer machen, aber dann muss die CPU irgendwann doch wieder auf die GPU warten.

 

Draw Calls und Batch Count zu reduzieren ist also eigentlich dasselbe, wenn man's richtig macht: Je mehr Draw Calls zu in Batches zusammenfasst, desto größer werden deine Batches. Wenn dein Batch zu groß werden würde, musst du halt einen zweiten Batch anfangen. Auf diese Art entstehen nicht mehr Batches als nötig, und möglichst viele Draw Calls werden zusammengefasst.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ah okay ich glaub ich hab das jetzt verstanden, vielen Dank :)

 

Und was hat es dann noch mit diesen ominösen "SetPass calls" auf sich? Sind das jetzt die Draw Calls oder zeigt die Unity überhaupt nicht mehr an weil sie sagen, dass Batches eh wichtiger sind und man sich dann überhaupt nicht auf die Draw Calls konzentrieren soll?

 

Ich kenne "Passes" nur vom Shader aber da wird im Stat Window was anderes gemeint sein oder?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Soweit ich das verstanden habe, ist jeder Pass, den du renderst, mit einem Draw Call verbunden. Die CPU muss also zur GPU gehen und den Pass ansagen. Es wird also nicht gesagt "Zeichne Mesh x mit Shader y und Textur z" sondern eher "Zeichne Mesh x mit Shader y, Pass blub und Textur z".

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 3 years later...
Am 15.4.2016 um 15:06 schrieb Sascha:

Also, ich hab mal hier und da ein bisschen recherchiert und die Quellen widersprechen sich hier und da.

 

Fangen wir mal am Anfang an.

Ein Draw Call ist, wenn die CPU zur GPU geht und ihr sagt, sie solle doch bitte ein bekanntes Modell mit einem bekannten Shader und bekannten Texturen zeichnen. "Bekannt" heißt hierbei, das der Kram schon im VRAM bereit liegt. Dazu gegeben werden nur aktuelle Matrizen, also quasi die Transformation relativ zur Kamera, und vielleicht ein paar Floats hier und da.

 

Der Draw Call muss dabei über zwei Busse und die North Bridge geleitet werden (Grafikkarte ist links, heutzutage meist an PCI Express):

370px-Motherboard_diagram.svg.png

 

Die CPU haut jetzt gerne mal weniger schnell Draw Calls raus als die GPU rendern kann. Ein Draw Call kostet die CPU relativ konstante Zeit, und je weniger Vertices dein Mesh hat, desto schneller ist die Grafikkarte.

Hat dein Mesh allerdings so viele Vertices, dass das Rendern ungefähr so lange dauert wie das Losschicken des Draw Calls, erübrigt sich das mehr oder weniger.

 

Ohne Batching wird für jedes Material auf jedem 3D-Objekt ein Draw Call losgeschickt, egal, wie komplex das Mesh ist.

Static Batching nutzt jetzt die static-Flags auf deinen Objekten um zu wissen, dass die Objekte sich nie relativ zueinander bewegen werden. Haben zwei statische Meshes jetzt dasselbe Material, könnten sie genauso gut ein Mesh sein. Also werden sie zu einem zusammengefügt und auch als eines gerendert. Anstatt also zwei Mal einen Draw Call von der CPU abzuwarten, wird nur noch ein Draw Call geschickt. Die Grafikkarte arbeitet genauso lange - der Unterschied ist nur, dass sie weniger lange auf den nächsten Draw Call wartet, weil sie an dem größeren Mesh länger zu knabbern hat.

Packst du also zwei komplexe Meshes mit vielen Vertices nebeneinander, können sie noch so statisch sein und das gleiche Material haben; da passiert kein Batching. Wird der Batch nämlich zu groß, muss die CPU auf die Grafikkarte warten, und das wäre genauso schlimm wie das Gegenteil.

Static Batching lädt das zusammengefügte Mesh gleich als ein Mesh in den VRAM, es ist also zur Laufzeit so, als würde gar kein Batching passieren.

 

Dynamic Batching dagegen ist für dynamische Objekte (wer hätt's gedacht), die deshalb nicht zu einem Mesh zusammengefügt werden können. Stattdessen wird ein Batch-Draw Call an die GPU geschickt, der anweist, mehrere Meshes mit ähnlichen Eigenschaften (gleicher Shader usw.) direkt hintereinander zu zeichnen, während sich die CPU den nächsten Draw Call überlegt. Einen solchen Draw Call zusammenzustellen, kostet die CPU natürlich etwas Zeit, aber das gleicht sich oft durch die reduzierte Idle Time der GPU aus.

 

Zusammenfassend also: Man sollte versuchen, dass die GPU so viel leistet, wie sie kann. Muss die GPU auf die CPU warten, ist das verschwendete Zeit. Wenn man aber durch Batching pro Draw Call der GPU so viel Arbeit aufhalst, dass sie gerade so fertig ist, wenn der nächste von der CPU kommt, nutzt man die Möglichkeiten der Grafikkarte gut aus.

 

Ich denke, da kann man sich einig sein.

Was dein Zitat sagt, ist, dass bei jedem Draw Call (oder Batch-Draw Call!), den die GPU kriegt, Dinge passieren, die Zeit kosten.

So steht ja im Draw Call "Zeichne Mesh an Adresse 0x11d4blub mit Shader an Adresse 0xf13cblub mit Textur 0xbla" und so weiter.

Dass die Zeiger auf diese Adressen gesetzt werden und daraufhin offenbar die Daten an jener Adresse validiert werden, kostet wohl Zeit. Man sollte also möglichst selten diese Daten raussuchen und damit validieren lassen.

Kommt während eines Frames mehrere Male ein Draw Call für denselben Mesh oder denselben Shader, hat das natürlich überflüssiges Rumvalidieren zur Folge.

Zu sagen, dass man deswegen den Batch Count reduzieren soll, halte ich aber für sehr kritisch. Batches sollten schon nach dem oben genannten so viele Vertices wie möglich beinhalten (unter Berücksichtigung der Tatsache, dass die Komplexität des Shaders bei der Bearbeitungsdauer des Batches eine Rolle spielt).

Um den Batch Count zu reduzieren, müsste man die Batches größer machen, aber dann muss die CPU irgendwann doch wieder auf die GPU warten.

 

Draw Calls und Batch Count zu reduzieren ist also eigentlich dasselbe, wenn man's richtig macht: Je mehr Draw Calls zu in Batches zusammenfasst, desto größer werden deine Batches. Wenn dein Batch zu groß werden würde, musst du halt einen zweiten Batch anfangen. Auf diese Art entstehen nicht mehr Batches als nötig, und möglichst viele Draw Calls werden zusammengefasst.

Zusammenfassenm, ist das, wenn ichs richtig verstanden habe:

Besser mehr Draw Calls und weniger Batches?

Würde zu meinem Test gerade passen.

830 DC zu 760 Bat

Redutiert zu:

800 DC zu 670 Bat

Hab damit gerade 25 FPS gewonnen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 2 weeks later...

Archiviert

Dieses Thema ist jetzt archiviert und für weitere Antworten gesperrt.

×
×
  • Neu erstellen...