Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

Alright, I'm having a hard time getting a bool packed and aligned into a hlsl constant buffer and I'm not sure why.

Here is the buffer in hlsl

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

And here it is in c++

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

I've tried moving the bool and padding the struct in all kinds of ways with no luck. What is the correct way to do this?

share|improve this question
    
What's the issue it's causing? –  Byte56 Jan 18 '12 at 21:25
    
The bool is used to determine whether or not the shader needs to sample a texture. This way I can render textured and untextured objects with the same shader. The bool is simply used in a conditional statement. It isn't getting the correct data because it's treating all objects the same. This is incorrect because my sky sphere is the only thing that has a texture at the moment. –  KlashnikovKid Jan 18 '12 at 21:30
    
The other values work but not the bool? Have you tried using one of the debuggers available for shaders to see what's getting put in to it? –  Byte56 Jan 18 '12 at 21:36
2  
try to store the bool value in a char. store as 1 for true and 0 for false. Just for test, and also, a bool is 1 byte in C++ anyway... –  Gustavo Maciel Jan 18 '12 at 21:43
3  
The size of a bool is implementation dependent. On some platforms it's the same size as an int. stackoverflow.com/questions/5067492/… –  Tetrad Jan 18 '12 at 22:02

2 Answers 2

up vote 2 down vote accepted

For efficiency, constant buffers will be mapped such that values do not straddle GPU registers. Each register is four floats in size (16 bytes) so constant buffer structures must be a multiple thereof on the GPU. Your C++ structure should be padded accordingly if you want to use it as a convenience for mapping data (this, note, doesn't always scale well).

Your issue, then, is that an HLSL boolean is four bytes, but one byte on the CPU side (in your specific implementation). This causes your C++ structure to not align properly: the significant bit of a boolean value (the 0 or 1 that matters) is going to be stored in the least-signficant byte of the value, and since the sizes don't agree the location of that byte in memory will differ in the CPU and GPU versions of the structure.

Manually inserting the appropriate padding and ensuring proper 16-byte alignment, or just using an appropriately-sized type, like an integer, should fix the issue. This thread may also be of use to you as it contains a more in-depth discussion of roughly the same problem.

share|improve this answer
    
I don't follow: "isTextured fit into that same register since it would have to straddle into the next one. Thus it is bumped entirely in to the next register." The second register consists of specular in the first three components and isTextured in the last, so I don't see that anything needs to get bumped into the next register? The 1-byte vs 4-byte bool length obviously matters, but either one would fit after specular in the same register. –  Nathan Reed Jan 18 '12 at 22:45
    
You are correct; I confused myself w.r.t to the size of the registers versus the size of types and came up with an incorrect representation of the mapping. The only problem is the location of the relevant byte in memory. I've adjusted my answer accordingly. –  Josh Petrie Jan 18 '12 at 22:51
    
Accepting your answer for thoroughness. Like you mentioned, it was a big/little endian issue and using an int solved it. –  KlashnikovKid Jan 19 '12 at 1:29

Alright, did some reading and noticed that a hlsl bool is essentially a 32 bit integer. So I just used an int in the c++ struct to solve my problem.

struct GeometryBufferPass_MaterialBuffer {
    XMFLOAT3 diffuse;
    float specularExponent;
    XMFLOAT3 specular;
    int isTextured;
};
share|improve this answer
    
Why don't you keep the bool type but just use int in the compiler side? Just to keep the semantics. –  Gustavo Maciel Jan 18 '12 at 23:55
    
Yeah, that is what I'm doing above. Used an integer for the struct cpu side and a bool for the constant buffer gpu side. –  KlashnikovKid Jan 19 '12 at 1:31

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.