Perché non riesco a ottenere un bool impacchettato e allineato in un buffer costante D3D?


9

Va bene, sto facendo fatica a ottenere un bool impacchettato e allineato in un buffer costante hlsl e non sono sicuro del perché.

Ecco il buffer in hlsl

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

Ed eccolo in c ++

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

Ho provato a spostare il bool e riempire la struttura in tutti i modi senza fortuna. Qual è il modo corretto per farlo?


Qual è il problema che sta causando?
MichaelHouse

Il bool viene utilizzato per determinare se lo shader deve o meno campionare una trama. In questo modo posso renderizzare oggetti testurizzati e non testurizzati con lo stesso shader. Il bool è semplicemente usato in una dichiarazione condizionale. Non sta ottenendo i dati corretti perché tratta tutti gli oggetti allo stesso modo. Questo non è corretto perché la mia sfera celeste è l'unica cosa che al momento ha una trama.
KlashnikovKid

Gli altri valori funzionano ma non il valore? Hai provato a utilizzare uno dei debugger disponibili per gli shader per vedere cosa viene inserito?
MichaelHouse

2
prova a memorizzare il valore bool in un carattere. memorizza come 1 per vero e 0 per falso. Solo per il test, e inoltre, un bool è 1 byte in C ++ comunque ...
Gustavo Maciel,

3
La dimensione di un bool dipende dall'implementazione. Su alcune piattaforme ha le stesse dimensioni di un int. stackoverflow.com/questions/5067492/…
Tetrad

Risposte:


9

Per efficienza, i buffer costanti verranno mappati in modo tale che i valori non si sovrappongano ai registri GPU . Ogni registro ha una dimensione di quattro float (16 byte), pertanto le strutture di buffer costanti devono essere un multiplo della stessa sulla GPU. La tua struttura C ++ dovrebbe essere riempita di conseguenza se vuoi usarla come comodità per mappare i dati (questo, nota, non sempre si adatta bene).

Il tuo problema, quindi, è che un booleano HLSL è di quattro byte, ma un byte sul lato CPU (nella tua specifica implementazione). Questo fa sì che la tua struttura C ++ non si allinei correttamente: il bit significativo di un valore booleano (lo 0 o 1 che conta) verrà memorizzato nel byte meno significativo del valore e poiché le dimensioni non concordano con la posizione di quel byte in memoria differirà nelle versioni CPU e GPU della struttura.

L'inserimento manuale dell'imbottitura appropriata e la garanzia di un corretto allineamento a 16 byte o l'utilizzo di un tipo di dimensioni appropriate, come un numero intero, dovrebbero risolvere il problema. Questo thread può essere utile anche perché contiene una discussione più approfondita sullo stesso problema.


1
Non seguo: " isTexturedinserirsi nello stesso registro poiché dovrebbe passare a quello successivo. Quindi viene inserito completamente nel registro successivo". Il secondo registro consiste specularnei primi tre componenti e isTexturednell'ultimo, quindi non vedo che qualcosa deve essere inserito nel registro successivo? La lunghezza bool 1-byte vs 4-byte è ovviamente importante, ma uno dei due si adatterebbe specularnello stesso registro.
Nathan Reed,

Hai ragione; Mi sono confuso rispetto alle dimensioni dei registri rispetto alle dimensioni dei tipi e ho trovato una rappresentazione errata della mappatura. L'unico problema è la posizione del byte rilevante in memoria. Ho adattato la mia risposta di conseguenza.

Accettare la tua risposta per completezza. Come hai menzionato, era un problema big / little endian e usando un int risolto.
KlashnikovKid

3

Bene, ho fatto qualche lettura e ho notato che un hlsl bool è essenzialmente un numero intero a 32 bit. Quindi ho appena usato un int nella struttura c ++ per risolvere il mio problema.

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

Perché non mantieni il tipo bool ma usi solo int nel lato compilatore? Solo per mantenere la semantica.
Gustavo Maciel il

Sì, è quello che sto facendo sopra. Utilizzato un numero intero per il lato struct cpu e un valore booleano per il lato gpu buffer costante.
KlashnikovKid

0

float, bool e int non sono necessariamente allineati per endian, in particolare per più elementi.

Il passaggio a int o float funziona in alcuni degli esempi elencati qui come allineati tra gli elementi XMFLOAT3, quindi vengono referenziati correttamente. Tuttavia, se è necessario dichiarare un array o più elementi nella struttura per int, float (nessuno dei tipi XM), è probabile che i valori GPU non corrispondano ai valori impostati nella struttura della CPU.

L'ho fatto sicuramente quando ho aggiunto una matrice di tipo int da utilizzare per il tipo di illuminazione.

Il modo più semplice che ho trovato è attenersi ai tipi XM che si allineano per 16, il che può richiedere elementi / byte sprecati ma ordina l'endian per te. EG XMINT4 e hai appena usato il primo elemento .x per il tuo valore, o se ne hai la necessità usa gli altri elementi per un altro scopo ma significa scarsa denominazione (assicurati di commentare). Nota: anche l'array XMINT2 sarà fuori dall'ordine logico

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.