OpenGLException: Cannot use Buffers when Element Array Buffer Object is enabled

Home Forum Troubleshooting General OpenGLException: Cannot use Buffers when Element Array Buffer Object is enabled

This topic contains 8 replies, has 4 voices, and was last updated by  blobby 5 years, 9 months ago.

Viewing 9 posts - 1 through 9 (of 9 total)
  • Author
    Posts
  • #12248

    blobby
    0p
    Member

    Hello everybody,

    I have an issue with the VBO rendering. My scene draws some TriMesh with VBO enabled for the index buffer and also some lines with no VBO at all. Here is a simple example showing what I try to do:

    protected final void simpleInitGame() {
       
          Quad test = new Quad("VBOObject", 20.0f, 20.0f);
          VBOInfo vbi = new VBOInfo(true);
          vbi.setVBOIndexEnabled(true);
          test.setVBOInfo(vbi);
          rootNode.attachChild(test);
          
          FloatBuffer vertexBuffer = BufferUtils.createFloatBuffer(2 * 3);
          vertexBuffer.put(0);
          vertexBuffer.put(0);
          vertexBuffer.put(0);
          vertexBuffer.put(10);
          vertexBuffer.put(10);
          vertexBuffer.put(10);

          Line l = new Line("NoVBO", vertexBuffer, null, null, null);
          l.generateIndices();
          //Quad l = new Quad("NoVBOWithQuad", 30.0f, 20.0f);
          l.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT);
          l.updateRenderState();
          l.updateGeometricState(0.f, true);
          rootNode.attachChild(l);
       }

    If I execute this code, I have the following exception:


    org.lwjgl.opengl.OpenGLException: Cannot use Buffers when Element Array Buffer Object is enabled
       at org.lwjgl.opengl.GLChecks.ensureElementVBOdisabled(GLChecks.java:96)
       at org.lwjgl.opengl.GL11.glDrawElements(GL11.java:1074)
       at com.jme.renderer.lwjgl.LWJGLRenderer.draw(LWJGLRenderer.java:783)
       at com.jme.scene.Line.draw(Line.java:413)
       at com.jme.renderer.RenderQueue.renderTransparentBucket(RenderQueue.java:277)
       at com.jme.renderer.RenderQueue.renderBuckets(RenderQueue.java:238)
       at com.jme.renderer.Renderer.renderQueue(Renderer.java:379)
       at com.jme.renderer.lwjgl.LWJGLRenderer.displayBackBuffer(LWJGLRenderer.java:495)
       at com.jme.app.BaseGame.start(BaseGame.java:87)

    • This exception appears only when a line is drawn after a Trimesh with VBO enabled on index buffer
    • There is a exception even if I enable the VBO on the Line
    • There is no exception if I replace the line by a Quad or a TriMesh
    • There is no exception if I don't enable VBO on index buffer for the Quad

    In the predrawGeometry() method, there is the following code:


    if (g instanceof TriMesh) {
            if ((supportsVBO && vbo != null && vbo.getVBOIndexID() > 0)) { // use VBO
                indicesVBO = true;
                rendRecord.setBoundElementVBO(vbo.getVBOIndexID());
            } else if (supportsVBO) {
                rendRecord.setBoundElementVBO(0);
            }
    }

    Maybe the same thing for a line is necessary???  :?


    if (g instanceof TriMesh || g instanceof Line) {
            if ((supportsVBO && vbo != null && vbo.getVBOIndexID() > 0)) { // use VBO
                indicesVBO = true;
                rendRecord.setBoundElementVBO(vbo.getVBOIndexID());
            } else if (supportsVBO) {
                rendRecord.setBoundElementVBO(0);
            }
    }

    Could someone help me?  :)

    #91077

    gouessej
    109p
    Participant

    /** Helper method to ensure that element array buffer objects are disabled. If they are enabled, we'll throw an OpenGLException */
       static void ensureElementVBOdisabled() {
          if ((GLContext.getCapabilities().OpenGL15 && !checkBufferObject(GL15.GL_ELEMENT_ARRAY_BUFFER_BINDING, false) ||
                   (GLContext.getCapabilities().GL_ARB_vertex_buffer_object && !checkBufferObject(ARBVertexBufferObject.GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, false))))
             throw new OpenGLException("Cannot use Buffers when Element Array Buffer Object is enabled");
       }

    I think that maybe your fix works, did you test it?

    #91078

    blobby
    0p
    Member

    Yes it works  :)

    But I have a doubt about the patch to write :

    In prepVBO we have:


            if (g instanceof TriMesh) {

                if (vbo.isVBOIndexEnabled() && vbo.getVBOIndexID() <= 0) {
                    TriMesh tb = (TriMesh) g;
                    if (tb.getIndexBuffer() != null) {
                        Object vboid;
                        if ((vboid = vboMap.get(tb.getIndexBuffer())) != null) {
                            vbo.setVBOIndexID(((Integer) vboid).intValue());
                        } else {
                            tb.getIndexBuffer().rewind();
                            int vboID = rendRecord.makeVBOId();
                            vbo.setVBOIndexID(vboID);
                            vboMap.put(tb.getIndexBuffer(), vboID);

                            rendRecord.invalidateVBO(); // make sure we set it...
                            rendRecord.setBoundElementVBO(vbo.getVBOIndexID());
                            ARBBufferObject
                                    .glBufferDataARB(
                                            ARBVertexBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB,
                                            tb.getIndexBuffer(),
                                            ARBBufferObject.GL_STATIC_DRAW_ARB);

                        }
                    }
                }
            }

    But nothing for Lines and QuadMesh (Lines and QuadMesh could use VBO for index buffer… ) so the code should be:

            IntBuffer indexBuffer = null;
            if (g instanceof TriMesh) {
               TriMesh tb = (TriMesh) g;
               indexBuffer = tb.getIndexBuffer();
            } else if (g instanceof Line) {
               Line l = (Line) g;
               indexBuffer = l.getIndexBuffer();
            } else if (g instanceof QuadMesh) {
               QuadMesh qm = (QuadMesh) g;
               indexBuffer = qm.getIndexBuffer();
            }
           
            if (indexBuffer != null) {
                if (vbo.isVBOIndexEnabled() && vbo.getVBOIndexID() <= 0) {              
                    Object vboid;
                    if ((vboid = vboMap.get(indexBuffer)) != null) {
                        vbo.setVBOIndexID(((Integer) vboid).intValue());
                    } else {
                       indexBuffer.rewind();
                        int vboID = rendRecord.makeVBOId();
                        vbo.setVBOIndexID(vboID);
                        vboMap.put(indexBuffer, vboID);

                        rendRecord.invalidateVBO(); // make sure we set it...
                        rendRecord.setBoundElementVBO(vbo.getVBOIndexID());
                        ARBBufferObject
                                .glBufferDataARB(
                                        ARBVertexBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB,
                                        indexBuffer,
                                        ARBBufferObject.GL_STATIC_DRAW_ARB);

                    }
                }
            }

    (To avoid the use of a lot of "instanceof" we could imagine to create a IndexedGeometry class… but that's a lot of work and a lot of test…  :D )

    In predrawGeometry() , we also need to add some instanceof :


     if (g instanceof TriMesh || g instanceof Line || g instanceof QuadMesh) {
                if ((supportsVBO && vbo != null && vbo.getVBOIndexID() > 0)) { // use VBO
                    indicesVBO = true;
                    rendRecord.setBoundElementVBO(vbo.getVBOIndexID());
                } else if (supportsVBO) {
                    rendRecord.setBoundElementVBO(0);
                }
     }

    I think the same fix is necessary for JOGL…

    #91079

    gouessej
    109p
    Participant

    Ok. Put this patch into the section "Contribution Depot" and if it is accepted for LWJGL, I will fix it in JOGL side but there are a lot of "instanceof"  :x

    #91080

    basixs
    0p
    Member

    Probably a dumb question (only looked at this briefly) but could you use 'instanceof Geometry'?

    #91081

    nymon
    1p
    Member

    basixs said:

    Probably a dumb question (only looked at this briefly) but could you use 'instanceof Geometry'?

    Sadly no. But perhaps the proper solution would include moving the index buffer up to geometry. We should check if there are any subclasses that *don't* have an index buffer.

    #91082

    blobby
    0p
    Member

    Oups… the Point class has also an index buffer, so with this solution we should add an "instanceof Point"
    Arggg the "instanceof" invades the Renderer!!  }:-@ Help! :-o

    Moving the indexBuffer in Geometry is probably the best solution  :). The class VBOInfo is already in Geometry and contains some methods relatives to the index buffer so it will be homogeneous.

    The bad point: Curve class inherit from Geometry: it doesn't need an index buffer and it's render doesn't use VBO at all…

    #91083

    gouessej
    109p
    Participant

    blobby said:

    The bad point: Curve class inherit from Geometry: it doesn't need an index buffer and it's render doesn't use VBO at all…

    Maybe we could use a dummy index buffer but Curve already uses a vertex buffer:
     

     public Curve(String name, Vector3f[] controlPoints) {
            super(name);
            if (null == controlPoints) {
                throw new JmeException("Control Points may not be null.");
            }

            if (controlPoints.length < 2) {
                throw new JmeException("There must be at least two control points.");
            }

            setVertexBuffer(BufferUtils.createFloatBuffer(controlPoints));
            steps = 25;
        }

    #91084

    blobby
    0p
    Member

    Maybe we could add a getIndexBuffer() method in Geometry: this method could return null when no index buffer is specified like getNormalBuffer(), getBinormalBuffer(), getTextureCoords() etc…

    What do you think about that?

Viewing 9 posts - 1 through 9 (of 9 total)

You must be logged in to reply to this topic.