OpenGL: INVALID_OPERATION following glEnableVertexAttribArray
c++, macos, opengl, xcode5
Solution
You're seeing this error on OS X because it only supports the OpenGL Core Profile if you're using OpenGL 3.x or higher. Your code is not Core Profile compliant. You were most likely using the Compatibility Profile on Windows.
Specifically, the Core Profile requires a Vertex Array Object (VAO) to be bound for all vertex related calls. So before calling `glEnableVertexAttribArray()`, or other similar functions, you will need to create and bind a VAO:
GLuint vaoId = 0;
glGenVertexArrays(1, &vaoId);
glBindVertexArray(vaoId);
On how to find out the error conditions: In this case, it's not nearly as easy as it should be. Let's say you work with a GL3 level feature set. In an ideal world, you would go to www.opengl.org, pull down the "Documentation" menu close to the top-left corner, choose "OpenGL 3.3 Reference Pages", click on `glEnableVertexAttribArray` in the left pane, and look at the "Errors" section on the page. Then you see that... `GL_INVALID_OPERATION` is not listed as a possible error.
Next, you might want to check if there's anything better in the latest version. You do the same, but choose "OpenGL 4 Reference Pages" instead. The error condition is still not listed.
By now you realize, like many before you, that these man pages are often faulty. So you go to the ultimate source: the specs. This time you choose "OpenGL Registry" in the Documentation menu. This gives you links to all the spec documents in PDF format. Again, let's try 3.3 first. Search for "EnableVertexAttribArray" in the document and there is... still no `GL_INVALID_OPERATION` documented as a possible error.
Last resort, checking the very latest spec document, which is 4.4. Again looking for "EnableVertexAttribArray", it's time for a heureka:
An INVALID_OPERATION error is generated if no vertex array object is bound.
I'm quite certain that the error also applies to GL3. While it's reasonably common for the man pages to be incomplete, it's much rarer for the spec documents to be missing things. The very closely related `glVertexAttribPointer()` call has this error condition documented in GL3 already.
Problem
I'm porting a functioning OpenGL app from Windows to OSX, and keep getting an "invalid operation" (code 1282) error after calling `glEnableVertexAttribArray()`. Here's the render method: ``` gl::Disable(gl::DEPTH_TEST); gl::Disable(gl::CULL_FACE); gl::PolygonMode(gl::FRONT_AND_BACK,gl::FILL); /// render full-screen quad gl::UseProgram(m_program); check_gl_error(); gl::BindBuffer(gl::ARRAY_BUFFER, m_vertexBuffer); gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, m_indexBuffer); check_gl_error(); GLint positionLocation = -1; positionLocation = gl::GetAttribLocation(m_program,"Position"); check_gl_error(); /// positionLocation now == 0 gl::EnableVertexAttribArray(positionLocation); //// ************ ERROR RETURNED HERE ********************** //// ************ ERROR RETURNED HERE ********************** check_gl_error(); gl::VertexAttribPointer(positionLocation,3,gl::FLOAT,false,3 * sizeof(GLfloat),(const GLvoid*)0); check_gl_error(); gl::DrawElements(gl::TRIANGLES,m_indexCount,gl::UNSIGNED_SHORT,0); check_gl_error(); gl::BindBuffer(gl::ARRAY_BUFFER,0); check_gl_error(); gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER,0); check_gl_error(); ``` `check_gl_error()` just gets the last GL error and returns a somewhat-readable description thereof. This code works fine under Windows. But, as I'm rapidly learning, that doesn't necessarily mean that it is correct. I've verified that all of the previously-bound objects (program, vertex buffer, index buffer) are valid handles. `glGetAttribLocation()` returns a valid location (0 in this case) for the `Position` attribute. What are the failure cases for `glEnableVertexAttribArray()`? Is there some state that I've not set before this? If I comment out the draw code, the window is cleared to my test color (red) (called from a method not shown in the code snippet) on every frame and everything else works fine, which implies that everything else is correct. Suggestions? Oh, for a GL state machine simulator that would tell me why it is an "invalid operation." (Or a reference to some mystical, magical documentation that describes required input state for each gl* call.)