Questions about uniform buffer objects - opengl

Is it guaranteed that if a uniform block is declared the same in multiple shader programs, say
uniform Matrices
{
mat4 ProjectionMatrix;
mat4 CameraMatrix;
mat4 ModelMatrix;
};
Will it have the same block index returned by glGetUniformBlockIndex(program, "Matrices")?
If the answer is yes, then I'm able to query the index of the block once and use it for all the shader programs that contain that block, right?
Second question: will ProjectionMatrix, CameraMatrix, ModelMatrix, always have the same layout order in memory, respectively? I'm asking this because the tutorial I read uses the next functions
// Query for the offsets of each block variable
const GLchar *names[] = { "InnerColor", "OuterColor",
"RadiusInner", "RadiusOuter" };
GLuint indices[4];
glGetUniformIndices(programHandle, 4, names, indices);
GLint offset[4];
glGetActiveUniformsiv(programHandle, 4, indices,
GL_UNIFORM_OFFSET, offset);
And I'm not sure if that's really needed, as long as I know the uniforms order inside the uniform block..?

will ProjectionMatrix, CameraMatrix, ModelMatrix, always have the same layout order in memory, respectively?
No. Here's what the standard states (emphasis mine):
If pname is UNIFORM_BLOCK_DATA_SIZE, then the implementation-
dependent minimum total buffer object size, in basic machine units, required to hold all active uniforms in the uniform block identified by uniformBlockIndex is returned. It is neither guaranteed nor expected that a given implementation will arrange uniform values as tightly packed in a buffer object. The exception to this is the std140 uniform block layout, which guarantees specific packing behavior and does not require the application to query for offsets and strides.
I'm not sure if that's really needed, as long as I know the uniforms order inside the uniform block..?
So, yes, the author is right in not assuming the layout is contiguous and does what's sensible (guaranteed to work always in all implementations): gets the uniform indices and assigns their values respectively.
Specifying layout(std140) will do the trick then, right?
Yes, you can avoid querying the location and uploading data every time by making use of both uniform buffer objects and std140. However, make sure you understand its alignment requirements. This information is detailed in ARB_uniform_buffer_object's specification. For an elaborate treatment with examples see OpenTK's article on Uniform Buffer Objects (UBO) using the std140 layout specification.
Is it guaranteed that if a uniform block is declared the same in multiple shader programs, will it have the same block index returned by glGetUniformBlockIndex(program, "Matrices")?
No. I've searched the OpenGL 3.3 specification which gives no such guarantees. From the standard's viewpoint, uniform blocks (default or named) are associated to a program, period. No existence/association of uniform blocks beyond a program is made in the specification.
Because there is no guarantee that uniform blocks will have the same index in different shader program, that means I need to call glBindBufferBase() everytime I switch programs, right?
Yes, see ARB_uniform_buffer_object's specification for an example.

Related

Multiple UBOs without specifying binding point index explicitly

I am looking into OpenGL Uniform Buffer Objects and Shader Storage Buffers. I think the question applies to both of them, but let's just focus on UBOs.
Tutorials seem to be saying that "block index" and "binding point index" are different things, and if I have more than one UBO in a shader, I need to specify the binding index
layout(binding = 0) uniform first_buffer {...};
layout(binding = 1) uniform second_buffer {...};
I get the impression that the block index is determined by the linker and can be read from glGetUniformBlockIndex, but the binding point index has to be hard-coded with arbitrary distinct binding=N in the layout, and a corresponding glBindBufferBase(GL_UNIFORM_BUFFER, N, ubo_handle), which strikes me as fragile and a nuisance.
What is the difference between a block index and a binding point?
Can I omit the binding=N in the layout? What happens then with glBindBufferBase?
Is this all the same for SSBOs?
See OpenGL 4.6 API Core Profile Specification - 7.6 Uniform Variables
Named uniform blocks, as described in the OpenGL Shading Language Specification, store uniform values in the data store of a buffer object corresponding to
the uniform block. Such blocks are assigned a uniform block index.
The block index is the "handle" for the active program resource of a shader program. If you have different shader programs with the "same" uniform block, then they may have different buffer indices.
A buffer is bound to the uniform block of a shader program the binding point (e.g. in shader by a Binding point Layout Qualifier). On the one side a uniform block (index) is associated to a binding point and on the other side a buffer is bound to the binding point (by glBindBufferBase). So one buffer can be bound to the uniform blocks of different programs.
While the buffer index is fixed and and can't be changed after the program is linked, the binding point is a dynamic value and can be changed by glUniformBlockBinding. When the program is linked, then the binding point is initialized by 0 or by the value which is set by the Binding point Layout Qualifier.
This principle is the same for a Shader Storage Buffer Object.
Related questions are:
Difference between glBindBuffer and glBindBufferBase
Is it safe to use the block index as the binding point for UniformBufferObject, ShaderStorageBufferObjects, etc?
How do I query the alignment/stride for an SSBO struct?

GLSL array of struct members locations

For example, I have code like this:
uniform struct MyStruct {
mat4 model;
mat4 view;
mat4 projection;
float f1;
vec4 v1;
}, myStructs[4];
Can I be sure that location of myStructs[1].projection is location of myStructs[0].projection + 5?
I didn't find the exact information about this on khronos.org, but I found some blurry statement:
struct Thingy
{
vec4 an_array[3];
int foo;
};
layout(location = 2) uniform Thingy some_thingies[6];
Each Thingy takes up 4 uniform locations; the first three going to
an_array and the fourth going to foo. Thus, some_thingies takes up 24
uniform locations.
It isn't clear here whether locations one after another. Perhaps about this somewhere is said more accurately?
Unless you explicitly specify the location of the uniform variable, the locations of arrays of non-basic types are not strictly defined, relative to the location of any particular member of that array. So you must query the location of every member of every array/struct that you use.
Or just explicitly specify the location with layout(location). That's a much easier option; those are explicitly required to allocate their locations sequentially. And for bonus points, you don't have to query anything.
Your first example uniform struct MyStruct is a raw uniform whose member locations are arbitrary and must be queried:
Uniform locations are unique to a specific program. If you do not explicitly assign a uniform to a location (via the OpenGL 4.3 or ARB_explicit_uniform_location feature mentioned above), then OpenGL will assign them arbitrarily.
Your second example layout(location = 2) uniform Thingy some_thingies[6]; is defining a uniform block to which the following memory layout applies:
Quote Memory layout:
The specific size of basic types used by members of buffer-backed blocks is defined by OpenGL. However, implementations are allowed some latitude when assigning padding between members, as well as reasonable freedom to optimize away unused members. How much freedom implementations are allowed for specific blocks can be changed.
There are four memory layout qualifiers: shared, packed, std140, and std430. Defaults can be set the same as for matrix ordering (eg: layout(packed) buffer; sets all shader storage buffer blocks to use packed). The default is shared.
So it seems that they are sequential in memory, but as t.niese points out: only std140 and std430 provide you with those guarantees (note that std430 can only be used with shader storage blocks, not uniform blocks). Since the default layout is shared some parts of your uniform might have been optimised out or padded differently, depending on your driver.
Use glGetUniformLocation to query each location of the members separately:
Uniform variables that are structures or arrays of structures may be queried by calling glGetUniformLocation for each field within the structure. The array element operator "[]" and the structure field operator "." may be used in name​ in order to select elements within an array or fields within a structure. The result of using these operators is not allowed to be another structure, an array of structures, or a subcomponent of a vector or a matrix. Except if the last part of name​ indicates a uniform variable array, the location of the first element of an array can be retrieved by using the name of the array, or by using the name appended by "[0]".

Identifying Uniform buffer in a GLSL shader

I use glGetActiveUniform to query uniforms from the shaders.But I also use uniform buffers (regular and std140).Querying them returns an arrays with the primitive type of the uniform in the buffer.But I need a way to identify those are uniform buffers and not uniforms.
Examples of uniform buffers in a shader:
layout(std140, binding = LIGHTS_UBO_INDEX) uniform LightsBuffer {
LightInfo lights[MAX_LIGHTS];
};
Is it possible to query only buffers from GLSL shader?
Technically, what you actually have here is a uniform block. It has a name, but no type; its members (which are uniforms) have types, and I think that is what you are actually describing.
It is a pretty important distinction because of the way program introspection works. Using OpenGL 4.3+ (or GL_ARB_program_interface_query), you will find that you cannot query a type for GL_UNIFORM_BLOCK interfaces.
glGetActiveUniformBlockiv (...) can be used to query information about the uniform block, but "LightsBuffer" is still a block and not a buffer. By that I mean even though it has an attribute called GL_BUFFER_BINDING, that is really the binding location of the uniform block and not the buffer that is currently bound to that location. Likewise, GL_BUFFER_DATA_SIZE is the size of the data required by the uniform block and not the size of the buffer currently bound.

When should I use STD140 in OpenGL?

When do I use the STD140 for uniform blocks in OpenGL?
Although I am not a 100% sure, I believe there is an alternative to it which can achieve the same thing, called "Shared".
Is it just preference for the coder? Or are there reasons to use one over the other?
Uniform buffer objects are described in http://www.opengl.org/registry/specs/ARB/uniform_buffer_object.txt
The data storage for a uniform block can be declared to use one of three layouts in memory: packed, shared, or std140.
packed uniform blocks have an implementation-dependent data layout for efficiency, and unused uniforms may be eliminated by the compiler to save space.
shared uniform blocks, the default layout, have an implementation-dependent data layout for efficiency, but the layout will be uniquely determined by the structure of the block, allowing data storage to be shared across programs.
std140 uniform blocks have a standard cross-platform cross-vendor layout. Unused uniforms will not be eliminated.
The std140 uniform block layout, which guarantees specific packing behavior and does not require the application to query for offsets and strides. In this case, the minimum size may still be queried, even though it is determined in advance based only on the uniform block declaration. The offset of each uniform in a uniform block can be derived from the definition of the uniform block by applying the set of rules described in the OpenGL specification.
std140 is most useful when you have a uniform block that you update all at once, for example a collection of matrix and lighting values for rendering a scene. Declare the block with std140 in your shader(s), and you can replicate the memory layout in C with a struct. Instead of having to query and save the offsets for every individual value within the block from C, you can just glBufferData(GL_UNIFORM_BUFFER, sizeof(my_struct), &my_struct, with one call.
You do need to be a little careful with alignment in C, for instance, a vec3 will take up 4 floats, not 3, but it is still much easier IMHO.

GLSL, Array of textures of differing size

When doing multitexturing in GLSL, is there anyway to have an indexable array of samplers where each texture is a different size? This syntax isn't valid:
uniform sampler2D texArray[5];
Right now it seems like the only option is to individually create the samplers:
uniform sampler2D tex1;
uniform sampler2D tex2;
uniform sampler2D tex3;
uniform sampler2D tex4;
uniform sampler2D tex5;
But then I can't iterate through them, which is a real pain in the ass. Is there a solution?
This syntax isn't valid:
Says who? Arrays of samplers most certainly are valid (depending on the version). How you use them is a different matter.
GLSL 1.20 and below do not allow sampler arrays.
In GLSL 1.30 to 3.30, you can have sampler arrays, but with severe restrictions on the index. The index must be an integral constant expression. Thus, while you can declare a sampler array, you can't loop over it.
GLSL 4.00 and above allow the index to be a "dynamically uniform integral expression". That term basically means that all instantiations of the shader (within the same draw call) must get the same values.
So you can loop over a constant range in GLSL 4.00+, and index a sampler array with the loop counter. You can even get the index from a uniform variable. What you can't do is have the index depend on an input to the shader stage (unless that value is the same across all instances caused by the rendering command), or come from a value derived from a texture access (unless that value is the same across all instances caused by the rendering command), or something.
The only requirement on the textures placed in arrays of samplers is that they match the sampler type. So you have to use a GL_TEXTURE_2D on all the elements of a sampler2D array. Beyond that, the textures can have any number of differences, including size. The array exists to make coding easier; it doesn't change the semantics of what is there.
And remember: each individual element in the sampler array needs to be bound to its own texture image unit.
is there anyway to have an indexable array of samplers where each texture is a different size?
Not yet. Maybe this gets added to a later OpenGL version down the road, but I doubt it.
But then I can't iterate through them, which is a real pain in the ass. Is there a solution?
As a workaround you could use Array Textures and use only subregions of each layer. Use a vec4 array to store the boudaries of each picture on each layer.