[C++] [D3D9] Texturkoordinaten und Skalierung

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [C++] [D3D9] Texturkoordinaten und Skalierung

Beitrag von dot »

Statt FVF Codes, die selbst in D3D9 damals schon veraltet waren, schau dir mal VertexDeclarations an: https://msdn.microsoft.com/en-us/librar ... 06335.aspx ;)
Goderion hat geschrieben:5. Laut Microsoft ist TEXCOORD[n] ein float4 (https://msdn.microsoft.com/en-us/librar ... 5).aspx#VS).
Das ist eine Shader Semantic, nicht zu verwechseln mit dem input vertex format. Wenn du FVF verwendest und nicht explizit per D3DFVF_TEXCOORDSIZEN die Größe der Texcoords änderst, dann hast du 2D input coordinates.
Benutzeravatar
Krishty
Establishment
Beiträge: 8240
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] [D3D9] Texturkoordinaten und Skalierung

Beitrag von Krishty »

Goderion hat geschrieben:1. Wenn ich im Test (ca. 60.000 Sprites, ca. 2.000 SetTexture) jedesmal beim SetTexture auch zusätzlich SetVertexShaderConstantF aufrufe, um z.B. die Texturgröße zu setzen, fallen die FPS von 330 auf 90. Wieso auch immer scheint der Aufruf von SetVertexShaderConstantF extrem langsam zu sein und ich werde alle nötigen Daten, die oft wechseln, wie z.B. hier bei jeder Textur, mit in die Vertexdaten packen müssen.
Gut möglich; siehe die Tabelle hier ganz unten: Accurately Profiling Direct3D API Calls (Direct3D 9) Ab D3D 10 müsste das durch Constant Buffers viel schneller sein.
Goderion hat geschrieben:2. Ich habe zwei Rendermodi, die eigentlich das gleiche machen, aber unterschiedliche FPS liefern. […] Mit "Image" erreiche ich ca. 330 FPS, mit "ImagePro" ca. 390 FPS. Warum?!
Irgendein Slow Path im Treiber; die wenigsten Spiele nutzen ausgiebig XYZRHW.
Goderion hat geschrieben:3. Ich habe auch nochmal Vertex -und Indexbuffer getestet. Es scheint so zu sein, das Vertex -und Indexbuffer nur sinnvoll sind, wenn man sie inhaltlich nicht in jedem Frame ändern muss, was bei mir aber leider der Fall ist.
Genau; die sind da nutzlos. D3D 10 und höher bieten auch keinen Ersatz für DrawPrimitiveUP(); ab D3D 12 kannst du immerhin synchron in Vertex Buffers schreiben.
Goderion hat geschrieben:4. Mit dem VertexFormat "XYZ | DIFFUSE | TEX1" erreiche ich ca. 390 FPS. Mit dem VertexFormat "XYZ | DIFFUSE | TEX1 | TEX2 | TEX3 | TEX4" fallen die FPS auf 300. Die VertexDaten für TEX2, TEX3 und TEX4 werden nicht gesetzt oder im VertexShader verarbeitet. Schon etwas erschreckend, dass 24 Byte mehr pro Vertex so auf die Performance gehen.
Äh … von Caches und Speicherbandbreite hast du aber schon gehört, oder? Wenn du statt 24 B jetzt 48 überträgst, ist die Übertragung halt nur noch halb so schnell … und dass die ein Flaschenhals ist, weißt du, seit Vertex Buffers nichts gebracht haben.
Goderion hat geschrieben:5. Laut Microsoft ist TEXCOORD[n] ein float4 (https://msdn.microsoft.com/en-us/librar ... 5).aspx#VS). Nutze ich das so, kommt bei mir bei der Verwendung mehrerer TEXCOORD[n] im VertexShader Blödsinn raus. In vielen Beispielen zu VertexShadern, die ich durch Googlen gefunden habe, wird TEXCOORD[n] aber als float2 genutzt. Stelle ich in meinen TestVertexShadern das auch auf float2, funktioniert alles wie erwartet. In der Struktur vom Vertex werden pro TEXCOORD[n] ja auch nur zwei float übergeben. Was ist hier los? Fehler von Microsoft oder habe ich was überlesen?
MSDN, Texture Coordinate Formats (Direct3D 9) hat geschrieben:The D3DFVF_TEXTUREFORMAT1 through D3DFVF_TEXTUREFORMAT4 flags describe the number of elements in a texture coordinate in a set, but these flags aren't used by themselves. Rather, the D3DFVF_TEXCOORDSIZEN set of macros use these flags to create bit patterns that describe the number of elements used by a particular set of texture coordinates in the vertex format.
Alternativ sind Vertex Declarations deutlich angenehmer zu benutzen.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [C++] [D3D9] Texturkoordinaten und Skalierung

Beitrag von dot »

Krishty hat geschrieben:
Goderion hat geschrieben:2. Ich habe zwei Rendermodi, die eigentlich das gleiche machen, aber unterschiedliche FPS liefern. […] Mit "Image" erreiche ich ca. 330 FPS, mit "ImagePro" ca. 390 FPS. Warum?!
Irgendein Slow Path im Treiber; die wenigsten Spiele nutzen ausgiebig XYZRHW.
Abgesehen davon, bedeutet XYZRHW doch, dass du deine Vertices auf der CPU transformieren und dann ständig neu auf die GPU laden musst!?
Benutzeravatar
Krishty
Establishment
Beiträge: 8240
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] [D3D9] Texturkoordinaten und Skalierung

Beitrag von Krishty »

Wenn man Spiele emuliert, die vor der T&L-Ära entwickelt wurden, ist das aber nötig. Ich mache das bei meinem Flugsimulator genauso.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Goderion
Beiträge: 82
Registriert: 16.09.2012, 12:02

Re: [C++] [D3D9] Texturkoordinaten und Skalierung

Beitrag von Goderion »

Vielen Dank für die Antworten!
dot hat geschrieben:Statt FVF Codes, die selbst in D3D9 damals schon veraltet waren, schau dir mal VertexDeclarations an: https://msdn.microsoft.com/en-us/librar ... 06335.aspx ;)
Krishty hat geschrieben:Alternativ sind Vertex Declarations deutlich angenehmer zu benutzen.
Ah, habe die schon oft in Beispielen und Erklärungen zu Vertexshadern gesehen. Direkt implementiert und SetFVF rausgeschmissen. Jetzt kann ich auch genau festlegen/sehen, wo welcher Wert in der Vertexstruktur zu liegen hat.
Krishty hat geschrieben:Gut möglich; siehe die Tabelle hier ganz unten: Accurately Profiling Direct3D API Calls (Direct3D 9) Ab D3D 10 müsste das durch Constant Buffers viel schneller sein.
Sehr interessante Tabelle/Liste, danke!
Krishty hat geschrieben:Äh … von Caches und Speicherbandbreite hast du aber schon gehört, oder? Wenn du statt 24 B jetzt 48 überträgst, ist die Übertragung halt nur noch halb so schnell … und dass die ein Flaschenhals ist, weißt du, seit Vertex Buffers nichts gebracht haben.
Ja klar, so gesehen ist das schon verständlich. Aber ich finde es trotzdem immer wieder etwas überraschend. Es geht um 60.000 x 6 x 24 Byte, also insgesamt 8,64 MB pro Frame. Bei 400 FPS wären das grob zusätzlich 3,5 GB/s. PCIe 3.0 x16 soll 32 GB/s schaffen. D3D9 ist da aber wohl bekannter Weise nicht so gut umgesetzt. Neuere D3D Versionen wie z.B. D3D10 würden das vermutlich besser "wegstecken", oder?
dot hat geschrieben:Abgesehen davon, bedeutet XYZRHW doch, dass du deine Vertices auf der CPU transformieren und dann ständig neu auf die GPU laden musst!?
Leider korrekt. Bei 3D-Titeln wird vermutlich erst immer ein statischer Teil, der den Großteil der Levelgeometrie/Leveldaten ausmacht und konstant bleibt, einmalig in einen Vertexbuffer gepackt und aufgrund von der Kameraposition/View durch die GPU transformiert. Die dynamischen Teile im Level, wie z.B. Animationen, wo mindestens die Texturkoordinaten alle paar Frames wechseln, werden dann am Ende gerendert und der Z-Buffer sorgt dafür, dass das auch alles korrekt passt. Man sorgt also dafür, das wirklich nur das Nötigste pro Frame neu zur GPU gesendet wird. So ein Konzept muss ich mir für meine 2D-Engine überlegen. Ein Z-Buffer finde ich dort schwieriger nutzbar zu machen, da die Objekte keine Distanz zu einer Kamera haben, sondern eher eine Renderordnung. Bei Ultima 7 ist das z.B. aufgrund von der Pseudo-Vogelperspektive völlig irre. Ich überlege da aber schon länger und vielleicht werde ich bald ein Konzept haben, wie ich wenigstens den Boden, bzw. dessen tatsächlichen konstanten Teile, per VertexBuffer rendern kann.
Benutzeravatar
Krishty
Establishment
Beiträge: 8240
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] [D3D9] Texturkoordinaten und Skalierung

Beitrag von Krishty »

Goderion hat geschrieben:
Krishty hat geschrieben:Äh … von Caches und Speicherbandbreite hast du aber schon gehört, oder? Wenn du statt 24 B jetzt 48 überträgst, ist die Übertragung halt nur noch halb so schnell … und dass die ein Flaschenhals ist, weißt du, seit Vertex Buffers nichts gebracht haben.
Ja klar, so gesehen ist das schon verständlich. Aber ich finde es trotzdem immer wieder etwas überraschend. Es geht um 60.000 x 6 x 24 Byte, also insgesamt 8,64 MB pro Frame. Bei 400 FPS wären das grob zusätzlich 3,5 GB/s. PCIe 3.0 x16 soll 32 GB/s schaffen. D3D9 ist da aber wohl bekannter Weise nicht so gut umgesetzt. Neuere D3D Versionen wie z.B. D3D10 würden das vermutlich besser "wegstecken", oder?
Keine Ahnung. Die 3.5 GB müssen ja mehrfach kopiert werden – erstmal erzeugst du sie auf dem Stack. Dann werden sie von DrawPrimitiveUP() in den Befehlspuffer des Treibers kopiert. Dann vom Befehlspuffer über PCIe auf die GPU. Da du die Vertices nicht auf einen Schlag zur Verfügung stellst, sondern auf viele Draw Calls verteilt, geht zwischendurch auch die Lokalität flöten.

Mit D3D 12 oder Vulkan kannst du direkt kopieren, also dir den Treiber-Puffer sparen. Das habe ich aber nur gehört und noch nicht selber umgesetzt. Und es wird sicherlich mindestens 20 Mal so viele Zeilen Code erfordern.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Antworten