Reputation: 11732
Currently, I call this function (simplified) everytime I want to switch shaders:
void switchToShader(ShaderProgram* newProg, Mesh& mesh) {
if(m_currentProg != nullptr) {
m_currentProg->disableAttributeArray("aPos");
}
newProg->enableAttributeArray("aPos");
mesh.vertexPosBuffer()->bind();
glVertexAttribPointer(newProg->attributeLocation("aPos"), 2, GL_FLOAT, false, 0, 0);
newProg->bind();
mesh.indexBuffer()->bind();
m_currentProg = newProg;
}
It seems needlessly inefficient though.
Note that this function is only intended to support switching between programs that have an identical set of attribute arrays.
Ideally, my code would look more like this:
ShaderProgram::ShaderProgram() {
// ...
enableAttributeArray("aPos");
glVertexAttribPointer(newProg->attributeLocation("aPos"), 2, GL_FLOAT, false, 0, 0);
}
void switchToShader(ShaderProgram* newProg, Mesh& mesh) {
mesh.vertexPosBuffer()->bind();
newProg->bind();
mesh.indexBuffer()->bind();
}
But for obvious reasons, this does not work.
Note that my class ShaderProgram
derives from Qt's QOpenGLShaderProgram.
Any hints how to make my code more efficient?
I'm aware that I could use glBindAttribLocation
to force the attrib array aPos
, at shader program initialization time, to use e.g. location 1
, for all my shader programs, and that would mean I can do enableAttributeArray
just once per frame and can skip the disableAttributeArray
. But that's a bit inelegant because it means writing a little extra code and passing my arbitrarily-chosen attrib locations around.
I'm currently looking into VAOs.
Edit: After making use of glBindAttribLocation and VAOs, my problem is solved. My code now looks like this:
void switchToShader(ShaderProgram* newProg, Mesh& mesh) {
newProg->bind();
mesh.vao()->bind();
m_currentProg = newProg;
}
And I can even bind the shader programs and the VAOs independently from each other, outside this function.
Upvotes: 0
Views: 63
Reputation: 474436
But that's a bit inelegant because it means writing a little extra code
Then put it in your shader with layout(location = #)
. That's not "inelegant"; tha'ts "putting the information where it goes".
and passing my arbitrarily-chosen attrib locations around.
And yet, you don't have a problem "passing my arbitrarily-choose attribute names around". There is no difference between "aPos" and 1, from the perspective of your code. You have to get some kind of identifier for that attribute to the VAO. In both cases, you could just hard-code it to a specific value; whether it's a string literal or an integer literal means nothing.
It's just that if you use an integer, you won't have to constantly recreate your VAO when you change programs.
The QT's API of putting VAO commands in the shader object is wrongheaded, and now you see exactly why. Programs should not be responsible for which attributes are enabled or where they come from.
You know how to solve your problem. So solve it.
Upvotes: 7