Std140 uniform block layout

hi,

is it correct that i have to circumvent a …

layout (std140, binding = 2) uniform Material_Indices_Block {
	uint material_indices[4096];
};

to something like …

layout (std140, binding = 2) uniform Material_Indices_Block {
	uvec4 material_indices[1024]; // contains 4096 indices
};

and calculate the correcponding index like that

	// FIX: std140: get material index from array of uvec4
	uint index_corrected = gl_DrawID / 4;
    if (gl_DrawID % 4 == 0)
        vs_out.material_index = material_indices[index_corrected].x;
	if (gl_DrawID % 4 == 1)
        vs_out.material_index = material_indices[index_corrected].y;
	if (gl_DrawID % 4 == 2)
        vs_out.material_index = material_indices[index_corrected].z;
	if (gl_DrawID % 4 == 3)
        vs_out.material_index = material_indices[index_corrected].w;

because of the std140 layout ??

if i use the “packed” layout qualifier instead, do i have to query any stride/alignment/offset values for such a simple uint array?

complete vertex shader:

#version 460 core

layout (location = 0) uniform mat4 Projection = mat4(1);


layout (location = 0) in vec3 in_position;
layout (location = 1) in vec3 in_normal;
layout (location = 2) in vec2 in_texcoord;
layout (location = 3) in vec4 in_color;
layout (location = 4) in mat4 in_mv;


out VS_FS {
	smooth vec3 position;
	smooth vec3 normal;
	smooth vec2 texcoord;
	smooth vec4 color;
	flat uint material_index;
} vs_out;


layout (std140, binding = 2) uniform Material_Indices_Block {
	uvec4 material_indices[1024]; // contains 4096 indices
};


void main()
{
	gl_Position = Projection * in_mv * vec4(in_position, 1);

	vs_out.position = (in_mv * vec4(in_position, 1)).xyz;
	vs_out.normal = (in_mv * vec4(in_normal, 0)).xyz;
	vs_out.texcoord = in_texcoord;
	vs_out.color = in_color;

	// FIX: std140: get material index from array of uvec4
	uint index_corrected = gl_DrawID / 4;
    if (gl_DrawID % 4 == 0)
        vs_out.material_index = material_indices[index_corrected].x;
	if (gl_DrawID % 4 == 1)
        vs_out.material_index = material_indices[index_corrected].y;
	if (gl_DrawID % 4 == 2)
        vs_out.material_index = material_indices[index_corrected].z;
	if (gl_DrawID % 4 == 3)
        vs_out.material_index = material_indices[index_corrected].w;
}

thanks for any suggestions !!

Yes, assuming that you don’t want to use four words for each element.

You can select individual elements from a vector using indexing, i.e.:

    vs_out.material_index = material_indices[gl_DrawID/4][gl_DrawID%4];

Yes; The packed qualifier doesn’t imply any particular layout. It simply indicates that the compiler is free to omit unused members. It’s entirely possible that the hardware is incapable of indexing uniform arrays with a single-word stride; this is why std140 rounds up to four-word alignment and why std430 can’t be used on uniform blocks. The shared qualifier doesn’t imply any particular layout either, but the layout is based solely upon the declaration to guarantee compatibility with any existing or future shader using the same declaration.

If you want a C-compatible array layout, you might try using a SSBO instead of a UBO. That allows the use of std430, which doesn’t have the four-word alignment constraint. I have no idea which approach is likely to be faster; it may depend upon hardware (uniform variables are read-only and thus simpler to cache). A buffer texture is another option.

ok thank you very much.
i’ll compare UBO vs SSBO then …