VAO and attrib pointers to multiple shader progs

Hello, I was wondering, is a VAO supposed to be able to keep track of shader attribute pointers to multiple programs?
I.e. consider the following code:


glGenBuffers(1, &model.vertices);
glBindBuffer(GL_ARRAY_BUFFER, model.vertices);
glBufferData(GL_ARRAY_BUFFER, model.n_vertices*4*sizeof(float), shape.vertices, GL_STATIC_DRAW);
glUseProgram(drawprog.program);
glVertexAttribPointer(drawprog.vertexLocation, 4, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(drawprog.vertexLocation);
glUseProgram(shadowprog.program);
glVertexAttribPointer(shadowprog.vertexLocation, 4, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(shadowprog.vertexLocation);
	
glGenBuffers(1, &model.normals);
glBindBuffer(GL_ARRAY_BUFFER, model.normals);
glBufferData(GL_ARRAY_BUFFER, model.n_vertices*3*sizeof(float), shape.normals, GL_STATIC_DRAW);
glUseProgram(drawprog.program);
glVertexAttribPointer(drawprog.normalLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(drawprog.normalLocation);
	
glGenBuffers(1, &model.indices);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, model.indices);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, model.n_indices*sizeof(unsigned), shape.indices, GL_STATIC_DRAW);
	
glBindVertexArray(0);

This code renders correctly with nVidia proprietary drivers, but fails with ATI proprietary drivers as well as intel mesa drivers. Specifically, the shadowprog only draws the last of a list of primitives aka. models, while the drawprog draws correctly. If I comment out the block setting the normal attribute pointer for the drawprog, the shadowprog draws correctly on all GPUs (the drawprog obviously not).
Can anyone clarify?
Thanks!
smani

glUseProgram is not a part of the VAO/VBO state and hence nothing about it is stored in the VAO. So depending on the actual values of drawprog.vertexLocation, drawprog.normalLocation, and shadowprog.vertexLocation you are probably overwriting one of the attribute’s “enabled” state. Does the following code work for you?


GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);

glGenBuffers(1, &model.vertices);
glBindBuffer(GL_ARRAY_BUFFER, model.vertices);
glBufferData(GL_ARRAY_BUFFER, model.n_vertices*4*sizeof(float), shape.vertices, GL_STATIC_DRAW);
	
glGenBuffers(1, &model.normals);
glBindBuffer(GL_ARRAY_BUFFER, model.normals);
glBufferData(GL_ARRAY_BUFFER, model.n_vertices*3*sizeof(float), shape.normals, GL_STATIC_DRAW);
	
glGenBuffers(1, &model.indices);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, model.indices);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, model.n_indices*sizeof(unsigned), shape.indices, GL_STATIC_DRAW);
	
glBindVertexArray(0);

… then when it comes to use the VAO with different Shader Programs


glBindVertexArray(vao);

glUseProgram(drawprog.program);
glBindBuffer(GL_ARRAY_BUFFER, model.vertices);
glVertexAttribPointer(drawprog.vertexLocation, 4, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(drawprog.vertexLocation);
glBindBuffer(GL_ARRAY_BUFFER, model.normals);
glVertexAttribPointer(drawprog.normalLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(drawprog.normalLocation);
draw(...);
glDisableVertexAttribArray(drawprog.vertexLocation);
glDisableVertexAttribArray(drawprog.normalLocation);

glUseProgram(shadowprog.program);
glBindBuffer(GL_ARRAY_BUFFER, model.vertices);
glVertexAttribPointer(shadowprog.vertexLocation, 4, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(shadowprog.vertexLocation);
draw(...);
glDisableVertexAttribArray(shadowprog.vertexLocation);

Thanks for your reply. Yes, enabling all attributes separately works fine. I tried now manually generating the location identifiers and setting them with glBindAttribLocation, before linking the program. Again, this generally works fine on a nvidia card, though of the two example programs I am playing with, one does not render correctly with an ati card.
If all manually provided location identifiers are unique and respect the fact that for instace for a 4x4 matrix, 4 identifiers are necessary, shouldn’t it work? Thanks!

I am a follower of Dark Photon’s advice, who advises us not to use VAO.

Why? VAO does reduce state switches, but the GL will usually still switch between VBO’s, which is supposedly expensive.

If you VBO cache, VAO is irrelevant, since you don’t know the pointers to attributes in advance.

If all manually provided location identifiers are unique and respect the fact that for instace for a 4x4 matrix, 4 identifiers are necessary, shouldn’t it work?

I haven’t tried that before so I cannot answer yes or no.

Ok thanks