HLSL float array packing in constant buffer?

Ben Goh picture Ben Goh · Feb 5, 2013 · Viewed 10k times · Source

people.

I have a problem passing a float array to vertex shader (HLSL) through constant buffer. I know that each "float" in the array below gets a 16-byte slot all by itself (space equivalent to float4) due to HLSL packing rule:

// C++ struct
struct ForegroundConstants
{
    DirectX::XMMATRIX transform;
    float bounceCpp[64];
};


// Vertex shader constant buffer
cbuffer ForegroundConstantBuffer : register(b0)
{
    matrix transform;
    float bounceHlsl[64];
};

(Unfortunately, the simple solution here does not work, nothing is drawn after I made that change)

While the C++ data gets passed, due to the packing rule they get spaced out such that each "float" in the bounceCpp C++ array gets into a 16-byte space all by itself in bounceHlsl array. This resulted in an warning similar to the following:

ID3D11DeviceContext::DrawIndexed: The size of the Constant Buffer at slot 0 of the Vertex Shader unit is too small (320 bytes provided, 1088 bytes, at least, expected). This is OK, as out-of-bounds reads are defined to return 0. It is also possible the developer knows the missing data will not be used anyway. This is only a problem if the developer actually intended to bind a sufficiently large Constant Buffer for what the shader expects.

The recommendation, as being pointed out here and here, is to rewrite the HLSL constant buffer this way:

cbuffer ForegroundConstantBuffer : register(b0)
{
    matrix transform;
    float4 bounceHlsl[16]; // equivalent to 64 floats.
};

static float temp[64] = (float[64]) bounceHlsl;

main(pos : POSITION) : SV_POSITION
{
    int index = someValueRangeFrom0to63;
    float y = temp[index];

    // Bla bla bla...
}

But that didn't work (i.e. ID3D11Device1::CreateVertexShader never returns). I'm compiling things against Shader Model 4 Level 9_1, can you spot anything that I have done wrong here?

Thanks in advance! :)

Regards, Ben

Answer

alanw picture alanw · Feb 7, 2013

One solution, albeit non optimal, is to just declare your float array as

float4 bounceHlsl[16];

then process the index like

float x = ((float[4])(bounceHlsl[i/4]))[i%4];

where i is the index you require.