Seite 1 von 1

(gelöst)[D3D9] Kosten redundanter State Changes

Verfasst: 04.07.2011, 10:00
von Krishty
Hi,

ungewöhnliche Frage, die man sicher nur durch Benchmarking testen kann – aber vielleicht hat das ja schon jemand für mich getan oder steckt tief genug in den Treibern:

Es gibt eine schöne Tabelle, wie viele Takte einzelne API-Aufrufe benötigen (hier ganz unten). Bspw. verbraucht SetVertexDeclaration() im Schnitt 6500–11250 Takte. Ich habe hier ein paar tausend Draw-Calls, und rufe jedes Mal vorher SetVertexDeclaration() auf. (Nicht nur diese eine Funktion, eigentlich stelle ich die komplette Pipeline vor jedem Draw Call ein.)

Jetzt des Pudels Kern: Meistens ändert sich garnichts, sondern ich setze die aktuellen Shader / Vertex Declarations / Render States etc. nochmal. Ist die Direct3D Runtime oder der Treiber klug genug, das als redundant zu erkennen und nach hundert Takten im User Mode zurückzukehren, oder sollte ich selber aufpassen, dass ich nichts redundant setze?

Ich würde dem Treiber das durchaus zutrauen, aber andererseits warnt ja die Debug Runtime vor redundanten Render States, was mich irgendwie vermuten lässt, dass die nicht wollen, dass ich mich drauf verlasse …

Gruß

Re: [D3D9] Kosten redundanter State Changes

Verfasst: 04.07.2011, 10:10
von CodingCat
Im DirectX SDK gibt es eine Beispielanwendung namens StateManager, dort lassen sich Pure und nicht-Pure-Devices mit und ohne Materialsortierung und mit und ohne eigener State-Verwaltung testen. Mein Ergebnis: nicht-Pure sind leicht schneller als Pure-Devices, in beiden Fällen bringt Materialsortierung ca. 50% weniger Framezeit, d.h. in beiden Fällen filtert die Runtime/der Treiber (mglw. abhängig von nicht-Pure/Pure?) zumindest teilweise redundante States, in beiden Fällen bringt der eigene StateManager nur Verlangsamung (der ist aber auch total miserable implementiert, IIRC). Schau einfach mal rein.

Re: [D3D9] Kosten redundanter State Changes

Verfasst: 04.07.2011, 10:21
von Krishty
Interessant. Das Pure Device wird durch den State Manager 20 % langsamer, das non-pure dagegen 10 % schneller. Beim zweiten Ausführen ist es, wie du gesagt hast: pure und non-pure ähnlich schnell, mit State Manager bedeutend langsamer.

Die Dokumentation des Beispiels beantwortet meine Frage eigentlich auch schon:
In constrast, a non-pure device (created without D3DCREATE_PUREDEVICE) will check each state change for redundancy, and discard them. This reduces the amount of work that the device will need to perform.
Aber offenbar macht der Treiber das auch nochmal.

Dann baue ich nur sehr grobes State Management ein, das per flinkem Test entweder zehn redundante Aufrufe auf einmal abfängt oder garkeine. Dankesehr!

P.S.: Lohnt es sich, DrawPrimitiveUP() zu batchen? Ich gehe mal stark davon aus, aber Fragen schadet ja nicht …

Re: [D3D9] Kosten redundanter State Changes

Verfasst: 04.07.2011, 10:40
von Dirk Schulz
Hi,

vor dem "Problem" stand ich vor kurzem auch, wollte auch schon D3D die Arbeit machen lassen, bis ich über diesen Post stolperte:

http://forums.create.msdn.com/forums/p/ ... spx#108930

20% ist schon ne Ansage. :shock:

Die Batchfrage muss man wohl wirklich nicht beantworten, oder? ;)

Re: [D3D9] Kosten redundanter State Changes

Verfasst: 04.07.2011, 11:04
von Krishty
Verdammt, es wird immer verwirrender :(
Dirk Schulz hat geschrieben:Die Batchfrage muss man wohl wirklich nicht beantworten, oder? ;)
Nochmal aus dem Artikel:
A less obvious secondary effect is that the work for DrawPrimitive is also reduced from 1500 calls to 1 call because all of the conditions for concatenating draw calls are satisfied. When the render sequence is processed, the runtime will process 1500 calls into a single driver call.
Die Runtime führt also automatisch Batching durch, so lange keine anderen API-Aufrufe dazwischenliegen. Falls ich also zwischen den meisten Draw Calls die redundanten State Changes rausoptimiere und keine mehr übrig bleiben, könnte theoretisch auch DrawPrimitiveUP() gebatcht werden. Die Frage ist, ob das auch praktisch der Fall ist …

Re: [D3D9] Kosten redundanter State Changes

Verfasst: 04.07.2011, 11:06
von Schrompf
Ich habe die Filterung unnötiger State-Änderungen 2006 oder so in unsere Basisklassen eingebaut und hatte damals eine Verdopplung der Framerate erreicht. Ich muss aber zugeben, dass ich die Ergebnisse seitdem nie wieder überprüft habe.

Re: [D3D9] Kosten redundanter State Changes

Verfasst: 04.07.2011, 11:12
von CodingCat
Dirk Schulz hat geschrieben:20% ist schon ne Ansage.
Allerdings geht es hier um XNA.
An Overview of Managed/Unmanaged Code Interop hat geschrieben:Approximate overhead for a COM interop call: 50 machine instructions (on an x86 processor)
Das dürfte bei +5000 Aufrufen ordentlich reinhauen, egal ob dann auf Runtimeseite gefiltert wird oder nicht.

Selbst in C++ ist der Overhead virtueller Methodenaufrufe jedoch alles andere als zu vernachlässigen, wie ich kürzlich mit Schrecken feststellen musste. Aua, ich habe gerade einen ultrapeinlichen Fehler im Benchmark entdeckt. Wenn man aufhört, die Zeit des falschen Timers abzufragen, ist die Welt wieder sehr viel mehr in Ordnung. In C++ liegt der Overhead Vergleich nach virtuellem Aufruf vs. Vergleich ohne Aufruf bei mir irgendwo bei 80%, bei +5000 Aufrufen ca. +0.008 ms.

Re: [D3D9] Kosten redundanter State Changes

Verfasst: 12.07.2011, 01:44
von Krishty
Meine CPU-Limitierung hat sich gerade verflüchtigt wie ein Spendenkoffer auf einem CDU-Parteitag. Ich habe direkt gebencht und kann mit Freude verkünden:
  • DrawIndexedPrimitiveUP() wird gebatcht
  • States sparen ist 0–1 % schneller als States verschwenden
  • Pure Device ist rund 0,5 % langsamer als non-pure
Mit starker CPU-Limitierung fiel die Pure-Device-Sache genau andersrum aus.

Kaum was der Rede wert. Ich bedanke mich dennoch für eure Hilfe!