Почему я не могу получить 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 и дополнить структуру различными способами. Как правильно это сделать?

KlashnikovKid
источник
Какая проблема это вызывает?
MichaelHouse
Bool используется для определения того, нужно ли шейдеру сэмплировать текстуру. Таким образом, я могу рендерить текстурированные и нетекстурированные объекты одним и тем же шейдером. Bool просто используется в условном выражении. Он не получает правильные данные, потому что обрабатывает все объекты одинаково. Это неверно, потому что моя небесная сфера - единственное, что в данный момент имеет текстуру.
KlashnikovKid
Другие ценности работают, но не bool? Вы пытались использовать один из отладчиков, доступных для шейдеров, чтобы увидеть, что на него положено?
MichaelHouse
2
попробуйте сохранить значение bool в символе. хранить как 1 для истины и 0 для ложных. Просто для теста, а также, bool 1 C байт в C ++ в любом случае ...
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-байтовая длина bool, но любой из них будет вписываться specularв тот же регистр.
Натан Рид
Ты прав; Я запутался в отношении размера регистров в зависимости от размера типов и пришел к неверному представлению отображения. Единственная проблема - расположение соответствующего байта в памяти. Я скорректировал свой ответ соответственно.
Принятие вашего ответа для тщательности. Как вы упомянули, это была проблема с прямым порядком байтов, и использование int решило ее.
KlashnikovKid
3

Хорошо, немного прочел и заметил, что hlsl bool - это 32-битное целое число. Поэтому я просто использовал int в структуре c ++ для решения моей проблемы.

struct GeometryBufferPass_MaterialBuffer {
    XMFLOAT3 diffuse;
    float specularExponent;
    XMFLOAT3 specular;
    int isTextured;
};
KlashnikovKid
источник
Почему бы вам не сохранить тип bool, а просто использовать int на стороне компилятора? Просто чтобы сохранить семантику.
Густаво Масиэль
Да, это то, что я делаю выше. Использовал целое число для стороны struct cpu и bool для стороны постоянного буфера gpu.
KlashnikovKid
0

float, bool и int не обязательны для endian, особенно для нескольких элементов.

Переключение на int или float работает в некоторых из перечисленных здесь примеров, поскольку оно выровнено между элементами XMFLOAT3, поэтому на них ссылаются правильно. Однако, если вам нужно объявить массив или несколько элементов в структуре для int, float (без типов XM), вы, скорее всего, обнаружите, что значения GPU не соответствуют значениям, заданным в структуре CPU.

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

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

DavrosX
источник