Mengapa saya tidak bisa mendapatkan bool yang dikemas dan disejajarkan dengan buffer konstan D3D?

9

Baiklah, saya mengalami kesulitan mendapatkan bool dikemas dan disejajarkan ke buffer hlsl konstan dan saya tidak yakin mengapa.

Berikut adalah buffer di hlsl

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

Dan ini dia di c ++

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

Saya sudah mencoba memindahkan bool dan mengisi struct dengan segala macam cara tanpa hasil. Apa cara yang benar untuk melakukan ini?

KlashnikovKid
sumber
Apa masalah yang ditimbulkannya?
MichaelHouse
Bool digunakan untuk menentukan perlu tidaknya shader mengambil sampel tekstur. Dengan cara ini saya dapat membuat objek bertekstur dan tidak bertekstur dengan shader yang sama. Bool hanya digunakan dalam pernyataan bersyarat. Itu tidak mendapatkan data yang benar karena itu memperlakukan semua objek sama. Ini tidak benar karena bola langit saya adalah satu-satunya yang memiliki tekstur saat ini.
KlashnikovKid
Nilai-nilai lain berfungsi tetapi tidak bool? Sudahkah Anda mencoba menggunakan salah satu pengadu yang tersedia untuk shader untuk melihat apa yang dimasukkan ke dalamnya?
MichaelHouse
2
cobalah untuk menyimpan nilai bool di char. simpan sebagai 1 untuk true dan 0 untuk false. Hanya untuk pengujian, dan juga, bool adalah 1 byte dalam C ++ ...
Gustavo Maciel
3
Ukuran bool tergantung pada implementasi. Pada beberapa platform ukurannya sama dengan int. stackoverflow.com/questions/5067492/…
Tetrad

Jawaban:

9

Untuk efisiensi, buffer konstan akan dipetakan sedemikian sehingga nilai-nilai tidak mengangkangi register GPU . Setiap register berukuran empat float (16 byte) sehingga struktur penyangga konstan harus merupakan kelipatannya pada GPU. Struktur C ++ Anda harus diisi sesuai jika Anda ingin menggunakannya sebagai kenyamanan untuk memetakan data (ini, perhatikan, tidak selalu skala dengan baik).

Masalah Anda, kemudian, adalah bahwa boolean HLSL adalah empat byte, tetapi satu byte di sisi CPU (dalam implementasi spesifik Anda). Ini menyebabkan struktur C ++ Anda tidak sejajar dengan benar: bit signifikan dari nilai boolean (0 atau 1 yang penting) akan disimpan dalam byte nilai yang paling tidak signifikan, dan karena ukurannya tidak sesuai dengan lokasi byte itu dalam memori akan berbeda dalam versi CPU dan GPU struktur.

Secara manual memasukkan padding yang sesuai dan memastikan keselarasan 16 byte yang tepat, atau hanya menggunakan jenis berukuran tepat, seperti integer, harus memperbaiki masalah. Utas ini juga dapat bermanfaat bagi Anda karena berisi diskusi yang lebih mendalam tentang masalah yang kira-kira sama.


sumber
1
Saya tidak mengikuti: " isTexturedmasuk ke dalam register yang sama karena harus mengangkang ke yang berikutnya. Dengan demikian ia sepenuhnya masuk ke register berikutnya." Register kedua terdiri dari speculartiga komponen pertama dan isTexturedyang terakhir, jadi saya tidak melihat ada yang perlu ditabrak ke register berikutnya? Panjang bool 1-byte vs 4-byte jelas penting, tetapi salah satu akan cocok setelah speculardalam register yang sama.
Nathan Reed
Anda benar; Saya bingung sendiri soal ukuran register versus ukuran tipe dan muncul dengan representasi pemetaan yang salah. Satu-satunya masalah adalah lokasi byte yang relevan dalam memori. Saya telah menyesuaikan jawaban saya sesuai dengan itu.
Terima jawaban Anda untuk ketelitian. Seperti yang Anda sebutkan, itu adalah masalah endian besar / kecil dan menggunakan int menyelesaikannya.
KlashnikovKid
3

Baiklah, saya membaca dan memperhatikan bahwa hlsl bool pada dasarnya adalah integer 32 bit. Jadi saya hanya menggunakan int di c ++ struct untuk menyelesaikan masalah saya.

struct GeometryBufferPass_MaterialBuffer {
    XMFLOAT3 diffuse;
    float specularExponent;
    XMFLOAT3 specular;
    int isTextured;
};
KlashnikovKid
sumber
Mengapa Anda tidak menyimpan tipe bool tetapi hanya menggunakan int di sisi kompiler? Hanya untuk menjaga semantiknya.
Gustavo Maciel
Ya, itulah yang saya lakukan di atas. Digunakan integer untuk sisi cpu struct dan bool untuk sisi gpu buffer konstan.
KlashnikovKid
0

float, bool dan int tidak perlu berbaris untuk endian terutama untuk beberapa item.

Beralih ke int atau float berfungsi dalam beberapa contoh yang tercantum di sini sebagai yang disejajarkan antara item XMFLOAT3 sehingga dirujuk dengan benar. Namun jika Anda perlu mendeklarasikan array atau beberapa item dalam struktur untuk int, float (tidak ada tipe XM) maka Anda mungkin akan menemukan bahwa nilai GPU tidak cocok dengan nilai yang diatur dalam struktur CPU.

Tentu saya lakukan ketika menambahkan array tipe int untuk digunakan untuk jenis pencahayaan.

Cara termudah yang saya temukan adalah menempel pada tipe XM yang sejajar dengan 16, yang mungkin memerlukan elemen / byte yang terbuang tetapi mengurutkan endian untuk Anda. EG XMINT4 dan baru saja menggunakan elemen pertama .x untuk nilai Anda, atau jika Anda membutuhkannya, gunakan elemen-elemen lain untuk tujuan lain tetapi artinya penamaan yang buruk (pastikan untuk berkomentar). Catatan: array XMINT2 juga akan keluar dari urutan logis

DavrosX
sumber