Aligning structures to std140, CPU side
Asked Answered
L

1

9

I suppose this is a kind-of cross between a pure C++ question and an OpenGL question. I have a uniform buffer and am allocating space in it of sizeof(ShaderData) bytes. I'm using std140 layout on the GPU side in the shader.

According to std140 rules, I need to add padding in various places in my structure to make sure things like vectors are aligned correctly. The structure below is an example (for my light):

struct ShaderData {

    float Light_Intensity;  
    float _pad1[3];    // align following vec3 on 4N boundary
    Math::Vec3f Light_Position;
    float _pad2;       // align following vec4 on 4N boundary
    Math::Colour4f Light_Ambient;
    Math::Colour4f Light_Diffuse;
    Math::Colour4f Light_Specular;    
    float Light_AttenuationMin;
    float Light_AttenuationMax;

} MyShaderData;

Is this the way people generally do things in C++, or are there special keywords or pragmas for aligning individual elements of a structure CPU side that are a little tidier?

Lukin answered 13/11, 2013 at 14:54 Comment(0)
S
9

No, in this way you just waste space. You have to find the optimized layout according to std140 rules.

  • a float needs 4 bytes and it's 4 bytes aligned
  • a vec3 needs 12 bytes and it's 16 bytes aligned
  • a vec4 needs 16 bytes and it's 16 bytes aligned

This means that you can find a better layout for your struct:

float Light_Intensity;          X
float _pad1[3];                  XXX
Math::Vec3f Light_Position;         XXX
float _pad2;                           X

As you can see you are wasting 4 bytes and what's worse is the fact that you can just do something like:

Math::Vec3f Light_Position      XXX
float Light_Intensity;             X

To have it aligned and without the need to waste a byte. This works because vec3 will be aligned to 16 bytes boundaries while the float will be still aligned to 4 bytes boundaries.

Shirberg answered 13/11, 2013 at 15:2 Comment(7)
OK, correct, I saw that a moment ago. But in the general case (rather than my specific case), what's the best way of putting padding in? Is there always an optimised order that doesn't require it? Seems unlikely.Lukin
AFAIK there is not a standardized way to define padding in a common way which is not like you are doing (fictitious struct members). There are some #pragma directives related to alignment but I'm unsure about how much are they standard. gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.htmlShirberg
I guess you should go somethink like #pragma pack(push,16) to set the alignment and then #pragma pack(pop) to restore it after.Shirberg
OK, that would look pretty horrendous. Probably better just to slip in some float _pad and add a comment about intention.Lukin
You could use your own macro, eg PADDING(4) PADDING(16) if you feel more comfortable, surely better than #pragma pack(push,16)Shirberg
@Lukin Apart from compiler-specific stuff (like __declspec(align(16)) on MSVC, __attribute__((aligned(16))) for gcc), C++11 has the protable alignas(16) (though not supported by all compilers), just add those in front of the respective member declarations: alignas(16) Math::Vec3f Light_Position. Changing the struct packing to 16 would be a bit too strict for floats which don't need 16-aignment.Dumuzi
As iti s not mentioned here, note that for vec2 the rules are: "a vec2 needs 8 bytes and it's 8 bytes aligned"Isometric

© 2022 - 2024 — McMap. All rights reserved.