Warum kann ich einen Bool nicht in einen konstanten D3D-Puffer packen und ausrichten?

9

Okay, es fällt mir schwer, einen Bool zu packen und in einen konstanten Hlsl-Puffer auszurichten, und ich bin mir nicht sicher, warum.

Hier ist der Puffer in hlsl

cbuffer MaterialBuffer : register(b1) {
    float3 materialDiffuseAlbedo;
    float  materialSpecularExponent;
    float3 materialSpecularAlbedo;
    bool isTextured;
};

Und hier ist es in c ++

struct GeometryBufferPass_MaterialBuffer {
    XMFLOAT3 diffuse;
    float specularExponent;
    XMFLOAT3 specular;
    bool isTextured;
};

Ich habe versucht, den Bool zu bewegen und die Struktur auf alle möglichen Arten aufzufüllen, ohne Glück. Was ist der richtige Weg, um dies zu tun?

KlashnikovKid
quelle
Was ist das Problem, das es verursacht?
MichaelHouse
Der Bool wird verwendet, um zu bestimmen, ob der Shader eine Textur abtasten muss oder nicht. Auf diese Weise kann ich strukturierte und nicht texturierte Objekte mit demselben Shader rendern. Der Bool wird einfach in einer bedingten Anweisung verwendet. Es werden nicht die richtigen Daten abgerufen, da alle Objekte gleich behandelt werden. Dies ist falsch, weil meine Himmelskugel das einzige ist, das im Moment eine Textur hat.
KlashnikovKid
Die anderen Werte funktionieren aber nicht der Bool? Haben Sie versucht, einen der für Shader verfügbaren Debugger zu verwenden, um zu sehen, was darin enthalten ist?
MichaelHouse
2
Versuchen Sie, den Bool-Wert in einem Zeichen zu speichern. Speichern Sie als 1 für wahr und 0 für falsch. Nur zum Testen und auch, ein Bool ist sowieso 1 Byte in C ++ ...
Gustavo Maciel
3
Die Größe eines Bools hängt von der Implementierung ab. Auf einigen Plattformen hat es die gleiche Größe wie ein Int. stackoverflow.com/questions/5067492/…
Tetrad

Antworten:

9

Aus Effizienzgründen werden konstante Puffer so zugeordnet, dass die Werte die GPU-Register nicht überspannen . Jedes Register hat eine Größe von vier Gleitkommazahlen (16 Byte), daher müssen konstante Pufferstrukturen ein Vielfaches davon auf der GPU sein. Ihre C ++ - Struktur sollte entsprechend aufgefüllt werden, wenn Sie sie als Komfort für die Zuordnung von Daten verwenden möchten (dies ist nicht immer gut skalierbar).

Ihr Problem ist also, dass ein HLSL-Boolescher Wert vier Bytes, aber ein Byte auf der CPU-Seite (in Ihrer spezifischen Implementierung) umfasst. Dies führt dazu, dass Ihre C ++ - Struktur nicht richtig ausgerichtet wird: Das signifikante Bit eines booleschen Werts (die 0 oder 1, die wichtig ist) wird im am wenigsten signifikanten Byte des Werts gespeichert, und da die Größen nicht mit der Position übereinstimmen Dieses Byte im Speicher unterscheidet sich in den CPU- und GPU-Versionen der Struktur.

Das manuelle Einfügen des entsprechenden Auffüllens und das Sicherstellen einer korrekten 16-Byte-Ausrichtung oder die Verwendung eines Typs mit geeigneter Größe, z. B. einer Ganzzahl, sollte das Problem beheben. Dieser Thread kann auch für Sie von Nutzen sein, da er eine eingehendere Diskussion ungefähr des gleichen Problems enthält.


quelle
1
Ich folge nicht: " isTexturedPassen Sie in dasselbe Register, da es sich in das nächste überspannen müsste. Somit wird es vollständig in das nächste Register gestoßen." Das zweite Register besteht aus specularden ersten drei Komponenten und isTexturedder letzten, also sehe ich nicht, dass irgendetwas in das nächste Register gestoßen werden muss? Die Bool-Länge von 1 Byte gegen 4 Byte ist offensichtlich wichtig, aber beide passen danach specularin dasselbe Register.
Nathan Reed
Du hast Recht; Ich habe mich mit der Größe der Register im Vergleich zur Größe der Typen verwechselt und eine falsche Darstellung der Zuordnung gefunden. Das einzige Problem ist die Position des relevanten Bytes im Speicher. Ich habe meine Antwort entsprechend angepasst.
Akzeptiere deine Antwort für Gründlichkeit. Wie Sie bereits erwähnt haben, war es ein großes / kleines Endian-Problem, und die Verwendung eines Int hat es gelöst.
KlashnikovKid
3

Okay, habe etwas gelesen und festgestellt, dass ein hlsl-Bool im Wesentlichen eine 32-Bit-Ganzzahl ist. Also habe ich einfach ein int in der c ++ - Struktur verwendet, um mein Problem zu lösen.

struct GeometryBufferPass_MaterialBuffer {
    XMFLOAT3 diffuse;
    float specularExponent;
    XMFLOAT3 specular;
    int isTextured;
};
KlashnikovKid
quelle
Warum behalten Sie nicht den Bool-Typ bei, sondern verwenden nur int auf der Compilerseite? Nur um die Semantik beizubehalten.
Gustavo Maciel
Ja, das ist was ich oben mache. Verwendete eine Ganzzahl für die Struktur-CPU-Seite und ein Bool für die Konstantpuffer-GPU-Seite.
KlashnikovKid
0

float, bool und int sind für endian nicht erforderlich, insbesondere für mehrere Elemente.

Das Umschalten auf int oder float funktioniert in einigen der hier aufgeführten Beispiele, da es zwischen XMFLOAT3-Elementen ausgerichtet ist und daher korrekt referenziert wird. Wenn Sie jedoch ein Array oder mehrere Elemente in der Struktur für int, float deklarieren müssen (keine XM-Typen), werden Sie wahrscheinlich feststellen, dass die GPU-Werte nicht mit den in der CPU-Struktur festgelegten Werten übereinstimmen.

Ich habe es sicherlich getan, als ich ein Array vom Typ int hinzugefügt habe, das für den Beleuchtungstyp verwendet werden soll.

Der einfachste Weg, den ich gefunden habe, besteht darin, mich an XM-Typen zu halten, die um 16 ausgerichtet sind. Dies erfordert möglicherweise verschwendete Elemente / Bytes, sortiert aber den Endian für Sie. EG XMINT4 und hat gerade das erste Element .x für Ihren Wert verwendet, oder wenn Sie die Notwendigkeit haben, verwenden Sie die anderen Elemente für einen anderen Zweck, was jedoch eine schlechte Benennung bedeutet (stellen Sie sicher, dass Sie einen Kommentar abgeben). Hinweis: Das XMINT2-Array ist ebenfalls nicht in logischer Reihenfolge

DavrosX
quelle