GLSL buffer with multiple arbitrary sized variables - glsl

I'm trying to bind a storage buffer of object structs containing multiple variables of different types so that I can access them in my vertex shader.
Struct:
struct Object
{
vec2 vertices[4];
};
layout(std140, set = 0, binding = 0) buffer ObjectBlock
{
Object objects[];
};
Using the code above, although I am able to compile the shader and get the Vulkan program running, the values from the array variable vertices are completely different from the values I inputted. I'm not sure why this is happening.

Related

Accessing the index of an implicitly defined array in GLSL

I was trying to make a simple texture (fragment) shader that would loop through the uniform array atextures[] which is implicitly defined. The following code returns the following error
Code:
#version 330 core
out vec4 FragColor;
in vec2 TexCoord;
uniform sampler2D atextures[];
uniform int textureLength;
void main()
{
for (int i=0; i<textureLength; i++){
FragColor = texture(atextures[i], TexCoord);
}
}
Error:
Indirect index into implicitly-sized array
However when I change the index from i to 0, the following compiles fine. Did I setup the for loop wrong? Or did I initialise the array correctly?
You are getting the error because you have code that violates the specification. See the (most recent) OpenGL Shading Language 4.60 Specification - 4.1.9. Arrays:
It is legal to declare an array without a size (unsized) and then later redeclare the same name as an array of the same type and specify a size, or index it only with constant integral expressions (implicitly sized).
What you try to do is not the create an implicitly-sized array, but an dynamically-sized array.
It is not possible to create uniform array with a variable size. A variable size is just possible for the bottommost variable in a Shader Storage Block.
Anyway you should prefer to use an sampler2DArray instead of an array of sampler2D. With a sampler array, you must use a separate texture unit for each element, and the array index must be a Dynamically uniform expression

OpenGL uniform blocks syntax

I was asking myself a question about UBO and the way of accessing them in GLSL with uniform blocks.
Following the official documentation, if I want to design an array of lights, I will probably write :
layout(std140, binding = 0) uniform LightBlock
{
vec4 position;
vec4 direction;
vec4 color;
...
} lights[8];
Now I see a lot of examples, where the uniform block is written that way :
struct LightStruct
{
vec4 position;
vec4 direction;
vec4 color;
...
};
layout(std140, binding = 0) uniform LightBlock
{
LightStruct lights[8];
};
What is the difference between the two ways ?
I guess it could help to reduce the number of uniform variables in use within a shader, but I'm not sure.
The first
layout(std140, binding = 0) uniform LightBlock
{
vec4 position;
vec4 direction;
vec4 color;
...
} lights[8];
declares an array of UBO buffer blocks itself. That means, that you can bind a different buffer object for each index in your array, or a different buffer range. Note that in this example, you will consume the UBO binding indices from 0 to 7, the GLSL spec explicitly states:
If the binding identifier is used with a uniform or shader storage
block instanced as an array, the first element of the array takes the
specified block binding and each subsequent element takes the next
consecutive uniform block binding point.
This has a couple of implications:
you can only use a very limited array size, because the number of UBO binding point is limited
you must index those arrays only with a dynamically uniform expression
you can bind the same UBO and buffer range to some or all of the indivudal indices of your array (something you could not do with an array inside the block)
In summary, you seldom really want to use an array of uniform blocks. Especially for your light example, you would use the latter:
layout(std140, binding = 0) uniform LightBlock
{
LightStruct lights[8];
};
just declares one uniform block with an array in it. It means you have to provide one consecutive UBO buffer range for the array, so you consume only one of the precious UBO binding points, and you can have the array as big as the maximum UBO size of your implementation is.

error declaration is incompatible c++ (Array)

Hi I've been asked to set my arrays that contain 3d cube information to "null" so that they can be used to take in the data that is required to draw them from a txt file but have run int this error.
Any help would be appreciated.
cube header file
class Cube
{
private:
static int numVertices, numColours, numIndices;
static Vertex indexedVertices[];
static Color indexedColors[];
static GLushort indices[];
GLfloat _rotation;
GLfloat _CubeX;
GLfloat _CubeY;
GLfloat _CubeZ;
Cube cpp file
Vertex *Cube::indexedVertices = nullptr;
Color *Cube::indexedColors[] = nullptr;
GLushort *Cube::indices[] = nullptr;
The error appears under indexedVertices , indexedColors and indices
Arrays can't be null.
Also, you didn't specify the size of the arrays in their definitions.
Also, your definitions don't match your declarations! Compare:
static Vertex indexedVertices[]; // declares an array of Vertexes
Vertex *Cube::indexedVertices = nullptr; // defines a pointer to a Vertex
Also compare:
static Color indexedColors[]; // declares an array of Colors
Color *Cube::indexedColors[] = nullptr; // defines an array of pointers to Colors
Arrays are not pointers. Sometimes the language will "helpfully" convert arrays to pointers for you (e.g. indexedVertices is converted to &indexedVertices[0] when used in an expression), but they are not the same thing!

glBindVertexBuffer vs glBindBuffer

I see that I can bind a vertex buffer using glBindBuffer(GL_ARRAY_BUFFER, vbo);. This works, and I can also bind an element array using glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);. When using these everything draws as desired.
In reading the OpenGL 4.4 specification in section 10.3.1 I find mention of glBindVertexBuffer. It looks like this permits binding multiple vertex buffers and then having them all rendered at once. Is this correct? Also, how does it differ from using glBindBuffer? Can you use an element array buffer when binding vertex buffers with this?
Actually, the point of glBindVertexBuffer (...) is entirely different.
The idea when it was introduced in GL_ARB_vertex_attrib_binding was to separate the fixed mapping that has always existed between vertex buffer and pointer and replace it with a more flexible system that allows you to setup a format for a vertex attribute, a binding location for the vertex buffer/attribute to use and then simply swap out the buffer bound to that location.
You will not simply be replacing a call to glBindBuffer (...) with this new function, you have at least two other functions you need to call to setup a generic vertex attribute to be able to take advantage of glBindVertexBuffer (...):
glVertexAttribFormat (...) - This is effectively the same thing as glVertexAttribPointer (...) except it does not setup a pointer, it merely establishes how the buffer that will be paired with this attribute is to be interpreted.
glVertexAttribBinding (...) - This associates the generic attribute location with a new type of binding location (vertex buffer binding) so that you can use glBindVertexBuffer (...) to bind your VBO to a location this attribute will use.
glVertexBindingDivisor (...) - This is a replacement for glVertexAttribDivisor(). This replacement respects the binding association between the Vertex Attribute index and the Binding Slot index made by glVertexAttribBinding(...). This is worth pointing out because it's name is somewhat out of form with the other two functions listed above, while the older glVertexAttribDivisor() appears more in-form, but is the wrong function to use.
To put this into perspective, I have included some pseudo-code from the extension specification that shows how glVertexAttribPointer (...) works in relation to this new API addition.
The commands:
void glVertexAttribPointer (GLuint index, GLint size, GLenum type,
GLboolean normalized, GLsizei stride,
const GLvoid *pointer);
void glVertexAttribIPointer (GLuint index, GLint size, GLenum type,
GLsizei stride, const GLvoid *pointer);
void glVertexAttribLPointer (GLuint index, GLint size, GLenum type,
GLsizei stride, const GLvoid *pointer);
Control vertex attribute state, a vertex buffer binding, and the mapping between a vertex attribute and a vertex buffer binding.
They are equivalent to (assuming no errors are generated):
if (no buffer is bound to GL_ARRAY_BUFFER and pointer != NULL)
{
generate GL_INVALID_OPERATION;
}
glVertexAttrib*Format (index, size, type, {normalized, }, 0);
glVertexAttribBinding (index, index);
if (stride != 0) {
effectiveStride = stride;
} else {
compute effectiveStride based on size/type;
}
GL_VERTEX_ATTRIB_ARRAY_STRIDE[index] = stride;
// GL_VERTEX_BINDING_STRIDE will be set to effectiveStride
// by glBindVertexBuffer.
glBindVertexBuffer (index, <buffer bound to GL_ARRAY_BUFFER>,
(GLchar *)pointer - (GLchar *)NULL, effectiveStride);
It is a little difficult to wrap your head around at first, but what it boils down to is very similar to the separation of sampler state from Texture Objects when Sampler Objects were introduced in GL 3.3. You can continue using the old API, but this alternative solution gives you some more flexibility.
Regarding element array buffers, no. This new part of the API has nothing to do with that, because Vertex Array Objects actually manage the one-and-only element array buffer binding.
Not really. glBindVertexBuffers
is used for binding multiple vertex buffers. As for glBindVertexBuffer, it is used for binding a buffer to a vertex buffer. You may have to call it many times to bind multiple vertex buffers.
You can check their documentation here:
http://www.opengl.org/sdk/docs/man/xhtml/glBindVertexBuffers.xml

difference between SSBO and Image load/store

What are the diffences between "Shader Storage Buffer Objects" (SSBO) and Image load store operations
When should one be used and not the other?
They both can have atomic operations and I assume they are stored in the same type of memory. And regardless if they are stored in the same type of memory, do they have the same performance characteristics?
edit: the original question was asking between SSBOs and Uniform buffer objects, it was meant to be between SSBO and Image load store.
The difference between shader storage buffer objects and image textures and why one would want to use them is that they can use interface blocks.
Images are just textures which mean only vec4's are in the data structure. Well not only vec4, it could have other formats, but the data structure would be many of one data type.
Where as, SSBO's are generic. They can use combinations of int's, float's, arrays of vec3's all in a single interface block.
So, SSBO's are much more flexible than just Image Texture's.
Your question is already answered more or less definitively at http://www.opengl.org/wiki/Shader_Storage_Buffer_Object. It says:
SSBOs are a lot like Uniform Buffer Objects. Shader storage blocks are
defined by Interface Block (GLSL)s in almost the same way as uniform
blocks. Buffer objects that store SSBOs are bound to SSBO binding
points, just as buffer objects for uniforms are bound to UBO binding
points. And so forth.
The major differences between them are:
SSBOs can be much larger. The smallest required UBO size is 16KB; the smallest required SSBO size is 16MB, and typical sizes will
be on the order of the size of GPU memory.
SSBOs are writable, even atomically; UBOs are uniform​s. SSBOs reads and writes use incoherent memory accesses, so they need the
appropriate barriers, just as Image Load Store operations.
SSBOs can have unbounded storage, up to the buffer range bound; UBOs must have a specific, fixed storage size. This means that you can
have an array of arbitrary length in an SSBO. The actual size of the
array, based on the range of the buffer bound, can be queried at
runtime in the shader using the length​ function on the unbounded
array variable.
As others have mentioned, SSBOs have much larger storage and supports atomic operations, the accepted answer also mentioned that SSBOs are generic in the sense that they allow users to combine different types. But personally, I just want to point out that I think this is usually BAD, it is not always ideal to use interface blocks or structs in SSBO. Here's an example:
Let's say you have a struct in C++ like this:
struct Foo {
glm::vec4 position;
glm::vec4 velocity;
glm::vec4 padding_and_range; // range is a float padded to a vec4
};
which corresponds to an SSBO buffer in glsl:
struct Foo {
vec4 position;
vec4 velocity;
vec4 padding_and_range; // range is a float padded to a vec4
};
layout(std430, binding = 0) readonly buffer SSBO {
Foo data[];
} foo;
Although the SSBO buffer is able to hold an array of struct Foo, notice that paddings must be taken into account as per the std430 memory layout, you have to padded your float range to a vec4, and then use foo.data[i].padding_and_range.w to access it. This is error-prone, let alone the waste of memory spaces, especially when your SSBO is large (to be used in a compute shader) and your Foo struct is complex (needs a lot of paddings). Apart from that, you often need to fill in the buffer data in a loop like this:
Foo* foos = reinterpret_cast<Foo*>(glMapNamedBufferRange(ssbo, offset, size, GL_MAP_READ_BIT));
for (int i = 0; i < n_foos; i++) {
Foo& foo = foos[i];
foo.position = glm::vec4(1.0f);
foo.velocity = glm::vec4(2.0f);
foo.padding_and_range = glm::vec4(glm::vec3(0.0f), 3.5f);
}
glUnmapNamedBuffer(ssbo);
instead of simply writing data to it in one go using glNamedBufferData or glNamedBufferSubData.
A better way of handling struct is to store each struct element into a separate SSBO, so that each SSBO buffer array is tightly packed and homogeneous. Even though the performance may not be any better, it helps keep your code clean and more readable. Rarher than using the struct, you would want to use:
layout(std430, binding = 0) buffer FooPosition {
vec4 position[];
};
layout(std430, binding = 1) buffer FooVelocity {
vec4 velocity[];
};
layout(std430, binding = 2) buffer FooRange {
float range[];
};