Por que não consigo colocar um bool empacotado e alinhado em um buffer constante do D3D?


9

Tudo bem, estou tendo dificuldade para obter um bool empacotado e alinhado em um buffer constante hlsl e não sei por que.

Aqui está o buffer em hlsl

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

E aqui está em c ++

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

Eu tentei mover o bool e preencher a estrutura de todos os tipos, sem sorte. Qual é a maneira correta de fazer isso?


Qual é o problema que está causando?
MichaelHouse

O bool é usado para determinar se o shader precisa ou não provar uma textura. Dessa forma, eu posso renderizar objetos texturizados e não texturizados com o mesmo sombreador. O bool é simplesmente usado em uma declaração condicional. Não está obtendo os dados corretos porque está tratando todos os objetos da mesma forma. Isso está incorreto porque minha esfera do céu é a única coisa que tem uma textura no momento.
usar o seguinte código

Os outros valores funcionam, mas não o bool? Você já tentou usar um dos depuradores disponíveis para shaders para ver o que está acontecendo nele?
MichaelHouse

2
tente armazenar o valor bool em um caractere. armazene como 1 para verdadeiro e 0 para falso. Apenas para teste, e também, um bool é 1 byte em C ++ de qualquer maneira ...
Gustavo Maciel

3
O tamanho de um bool depende da implementação. Em algumas plataformas, é do mesmo tamanho que um int. stackoverflow.com/questions/5067492/…
Tetrad

Respostas:


9

Para eficiência, buffers constantes serão mapeados de forma que os valores não ultrapassem os registros da GPU . Cada registrador tem quatro flutuadores de tamanho (16 bytes); portanto, as estruturas de buffer constantes devem ser múltiplas na GPU. Sua estrutura C ++ deve ser preenchida de acordo, se você quiser usá-la como uma conveniência para mapear dados (isso, note, nem sempre é dimensionável).

Seu problema, então, é que um booleano HLSL tem quatro bytes, mas um byte no lado da CPU (em sua implementação específica). Isso faz com que sua estrutura C ++ não se alinhe corretamente: o bit significativo de um valor booleano (o 0 ou 1 que importa) será armazenado no byte menos significativo do valor, e como os tamanhos não concordam com a localização desse byte na memória será diferente nas versões de CPU e GPU da estrutura.

Inserir manualmente o preenchimento apropriado e garantir o alinhamento adequado de 16 bytes, ou apenas usar um tipo de tamanho apropriado, como um número inteiro, deve corrigir o problema. Esse tópico também pode ser útil para você, pois contém uma discussão mais aprofundada sobre o mesmo problema.


11
Eu não sigo: " isTexturedencaixam-se no mesmo registro, pois ele teria que passar para o próximo. Assim, ele é colidido inteiramente com o próximo registro". O segundo registro consiste specularnos três primeiros componentes e isTexturedno último, então não vejo que algo precise ser esbarrado no próximo registro? O comprimento do bool de 1 byte vs 4 bytes obviamente importa, mas qualquer um deles caberia depois specularno mesmo registro.
Nathan Reed

Você está certo; Confundi-me com o tamanho dos registros versus o tamanho dos tipos e criei uma representação incorreta do mapeamento. O único problema é a localização do byte relevante na memória. Eu ajustei minha resposta de acordo.

Aceitando sua resposta com rigor. Como você mencionou, era um problema grande / pequeno de endian e o uso de um int resolveu.
precisa saber é o seguinte

3

Tudo bem, fiz algumas leituras e percebi que um hlsl bool é essencialmente um número inteiro de 32 bits. Então, eu apenas usei um int na estrutura c ++ para resolver meu problema.

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

Por que você não mantém o tipo bool, mas apenas usa int no lado do compilador? Apenas para manter a semântica.
Gustavo Maciel

Sim, é isso que estou fazendo acima. Utilizou um número inteiro para o lado da estrutura da CPU e um bool para o lado constante da CPU da reserva.
usar o seguinte código

0

float, bool e int não são necessários para o endian, principalmente para vários itens.

Alternar para int ou float funciona em alguns dos exemplos listados aqui como alinhados entre os itens XMFLOAT3, portanto, são referenciados corretamente. No entanto, se você precisar declarar uma matriz ou vários itens na estrutura para int, float (nenhum tipo XM), provavelmente descobrirá que os valores da GPU não correspondem aos valores definidos na estrutura da CPU.

Certamente o fiz ao adicionar uma matriz do tipo int a ser usada para o tipo de iluminação.

A maneira mais fácil que encontrei é manter os tipos XM alinhados por 16, o que pode exigir elementos / bytes desperdiçados, mas classifica o endian para você. EG XMINT4 e acabou de usar o primeiro elemento .x para o seu valor, ou se você precisar, use os outros elementos para outra finalidade, mas significa má nomeação (certifique-se de comentar). Nota: A matriz XMINT2 também estará fora de ordem lógica

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.