OpenGL compute shader not putting value in uniform buffer - opengl

I'm trying to make a compute shader for computing texture samples. For now I just want it to sample a single point in a texture, and later on I will try to have it do so for an array of vectors. While testing this, I found that the shader doesn't seem to be setting the value I'm using as the output.
Shader:
#version 430
layout(local_size_x = 1) in;
layout(std430, binding = 1) buffer samplePoints {
vec2 pos;
};
layout(std430, binding = 2) buffer samples {
float samp;
};
uniform sampler2D tex;
void main() {
//samp = texture(tex, pos).r;
samp = 7.0f;
}
Setting samp to 7 is a test. I run the shader with PyOpenGL, the relevant part being:
shader = GL.glCreateShader(GL.GL_COMPUTE_SHADER)
GL.glShaderSource(shader, open("test.glsl").read())
GL.glCompileShader(shader)
program = GL.glCreateProgram()
GL.glAttachShader(program, shader)
GL.glLinkProgram(program)
points, samples = GL.glGenBuffers(2)
GL.glBindBuffer(GL.GL_UNIFORM_BUFFER, points)
GL.glBufferData(GL.GL_UNIFORM_BUFFER, 8, b"\0\0\0\0\0\0\0\0", GL.GL_STATIC_DRAW)
GL.glBindBuffer(GL.GL_UNIFORM_BUFFER, samples)
GL.glBufferData(GL.GL_UNIFORM_BUFFER, 4, b"\0\0\0\0", GL.GL_STATIC_DRAW)
GL.glUseProgram(program)
GL.glBindBufferBase(GL.GL_UNIFORM_BUFFER, 1, points)
GL.glBindBufferBase(GL.GL_UNIFORM_BUFFER, 2, samples)
GL.glDispatchCompute(1, 1, 1)
GL.glBindBuffer(GL.GL_UNIFORM_BUFFER, samples)
a = GL.glGetBufferSubData(GL.GL_UNIFORM_BUFFER, 0, 4).view("<f4")
print(a)
This results in just printing the float made from the 4 bytes I placed in the samples buffer earlier. 0 in this case. I've omitted various bits of error-checking, none of which report any errors along the way.
Where am I going wrong?

That looks like a storage buffer, not a uniform buffer, so wouldn't you need to use GL_SHADER_STORAGE_BUFFER? Also you need to use glMemoryBarrier before accessing the contents.

Related

What is wrong with my compute shader array indexing?

I'm currently having a problem with my compute shader failing to properly get an element at a certain index of an input array.
I've read the buffers manually using NVidia NSight and it seems to be input properly, the problem seems to be with indexing.
It's supposed to be drawing voxels on a grid, take this case as an example (What is supposed to be drawn is highlighted in red while blue is what I am getting):
And here is the SSBO buffer capture in NSight transposed:
This is the compute shader I'm currently using:
#version 430
layout(local_size_x = 1, local_size_y = 1) in;
layout(rgba32f, binding = 0) uniform image2D img_output;
layout(std430) buffer;
layout(binding = 0) buffer Input0 {
ivec2 mapSize;
};
layout(binding = 1) buffer Input1 {
bool mapGrid[];
};
void main() {
// base pixel colour for image
vec4 pixel = vec4(1, 1, 1, 1);
// get index in global work group i.e x,y position
ivec2 pixel_coords = ivec2(gl_GlobalInvocationID.xy);
vec2 normalizedPixCoords = vec2(gl_GlobalInvocationID.xy) / gl_NumWorkGroups.xy;
ivec2 voxel = ivec2(int(normalizedPixCoords.x * mapSize.x), int(normalizedPixCoords.y * mapSize.y));
float distanceFromMiddle = length(normalizedPixCoords - vec2(0.5, 0.5));
pixel = vec4(0, 0, mapGrid[voxel.x * mapSize.x + voxel.y], 1); // <--- Where I'm having the problem
// I index the voxels the same exact way on the CPU code and it works fine
// output to a specific pixel in the image
//imageStore(img_output, pixel_coords, pixel * vec4(vignettecolor, 1) * imageLoad(img_output, pixel_coords));
imageStore(img_output, pixel_coords, pixel);
}
NSight doc file: https://ufile.io/wmrcy1l4
I was able to fix the problem by completely ditching SSBOs and using a texture buffer, turns out the problem was that OpenGL treated each value as a 4-byte value and stepped 4 bytes instead of one for each index.
Based on this post: Shader storage buffer object with bytes

Reading from different samplers in an OpenGL Compute Shader results in odd pixelation

When using an OpenGL 4.5 compute shader, sampling from different textures based on a variable in the following manner results in odd pixelation. (first texture is red and second texture is blue)
#version 450
uniform sampler2D textures[2];
layout (binding = 0, rgba32f) uniform image2D framebuffer;
layout (local_size_x = 32, local_size_y = 32) in;
void main() {
ivec2 pix = ivec2(gl_GlobalInvocationID.xy);
ivec2 size = imageSize(framebuffer);
if (pix.x >= size.x || pix.y >= size.y) {
return;
}
vec2 tex_coords = vec2(pix)/size;
int index;
vec4 col;
if (tex_coords.x > tex_coords.y) {
index = 0;
} else {
index = 1;
}
/* This works */
// for (int i=0; i<=index; i++)
// if (i==index)
// col = textureLod(textures[index], vec2(0,0), 0);
/* These don't */
col = textureLod(textures[index], vec2(0,0), 0);
// col = texelFetch(textures[index], ivec2(0,0), 0);
imageStore(framebuffer, pix, col);
}
Oddly enough, offsetting when the samples for different textures happens using a while loop seems to fix the problem. Using a workgroup size of 1 also seems to fix it. Anyone know why this behavior is happening and/or have a less hacky way of preventing it?
The full MRE for the code can be found at https://github.com/Luminic/TextureSamplingIssues
The result you get is well within the spec. THe GLSL spec states:
Texture-combined sampler types are opaque types, declared and behaving as described above for
opaque types. When aggregated into arrays within a shader, they can only be indexed with a
dynamically uniform integral expression, otherwise results are undefined.
You can't really do that, and the workaround with the loop still is undefined behavior (although it is more likely to work by the way current GPUs work). A correct workaround would be:
vec4 texSamples[2];
texSamples[0]=texture(textures[0],...);
texSamples[1]=texture(textures[1],...);
col = texSamples[index];
However, you may be able to use array textures instead, where you can select the layer via arbitrary non-uniform expressions.

OpenGL instancing : how to debug missing per instance data

I am relatively familiar with instanced drawing and per instance data: I've implemented this in the past with success.
Now I am refactoring some old code, and I introduced a bug on how per instance data are supplied to shaders.
The relevant bits are the following:
I have a working render loop implemented using glMultiDrawElementsIndirect: if I ignore the per instance data everything draws as expected.
I have a vbo storing the world transforms of my objects. I used AMD's CodeXL to debug this: the buffer is correctly populated with data, and is bind when drawing a frame.
glBindBuffer(GL_ARRAY_BUFFER,batch.mTransformBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::mat4) * OBJ_NUM, &xforms, GL_DYNAMIC_DRAW);
The shader specifies the input location explicitly:
#version 450
layout(location = 0) in vec3 vertexPos;
layout(location = 1) in vec4 vertexCol;
//...
layout(location = 6)uniform mat4 ViewProj;
layout(location = 10)uniform mat4 Model;
The ViewProj matrix is equal for all instances and is set correctly using:
glUniformMatrix4fv(6, 1, GL_FALSE, &viewProjMat[0][0]);
Model is per instance world matrix it's wrong: contains all zeros.
After binding the buffer and before drawing each frame, I am trying to setup the attribute pointers and divisors in such a way that every drawn instance will receive a different transform:
for (size_t i = 0; i < 4; ++i)
{
glEnableVertexAttribArray(10 + i);
glVertexAttribPointer(10 + i, 4, GL_FLOAT, GL_FALSE,
sizeof(GLfloat) * 16,
(const GLvoid*) (sizeof(GLfloat) * 4 * i));
glVertexAttribDivisor(10 + i, 1);
}
Now, I've looked and the code for a while and I really can't figure out what I am missing. CodeXL clearly show that Model (location 10) isn't correctly filled. No OpenGL error is generated.
My question is: does anyone know under which circumstances the setup of per instance data may fail silently? Or any suggestion on how to debug further this issue?
layout(location = 6)uniform mat4 ViewProj;
layout(location = 10)uniform mat4 Model;
These are uniforms, not input values. They don't get fed by attributes; they get fed by glUniform* calls. If you want Model to be an input value, then qualify it with in, not uniform.
Equally importantly, inputs and uniforms do not get the same locations. What I mean is that uniform locations have a different space from input locations. An input can have the same location index as a uniform, and they won't refer to the same thing. Input locations only refer to attribute indices; uniform locations refer to uniform locations.
Lastly, uniform locations don't work like input locations. With attributes, each vec4-equivalent uses a separate attribute index. With uniform locations, every basic type (anything that isn't a struct or an array) uses a single uniform location. So if ViewProj is a uniform location, then it only takes up 1 location. But if Model is an input, then it takes up 4 attribute indices.

Output per fragment data through SSBO

I need to output 24 indices per fragment in a shader. I already reached the maximum amount of rendertargets because I'm using four other rendertargets for my gbuffer. So I tried to output the data with an SSBO, indexing it with the gl_FragCoord of the pixel. The problem is, that it needs to be depth correct. So I tried to use layout(early_fragment_tests) in; and watched over the indices. I can see strange per pixel errors on some spots now and it looks like the indices from the triangles below are coming through plus it stops when I'm moving the camera closer to those spots.
I double checked the indexing of the ssbo and it's correct + the indices should be the same for a whole triangle, but the flickering is per pixel. So I think the depth test works only for the rasterized per pixel output and not for the whole fragment shader code. Could it be the problem or does somebody know if the depth test should stop the whole processing of the fragment? If that's not the case, even a separate depth pre pass couldn't help me.
Here is a fragment shader example:
#version 440 core
layout(early_fragment_tests) in;
layout(location = 0) uniform sampler2D texSampler;
#include "../Header/MaterialData.glslh"
#include "../Header/CameraUBO.glslh"
layout(location = 3) uniform uint screenWidth;//horizontal screen resolution in pixel
layout(location = 0) out vec4 fsout_color;
layout(location = 1) out vec4 fsout_normal;
layout(location = 2) out vec4 fsout_material;
coherent layout(std430, binding = 3) buffer frameCacheIndexBuffer
{
uvec4 globalCachesIndices[];
};
in vec3 gsout_normal;
in vec2 gsout_texCoord;
flat in uvec4 gsout_cacheIndices[6];
flat in uint gsout_instanceIndex;
void main()
{
uint frameBufferIndex = 6 * (uint(gl_FragCoord.x) + uint(gl_FragCoord.y) * screenWidth);
for(uint i = 0; i < 6; i++)
{
globalCachesIndices[frameBufferIndex + i] = gsout_cacheIndices[i];//only the closest fragment should output
}
fsout_normal = vec4(gsout_normal * 0.5f + 0.5f, 0);
fsout_color = vec4(texture(texSampler, gsout_texCoord));
MaterialData thisMaterial = material[materialIndex[gsout_instanceIndex]];
fsout_material = vec4(thisMaterial.diffuseStrength,
thisMaterial.specularStrength,
thisMaterial.ambientStrength,
thisMaterial.specularExponent);
}

texture3d generates GL_INVALID_OPERATION

Have a strange issue with my glsl shader. It renders nothing (eg black screen) and makes my glDrawElements cast a GL_INVALID_OPERATION. The shader in use is shown bellow. When I comment out the line with v = texture3D(texVol,pos).r; and replace it with v = 0.4; it outputs what is expected (orange-like color) and no gl errors is generated.
uniform sampler2D texBack;
uniform sampler3D texVol;
uniform vec3 texSize;
uniform vec2 winSize;
uniform float iso;
varying vec3 inCoords;
vec4 raytrace(in vec3 entryPoint,in vec3 exitPoint){
vec3 dir = exitPoint - entryPoint;
vec3 pos = entryPoint;
vec4 color = vec4(0.0,0.0,0.0,0.0);
int steps = int(2.0*length(texSize));
dir = dir * (1.0/steps);
vec3 n;
float v,m=0.0,avg=0.0,avg2=0.0;
for(int i = 0;i<steps || i < 2500;i++){
v = texture3D(texVol,pos).r;
m = max(v,m);
avg += v;
pos += dir;
}
return vec4(avg/steps,m,0,1);
}
void main()
{
vec2 texCoord = gl_FragCoord.xy/winSize;
vec3 exitPoint = texture2D(texBack,texCoord).xyz;
gl_FragColor = raytrace(inCoords,exitPoint);
}
I am using an VBO for rendering a color cube as entry and exist point for my rays. They are stored in FBOs and they look ok when I render them directly to the screen.
I have tried chaning to glBegin/glEnd and draw the cube with quads and then I get the same errors.
I cant find what I am doing wrong and now I need your help. Why is my texture3D generating GL_INVALID_OPERATION?
Note:
I have enabled both 2d and 3d textures.
Edit:
I've just uploaded the whole project to github. browse to for more code https://github.com/r-englund/rGraphicsLibrary
This is tested on both Intel HD 3000 and Nvidia GT550m
According to OpenGL specification glDrawElements() generates GL_INVALID_OPERATION in the following cases:
If a geometry shader is active and mode is incompatible with the input primitive type of the geometry shader in the currently installed program object.
If a non-zero buffer object name is bound to an enabled array or the element array and the buffer object's data store is currently mapped.
This means the problem has nothing to do with your fragment shader. If you don't use geometry shaders, you should fix the buffer objects accordingly.
It looks like your are not providing additional relevant information in your question.