Seite 1 von 1

[D3D9] Last auf Input Assembler reduzieren

Verfasst: 19.09.2012, 14:49
von Schrompf
Guten Tag, verehrte Expertinnen und Experten.

Wie schon im Jammer-Thread angedeutet habe ich aktuell ein Problem mit vielen vielen kleinen Flächen, die ich effizient rendern möchte. NVidia NSight ist zwar nur ein unvollkommenes Werkzeug, aber der Grundaussage der Profiler-Läufe kann ich wohl trauen: die GPU verbringt drei Viertel der Zeit im Input Assembler. Was kann ich dagegen tun?

Ich dachte mir, das Verkleinern der Eingabestrukturen könnte helfen. Das habe ich wie folgt ausprobiert:

Code: Alles auswählen

struct VoxelVertex 
{ 
  float3 vpos; 
  ubyte4 vtex; 
};
struct InstanzVertex 
{
  float3 ipos; 
  ubyte4 inorm; 
  ubyte4 igr_und_tex; 
  ubyte4 ifarbe;
};

VertexAusgabe main( const VertexEingabe rein)
{
  // Ausgabestruktur
  VertexAusgabe raus;

  // Instanz in Kamerakoordinaten transformieren
  float4 pos = float4( rein.ipos * gVoxelGroesse, 1.0f);
  float3 norm = mul( (float3x3) gObjektMatrix, rein.inorm * (2.0f / 255.0f) - float3( 1.0f, 1.0f, 1.0f));
  float4 weltPos = mul( gObjektMatrix, pos);
  float4 kamPos = mul( gWeltMatrix, pos);

  // dort zu Quadrat entfalten
  float igr = rein.igr_und_tex.x * (1.0f / 255.0f) + rein.igr_und_tex.y;
  kamPos.xyz += rein.vpos * gVoxelGroesse * igr;
  // und ausgeben
  raus.mPosition = mul( gProjMatrix, kamPos);

  // Texturkoordinaten erstellen
  float texgr = 32.0f / 2048.0f;
  float2 texpos = (rein.igr_und_tex.zw * 40.0f + 4.0f) * (1.0f / 2048.0f);
  raus.mTexKoords = texpos + rein.vtex * texgr;
                        
  return raus;
}
Erklärung: Ein Voxel ist ein Billboard besteht aus zwei Dreiecken, die ich dann per Instancing in Rudeln zeichne. Das hier ist eine vereinfachte Form, bei der ich mal alle relevanten Sachen zusammenkopiert habe. Ich könnte die Vertex-Strukturen noch ein bisschen weiter eindampfen, aber ich bezweifle, ob das noch irgendwas bringt. Der Mesh-Vertex ist jetzt noch 16 Byte groß und der InstanzVertex noch 24 Byte - gegenüber vorher 28 Byte und 56Byte habe ich gerade mal 30% Performance gewonnen. Es liegt also anscheinend nicht am Speicherdurchsatz, sondern der Input Assembler ist irgendwie anderweitig überlastet. Hat jemand noch eine Idee, was ich hier tun könnte?

Eine Idee wäre noch, das Instancing sein zu lassen, und mit DX10 und einem GeometrieShader Point Sprites zu pinseln. Das würde evtl. den Input Assembler entlasten, weil der dann kein Instancing mehr zusammensuchen muss und der VertexShader nur noch pro Voxel einmal läuft. Dazu müsste ich aber auf DX10 wechseln, was ich bisher eigentlich nicht wollte.

Re: [D3D9] Last auf Input Assembler reduzieren

Verfasst: 19.09.2012, 15:01
von CodingCat
Stimmt die Vertex Declaration bzgl. Reihenfolge und Offsets (auch Stream-übergreifend) exakt mit der Shader-Input-Signatur überein? Wenn ja, dann sieht es tatsächlich düster aus. Du könntest allenfalls noch Mini-Vertices probieren, in denen du VoxelVertex durch ein einziges Byte oder Uint mit ID zwischen 0 und 3 ersetzt. Wenn auch das nicht hilft, fällt mir höchstens noch Texture-Lookup statt Instancing-Stream ein, um die gesamte Multi-Stream-Assembly loszuwerden. Ob das dann aber tatsächlich schneller als der Input Assembler ist, kann ich nicht voraussagen.

Re: [D3D9] Last auf Input Assembler reduzieren

Verfasst: 19.09.2012, 15:28
von Schrompf
Danke. Der Gedanke, den MeshVertex auf 4Byte zu reduzieren, kam mir auch schon während des Schreibens. Aber ich bezweifle, dass da noch viel rauszuholen ist - das Assembling aus zwei Streams scheint das Problem zu sein.

Ich habe gerade mal nachgeschaut: die detail-dichteste Szene hat etwa 1000 Buffer mit insgesamt 42MB Größe. Ich könnte also schlimmstenfalls das Instancing sein lassen und wieder vier Vertices pro Voxel schreiben. Die Instanz-Positionen sind ganze Zahlen, also könnte 3x16Bit Position reichen und die Ecke-ID pack ich in den vierten 16Bit-Wert. Damit wären wir dann bei 20Byte pro Vertex und damit 80Byte pro Voxel. Werde ich mal ausprobieren.

Re: [D3D9] Last auf Input Assembler reduzieren

Verfasst: 19.09.2012, 17:48
von Schrompf
Und das ist das Ergebnis:

Instancing von 56Byte VertexStruktur auf 24Byte-VertexStruktur geschrumpft: 14 -> 18 fps
Instancing ausgebaut und stattdessen manuell 4 Vertizes pro Voxel geschrieben: 18fps -> 50 fps

Dafür bin ich jetzt bei 200MB VideoRAM anstatt vorher 42MB für die Buffer. Nuja... etwas Platz zum Optimieren ist noch, das war erstmal nur ein QuickHack zum Ausprobieren.

Re: [D3D9] Last auf Input Assembler reduzieren

Verfasst: 19.09.2012, 22:43
von Jörg
Kannst Du nicht alles aus der VertexID ableiten und ganz auf Voxelvertex verzichten?

Re: [D3D9] Last auf Input Assembler reduzieren

Verfasst: 19.09.2012, 22:47
von CodingCat
Das wäre mit Sicherheit der beste Weg, aber iirc erfordert das mindestens DX10. Lässt sich aber sehr leicht herausfinden, einfach mal SV_VertexID zum Input des VS hinzufügen. :|

Re: [D3D9] Last auf Input Assembler reduzieren

Verfasst: 19.09.2012, 23:05
von Schrompf
Braucht nach meinem Wissen mindestens DX10. Die ganzen SV_Defs heißen vorher ja noch POSITION0, TEXCOORD0 und so.