Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenGL and GLSL memory alignment for uniforms and varyings

I've come up against something that's confused me, and I can't find the answer to it. When I write shader like this:

layout (location = 0) in vec3 inPosition;
layout (location = 1) in vec3 inNormal;
layout (location = 2) in vec2 inTexCoords;

I know that the vec3's aren't 16 byte aligned as many vec4's are, or SIMD compatible data types. I know this (I think), because my data in my C++ code is:

struct Vertex
{
    vec3 position;
    vec3 normal;
    vec2 texCoords;
};

Each vector sits snugly with each other, with no padding, the size being 8 * sizeof(float), 32 bytes. I pass it to the uniform and the shader reads it fine, so I know they are both aligned.

But when it comes to uniform blocks in GLSL, with for example the std140 standard a vec3 must be padded with an extra four bytes before adding another vec3 or vec4:

  1. If the member is a three-component vector with components consuming N basic machine units, the base alignment is 4N

However you can also store a four-byte int or four-byte bool in between the vec3 and the next vec3 to compact the size. So does this mean that the attrib pointer values for the vertex layout doesn't follow std140 layout? Also if for example I use SIMD 16-byte aligned vectors in my C++ code does this mean I'll no longer be able to set the attrib pointer values as vec3, vec3, vec2, but rather have all vec4's?

Also I saw the following warning on the documentation:

Warning: Implementations sometimes get the std140 layout wrong for vec3 components. You are advised to manually pad your structures/arrays out and avoid using vec3 at all.

Here it's saying to avoid using vec3 at all, but I thought it was a smart space-saving technique to pack a four byte int or bool after a vec3.

like image 844
Zebrafish Avatar asked Dec 03 '17 06:12

Zebrafish


1 Answers

The std140 layout only applies to interface blocks, not to the content of a buffer or attributes outside of a interface block. Since interface blocks cannot be used as input to a vertex shader or output from a fragment shader, std140 will not influence in any way how glVertexAttribPointer are setup or how the vertex data is stored.

About the warning: Yes, it is a smart technique to use the space after a vec3 to store and int/float/bool. But as the warning states, driver implementations sometimes get that wrong. So if you want to make sure that your code runs reliably everywhere you either have to test a lot or don't use vec3's at all. Again, note, that this is only relevant in case of interface blocks. Normal vec3 uniforms are not touched by this.

What you can do is to pack to store 3 floats and an int on your C++ side, but access it through a vec4 in the interface block. You can than retrieve the integer by using floatBitsToInt(myBlock.myVec4.w).

like image 92
BDL Avatar answered Nov 15 '22 08:11

BDL