Bug 692

Summary: Spurious exception thrown when using Vertex Array Objects (VAO) and glDrawElements
Product: [JogAmp] Jogl Reporter: Edgar Velazquez-Armendariz <edgarv.dev>
Component: openglAssignee: Sven Gothel <sgothel>
Status: UNCONFIRMED ---    
Severity: normal CC: fredrik, gouessej
Priority: P3    
Version: 2   
Hardware: pc_x86_64   
OS: windows   
Type: DEFECT SCM Refs:
594329b4334e453a3f0b7bb6f576a6e943263f95 d7096cfeee500177db85d97241cc142af41517cb b414c4b1be05249590138e73558ada82bd170f15 10b2f2219306746f3a3af6043717f42ae32c31e3
Workaround: ---
Attachments: Stand-alone test program

Description Edgar Velazquez-Armendariz 2013-02-19 06:51:46 CET
Created attachment 411 [details]
Stand-alone test program

When calling glDrawElements after binding a Vertex Array Object which contains bindings for both ARRAY_BUFFER and ELEMENT_ARRAY_BUFFER jogl throws a GLException with the message “element vertex_buffer_object must be enabled to call this method”. According to the OpenGL 3.2 core spec, this behavior is incorrect. A workaround is binding the ELEMENT_ARRAY_BUFFER again after binding the VAO. To reproduce:

1) Setup VAO:
    glBindVertexArray(vao);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
    // glEnableVertexAttribArray + glVertexAttribPointer …
    glBindVertexArray(0);

2) Upon drawing, this throws a GLException:
    glBindVertexArray(vao);
    glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, 0L);
    glBindVertexArray(0);

3) The expected behavior is for glDrawElements to succeed.

4) Workaround:
    glBindVertexArray(vao);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); // This shouldn't be necessary
    glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, 0L);
    glBindVertexArray(0);

Online I found only one reference to this issue, on a forum post without replies from 2009: http://www.java-gaming.org/index.php?topic=21093.0

In the self-contained example program submitted as an attachment I call directly the native entry point for glDrawElements through reflection, thus avoiding the buffer checks which throw the exception. This way the call succeeds and behaves as expected.

I am using jogl 2.0 rc11 (javax.media.opengl implementation version 2.0-b66-20121101) with Java 7u13 64-bit on Windows 7. The GPU is the NVIDIA Quadro 1000M with drivers version 311.00.
Comment 1 Edgar Velazquez-Armendariz 2013-02-20 03:12:56 CET
The results of the test program are the same on an Intel HD Graphics 3000 GPU, driver version 9.17.10.2932 (Windows 7 64-bit.)
Comment 2 Sven Gothel 2013-02-21 11:13:16 CET
Thank you Edgar.

Yes indeed - I see that our VBO validation is wrong is using VAO (ctx  >= GL3.1).
Either we have to skip VBO tracking [maybe if VAO is in use], 
or would need to add full VAO/VBO tracking .. which I don't favor ofc.

Let me look at the details next week.
Comment 3 Sven Gothel 2013-04-14 02:23:56 CEST
.. working on it now ..
Comment 4 Sven Gothel 2013-04-14 06:32:24 CEST
Add modified version of Edgar Velazquez-Armendariz's test case for testing alternating VAO and VBO usage.
    
    Alternating VBO/VAO usage triggers bug 692, where our VBO enable check throws an exception:

      javax.media.opengl.GLException: element vertex_buffer_object must be enabled to call this method
            at jogamp.opengl.gl4.GL4bcImpl.checkBufferObject(GL4bcImpl.java:34318)
            at jogamp.opengl.gl4.GL4bcImpl.checkElementVBOEnabled(GL4bcImpl.java:34361)
            at jogamp.opengl.gl4.GL4bcImpl.glDrawElements(GL4bcImpl.java:4395)
            at javax.media.opengl.DebugGL3.glDrawElements(DebugGL3.java:1006)
            at com.jogamp.opengl.test.junit.jogl.acore.TestBug692GL3VAO$GL3VAODemo.displayVAONormal(TestBug692GL3VAO.java:254)

+++

Add tracking of VERTEX_ARRAY_BINDING, and enable allowing a bound non default VAO 
to pass VBO enabled test, even if VBO is disabled.
    
  VAO is available if: GL >= 3.0 or is having GL_ARB_vertex_array_object extension.
    
  checkBufferObject(..) checks whether VERTEX_ARRAY_BINDING has a non default VAO bound 
  in case no VBO is being bound and VAO is allowed.
    
  glBindVertexArray(int) is being tracked, i.e. on state VERTEX_ARRAY_BINDING
Comment 5 Fredrik Tolf 2013-07-31 22:31:19 CEST
From what I can see, only one side of the problem has been fixed. JOGL now seems to properly understand that an element buffer has been bound when I bind a VAO that previously had such a buffer attached.

However, when I unbind the VAO (that is, when I call gl.glBindVertexArray(0)), JOGL does not seem to track that the element buffer associated with the previous VOA is now unbound, and I get the following exception when I try to call glDrawElements with an element buffer in an ordinary java.nio Buffer:

Caused by: javax.media.opengl.GLException: element vertex_buffer_object must be disabled to call this method
        at jogamp.opengl.gl4.GL4bcImpl.checkBufferObject(GL4bcImpl.java:37273)
        at jogamp.opengl.gl4.GL4bcImpl.checkElementVBODisabled(GL4bcImpl.java:37296)
        at jogamp.opengl.gl4.GL4bcImpl.glDrawElements(GL4bcImpl.java:4675)
        at haven.FastMesh.cdraw(FastMesh.java:103) <-- My program
        ...

It starts working if I just add a call to glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, 0) whenever I call glBindVertexArray(0), but it does not seem to me that the should be necessary.
Comment 6 Fredrik Tolf 2013-07-31 22:34:16 CEST
By the way, I'm using 2.0.2, which the website currently links to as both jogamp-current and jogamp-next.
Comment 7 Sven Gothel 2013-11-01 05:25:23 CET
10b2f2219306746f3a3af6043717f42ae32c31e3

Comment 5 [seems] to be invalid:

    + * Note that VAO initialization does unbind the VBO .. since otherwise they are still bound
    + * and the CPU_SRC test will fail!<br/>
    + * The OpenGL spec does not mention that unbinding a VAO will also unbind the bound VBOs
    + * during their setup.<br/>
    + * Local tests here on NV and AMD proprietary driver resulted in <i>no ourput image</i>
    + * when not unbinding said VBOs before the CPU_SRC tests.<br/>
    + * Hence Bug 692 Comment 5 is invalid, i.e. <https://jogamp.org/bugzilla/show_bug.cgi?id=692#c5>,
    + * and we should throw an exception to give users a hint!
Comment 8 Fredrik Tolf 2013-11-01 06:12:51 CET
(In reply to comment #7)
>     + * The OpenGL spec does not mention that unbinding a VAO will also
> unbind the bound VBOs

The vertex_array_object extension[1] states that a VAO tracks all the state in tables 6.6, 6.7 and 6.8 from the OpenGL 2.1 specification[2], excepting only the CLIENT_ACTIVE_TEXTURE and ARRAY_BUFFER_BINDING state. Table 6.8 does however also contain ELEMENT_ARRAY_BUFFER_BINDING state.

That should imply that the OpenGL spec implies that the element array buffer should be unbound when rebinding a VAO that had no bound such state, shouldn't it?

  [1]: http://www.opengl.org/registry/specs/ARB/vertex_array_object.txt
  [2]: www.opengl.org/registry/doc/glspec21.20061201.pdf‎
Comment 9 Sven Gothel 2013-11-01 09:01:38 CET
(In reply to comment #8)
> (In reply to comment #7)
> >     + * The OpenGL spec does not mention that unbinding a VAO will also
> > unbind the bound VBOs
> 
> The vertex_array_object extension[1] states that a VAO tracks all the state
> in tables 6.6, 6.7 and 6.8 from the OpenGL 2.1 specification[2], excepting
> only the CLIENT_ACTIVE_TEXTURE and ARRAY_BUFFER_BINDING state. Table 6.8
> does however also contain ELEMENT_ARRAY_BUFFER_BINDING state.
> 
> That should imply that the OpenGL spec implies that the element array buffer
> should be unbound when rebinding a VAO that had no bound such state,
> shouldn't it?
> 
>   [1]: http://www.opengl.org/registry/specs/ARB/vertex_array_object.txt
>   [2]: www.opengl.org/registry/doc/glspec21.20061201.pdf‎


I read the 3.2 and 4.4 spec (w/ compatibility) and yes, they are _tracked_,
but it doesn't explicitly state that unbinding clears them if 'manually' bound earlier (for VAO setup).
At least I couldn't find such statement.

However, I tested the clearing, you can see this in the unit test change and GLBufferStateTracker,
but got no visible result :(

Long story short: Can you try to patch GLBufferStateTracker
(enable the clearance .. and clear the states you think which should be cleared
by unbinding a VAO .. w/ your above reference) and the unit tests init_vao().
If you got 'visible' results .. we can go from there.

Or .. if you have a better unit tests, please provide it.

Today is 2.1.2 .. release, maybe we can get this in .. if working, 
otherwise .. next release.

Thank you!
Comment 10 Fredrik Tolf 2014-01-03 21:40:20 CET
I finally got this tested. Instead of trying to understand JOGL's build system to patch the tests, I wrote a small test program i C. You can get it at <http://www.dolda2000.com/~fredrik/tmp/vaotest.c>. It uses SDL for the window system interface.

It does seem to work quite fine for me. As you can see, I never explicitly unbind the GL_ELEMENT_ARRAY_BUFFER binding, but simply reset the VAO binding to 0. I also explicitly leave the first vertex unused in the triangle that I draw from memory, just to make sure that the element arrays are different for the VAO triangle and the client-memory triangle.

Also, this makes sense to me, seeing as how OpenGL seems to define glBindVertexArray(0) not as "unbinding" the VAO, but simply as rebinding the default VAO (named 0), which should already be tracking its own GL_ELEMENT_ARRAY_BUFFER binding as being unbound.

I'm therefore reopening the bug, if you don't bind.