In my OpenGL program I need to find a way to differentiate writable shader storage blocks from read-only shader storage blocks. In other words I need to be able to detect glsl code like this:
layout(std140) readonly buffer StorageBuffer
{
vec4 data;
}g_Buffer;
glGetProgramResourceiv does not seem to provide this information. Is there another way to check this?
Related
In OpenGL, I have one compute shader which writes output values into a shader storage buffer on the device.
Then another shader (fragment shader) reads that value and uses it.
So this happens all on the device, without synchronizing with the host.
Is there way to instead have the fragment shader receive the values as a uniform, except that the content of the uniform is not set by the host with glUniform(), but it takes the value that is on the device-side shader storage buffer? In a way similar to how glDrawIndirect() can take parameters from a device-side buffer, instead of from the host, avoiding pipeline stalling.
This would allow simplifying a program where the fragment shader will receive the value either as a constant set by the host, or dynamically from a previous shader, depending on configuration.
Uniforms can be aggregated into an interface block:
layout(binding = 0) uniform InBlock {
// ... your uniforms go here ...
} IN;
Then the compute-shader written buffer can be bound to that interface block binding point:
glBindBuffersBase(GL_UNIFORM_BUFFER, 0, buffer_id);
In fact this is the preferred way of doing things in general, rather than setting each uniform one-by-one.
I have a an SSBO which stores vec4 colour values for each pixel on screen and is pre populated with values by a compute shader before the main loop.
I'm now trying to get this data onscreen which I guess involves using the fragment shader (Although if you know a better method for this I'm open to suggestions)
So I'm trying to get the buffer or at least the data in it to the fragment shader so that I can set the colour of each fragment to the corresponding value in the buffer but I cannot find any way of doing this?
I have been told that I can bind the SSBO to the fragment shader but I don't know how to do this? Other thoughts I had was somehow moving the data from the SSBO to a texture but I can't work that out either
UPDATE:
In response thokra's excellent answer and following comments here is the code to set up my buffer:
//Create the buffer
GLuint pixelBufferID;
glGenBuffers(1, &pixelBufferID);
//Bind it
glBindBuffer(GL_SHADER_STORAGE_BUFFER, pixelBufferID);
//Set the data of the buffer
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4) * window.getNumberOfPixels, new vec4[window.getNumberOfPixels], GL_DYNAMIC_DRAW);
//Bind the buffer to the correct interface block number
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, pixelBufferID);
Then I call the compute shader and this part works, I check the data has been populated correctly. Then in my fragment shader, just as a test:
layout(std430, binding=0) buffer PixelBuffer
{
vec4 data[];
} pixelBuffer
void main()
{
gl_FragColor = pixelBuffer.data[660000];
}
What I've noticed is that it seems to take longer and longer the higher the index so at 660000 it doesn't actually crash its just taking an silly amount of time.
Storage buffers work quite similarly to uniform buffers. To get a sense of how those work I suggest something like this. The main differences are that storage buffer can hold substantially higher amounts of data and the you can randomly read from and write to them.
There are multiple angles of working this, but I'll start with the most basic one - the interface block inside your shader. I will only describe a subset of the possibilities when using interface blocks but it should be enough to get you started.
In contrast to "normal" variables, you cannot specify buffer variables in the global scope. You need to use an interface block (Section 4.3.9 - GLSL 4.40 Spec) as per Section 4.3.7 - GLSL 4.40 Spec:
The buffer qualifier can be used to declare interface blocks (section 4.3.9 “Interface Blocks”), which are then referred to as shader storage blocks. It is a compile-time error to declare buffer variables at global scope (outside a block).
Note that the above mentioned section differs slightly from the ARB extension.
So, to get access to stuff in your storage buffer you'll need to define a buffer interface block inside your fragment shader (or any other applicable stage):
layout (binding = 0) buffer BlockName
{
float values[]; // just as an example
};
Like with any other block without an instance name, you'll refer to the buffer storage as if values were at global scope, e.g.:
void main()
{
// ...
values[0] = 1.f;
// ...
}
On the application level the only thing you now need to know is that the buffer interface block BlockName has the binding 0 after the program has been successfully linked.
After creating a storage buffer object with your application, you first bind the buffer to the binding you specified for the corresponding interface block using
glBindBufferBase(GLenum target, GLuint index, GLuint buffer);
for binding the complete buffer to the index or
glBindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
for binding a subset specified by an offset and a number of of the buffer to the index.
Note that index refers to the binding specified in your layout for the corresponding interface block.
And that's basically it. Be aware that there are certain limits for the storage buffer size, the number of binding points, maximum storage block sizes and so on. I refer you to the corresponding sections in the GL and GLSL specs.
Also, there is a minimal example in the ARB extension. Reading the issues sections of extension also often provides further insight into the exposed functionality and the rationale behind it. I advise you to read through it.
Leave a comment if you run into problems.
My (fragment) shader has a uniform array containing 12 structs:
struct LightSource
{
vec3 position;
vec4 color;
float dist;
};
uniform LightSource lightSources[12];
In my program I have 12 buffer objects that each contain the data for one light source. (They need to be seperate buffers.)
How can I bind these buffers to their respective position inside the shader?
I'm not even sure how to retrieve the location of the array.
glGetUniformLocation(program,"lightSources");
glGetUniformLocation(program,"lightSources[0]");
These run without invoking an error, but the location is definitely wrong(4294967295). (The array is being used inside the shader, so I don't think it's being optimized out)
As glGetUniformLocation docs say:
name must be an active uniform variable
name in program that is not a structure,
an array of structures, or a subcomponent of a vector or a
matrix.
...
Uniform variables that are structures or arrays of
structures may be queried by calling
glGetUniformLocation for each field within
the structure.
So, you can only query one field at a time.
Like this:
glGetUniformLocation(program,"lightSources[0].position")
glGetUniformLocation(program,"lightSources[0].color")
glGetUniformLocation(program,"lightSources[0].dist")
Hope it helps.
Edit:
You can make your life easier (at a cost of old hardware/drivers compatibility) by using Interface Blocks, Uniform Buffer Objects and glGetUniformBlockIndex. This will be more like DirectX constant buffers. Required hardware/drivers support for that: either OpenglGL 3.1 core or ARB_uniform_buffer_object extension.
The number of per vertex attributes that I need to calculate my vertex shader output is bigger than GL_MAX_VERTEX_ATTRIBS. Is there an efficient way to e.g. point to a number of buffers using a uniform array of indices and to access the per vertex data this way?
This is a hardware limitation so the short answer is no.
If you consider workarounds for other ways, like using uniforms that also got limitations so that is a no way to go either.
One possible way I can think of which is rather hackish is to get the extra data from a texture. Since you can access textures from the vertex shader, but texture filtering is not supported ( you wont need it so it doesn't matter for you ).
With the newer OpenGLs its possible to store rather large amount of data in textures and access them without limitation even in the vertex shader, it seems to be one way to go.
Altho with this approach there is a problem you need to face, how do you know the current index, i.e. which vertex it is?
You can check out gl_VertexID built-in for that.
You could bypass the input assembler and bind the extra attributes in an SSBO or texture. Then you can use gl_VertexID in the vertex shader to get the value of index buffer entry you are currently rendering (eg: the index in the vertex data you need to read from)
So for example in a VS the following code is essentially identical (it may however have different performance characteristics depending on your hardware)
in vec3 myAttr;
void main() {
vec3 vertexValue = myAttr;
//etc
}
vs.
buffer myAttrBuffer {
vec3 myAttr[];
};
void main() {
vec3 vertexValue = myAttr[gl_VertexID];
//etc
}
The CPU-side binding code is different, but generally that's the concept. myAttr counts towards GL_MAX_VERTEX_ATTRIBS, but myAttrBuffer does not since it is loaded explicitly by the shader.
You could even use the same buffer object in both cases by binding with a different target.
If you can not absolutely limit yourself to GL_MAX_VERTEX_ATTRIBS attributes, I would advise using multi pass shaders. Redesign your code to work with data with half set of attributes in first pass, and the remaining in second pass.
I have a fragment shader that uses a few uniforms which are set on a per-object basis. Is there a way to store these uniforms on the graphics card somehow? I've heard of (but cannot find a tutorial for) vertex buffer objects--is there a trick to storing the information in there, so that I don't need to re-set the variables every time I draw a new object?
Each object has very few vertices, but they are completely static.
There are indeed Uniform Buffer Objects in later versions of OpenGL http://www.opengl.org/wiki/Uniform_Buffer_Object
If you use the same shader program ID for all the objects, then you can just set the uniforms once before you render your objects as their value will stay the same until you set them again. So e.g. in your code where you load and compile the shader source, set the uniform variables that are common for all the objects, then render your objects, only setting the per-object uniforms.
The uniform buffer idea in one of the answers can be used if you have different shaders for different objects but you want to share some data between them. This is not necessary in your case as you mention a single shader.