Чому я не можу отримати пакет bool упакований і вирівняний у постійний буфер D3D?


9

Гаразд, мені важко отримати папку bool і вирівняти в постійний буфер hlsl, і я не знаю, чому.

Ось буфер в hlsl

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

І ось це в c ++

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

Я намагався переміщати bool і набивати структуру різними способами, не пощастивши. Який правильний спосіб це зробити?


Яке це питання викликає?
MichaelHouse

Буль використовується для визначення того, чи потрібно шейдеру відбирати текстуру. Таким чином я можу зображувати текстуровані та нетекстуровані об'єкти одним шейдером. Буль просто використовується в умовному викладі. Він не отримує правильних даних, оскільки обробляє всі об'єкти однаково. Це неправильно, тому що моя небесна сфера - це єдине, що має текстуру на даний момент.
KlashnikovKid

Інші значення працюють, але не бул? Ви спробували скористатись одним з налагоджувачів, доступним для шейдерів, щоб побачити, що в нього вставлено?
MichaelHouse

2
спробуйте зберегти значення bool у знаку. зберігати як 1 для істинного та 0 для хибного. Тільки для тестування, а також бул - 1 байт у С ++ у будь-якому разі ...
Gustavo Maciel

3
Розмір bool залежить від реалізації. На деяких платформах він такого ж розміру, як і int. stackoverflow.com/questions/5067492/…
Тетрад

Відповіді:


9

Для ефективності константні буфери будуть відображені таким чином, що значення не обмежують регістри GPU . Кожен реєстр має чотири поплавці розміром (16 байт), тому постійні буферні структури повинні бути кратними в GPU. Структуру C ++ слід відповідно доповнити, якщо ви хочете використовувати її як зручність для відображення даних (це, зауважте, не завжди добре масштабує).

Ваша проблема полягає в тому, що булевий HLSL - чотири байти, але один байт на стороні процесора (у вашій конкретній реалізації). Це призводить до того, що ваша структура C ++ не вирівнюється належним чином: значний біт булевого значення (0 або 1, що має значення) буде зберігатися в байті найменш значущого значення, а оскільки розміри не узгоджують місцеположення цього байту в пам'яті буде відрізнятися у версіях CPU та GPU.

Вручну вставити відповідну підкладку та забезпечити правильне вирівнювання у 16 ​​байт або просто використовувати відповідний розмір типу, як ціле число, має вирішити проблему. Ця нитка також може бути вам корисною, оскільки містить більш глибоке обговорення приблизно тієї самої проблеми.


1
Я не випливаю: " isTexturedвписується в той самий реєстр, оскільки йому доведеться перейти в наступний. Таким чином, він цілком стикається з наступним реєстром." Другий реєстр складається з specularперших трьох компонентів і isTexturedв останньому, тому я не бачу, що щось потрібно потрапляти в наступний реєстр? Довжина значень 1-байтового та 4-байтового значень очевидно має значення, але будь-який з них буде вписуватися specularв той же реєстр.
Натан Рід

Ви праві; Я переплутав wrt з розміром регістрів порівняно з розміром типів і придумав неправильне зображення відображення. Єдина проблема - розташування відповідного байта в пам'яті. Я відповідно скоригував свою відповідь.

Приймаючи вашу відповідь за ґрунтовність. Як ви вже згадували, це було великим / маленьким ендіанським питанням, і використання int вирішило це.
KlashnikovKid

3

Добре, почитав і помітив, що hlsl bool - це по суті 32-бітове ціле число. Тому я просто використав int у структурі c ++, щоб вирішити свою проблему.

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

Чому б вам не зберегти тип bool, а просто використовувати int на стороні компілятора? Просто, щоб зберегти семантику.
Густаво Масіель

Так, це я роблю вище. Використовували ціле число для strani процесорного процесора і bool для сторони постійного буфера gpu.
KlashnikovKid

0

float, bool та int не потрібні для ендіану, особливо для кількох предметів.

Перехід до int або float працює в деяких із наведених тут прикладів як його вирівнювання між елементами XMFLOAT3, тому вони посилаються правильно. Однак якщо вам потрібно оголосити масив або кілька елементів у структурі для int, float (жодних типів XM), ви, ймовірно, виявите, що значення GPU не відповідають значенням, встановленим у структурі процесора.

Я звичайно робив, додаючи масив типу int, який буде використовуватися для типу освітлення.

Найпростіший спосіб, який я знайшов, - це дотримуватися типів XM, які вирівнюються по 16, що може зажадати витрачених елементів / байтів, але сортувати ендіан для вас. EG XMINT4 і щойно використали перший елемент .x для вашої вартості, або якщо у вас є необхідність, тоді використовуйте інші елементи з іншою метою, але означає погану назву (обов'язково коментуйте). Примітка: масив XMINT2 також буде не в логічному порядку

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.