Just compile your code with FXC and see the printed layout. Are you sure it works?
I compiled this:
struct Light
{
float4 position;
float radius;
float intensity;
};
cbuffer lightData : register(b0)
{
uint dummy1;
Light lights[9];
uint dummy2;
};
float4 main(uint idx : SV_VertexID) : SV_Position
{
return (dummy1 + lights[0].position * lights[7].radius + lights[8].intensity + dummy2).xxxx;
}
And got this:
// cbuffer lightData
// {
//
// uint dummy1; // Offset: 0 Size: 4
//
// struct Light
// {
//
// float4 position; // Offset: 16
// float radius; // Offset: 32
// float intensity; // Offset: 36
//
// } lights[9]; // Offset: 16 Size: 280
// uint dummy2; // Offset: 296 Size: 4
//
// }
It will align lights[0] at 16-bytes. From this it looks like sizeof(Light)=32. What puzzles me is 32*9 = 288 and not 280 as reported. What's totally NOT understandable is dummy2 being at offset 296 = 16 + 32*9 - 8, as if it figured that in lights[8], there's 8 bytes padding, so let's put dummy2 there. Would anyone care guessing wtf?
So I totally don't understand this now My FXC.exe is 6.3.9600 from Windows Kit 8.1.
One thing is for sure, directly in cbuffers, you can have 4-byte constants (uint, float, int, ...) on 4-byte boundaries. Also, structs will be aligned to 16 bytes.
The final takeaway is to always query the compiled version for offsets of individual constants, so you know where to memcpy what.