Hello together,
I am working on a rather complex shader setup and need to pass lots of data a shader and want to use Uniform buffers. I create a UBO containing an array where each elements is of type of a struct consisting of two vec4
.
struct ElementInBuffer { // I assume an element size of 8
vec4 a;
vec4 b;
};
layout(std140) uniform MyBuffer
{
ElementInBuffer elementsArray[2];
} myBuffer;
I am adding this interface block to my UBO using addUniform. I assume that I need to call addUniform
as follows:
buffer.addUniform('elements', 8, 2); // 8 -> 2*vec4, 2 -> 2 elements in the arry
However, this leads to an error message of a buffer beeing to small. I tried a few other combinations that magically work, such as 16,2
or 8,4
.
Looking into the source code:
I see that the case of size = 16
is handled differently, so this could be the reason why this works. The magic number of 16 only makes sense for me if we are counting bytes and then indeed 16 is the size of a vec4 assuming 32 bit floats.
I also tried to figure out whether the calculation of the buffer might go wrong for my cases but I cannot proof that anything goes wrong even if l. 377 look suspicious to me as size
is actually substracted from perElementPadding
and might get negative.
However, both of my examples lead to a correct buffer size of 16 if we assume the buffer size measured in full floats and not in bytes, so the problem must somewhere else:
size = 8, arraySize = 4
:
// const totalPadding = perElementPadding * arraySize;
const totalPadding = -4 * 4; // -> -16
// size = size * arraySize + totalPadding;
size = 8 * 4 + -16; // 16
size = 8, arraySize = 2
:
// const totalPadding = perElementPadding * arraySize;
const totalPadding = 2 * 4; // -> 8
// size = size * arraySize + totalPadding;
size = 8 * 2 + 8; // 16
I prepared a playground:
What you can do with it:
- The offending line is 67: Here you can change 16 to elementSize and see that the program breaks.
- You can see that the buffer elements are actually accessible using a stride of 8 by changing l. 31 and access either element 0 or 1 and either member
a
or memberb
and figure out than you can access all the colors added from l.73 to l.94.
One might argue that a value of 16 actually makes sense as it is the total size of the buffer. However, I think this is just a coincidence as reducing the number of elements to the array to 1 and then reducing the array size to 8 as well will also break the application.
What do you think? Did I get something fundamentally wrong here or is there indeed a bug?
Best regards,
Axel