UBO padding of uint64_t typed array
UBO padding of uint64_t typed array
I have the following situation. UBO structure that holds 4 uint64_t in an array.
struct MaterialData
uint64_t comps[4];
;
layout (std140, binding = 0) uniform MaterialBlock
MaterialData data[50];
material;
The problem is,only index = 0 gives me correct data.But if I change to GLSL built-in type vector of uint64_t, it all works ok:
struct MaterialData
u64vec4 textures;
;
It surely has something to do with padding rules for std140.And here is what OpenGL 4.5 specs says:
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.
So I understand from this part
the base alignment and array stride are set to match the base
alignment of a single array element
that each array's member alignment is the size of the member,which is 8 bytes.Though this is not exactly clear.And in reality it doesn't work.I can get along with u64vec4 but I want to know how to pad an array of uint64_t?
2 Answers
2
You missed the key phrase:
and rounded up to the base alignment of a vec4
That means the stride for an array of 64-bit integers is the same as the alignment of a vec4: 16. So a 64-bit integer in an array has 8 bytes of useful data, followed by 8 bytes of padding, followed by the next element.
So in C++, the equivalent array would have to look something like:
struct 64_bit_array_element
std::uint64_t value;
std::uint8_t padding[8];
;
struct UBO
64_bit_array_element comps[4];
;
Of course, that's hugely wasteful. A better way to handle this is to use an array of u64vec2
s.
u64vec2
Or you could just use an SSBO and std430
layout, for which the offending line in the specification does not apply.
std430
You already are quoting the relevant part of the GL spec, I just add some emphasis here:
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.
In std140
, array stride is always a multiple of 16 bytes. (This is btw one major difference to the later std430
, which is allowed for SSBOs). So if you really want the uint64_t[4]
type, you need to pad each element with additional 8 bytes, wasting 50% of the storage.
std140
std430
uint64_t[4]
I do see 2 alternatives:
u64vec4
uint64_t[4]
std430
@MichaelIV: There are such things as memory/performance tradeoffs. Also, if the array is of a small size, then the cost of accessing it will quickly be eliminated thanks to caching. Lastly, pay attention to words like "all things being equal"; I didn't write those words because I like being wordy.
– Nicol Bolas
Aug 19 at 14:48
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Yeah,indeed,waste of space using array... "SSBO access, all things being equal, will likely be slower than UBO access" khronos.org/opengl/wiki/Shader_Storage_Buffer_Object makes me feel like UBO is more optimal for performance.Though I never benchmarked
– Michael IV
Aug 19 at 14:34