Bug 356

Summary: TextRenderer causes a GLException on pre-OpenGL 1.5 version
Product: [JogAmp] Jogl Reporter: Sven Gothel <sgothel>
Component: awtAssignee: Sven Gothel <sgothel>
Status: RESOLVED INVALID    
Severity: normal    
Priority: P5    
Version: 1   
Hardware: All   
OS: all   
Type: DEFECT SCM Refs:
Workaround: ---
Attachments: Log file obtained when the JVM crashed with JOGL 1.1.1 release candidate 5
source code to reproduce the bug easily
Cleanest bug fix (force the use of VBO on OpenGL 1.4 if GL_ARB_vertex_buffer_object is available)
Cleanest bug fix version 2 (GL_ARB_vertex_buffer_object can be supported in OpenGL 1.3 on some graphics cards)
Cleanest bug fix version 3 following Kenneth Russell's suggestions
Cleanest bug fix version 4 (tested, works but has poor performance)
Final cleanest fix, tested under OpenGL 1.3
Fix handling the crash with Intel chips and working with OpenGL 1.4 too

Description Sven Gothel 2010-03-24 07:51:28 CET


---- Reported by javalution 2008-06-01 05:02:13 ----

On JOGL 1.1.1 release candidate 5, the JVM crashes completely and produces a log
file. The other release candidates (rc6, rc7 and rc8) and the stable current
version produces the following trace:

Exception in thread "AWT-EventQueue-0" javax.media.opengl.GLException: array
vertex_buffer_object must be disabled to call this method
       at com.sun.opengl.impl.GLImpl.checkBufferObject(GLImpl.java:30667)
       at com.sun.opengl.impl.GLImpl.checkArrayVBODisabled(GLImpl.java:30715)
       at com.sun.opengl.impl.GLImpl.glVertexPointer(GLImpl.java:27936)
       at
com.sun.opengl.util.j2d.TextRenderer$Pipelined_QuadRenderer.drawVertexArrays(TextRenderer.java:1771)
       at
com.sun.opengl.util.j2d.TextRenderer$Pipelined_QuadRenderer.draw(TextRenderer.java:1745)
       at
com.sun.opengl.util.j2d.TextRenderer$Pipelined_QuadRenderer.access$000(TextRenderer.java:1687)
       at
com.sun.opengl.util.j2d.TextRenderer.flushGlyphPipeline(TextRenderer.java:809)
       at com.sun.opengl.util.j2d.TextRenderer.endRendering(TextRenderer.java:705)
       at com.sun.opengl.util.j2d.TextRenderer.endRendering(TextRenderer.java:541)
       at HelloWorldDemo.display(HelloWorldDemo.java:82)
       at com.sun.opengl.impl.GLDrawableHelper.display(GLDrawableHelper.java:78)
       at javax.media.opengl.GLCanvas$DisplayAction.run(GLCanvas.java:435)
       at com.sun.opengl.impl.GLDrawableHelper.invokeGL(GLDrawableHelper.java:194)
       at
javax.media.opengl.GLCanvas.maybeDoSingleThreadedWorkaround(GLCanvas.java:412)
       at javax.media.opengl.GLCanvas.display(GLCanvas.java:244)
       at javax.media.opengl.GLCanvas.paint(GLCanvas.java:277)
       at sun.awt.RepaintArea.paintComponent(RepaintArea.java:248)
       at sun.awt.X11.XRepaintArea.paintComponent(XRepaintArea.java:56)
       at sun.awt.RepaintArea.paint(RepaintArea.java:224)
       at sun.awt.X11.XComponentPeer.handleEvent(XComponentPeer.java:683)
       at java.awt.Component.dispatchEventImpl(Component.java:4489)
       at java.awt.Component.dispatchEvent(Component.java:4243)
       at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
       at
java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:273)
       at
java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:183)
       at
java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:173)
       at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:168)
       at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:160)
       at java.awt.EventDispatchThread.run(EventDispatchThread.java:121)
Exception in thread "Thread-1" javax.media.opengl.GLException:
javax.media.opengl.GLException: array vertex_buffer_object must be disabled to
call this method
       at javax.media.opengl.Threading.invokeOnOpenGLThread(Threading.java:271)
       at
javax.media.opengl.GLCanvas.maybeDoSingleThreadedWorkaround(GLCanvas.java:410)
       at javax.media.opengl.GLCanvas.display(GLCanvas.java:244)
       at com.sun.opengl.util.Animator.display(Animator.java:144)
       at com.sun.opengl.util.Animator$MainLoop.run(Animator.java:181)
       at java.lang.Thread.run(Thread.java:619)
Caused by: javax.media.opengl.GLException: array vertex_buffer_object must be
disabled to call this method
       at com.sun.opengl.impl.GLImpl.checkBufferObject(GLImpl.java:30667)
       at com.sun.opengl.impl.GLImpl.checkArrayVBODisabled(GLImpl.java:30715)
       at com.sun.opengl.impl.GLImpl.glVertexPointer(GLImpl.java:27936)
       at
com.sun.opengl.util.j2d.TextRenderer$Pipelined_QuadRenderer.drawVertexArrays(TextRenderer.java:1771)
       at
com.sun.opengl.util.j2d.TextRenderer$Pipelined_QuadRenderer.draw(TextRenderer.java:1745)
       at
com.sun.opengl.util.j2d.TextRenderer$Pipelined_QuadRenderer.access$000(TextRenderer.java:1687)
       at
com.sun.opengl.util.j2d.TextRenderer.flushGlyphPipeline(TextRenderer.java:809)
       at com.sun.opengl.util.j2d.TextRenderer.endRendering(TextRenderer.java:705)
       at com.sun.opengl.util.j2d.TextRenderer.endRendering(TextRenderer.java:541)
       at HelloWorldDemo.display(HelloWorldDemo.java:82)
       at com.sun.opengl.impl.GLDrawableHelper.display(GLDrawableHelper.java:78)
       at javax.media.opengl.GLCanvas$DisplayAction.run(GLCanvas.java:435)
       at com.sun.opengl.impl.GLDrawableHelper.invokeGL(GLDrawableHelper.java:194)
       at
javax.media.opengl.GLCanvas$DisplayOnEventDispatchThreadAction.run(GLCanvas.java:452)
       at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:199)
       at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
       at
java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:273)
       at
java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:183)
       at
java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:173)
       at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:168)
       at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:160)
       at java.awt.EventDispatchThread.run(EventDispatchThread.java:121)

The problem is reproducible only with graphics cards that are not at least
compatible with OpenGL 1.5. When I use both VBOs and a TextRenderer, I get the
exception trace above with the following source code:

import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.nio.FloatBuffer;

import com.sun.opengl.util.Animator;
import com.sun.opengl.util.BufferUtil;
import com.sun.opengl.util.j2d.TextRenderer;
import javax.media.opengl.GL;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;

public class HelloWorldDemo extends Frame implements GLEventListener{
    
    private static final long serialVersionUID = 1L;
    private TextRenderer textRenderer;
    private int[] id=new int[1];
    private FloatBuffer buffer=BufferUtil.newFloatBuffer(0);
    
    public HelloWorldDemo(){
        super("JOGL 1.1.1");
        setLayout(new BorderLayout());
        setSize(400, 400);
        setLocation(40, 40);
        setVisible(true);
        GLCapabilities caps = new GLCapabilities();
        caps.setDoubleBuffered(true);
        caps.setHardwareAccelerated(true);
        GLCanvas canvas = new GLCanvas(caps);
        canvas.addGLEventListener(this);
        add(canvas, BorderLayout.CENTER);
        Animator anim = new Animator(canvas);
        anim.start();
        addWindowListener(new WindowAdapter(){
            public void windowClosing(WindowEvent e){
                System.exit(0);
            }
        });
        buffer.put(new float[]{});
        buffer.position(0);
    }

    
    public void init(GLAutoDrawable drawable){
        GL gl = drawable.getGL();
        gl.glClearColor(0, 0, 0, 0);
        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glLoadIdentity();
        gl.glOrtho(0, 1, 0, 1, -1, 1);
        textRenderer=new TextRenderer(new Font("SansSerif",Font.PLAIN,12));
        gl.glGenBuffers(1,id,0);
        gl.glBindBuffer(GL.GL_ARRAY_BUFFER,id[0]);
       
gl.glBufferData(GL.GL_ARRAY_BUFFER,BufferUtil.SIZEOF_FLOAT*buffer.capacity(),buffer,GL.GL_STATIC_DRAW_ARB);
        this.buffer.position(0);
    }

    public void reshape(GLAutoDrawable drawable,
                        int x,
                        int y,
                        int width,
                        int height){
    }

    public void displayChanged(GLAutoDrawable drawable,
                               boolean modeChanged,
                               boolean deviceChanged){
    }

    public void display(GLAutoDrawable drawable){
        GL gl = drawable.getGL();
        gl.glClear(GL.GL_COLOR_BUFFER_BIT);
        gl.glEnableClientState(GL.GL_VERTEX_ARRAY);
        gl.glEnableClientState(GL.GL_TEXTURE_COORD_ARRAY);
        gl.glBindBuffer(GL.GL_ARRAY_BUFFER,id[0]);
        gl.glDrawArrays(GL.GL_QUADS,0,0);
        gl.glDisableClientState(GL.GL_TEXTURE_COORD_ARRAY);       
        gl.glDisableClientState(GL.GL_VERTEX_ARRAY);
        textRenderer.beginRendering(100,100);
        textRenderer.draw("JOGL 1.1.1",0,0);
        textRenderer.endRendering();       
        gl.glFlush();
    }

    public static void main(String[] args){
        HelloWorldDemo demo = new HelloWorldDemo();
        demo.setVisible(true);
    }
}



---- Additional Comments From javalution 2008-06-01 05:03:57 ----

Created an attachment
Log file obtained when the JVM crashed with JOGL 1.1.1 release candidate 5




---- Additional Comments From javalution 2008-06-01 05:10:07 ----

Created an attachment
source code to reproduce the bug easily




---- Additional Comments From javalution 2008-06-01 07:41:16 ----

I have found a workaround that works sometimes.

Explicitly unbind the last buffer you use by doing this:
gl.glBindBuffer(GL.GL_ARRAY_BUFFER,0);

It should not be required except if you don't use the same mechanism to check if
VBO extensions are available... that's the case of TUER. JOGL tests if OpenGL
1.5 is available and if it can bind a buffer (if there is no exception by using
a try catch clause), then it considers that VBO extensions are available. TUER
(WWJ and other engines too) uses a finer method. It checks only once if the
functions and the VBO extensions are both available. Then, under OpenGL 1.4, if
ARB VBO extensions are available, TUER uses VBOs and JOGL doesn't use them and
ignores the case of someone using VBOs. Here is the modification to do to allow
this to work in all cases (not yet tested as I don't succeed in building JOGL):

in com.sun.opengl.util.j2d.TextRenderer:
...
[color=red][b]private boolean bindBufferAvailable;[/b][/color]
...
public TextRenderer(Font font, boolean antialiased,
                        boolean useFractionalMetrics, RenderDelegate renderDelegate,
                        boolean mipmap){
[color=red][b]GL gl = GLU.getCurrentGL();
bindBufferAvailable = gl.isFunctionAvailable("glBindBufferARB") ||
gl.isFunctionAvailable("glBindBuffer");[/b][/color]
...
}

in com.sun.opengl.util.j2d.TextRenderer$Pipelined_QuadRenderer.drawVertexArrays()

......
if (usingVBOs) {
                    gl.glBindBuffer(GL.GL_ARRAY_BUFFER,
                                    mVBO_For_ResuableTileVertices);
                    gl.glBufferSubData(GL.GL_ARRAY_BUFFER, 0,
                                       mOutstandingGlyphsVerticesPipeline *
kSizeInBytes_OneVertices_VertexData,
                                       mVertCoords); // upload only the new stuff
                    gl.glVertexPointer(3, GL.GL_FLOAT, 0, 0);
                } else {
                    [color=red][b]if(bindBufferAvailable)
                         gl.glBindBuffer(GL.GL_ARRAY_BUFFER,0);//unbinds any
already bound buffer[/b][/color]
                    gl.glVertexPointer(3, GL.GL_FLOAT, 0, mVertCoords);
                }



---- Additional Comments From javalution 2008-06-01 08:01:35 ----

The workaround always works if it is called just before beginRendering() and
begin3DRendering().



---- Additional Comments From javalution 2008-06-02 12:59:21 ----

Created an attachment
Cleanest bug fix (force the use of VBO on OpenGL 1.4 if GL_ARB_vertex_buffer_object is available)




---- Additional Comments From javalution 2008-06-02 23:58:14 ----

Created an attachment
Cleanest bug fix version 2 (GL_ARB_vertex_buffer_object can be supported in OpenGL 1.3 on some graphics cards)




---- Additional Comments From kbr 2008-06-03 02:09:03 ----

This fix doesn't do what you think it does and frankly I don't see how it can
possibly change the behavior. With this fix the sequence of operations is as
follows:

 - The TextRenderer thinks it has VBOs available
 - It attempts to call glBindBuffer
 - This fails because OpenGL 1.5 is not available
 - It falls back to the vertex array implementation
 - It calls glVertexPointer with a Buffer as argument even though a VBO is
already bound and should fail in the same way as before

If you want to add a code path for ARB_vertex_buffer_object you are going to
need to change the calls to glBindBuffer, etc. to instead call glBindBufferARB
in this case.




---- Additional Comments From javalution 2008-06-03 05:01:37 ----

I don't succeed in building JOGL, it doesn't help... When you call glBindBuffer
under OpenGL 1.3 through JOGL 1.1.1, it works like glBindBufferARB, my graphics
card is compatible with OpenGL 1.3 (ATI Radeon 9250 Pro) and using glBindBuffer
works, I tested this point, I replaced all calls of glBindBufferARB by
glBindBuffer and this didn't fail. The indirect rendering by Mesa supports only
OpenGL 1.2, therefore it doesn't come from this. With this fix, the sequence of
operations should be:
- The TextRenderer thinks it has VBOs available
- It attempts to call glBindBuffer
- It works as glBindBuffer points on glBindBufferARB
Did you test my fix with graphics cards compatible with OpenGL 1.4 or OpenGL 1.3
only?
Could you include my fix in the nightly build to allow me to test it or do you
prefer me to try again to build JOGL with my fix before adding it into the
nightly build?



---- Additional Comments From javalution 2008-06-03 05:46:01 ----

Created an attachment
Cleanest bug fix version 3 following Kenneth Russell's suggestions




---- Additional Comments From kbr 2008-06-03 09:09:01 ----

You must test and validate your own fix before I will consider checking it in. I
do not have access to graphics cards supporting only OpenGL 1.3 / 1.4 any more.




---- Additional Comments From javalution 2008-06-03 12:39:40 ----

Created an attachment
Cleanest bug fix version 4 (tested, works but has poor performance)




---- Additional Comments From javalution 2008-06-03 12:43:17 ----

The versions 2 and 3 of the bug fix crashes the JVM. The version 4 works but has
very poor performance. I don't find a competitive solution. Please investigate.
I don't understand why the JVM crashes on glDrawArrays after some seconds.



---- Additional Comments From javalution 2008-08-19 13:44:27 ----

Created an attachment
Final cleanest fix, tested under OpenGL 1.3




---- Additional Comments From javalution 2008-08-19 13:47:49 ----

The latest bug fix works good. The impact on the performance is not really
noticeable if and only if you use VBOs whose element count is less than
GL_MAX_ELEMENTS_VERTICES.

I tried other approaches some weeks but the JVM crashed several times. This fix
is the only reliable and performant solution I have found. Please include it in
the nightly build as soon as possible.



---- Additional Comments From javalution 2008-08-19 14:18:34 ----

Created an attachment
Fix handling the crash with Intel chips and working with OpenGL 1.4 too




---- Additional Comments From javalution 2008-08-19 14:19:57 ----

Please test the latest fix with an Intel on-board graphics and under OpenGL 1.4
as I don't have such things at home. I had forgotten some try/catch. Now, it
should be fine.



---- Additional Comments From javalution 2008-09-12 16:57:26 ----

Sorry. The fix doesn't work fine on some versions of Mesa, TUER crashes after 99
seconds, the JVM writes a log file. I have had to use the older implementation
to fix the bug. glBindBufferARB seems to be very unstable when used to unbind a
buffer.



--- Bug imported by sgothel@jausoft.com 2010-03-24 07:51 EDT  ---

This bug was previously known as _bug_ 356 at https://jogl.dev.java.net/bugs/show_bug.cgi?id=356
Imported an attachment (id=126)
Imported an attachment (id=127)
Imported an attachment (id=128)
Imported an attachment (id=129)
Imported an attachment (id=130)
Imported an attachment (id=131)
Imported an attachment (id=132)
Imported an attachment (id=133)

The original submitter of attachment 126 [details] is unknown.
   Reassigning to the person who moved it here: sgothel@jausoft.com.
The original submitter of attachment 127 [details] is unknown.
   Reassigning to the person who moved it here: sgothel@jausoft.com.
The original submitter of attachment 128 [details] is unknown.
   Reassigning to the person who moved it here: sgothel@jausoft.com.
The original submitter of attachment 129 [details] is unknown.
   Reassigning to the person who moved it here: sgothel@jausoft.com.
The original submitter of attachment 130 [details] is unknown.
   Reassigning to the person who moved it here: sgothel@jausoft.com.
The original submitter of attachment 131 [details] is unknown.
   Reassigning to the person who moved it here: sgothel@jausoft.com.
The original submitter of attachment 132 [details] is unknown.
   Reassigning to the person who moved it here: sgothel@jausoft.com.
The original submitter of attachment 133 [details] is unknown.
   Reassigning to the person who moved it here: sgothel@jausoft.com.