Compute shader doesn't change texture - c++

I'm trying currently to change the color of a texture to black with a compute shader, but it doesn't work and i don't find why. There is no problem with the shader compilation, neither with the program linking, so i think that the problem is in the update of the shader. Here's my code :
Update :
glUseProgram(m_programID);
int location = glGetUniformLocation(m_programID, "img_out");
glUniform1i(location, 0);
glBindImageTexture(0, texID, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
glDispatchCompute(1024, 1024, 1);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
int format;
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &format);
unsigned char* img = new unsigned char[1024 * 1024 * 4];
glGetTexImage(GL_TEXTURE_2D, 0, format, GL_UNSIGNED_BYTE, img);
int i = SOIL_save_image("img.bmp", SOIL_SAVE_TYPE_BMP, 1024, 1024, 4, img);
std::cout << SOIL_last_result() << std::endl;
delete[] img;
glUseProgram(0);
Shader :
#version 450 core
layout(local_size_x = 1, local_size_y = 1) in;
layout(binding = 0, RGBA32F) uniform image2D img_out;
void main()
{
ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
imageStore(img_out, pos, vec4(0.f, 0.f, 0.f, 1.f));
}
ps : texture used here is an image loaded with soil but does it matter?

Related

Why there is no output to the framebuffer's textures?

Here is the code:
int main(){
//init gl environment
//...
//create textures for pass 1
GLuint normal_color_output;
glCreateTextures(GL_TEXTURE_2D_MULTISAMPLE, 1, &normal_color_output);
glTextureStorage2DMultisample(normal_color_output, 8, GL_RGBA32F, 1000, 800, GL_TRUE);
GLuint high_color_output;
glCreateTextures(GL_TEXTURE_2D_MULTISAMPLE, 1, &high_color_output);
glTextureStorage2DMultisample(high_color_output,8, GL_R11F_G11F_B10F, 1000, 800,GL_TRUE);
//init framebuffer
GLuint render_buffer;
glCreateRenderbuffers(1, &render_buffer);
glNamedRenderbufferStorageMultisample(render_buffer, 8, GL_DEPTH24_STENCIL8, 1000, 800);
GLuint framebuffer;
glCreateFramebuffers(1, &framebuffer);
glNamedFramebufferTexture(framebuffer, GL_COLOR_ATTACHMENT0, normal_color_output,0);
glNamedFramebufferTexture(framebuffer, GL_COLOR_ATTACHMENT1, high_color_output, 0);
glNamedFramebufferRenderbuffer(framebuffer, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, render_buffer);
const GLenum drawbuffers[] = {GL_COLOR_ATTACHMENT0,GL_COLOR_ATTACHMENT1};
glNamedFramebufferDrawBuffers(framebuffer, 2, drawbuffers);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
//init another framebuffer
//What I want to do is trying to achieve implementing my own msaa color resolve solution.
GLuint mix_framebuffer;
glCreateFramebuffers(1, &mix_framebuffer);
GLuint mix_renderbuffer;
glCreateRenderbuffers(1, &mix_renderbuffer);
glNamedRenderbufferStorage(mix_renderbuffer, GL_DEPTH24_STENCIL8, 1000, 800);
GLuint normal_antialiasing_texture, hdr_antialiasing_texture;
glCreateTextures(GL_TEXTURE_2D, 1, &normal_antialiasing_texture);
glTextureStorage2D(normal_antialiasing_texture, 1, GL_RGBA32F, 1000, 800);
glCreateTextures(GL_TEXTURE_2D, 1, &hdr_antialiasing_texture);
glTextureStorage2D(hdr_antialiasing_texture, 1, GL_RGBA32F, 1000, 800);
glNamedFramebufferTexture(mix_framebuffer, GL_COLOR_ATTACHMENT0, normal_antialiasing_texture, 0);
glNamedFramebufferTexture(mix_framebuffer, GL_COLOR_ATTACHMENT1, hdr_antialiasing_texture, 0);
glNamedFramebufferDrawBuffers(mix_framebuffer,2, drawbuffers);
glNamedFramebufferRenderbuffer(mix_framebuffer, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, mix_renderbuffer);
glBindFramebuffer(GL_FRAMEBUFFER, mix_framebuffer);
//....
//draw commands
while (!glfwWindowShouldClose(window)) {
// pass 1
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glUseProgram(program);
glUniformMatrix4fv(3, 1, GL_FALSE, glm::value_ptr(camera.GetViewMat()));
model.Render(program);
glPointSize(20.f);
glUseProgram(light_shader);// I draw a point to show the light's position
glUniformMatrix4fv(0, 1, GL_FALSE, glm::value_ptr(camera.GetViewMat()));
glDrawArrays(GL_POINTS, 0, 1);
//pass 2
glBindFramebuffer(GL_FRAMEBUFFER, mix_framebuffer);
glUseProgram(mix_program);
glBindTextureUnit(0, normal_color_output);
glBindTextureUnit(1, high_color_output);
glClear(GL_COLOR_BUFFER_BIT);
glNamedFramebufferDrawBuffers(mix_framebuffer, 2, drawbuffers);
glDrawArrays(GL_POINTS, 0, 1);
//...
}
}
I use geometry shader to model a square, here is the code:
//mix_gs.glsl
#version 450 core
layout(points) in;
layout(triangle_strip) out;
layout(max_vertices = 4) out;
void main(){
gl_Position = vec4(-1,1,-1,1);
EmitVertex();
gl_Position = vec4(-1,-1,-1,1);
EmitVertex();
gl_Position = vec4(1,1,-1,1);
EmitVertex();
gl_Position = vec4(1,-1,-1,1);
EmitVertex();
EndPrimitive();
}
here is the mix_fs.glsl:
#version 450 core
layout(location = 0)out vec4 color;
layout(location = 1)out vec4 hdr_color;
layout(binding = 0) uniform sampler2DMS color_sdms;
layout(binding = 1) uniform sampler2DMS hdr_sdms;
void main(){
/*
for(int i=0;i<8;i++){
color += texelFetch(color_sdms,ivec2(gl_FragCoord.xy),i);
hdr_color += vec4(texelFetch(hdr_sdms,ivec2(gl_FragCoord.xy),i).xyz,1);
}
*/
color = vec4(1,0,0,1);//I just output a color
hdr_color = vec4(0,1,0,1);
}
I encount a problem that I find during the draw pass 2, gl cannot outout any color to textures bind to mix_framebuffer.
Here is the debugging info in RenderDoc:
draw pass 1 texture output:
draw pass 2's geometry output:
draw pass 2 texture input:
draw pass 2 texture output:
You can see, draw-pass 1's output was passed to draw-pass2's pipeline successfully, but there is no output to draw-pass2's textures. I don't know why.
If you don't see even the plain color, the first I'd recommend to check how it was discarded. There are no so many options:
glColorMask. Highly likely it's not your case, since pass 1 works;
Wrong face culling and polygon winding order (CW, CCW). By your geometry shader, it looks like CW;
Blending options;
Depth-stencil state. I see you use glNamedRenderbufferStorage(mix_renderbuffer, GL_DEPTH24_STENCIL8, 1000, 800); What are depth-stencil settings?
If everything above looks good, any glGetError messages? If it's ok, try to remove MRT for a debugging purposes and output the only color in the second pass. If it would work, probably some error in MRT + Depth buffer setup.

Opengl Textures dont display but give corrupted double linked list error

I've been playing with textures for some time and i just can't get it to work
Here is the code
#include "App.h"
std::array <float, 4> background_col = {0.25, 0.25, 0.25, 1.0} ;
std::string name = "OpenGL" ;
std::string icon = "data/images/dot.png" ;
const int width = 800 ;
const int height = 800 ;
bool anti_aliasing = true ;
bool FPS_60_CAP = true ;
MVP mvp;
void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods)
{
}
void App::run()
{
Window window(true, anti_aliasing);
window.make_Window(glfwCreateWindow(width, height, name.c_str(), NULL, NULL), key_callback, icon);
srand(time(NULL));
mvp.view = glm::ortho(0.0f, (float)width, 0.0f, (float)height);
Renderer renderer;
Player player;
// redesighn with errors in mind
// 1. TODO: Implement Text
// 2. TODO: Implement UI
std::vector<float> vertexes = {
200, 200, 1, 1, 1, 1, 0, 0,
200, 600, 1, 1, 1, 1, 0, 1,
600, 600, 1, 1, 1, 1, 1, 1,
600, 200, 1, 1, 1, 1, 1, 0
};
std::vector<uint32_t> indexes = {0, 1, 2, 3};
while (!glfwWindowShouldClose(window.window))
{
glClearColor(background_col[0], background_col[1], background_col[2], background_col[3]);
glClear(GL_COLOR_BUFFER_BIT);
warn(0);
Shader shader("shaders/text.shader");
shader.useShader();
warn(1);
Texture tex("data/images/dot.png");
tex.Bind();
warn(2);
shader.uniformMat4Float("u_projection_matrix", mvp.projection * mvp.view * mvp.model);
shader.uniformInt({0}, "tex");
warn(3);
VBO vbo;
VAO vao;
IBO ibo;
warn(4);
vbo.write(vertexes.data(), vertexes.size() * sizeof(float));
ibo.write(indexes.data(), indexes.size() * sizeof(uint32_t));
warn(5);
ibo.bind();
vbo.bind();
vao.bind();
warn(6);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 8, (const void *)(sizeof(float) * 0));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 8, (const void *)(sizeof(float) * 2));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 8, (const void *)(sizeof(float) * 6));
warn(7);
glDrawElements(GL_QUADS, indexes.size(), GL_UNSIGNED_INT, nullptr);
warn(8);
ibo.unbind();
vbo.unbind();
vao.unbind();
warn(9);
tex.unBind();
tex.~Texture();
warn(10);
vbo.~VBO();
vao.~VAO();
ibo.~IBO();
warn(11);
shader.deleteShader();
warn(12);
glfwSwapBuffers(window.window);
glfwSwapInterval(FPS_60_CAP);
glfwPollEvents();
}
alcCloseDevice(player.Device);
window.~Window();
}
the texture class:
#include "Core.h"
Texture::Texture(std::string path)
{
this->path = path;
this->bpp = 0;
this->height = 0;
this->width = 0;
this->localbuffer = nullptr;
this->TexID = 0;
stbi_set_flip_vertically_on_load(1);
localbuffer = stbi_load(path.c_str(), &width, &height, &bpp, 4);
glGenTextures(1, &TexID);
glBindTexture(GL_TEXTURE_2D, TexID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, localbuffer);
glBindTexture(GL_TEXTURE_2D, 0);
if (localbuffer) { stbi_image_free(localbuffer); }
else { info("h"); }
}
void Texture::Bind(uint32_t slot)
{
glActiveTexture(GL_TEXTURE0 + slot);
}
void Texture::unBind()
{
glBindTexture(GL_TEXTURE_2D, 0);
}
Texture::~Texture()
{
glDeleteTextures(1, &TexID);
}
and the shader:
#shader vertex
#version 400 core
layout (location = 0) in vec4 Pos;
layout (location = 1) in vec4 vColor;
layout (location = 2) in vec2 vTexCoord;
out vec4 color;
out vec2 TexCoord;
uniform mat4 u_projection_matrix;
void main()
{
gl_Position = u_projection_matrix * Pos;
color = vColor;
TexCoord = vTexCoord;
}
#shader fragment
#version 400 core
in vec4 color;
in vec2 TexCoord;
uniform sampler2D tex;
void main()
{
vec4 texcol = texture(tex, TexCoord);
gl_FragColor = texcol;
}
it just stays blank and displays this error
corrupted double-linked list
it is important to mention this error happens on the second frame
The code that I know works because I've got textures to display before correctly is:
the Shader class
VAO VBO and IBO
EDIT: after the fix from rafix07 it doesn't crash anymore it just doesn't display
EDIT2:
I've implemented glDebugMessageCallback, and it gives me this error:
source: 33352
type: 33361
id: 1
severity: 33387
length: 130
GL ERROR!: Shader Stats: SGPRS: 24 VGPRS: 24 Code Size: 72 LDS: 0 Scratch: 0 Max Waves: 10 Spilled SGPRs: 0 Spilled VGPRs: 0 PrivMem VGPRs: 0
Remove all explicit invocations of destructors, like:
tex.~Texture();
You get corrupted double-linked list because you deallocate a resource twice: first time by calling destructor explicitly and the second one when destructor is called at the end of scope within object is defined.
{
Texture tex;
// ...
tex.~Texture(); // texture is deallocated and id texture is dangling reference
// <-- dtor of tex is called implicitly, and the same id texture is deleted again leading to crash
}

Why always produce 4 pictures in my qt opengl program?

Here is my code:
modify from qt example: Examples\Qt-5.14.2\quick\scenegraph\openglunderqml
void SquircleRenderer::init()
{
unsigned char* data = (unsigned char*)malloc(1200*4);
for(int i=0;i<600;i++)
{
data[i*4] = 0;
data[i*4+1] = 255;
data[i*4+2] = 0;
data[i*4+3] = 255;
}
for(int i=600;i<1200;i++)
{
data[i*4] = 0;
data[i*4+1] = 0;
data[i*4+2] = 255;
data[i*4+3] = 255;
}
if (!m_program) {
QSGRendererInterface *rif = m_window->rendererInterface();
Q_ASSERT(rif->graphicsApi() == QSGRendererInterface::OpenGL || rif->graphicsApi() == QSGRendererInterface::OpenGLRhi);
initializeOpenGLFunctions();
if (texs[0])
{
glDeleteTextures(1, texs);
}
glGenTextures(1, texs);
glBindTexture(GL_TEXTURE_2D, texs[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 30, 40, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
m_program = new QOpenGLShaderProgram();
m_program->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex,
"attribute highp vec4 vertices;"
"varying highp vec2 coords;"
"void main() {"
" gl_Position = vertices;"
" coords = vertices.xy;"
"}");
m_program->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment,
"varying highp vec2 coords;"
"uniform sampler2D inputImageTexture;"
"void main() {"
" gl_FragColor = texture2D(inputImageTexture, coords);"
"}");
m_program->bindAttributeLocation("vertices", 0);
m_program->link();
arrUni[0] = m_program->uniformLocation("inputImageTexture");
}
}
//! [4] //! [5]
void SquircleRenderer::paint()
{
// Play nice with the RHI. Not strictly needed when the scenegraph uses
// OpenGL directly.
m_window->beginExternalCommands();
m_program->bind();
m_program->enableAttributeArray(0);
float values[] = {
-1, 1,
1, 1,
-1, -1,
1, -1
};
// This example relies on (deprecated) client-side pointers for the vertex
// input. Therefore, we have to make sure no vertex buffer is bound.
glBindBuffer(GL_ARRAY_BUFFER, 0);
m_program->setAttributeArray(0, GL_FLOAT, values, 2);//values
//m_program->setUniformValue("t", (float) m_t);
qDebug()<<m_viewportSize.width()<<m_viewportSize.height()<<"\n";
glViewport(0, 0, m_viewportSize.width(), m_viewportSize.height());
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texs[0]);
glUniform1i(arrUni[0], 0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
m_program->disableAttributeArray(0);
m_program->release();
m_window->endExternalCommands();
}
As the picture you can see,it produces 4 same pictures,could you tell me how to produce 1 picture fill the whole window?:
I tried so many methods, but it didn't work, I guess the problem exists in the values array or the glTexImage2D function.
Textures are mapped accross the [0, 1] range, and values outside of that range are modulo-looped back into it, which creates a repeating pattern. Interpreting the texture over the [-1, 1] range leads to what you are seeing since you are mapping exactly twice the UV range in both axises.
There's a few ways to fix this. But my personal preference for a full-framebuffer pass like this is to have the attribute be normalized, and then have it converted to the expected [-1, 1] range for the clip-space coordinate in the vertex shader:
float values[] = {
0.f, 1.f,
1.f, 1.f,
0.f, 0.f,
1.f, 0.f
};
gl_Position = vertices * 2.0 - vec4(1.0, 1.0,0.0,1.0);
Another common technique is to do away with the attribute buffer altogether, and use gl_VertexID to directly generate both the UVs and coordinates.

Can I use three-dimensional compute shader to write to a three-dimensional image

define a three-dimensional Texture and dispatch compute
glTexStorage3D(GL_TEXTURE_3D, 1, GL_RGBA32F, SCREEN_WIDTH, SCREEN_HEIGHT, TEXTURE_DEPTH);
glBindImageTexture(0, m_Texture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
glDispatchCompute(16, 16, 2);
compute shader
#version 450
layout(local_size_x = 32,local_size_y = 32, local_size_z = 2) in;
layout(binding = 0, rgba32f) uniform image3D Image;
void main()
{
ivec3 position = ivec3(gl_GlobalInvocationID.xyz);
vec4 color = vec4(gl_WorkGroupID / vec3(gl_NumWorkGroups), 1.0);
imageStore(Image, position, color);
}
but the code doesn't work, I want to konw the value of gl_GlobalInvocationID.z is the depth of space
I had solved this probelm, the parameters of glDispatchCompute() is x,y,z, ifxyzlocal_size_xlocal_size_ylocal_size_z > screensize.xscreensize.y, it cannot work, so I downsample the texture resolution.

Open gl draw turns white after one frame drawn

I am newbie in Opengl. I used the following example from Qt as a start in Opengl as I know Qt.
http://doc.qt.io/qt-5/qtquick-scenegraph-openglunderqml-squircle-cpp.html
I replaced the paint function of the program with following code with an intent to draw chess board pattern. Following is not the paint or render function of my program
paint()
{
if (!m_program) {
initializeOpenGLFunctions();
m_program = new QOpenGLShaderProgram();
m_program->addShaderFromSourceCode(QOpenGLShader::Vertex,
"attribute highp vec4 vertices;"
"varying highp vec2 coords;"
"void main() {"
" gl_Position = vertices;"
" coords = vertices.xy;"
"}");
m_program->addShaderFromSourceCode(QOpenGLShader::Fragment,
"uniform lowp float t;"
"varying highp vec2 coords;"
"void main() {"
" lowp float i = 1. - (pow(abs(coords.x), 4.) + pow(abs(coords.y), 4.));"
" i = smoothstep(t - 0.8, t + 0.8, i);"
" i = floor(i * 20.) / 20.;"
" gl_FragColor = vec4(coords * .5 + .5, i, i);"
"}");
m_program->bindAttributeLocation("vertices", 0);
m_program->link();
}
auto width = static_cast<float>(m_viewportSize.width());
auto height = static_cast<float>(m_viewportSize.height());
auto a = 2.f / width;
auto b = 2.f / height;
std::vector<float> matrix =
{
a , 0, 0, 0,
0, -b, 0, 0,
0, 0, 1, 0,
-1, 1, 0, 1
};
// Set the projection matrix
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(matrix.data());
// Initialize vertices:
std::vector<float> vertices =
{
0, 0,
0, height,
width, height,
width, 0
};
// Initialize colors
std::vector<float> colors =
{
1, 0, 0,
0, 1, 0,
0, 0, 1,
0, 1, 1
};
// Initialize texture virtice
std::vector<float> texCoord =
{
0, 0,
0, 1,
1, 1,
1, 0
};
// Create texture: simple chess board 8x8
auto numRows = 8u;
auto numCols = 8u;
auto character = 172u;
auto remain = 255u - character;
std::vector<unsigned char> texture(numCols * numRows);
for (auto i = 0u; i < texture.size(); ++i)
texture[i] = ((i + (i / numCols)) % 2) * remain + character;
// Upload to GPU texture
unsigned textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, numCols, numRows, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, texture.data());
// Initialize clear colors
glClearColor(0.f, 0.f, 0.f, 1.f);
// Activate necessary states
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vertices.data());
glColorPointer(3, GL_FLOAT, 0, colors.data());
glTexCoordPointer(2, GL_FLOAT, 0, texCoord.data());
// render
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_QUADS, 0, 4);
m_program->disableAttributeArray(0);
m_program->release();
m_window->resetOpenGLState();
}
The chess board is drawn. But its drawn for a split second & then the screen turns fully white. I want to draw the chess board pattern continiously with each frame draw.
Can someone pls point out what might be going wrong ?
At the very top you have:
if (!m_program) {
then you initialize m_program, at the very bottom you have:
m_program->release();
which as Harish in comments points out is equivalent to calling glUseProgram(0);. So in the next iteration of paint your shader is not bound and not available.
According to docs, the reverse of release(); is bind(); so (I am not expert on this class) the solution might be to call QOpenGLShaderProgram::bind() on the next iteration of your paint.
For future reference, it's a good idea to run opengl programs through a graphics debugger like gDEbugger to give you an insight into what's actually happening inside the API.