PDA

View Full Version : Problems with shaders and their context's



Elberion
20th June 2011, 20:00
Hi!
I am doing an application that renders different views of an object. I do the rendering of the objects i have in a modified QGLWidget(glWidget). So to have different views of the objects that i render, i instantiate glWidget X Times with different id's.
Getting to the point glWidget has a shader, that does phong shading and the problem is, that when i run more than one view(more than one instantiation of glWidget), only the first glWidget shows the correct shader. The other 3 give a warning message:
QGLShaderProgram::bind: program is not valid in the current context.

Here is how i instantiate glWidget:


GLWidget *topleft = new GLWidget(1);
GLWidget *topright = new GLWidget(2);
GLWidget *botleft = new GLWidget(3);
GLWidget *botright = new GLWidget(4);

And here is how i create the shader program:

shaderProgram = new QGLShaderProgram(context());

So every instantiation of GLWidget should have a different context and (because its a different object) a different shader, so it should work?

Can someone see the problem, or how it is to be solved?

Thanks,
Elbe

stampede
20th June 2011, 22:30
Have you tried to call makeCurrent() before creating shader ?

Elberion
21st June 2011, 01:26
If i put this for the widget itself, with all the id's, it doesnt work at all.
If i just put it for widget with id 1 it works only for id one. As before.

stampede
21st June 2011, 09:32
Can you post some code ? Where are the shaders created, in the initializeGL() method ?
Does it work if you use different shader for each widget ?

Elberion
21st June 2011, 12:54
Shader is created in inicializeGL funktion:


shaderProgram = new QGLShaderProgram(context());

shaderProgram->addShaderFromSourceFile(QGLShader::Vertex,"../phong.vert");
shaderProgram->addShaderFromSourceFile(QGLShader::Fragment,"../phong.frag");
shaderProgram->link();

shaderProgram is a private QGLShaderProgram.
This is what every instantiation of GLWidget calls.

I also have buttons to change between visualisations. Here the slots(in GLWidget)


void GLWidget::setWireframe()
{
shaderProgram->release();
//glEnable(GL_LIGHTING);
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
activateShader =false;
scene->activateShader(currentPrimitive,false);
updateGL();
}
void GLWidget::setFlat()
{
shaderProgram->release();
//glEnable(GL_LIGHTING);
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
glShadeModel(GL_FLAT);
activateShader =false;
scene->activateShader(currentPrimitive,false);
updateGL();
}

void GLWidget::setGouraud()
{
shaderProgram->release();
//glEnable(GL_LIGHTING);
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
glShadeModel(GL_SMOOTH);
activateShader =false;
scene->activateShader(currentPrimitive,false);
updateGL();
}

void GLWidget::setPhong()
{
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
shaderProgram->bind();
activateShader =true;
scene->activateShader(currentPrimitive,true);
updateGL();
}

So these are the bind that through the Warning:
QGLShaderProgram::bind: program is not valid in the current context.

What do you mean with different shader for each widget?

Thanks very much for answering!
Elbe

stampede
21st June 2011, 13:06
Never mind, I thought that the shader is somehow shared, my mistake.
Try calling makeCurrent() at the beginning of each setWireFrame, setFlat etc. method, maybe the first opengl context stays current the whole time.

Elberion
21st June 2011, 13:25
Stays the same, the first instantiation of glWidget show the shader as it has to be, the other three just give the wrong context warning message.

stampede
21st June 2011, 13:37
Ok, and how is the activateShader implemented ?

Elberion
21st June 2011, 14:01
It is just setting a private boolean to true or to false depending on if we want to use the shader or not.
So if this boolean is true, in an object render function i send a uniform value to the shader, that is basicaly the color.

stampede
21st June 2011, 14:15
I see that you release the shader, but can you post the code where you actually bind it ?

Elberion
21st June 2011, 14:21
void GLWidget::setPhong()
{
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
shaderProgram->bind();
activateShader =true;
scene->activateShader(currentPrimitive,true);
updateGL();
}

stampede
21st June 2011, 14:33
Oh yes, I haven't noticed that. So when is setPhong called ? Is makeCurrent() called before calling shader->bind() ?
I was little confused, I thought that you are setting shaders in setWireFrame, setGouraud as well. If setPhong is the only place where you call bind(), make sure you made OpenGL context current before binding the shader.
edit:
makeCurrent should be called explicitly before any method that does OpenGL calls, except for initializeGL, updateGL and renderGL, so makeCurrent() at first line of setPhong().

Elberion
21st June 2011, 16:27
Thank you very much, that was it!
It was all about setting that makeCurrent in the right place!
Thanks again!

stampede
21st June 2011, 16:34
Great, no problem ;)