directx-11direct3d

CreateBuffer fails when adding an extra variable to cbuffer


Using d3d11, I have two cbuffer in a vertex shader that's

cbuffer A{
 float2
 float2
 float2 
 float2
};

cbuffer B {
 uint2
 uint2
 float2
 float2
 float2 
 float2
};

Their buffers are created and run on my vertex shader successfully.

However when I add a bool to the second cbuffer:

(c++ side)    
struct B {
 uint32_t, uint32_t,
 uint32_t, uint32_t,
 float, float,
 float, float,
 float, float, 
 float, float,
 uint32_t
};

(hlsl)
cbuffer B {
 uint2
 uint2
 float2
 float2
 float2 
 float2
 bool
};

CreateBuffer fails with an unhandled exception. The buffer packing all seems fine, the bool should be the first element in a new row after the 48th byte. Anyone know what the issue could be?


Solution

  • Directx 11 cbuffer sizes must be a multiple of 16. Prior to adding the bool the size was exactly 48 bytes, 3x16. Adding the bool puts it out-of-line with the required byte boundary. Add 3 floats (or 3 ints) to put it back on the 16-byte boundary:

    cbuffer B {
     uint2 var1
     uint2 var2
     float2 var3
     float2 var4
     float2 var5
     float2 var6
     float4 bool_padding3
    };
    

    IMO, to make it easier on myself I always pack my cbuffers in float4 "chunks", that is, each member is exactly the size of a 16-byte row and I store multiple c++-side variables in each. In your case, I'd lay out your cbuffer like so (names are purely for example):

    cbuffer B {
     float4 var1_var2
     float4 var3_var4
     float4 var5_var6
     float4 var7_padding3
    };
    

    This way I'm guaranteed that the byte boundary is preserved.

    Your C++-side struct would change accordingly:

    (IntVector2/3/4 are structs that contain x/y/z/w int members, likewise for Vector2/3/4 but with float members)

    struct B {
     IntVector4
     Vector4
     Vector4
     uint32_t //Uh-oh! outside the boundary. Convert.
    };
    

    As you can see, by adhering to the int4/float4 requirement, you can more easily detect that your struct is out-of-boundary and the variable needs to be packed correctly, like so:

    struct B {
     IntVector4
     Vector4
     Vector4
     IntVector4 //Corrected, guaranteed to be on a 16-byte boundary.
    };