Regarding arrays in layout std140 uniform block for OpenGL - opengl

According to specification:
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.
Does this mean that if I had an array of size 3 of a (float)vec3, would it be
vec3,vec3,vec3, (12 empty bytes to reach a vec4 multiple), (16 empty bytes because of the last sentence)
or
vec3, (4 empty bytes),vec3,(4 empty bytes)vec3,(4 empty bytes), (16 empty bytes because of the last sentence)

From the actual OpenGL Specification, version 4.3 (PDF):
3: If the member is a three-component vector with components consuming N
basic machine units, the base alignment is 4N.
4: If the member is an array of scalars or vectors, the base alignment and array
stride are set tomatch 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.
So a vec3 has a base alignment of 4*4. The base alignment and array stride of an array of vec3's is therefore 4*4. The stride is the number of bytes from one element to the next. So each element is 16 bytes in size, with the first 12 being the actual vec3 data.
Finally, there is padding equal to the base alignment at the end, so there is empty space from that.
Or, in diagram form, a vec3[3] looks like this:
|#|#|#|0|#|#|#|0|#|#|#|0|
Where each cell is 4 bytes, # is actual data, and 0 is unused data.

Neither.
The appendix L from the redbook states this:
An array of scalars or vectors -> Each element in the array is the size of the underlying type (sizeof(vec4) for vec3), and the offset of any element is its index (using zero-based indexing) times the elements size (again sizeof(vec4)). The entire array is padded to be a multiple of the size of a vec4.
So the correct answer is vec3, (4 empty), vec3, (4 empty),vec3, (4 empty) -> 48 bytes

Related

align array elements differently in aligned union

I'm using SSE/AVX and I need to store aligned data. how ever, my data can be of different types. so I use a union like this
union Data
{
bool Bools[128];
int32 Ints32[128];
int64 Ints64[128];
// ... other data types
} data;
Can I do the following?
union alignas(16) Data
{
alignas(4) bool Bools[128];
alignas(4) int32 Ints32[128];
alignas(8) int64 Ints64[128];
alignas(16) Bar Bars[128]; // Bar is 16 bytes
} data;
so I expect Ints32 and Bool elements to be aligned as 4 bytes, yet Int64 elements are aligned as 8 bytes.
because of Bar first element of each array (or basically &data) should also be aligned to 16 bytes. but elements of each array should be aligned as stated. so is my union correct?
The alignment specifier applies only to the entity it defines. It applies to the whole class (union) object's alignment or the alignment of the individual arrays. It never applies to elements of the array.
The alignment of elements in an array of type T can never be guaranteed to be stricter than the size of T, because elements of an array must be allocated contiguously in memory without padding. This is for example necessary so that pointer arithmetic can work. The type of the member doesn't include any information about the alignment specifier you used, so e.g. evaluating Bools[i] must be sure how far apart individual elements of type bool and can't adjust to alignment specifiers.
If you want to adjust element-wise alignment then you need to specify your own type with the required alignment and form an array of that type.
Because the initial address of the subobjects of a union has to be equal to that of the union object itself, there is also no point to add weaker alignment specifiers to the subobjects. They can't have any effect.

Is it guaranteed that sizeof(T[N]) == N * sizeof(T)?

I had always assumed that the size of an array of N elements of type T, as returned by sizeof was guaranteed to be exactly N times sizeof(T).
The comments on this question made me doubt it though. There are claims from reputable users that arrays may contain padding, which would break the equality. Of course such platforms may not exist, but are they allowed?
If allowed, this would break many common idioms, such as calculating the needed storage for an array with N * sizeof(T), or calculating the number of elements in an array using sizeof(a)/sizeof(a[0]).
Yes. [expr.sizeof] includes this bit about sizeof:
When applied to an array, the result is the total number of bytes in the array. This implies that the size of an array of n elements is n times the size of an element.
The whole point of sizeof is it includes the relevant padding. Every element of an array is exactly sizeof(T) bytes after the previous element. So the size of the entire array is N * sizeof(T).

Alignments of members in Unifrom buffer objects

I am having Uniform buffer object:
layout (std140) uniform ubo{
vec3 A;
float B;
vec4 C;
vec4 D;
vec4 E;
vec4 F;
float G;
};
I am assuming offset of each of them as A: 0, B: 12, C: 16, D: 32 E: 48 F:64 G:80
But it doesn't seem so if i use all of them as vec4s everything works fine.
What would be the offsets of each of them?
I tried with these new offsets:
A: 0, B: 16, C: 32, D: 48 E: 64 F:80 G:96 but it still doesn't work
From ARB_uniform_buffer_object
(1) If the member is a scalar consuming <N> basic machine units, the
base alignment is <N>.
(2) If the member is a two- or four-component vector with components
consuming <N> basic machine units, the base alignment is 2<N> or
4<N>, respectively.
(3) If the member is a three-component vector with components consuming
<N> basic machine units, the base alignment is 4<N>.
(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.
(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).
(6) If the member is an array of <S> column-major matrices with <C>
columns and <R> rows, the matrix is stored identically to a row of
<S>*<C> column vectors with <R> components each, according to rule
(4).
(7) If the member is a row-major matrix with <C> columns and <R> rows,
the matrix is stored identically to an array of <R> row vectors
with <C> components each, according to rule (4).
(8) If the member is an array of <S> row-major matrices with <C> columns
and <R> rows, the matrix is stored identically to a row of <S>*<R>
row vectors with <C> components each, according to rule (4).
(9) If the member is a structure, the base alignment of the structure is
<N>, where <N> is the largest base alignment value of any of its
members, and rounded up to the base alignment of a vec4. The
individual members of this sub-structure are then assigned offsets
by applying this set of rules recursively, where the base offset of
the first member of the sub-structure is equal to the aligned offset
of the structure. The structure may have padding at the end; the
base offset of the member following the sub-structure is rounded up
to the next multiple of the base alignment of the structure.
(10) If the member is an array of <S> structures, the <S> elements of
the array are laid out in order, according to rule (9).
Each vec3 counts as vec4 according to spec. I think that is only surprise that caused trouble for you.

OpenGL / GLSL - Uniform block data values incorrect

My shader has a uniform block as such:
layout (std140) uniform LightSourceBlock
{
vec3 test;
vec3 color;
} LightSources;
The data for this block is supposed to come from a buffer object which is created like so:
GLuint buffer;
glGenBuffers(1,&buffer);
GLfloat data[6] = {
0,0,0,
0,0,1
};
glBindBuffer(GL_UNIFORM_BUFFER,buffer);
glBufferData(GL_UNIFORM_BUFFER,sizeof(data),&data[0],GL_DYNAMIC_DRAW);
The buffer is linked to the uniform block before rendering:
unsigned int locLightSourceBlock = glGetUniformBlockIndex(program,"LightSourceBlock");
glUniformBlockBinding(program,locLightSourceBlock,8);
glBindBufferBase(GL_UNIFORM_BUFFER,8,buffer);
From my understanding this should be setting 'color' inside the block in the shader to (0,0,1), but the value I'm getting instead is (0,1,0).
If I remove the 'test' variable from the block and only bind the three floats (0,0,1) to the shader, it works as intended.
What's going on?
As you did specify layout (std140) for your UBO, you must obey the alginment rules defined there. That layout was first specified (in core) in the OpenGL 3.2 core spec, section 2.11.4 "Uniform Variables" in subsection "Standard Uniform Block Layout":
If the member is a scalar consuming N basic machine units, the base alignment is N.
If the member is a two- or four-component vector with components consuming N basic machine units, the base alignment is 2N or 4N,
respectively.
If the member is a three-component vector with components consuming N basic machine units, the base alignment is 4N.
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.
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).
If the member is an array of S column-major matrices with C columns and R rows, the matrix is stored identically to a row of S C column
vectors with R components each, according to rule (4).
If the member is a row-major matrix with C columns and R rows, the matrix is stored identically to an array of R row vectors with C
components each, according to rule (4).
If the member is an array of S row-major matrices with C columns and R rows, the matrix is stored identically to a row of S R row
vectors with C components each, according to rule (4).
If the member is a structure, the base alignment of the structure is N, where N is the largest base alignment value of any of its
members, and rounded up to the base alignment of a vec4. The
individual members of this substructure are then assigned offsets by
applying this set of rules recursively, where the base offset of the
first member of the sub-structure is equal to the aligned offset of
the structure. The structure may have padding at the end; the base
offset of the member following the sub-structure is rounded up to the
next multiple of the base alignment of the structure.
If the member is an array of S structures, the S elements of the array are laid out in order, according to rule (9).
For your case, point 3 applies. So, you need to pad another float before the second vector begins.

How is an array aligned in C++ compared to a type contained?

Suppose I have some type T that has to be N bytes aligned. Now I declare an array of type T:
T array[size];
Will the array have the same alignment requirements as type T or will it have any other alignment requirements?
Yes, the alignment requirements must be the same. Obviously an array of T must be aligned at least as strictly as a single T otherwise its first member would not be properly aligned. The fact that an array cannot be more strictly aligned than its element type follows from the standard section 8.3.4 which says that arrays are contiguously allocated element subobjects. Consider this array of arrays:
T a[2][size];
Whatever the value of size, there can be no "extra" padding between the two arrays a[0] and a[1] otherwise this violates the contiguosly allocated requirement.
Equivalently, we know that (char*)&a[1] == (char*)&a[0] + sizeof(a[0]) and sizeof(a[0]) == sizeof(T[size]) == size * sizeof(T). As this holds for any size it must be possible to place an array of T at any address which is suitably aligned for a single T object (given adequate address space).
The array's alignment requirements will be identical to those of the array elements, I believe.
Obviously, the start of the array must be aligned at least as strictly as its first element requires, so its alignment requirements can't be less strict.
The start address of the array plus the size of each element must leave the second element sufficiently aligned. That places a constraint on the size of the element type, which I believe means padding can be introduced at the end of a structure just to keep arrays aligned, even if you never use that struct in an array. But it does not mean there's any need for stricter alignment.
By induction, subsequent elements are OK if the first two are OK, so giving the array the same alignment requirements as its elements should be fine.
A citation from the spec would be nice, though.
The rules are the same i believe but the interpretation might be confusing.
I believed since each element of array would be of the same size so only aligning the first element would automatically align the rest and hence there would never be any padding between elements.
This might be true in case of a trivial array but not for complex scenarios.
The stride of an array can be large than element size i.e. there could be pads between each individual elements.
Following is a good example
struct ThreeBytesWide {
char a[3];
};
struct ThreeBytesWide myArray[100];
source - stride wikipedia
Each element of ThreeBytesWide array could be aligned to four byte boundary
Edit: As elaborated in the comments, the mention of having pads between individual elements is when the element itself is say 3 bytes and aligned to four byte boundary.
An array of objects is required to be contiguous, so there's never padding between the objects, though padding can be added to the end of an object (producing nearly the same effect).
C++ Data Member Alignment and Array Packing
#include <iostream>
__declspec(align(32))
struct Str1
{
int a;
char c;
};
template<typename T>
struct size
{
T arr[10];
};
int main()
{
size<Str1> b1;
std::cout << sizeof(Str1) << std::endl; // prints 32
std::cout << sizeof(b1) << std::endl; // prints 320
std::cin.ignore();
return 0;
}
References:
Data alignment in C++, standard and portability
http://msdn.microsoft.com/en-us/library/83ythb65.aspx