Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

LukasBanana

Alter Hase

  • »LukasBanana« ist der Autor dieses Themas

Beiträge: 1 097

Beruf: Shader Tools Programmer

  • Private Nachricht senden

1

05.06.2013, 10:46

D3D11: tbuffer & StructuredBuffer

Hallo,
ich suche momentan in D3D11 das Äquivalent zu OpenGL's Buffer Texture.
Ich dachte erst das wäre "tbuffer", aber nachdem ich über "StructuredBuffer" gelesen habe, dass diese ebenfalls mit einer Texture verknüpft werden können, bin ich mir nicht mehr so sicher.

Ich weiß, dass in OpenGL der Uniform Buffer (bzw. Constant Buffer in D3D) deutlich weniger Kapazität hat als eine Buffer Texture.
Der Uniform Buffer ist auf 64KB begränzt und die Buffer Texture auf 128 MB.

Also würde ich gerne wissen, was in D3D11 am besten dazu passt. Der Buffer den ich anlegen will, kann nämlich sehr groß werden.

EDIT:
Ich glaube den "StructuredBuffer" kann man doch nur mit einem ganz normalen Buffer (erstellt mit "ID3D11Device::CreateBuffer") verwenden.
Trotzdem würde ich den genauen Unterschied zu tbuffer gerne kennen und ob tbuffer wirklich das Äquivalent zu OpenGL's Buffer Texture ist.

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »LukasBanana« (05.06.2013, 10:51)


dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

2

06.06.2013, 02:11

Ja, OpenGL Buffer Textures sind wohl das Äquivalent zum Direct3D tbuffer. Der Unterschied zwischen einem cbuffer und einem tbuffer liegt nicht einfach nur in der maximalen Größe, sondern vor allem darin, dass beide für verschiedene Zugriffsmuster ausgelegt sind. In den Prozessoren einer GPU laufen Gruppen von 32 (NVIDIA) bzw. 64 (ATI) Threads entsprechend dem SIMD Prinzip im Lockstep; d.h. alle 32 bzw. 64 Threads führen in jedem Takt die selbe Instruktion aus. (Ok, im Falle von ATI ist bzw. war es auch in jüngerer Vergangenheit nicht unbedingt immer ganz so einfach, aber gut genug für unsere Zwecke hier ;)) Aktuelle GPUs haben mittlerweile 1000+ Cores, auf einer solchen GPU werden also im Idealfall zu jedem Zeitpunkt über 1000 Threads parallel ausgeführt. Die Versorgung dieser 1000+ Cores mit Daten wird sehr schnell zum limitierenden Faktor. Daher verfügt eine solche GPU über verschiedenste Mechanismen, um gewisse Arten von Speicherzugriffen möglichst effizient zu gestalten. Am einen Ende des Spektrums haben wir da z.B. deinen StructuredBuffer, im Prinzip einfach nur ein herkömmliches Array auf das jeder Thread jederzeit an jeder beliebigen Stelle zugreifen kann (im Falle eines RWStructuredBuffer auch schreibend). Da muss dann tatsächlich jeder Zugriff aus jedem Thread zum Speicher gehen. Im Falle einer klassischen Shaderkonstante, wie z.B. einer WorldViewProjection Matrix, ist es nun aber so, dass alle Threads einer SIMD Einheit zu jedem Zeitpunkt immer nur auf die selbe Speicherstelle und immer nur lesend zugreifen werden. Daher verfügen GPUs über eine eigene Cache-Hierarchie, durch die solche parallele, lesende Zugriffe auf die selbe Speicherstelle effizienter bedient werden können. Ein anderes Beispiel sind Texturen: Auch dort wird immer nur gelesen und wenn auch nicht alle Threads immer auf exakt die selbe Speicherstelle zugreifen, so ist es in der Regel so, dass benachbarte Threads auch benachbarte Speicherstellen lesen und daher gibt es auch für Texturen eine eigene Cache-Hierarchie. Man muss natürlich erwähnen, dass öffentlich zugängliche Dokumentation zu diesen Dingen in der Regel sehr vage ist, sodass man ab einem gewissen Punkt natürlich nur noch im Nebel stochern und bestenfalls informierte Vermutungen anstellen kann. Aber die D3D Doku sagt uns, dass cbuffer für "constant-variable usage" gedacht sind, während tbuffer für "arbitrarily indexed data" schneller sein können. Die 64KB sind sicherlich kein Zufall, denn die entsprechen genau der Größe des Constant Memory auf den ersten Direct3D 10 Karten. Und die Bezeichnung "Texture Buffer" im Gegensatz zu "Constant Buffer" lässt vermuten, dass solche Buffer einfach statt durch den Constant Cache durch den Texture Cache der Hardware laufen, was auch konsistent mit den beschriebenen Unterschieden im Verhalten wäre.

Zusammenfassend kann man also wohl sagen: Nimm cbuffer für typische Shaderkonstanten, wo sämtliche Vertices/Pixel/etc. die selben Elemente verwenden, nimm tbuffer für Daten, wo verschiedene Vertices/Pixel/etc. auf verschiedene Elemente zugreifen, den Zugriffen aber immer noch eine gewisse Lokalität innewohnt, wie z.B. die Tabelle der Matrizen der Joints eines animierten Modells. StructuredBuffer sind erst mit D3D11 dazugekommen und decken den allgemeinen Fall von völlig wahlfreiem Zugriff ab.

Und während all diese Dinge auf den ersten D3D10 Karten von potentiell fundamentaler Bedeutung waren (konnte sich um Größenordnungen handeln), verfügen moderne GPUs mittlerweile aber sowieso auch über allgemeine Caches und etwaige Geschwindigkeitsunterschiede können heutzutage je nach Anwendung auch nur mehr klein bis kaum messbar ausfallen...

Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von »dot« (06.06.2013, 02:37)


Schrompf

Alter Hase

Beiträge: 1 470

Wohnort: Dresden

Beruf: Softwareentwickler

  • Private Nachricht senden

3

06.06.2013, 11:52

Hervorragende Erklärung, die dot da geschrieben hat! Kann ich jedem nur empfehlen, der irgendwas mit Shadern machen will.
Häuptling von Dreamworlds. Baut aktuell an nichts konkretem, weil das Vollzeitangestelltenverhältnis ihn fest im Griff hat. Baut daneben nur noch sehr selten an der Open Asset Import Library mit.

Sc4v

Alter Hase

Beiträge: 376

Beruf: Student

  • Private Nachricht senden

4

06.06.2013, 11:56

Auch sehr informativ und interessant, danke dot :thumbsup:

LukasBanana

Alter Hase

  • »LukasBanana« ist der Autor dieses Themas

Beiträge: 1 097

Beruf: Shader Tools Programmer

  • Private Nachricht senden

5

07.06.2013, 14:09

Ja, danke für die ausführliche Erklärung :-)

EDIT:
Verstehe ich das richtig, dass ein tbuffer genau so wie ein cbuffer auch mit "D3D11_BIND_CONSTANT_BUFFER" gebunden und mit "xySetConstantBuffers" gesetzt werden muss?
Ich sehe hier nämlich sonst nichts passendes: D3D11_BIND_FLAG

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »LukasBanana« (07.06.2013, 14:42)


dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

6

07.06.2013, 23:29

tbuffer sind vermutlich wohl eher einfache Buffer, die als normale Shader Ressource gesetzt werden.

LukasBanana

Alter Hase

  • »LukasBanana« ist der Autor dieses Themas

Beiträge: 1 097

Beruf: Shader Tools Programmer

  • Private Nachricht senden

7

18.06.2013, 12:34

Hab nun endlich einen Texture Buffer mit D3D11 am Laufen.
Nun möchte ich mich noch mit den anderen Shader Ressourcen beschäftigen: Buffer, StructuredBuffer, RWBuffer etc.
Es sieht für mich ganz danach aus, als würden diese Buffer genau so wie ein tbuffer angesprochen. Soll heißen mein C++ Code muss gar nicht verändert werden wenn ich zwischen folgenden zwei Varianten wechsel:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
// Variante 1:
tbuffer MyBuffer
{
    float4 Colors[100];
};

// Variante 2:
Buffer<float4> Colors;

In der 2. Variante kann ich auch per [] Operator auf den Buffer zu greifen. Was ist also der Unterschied zwischen diesem "Buffer" und dem "tbuffer"?

Werbeanzeige