Reputation: 1033
My shader source is this one :
#version 330
uniform mat4 camera;
struct S {
vec2 v;
mat2 m;
};
layout(std140) uniform SS {
S s[2];
};
in vec2 v;
void main () {
gl_Position = camera * vec4(v.x + s[0].m[0][0], v.y, 0.0, 1.0);
}
When I ask how big is my uniform block, GL answers 96
. But if I assume that a mat2
is 4 floats, a vec2
is 2 floats and I have two of them, and that a float
is 4 bytes, then:
(4 + 2) * 2 * 4 = 48
I find 48
bytes… Why so much ?
Maybe it comes from alignement of my structs to 4 bytes. Let's add 2 bytes of padding to account for alignment, after my vec2
:
(4 + 2 + 2) * 2 * 4 = 64
This is 64
, not 96
. So where am I wrong? In fact I'm quite sure my floats are 4 bytes, since I can retrieve them when they follow each other…
Upvotes: 2
Views: 239
Reputation: 43369
Believe it or not, this is normal for the std140
layout. To understand why, you need to read up on the alignment rules outlined below:
Rule (4):
If the member is an array of scalars or vectors, the base alignment and array stride are set to match the base alignment of a single array element, according to rules (1), (2), and (3), and rounded up to the base alignment of a
vec4
. The array may have padding at the end; the base offset of the member following the array is rounded up to the next multiple of the base alignment.Rule (5):
If the member is a column-major matrix with C columns and R rows, the matrix is stored identically to an array of C column vectors with R components each, according to rule (4).
I have re-written your data structure to indicate how it looks from the perspective of std140
alignment:
struct S {
vec2 v;
vec2 v_padding; // NEW (satisfies rule 4 -- mat2 has base alignment 4N)
//mat2 m; // ORIGINAL (re-written below for alignment -- see rule 5)
vec2 m0;
vec2 m0_padding; // NEW (satisfies rule 4 -- column vectors are aligned to 4N)
vec2 m1;
vec2 m1_padding; // NEW (satisfies rule 4 -- column vectors are aligned to 4N)
};
vec2 v
-> 2N + 2Nmat2 m
-> 2N + 2N + 2N + 2NTotal Struct Size (in machine units): 4N + 8N = 12N
S s [2]
:12N * 2 = 24N * 4/N = 96
Your biggest problem here is the use of a mat
type.
Matrices are treated as arrays of vectors, which adds extra alignment oddities. In some cases you can get around these oddities by using row-major matrices, but since this is a square matrix that will not help any.
Instead of a mat2
, I would suggest you pack your data into a vec4
.
struct S {
vec2 v; // 2N + 2N (padding)
vec4 m; // 4N
}; // 8N
2N + 2N + 4N = 8N * 2 * 4/N = 64 bytes
You can write some extra code to unpack the vec4
into a mat2
variable if you really need a mat2
in your shader.
Upvotes: 3