Multiple GLCanvas slow

Hi, I’m having a problem displaying several JOGL context on screen (I’m NOT rendering in full screen mode). All of them are linked to a parent JPanel, and as I add more and more of these JPanel containing a GLCanvas (up to 8), the framerate of each of these canvas falls down. There is NOTHING displayed in these canvas, and it seems like vsync is enabled, even if I ask it to be disabled :

  • I’m using the FPSAnimator class from Sun (found it on NeHe’s first tutorial). When I ask to limit framerate, it falls down to the closest integer divider of my monitor frequency (which is actually 75 Hz, so if I ask a frame rate limit of 100, I get 75, and sometimes less if I have several GLCanvas displayed). If I disable the framerate limitation I get the same behaviour (meaning it’s refreshing as fast as it can, and it is definitely not fast).
  • I call gl.wglSwapIntervalEXT(0) ; quite everywhere to be sure it is correctly set (I don’t know if each of the GLCanvas share the same GL state or if they have their own)
  • I call m_Canvas.setIgnoreRepaint(true); right after the canvas creation
  • The FPSAnimator which extends the Animator base class calls drawable.setNoAutoRedrawMode(true); at the start of the loop.

I was expecting to get something like 1000 fps (P4 2,4 GHz, 512 RAM, GF 6800 Ultra), but I can’t seem to pass even 150. When I create 2 JPanel containing a GLCanvas each, I fall down to 35 fps for each GLCanvas. I can post source of the GLCanvas creation and of the FPSAnimator, but as it takes a lot of code, I’ll do it only if asked.

Has someone ever experienced this kind of problem ?

Thanks for the help,
SeskaPeel.

You should be able to call GL.setSwapInterval() instead of wglSetSwapIntervalEXT(). You also need to call this from your GLEventListener’s callback methods like init() rather than an arbitrary point in the program. When are you calling it? If you modify the Gears demo to call setSwapInterval(0), what is the effect?

Thanks Ken, a huge improvement. I can now have 4 contexts @ 80 fps.
Still, it seems way too slow.

I browsed a lot the forum and found several posts that say that I should use a single animator for all GLCanvas.
I’m trying this right now and will let you know (My problem is actually a bit more complex, as I’d like to limit each of the contexts to a constant frame rate, that can be different from one another).
Do you confirm that I should do this ?

Thanks,
SeskaPeel

It sounds to me like you should write your own animation loop driving your four GLCanvases manually. If I were you I wouldn’t be too concerned about not getting 2000 FPS with an empty Canvas because with your card you should be able to throw tons of geometry at those canvases and maintain the same frame rate. I don’t know whether JOGL’s internal single-threading of the OpenGL work for the GLCanvases could be having an effect here, but if I were you I would go into your driver settings and try forcibly disabling sync-to-vertical-refresh. Also make sure you’re specifying -Dsun.java2d.noddraw=true on the command line to make sure you aren’t running into DirectDraw/OpenGL driver-level conflicts.

Hi Ken,

I plugged in a custom loop that calls as fast as it can the display() method on each of my registered GLCanvas. It did not improve anything …
I disabled the autoSwapBuffer (so nothing was never displayed), and I got a 3x fps boost (from 500 to 1500) for a single GLCanvas. I added 1, 2 and then 3 others, and fps goes down and down linearly with the number of GLCanvas. I suppose the code in GLContext.invokeGL is the bottleneck …

Anyway … it seems that the CPU is not that much stressed. But … I added params -Djogl.verbose -Djogl.debug.GLContext and saw that a lot of context swaps occur, even when only a single GLCanvas is created.

AWT-EventQueue-0: wglMakeCurrent(hdc 0xffffffff87010542, hglrc 0x10000) succeeded
AWT-EventQueue-0: Making context net.java.games.jogl.impl.windows.WindowsOnscreenGLContext@1a16869 current
AWT-EventQueue-0: Freeing context net.java.games.jogl.impl.windows.WindowsOnscreenGLContext@1a16869
AWT-EventQueue-0: wglMakeCurrent(hdc 0xffffffff87010542, hglrc 0x10000) succeeded
AWT-EventQueue-0: Making context net.java.games.jogl.impl.windows.WindowsOnscreenGLContext@1a16869 current
AWT-EventQueue-0: Freeing context net.java.games.jogl.impl.windows.WindowsOnscreenGLContext@1a16869
AWT-EventQueue-0: wglMakeCurrent(hdc 0xffffffff87010542, hglrc 0x10000) succeeded
AWT-EventQueue-0: Making context net.java.games.jogl.impl.windows.WindowsOnscreenGLContext@1a16869 current
AWT-EventQueue-0: Freeing context net.java.games.jogl.impl.windows.WindowsOnscreenGLContext@1a16869
... and so on for each frame

When I have two contexts :

AWT-EventQueue-0: wglMakeCurrent(hdc 0x4012247, hglrc 0x10000) succeeded
AWT-EventQueue-0: Making context net.java.games.jogl.impl.windows.WindowsOnscreenGLContext@1a16869 current
AWT-EventQueue-0: Freeing context net.java.games.jogl.impl.windows.WindowsOnscreenGLContext@1a16869
AWT-EventQueue-0: wglMakeCurrent(hdc 0x7b0119d9, hglrc 0x10001) succeeded
AWT-EventQueue-0: Making context net.java.games.jogl.impl.windows.WindowsOnscreenGLContext@7c6768 current
AWT-EventQueue-0: Freeing context net.java.games.jogl.impl.windows.WindowsOnscreenGLContext@7c6768
AWT-EventQueue-0: wglMakeCurrent(hdc 0x4012247, hglrc 0x10000) succeeded
AWT-EventQueue-0: Making context net.java.games.jogl.impl.windows.WindowsOnscreenGLContext@1a16869 current
AWT-EventQueue-0: Freeing context net.java.games.jogl.impl.windows.WindowsOnscreenGLContext@1a16869
AWT-EventQueue-0: wglMakeCurrent(hdc 0x7b0119d9, hglrc 0x10001) succeeded
AWT-EventQueue-0: Making context net.java.games.jogl.impl.windows.WindowsOnscreenGLContext@7c6768 current
AWT-EventQueue-0: Freeing context net.java.games.jogl.impl.windows.WindowsOnscreenGLContext@7c6768
... and so on

It seems natural to swap context when you have more than one, but when you have only one ?
The animator code (simplified) :

// Add a canvas
public void addCanvas(GLCanvas canvas) {
        //Link to internal thread
        canvas.setRenderingThread(thread);
        canvasList.add(canvas);
}

// Main loop
public void run() {
        goOn = true;
        while (goOn) {
                    canvasList.get(index).display();
                    index++;
                    if (index == canvasList.size()) {
                        index = 0;
                    }
        }
}


vsync is disabled in each Canvas’ listener init function with a gl.setSwapInterval(0) ; and the canvas is created this way :

GLCapabilities glcaps = new GLCapabilities();
m_Canvas = GLDrawableFactory.getFactory().createGLCanvas(glcaps);
m_Canvas.setIgnoreRepaint(true);
m_Canvas.addGLEventListener(new EVJOGLListener(this)) ;
GLCanvasAnimator animator = GLCanvasAnimator.getInstance();
animator.addCanvas(m_Canvas);
m_Canvas.setNoAutoRedrawMode(true);
m_Canvas.setAutoSwapBufferMode(false) ;

Is this the best I can do about it ?

Don’t forget, if you want your frame rate to exceed your monitor refresh rate you will have to disable vertical sync, normally in your driver settings.

GLContext.invokeGL() does no work except for the mandatory OpenGL context management and buffer swapping. JOGL releases the OpenGL context at the end of every rendering cycle because it is impossible in the general case to correctly manipulate OpenGL rendering contexts without doing so. I don’t really have any other suggestions at this point aside to always run your app with -Dsun.java2d.noddraw=true on Windows to avoid DirectDraw/OpenGL driver-level conflicts.