HLSL matrix, colum major

Started by
1 comment, last by Giallanon 9 years, 11 months ago

There's something I don't understand with the way DX11 HLSL parse a constant buffer when it's time to "transform it" in a matrix.
I've declared a constant buffer like this:


cbuffer cbPerMesh : register( b1 )
{
   matrix<float,3,4> World;
}


The shader is compiled with D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR.

The shader expects to receive matrix in a colum major form, but it's not working as I supposed to.
I'm feeding the shader with this data:


f32 temp[12] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
gpuProg.updateConstantBuffer (hCBPerMesh, &temp, sizeof(f32) * 12);


To my understanding, the World matrix should be like this:


1 2 3 4
5 6 7 8
9 10 11 12

ie: 3 rows, 4 columns per row, feeded by an array of 12 floats.


By debugging the shader, I'm able to see the following:


Data buffer:
#,Indirizzo,Float4
0,[0x00000000-0x0000000F],{+1, +2, +3, +4}
1,[0x00000010-0x0000001F],{+5, +6, +7, +8}
2,[0x00000020-0x0000002F],{+9, +10, +11, +12}

which is right, and means that I'm transferring the buffer correctly.

What I don't understand, is that the World matrix, inside the vertex shader, appears like this:


World[0] x = 1.000000000, y = 5.000000000, z = 9.000000000, w = 0.000000000 float4
World[1] x = 2.000000000, y = 6.000000000, z = 10.000000000, w = 0.000000000 float4
World[2] x = 3.000000000, y = 7.000000000, z = 11.000000000, w = 8.660300000 float4


I see 2 "errors":
First, my buffer is not taken as a colum major, otherwise World[0] should be like "1, 2, 3, 4"
Second, where are my "4", "8" and "12" left? They are skipped when the compiler parse the buffer into the matrix.


To fix this, I have to transpose() my buffer, and then declare


row_major float3x4 World;

This way everything works as expected

Advertisement
If your values are 1,2,3,4,5,6...
Then the first column will contain 1,2,3, the next column will contain 4,5,6, and so on (you've visualized your matrix with 1,2,3,4 in the first row).

myMat[0] gives you the first row, which should be float3(1,4,7,10).

However, there's a quirk! A 3x4 matrix, using column-major storage, is really 4x float3 variables. Due to cbuffer packing rules, those float3 variables are allocated the same space as a float4 variable - they have an extra 4bytes of padding on the end.

So the first column gets 1,2,3 (and 4 in its padding space), the next gets 5,6,7 (and 8 in its padding space), etc...
So, when you ask for the first row, you actually get 1,5,9,<undefined>!

If you use row major storage for this type of matrix, you don't end up with any padding bytes.
Thank you. After years of working with row major, I've some trouble figuring the Real Memory layout of a column major Matrix. It makes sense, a column of 3 floats it's represented as a 4float register inside hlsl. That explains everything.

This topic is closed to new replies.

Advertisement