LWJGL Forum

Programming => Lightweight Java Gaming Library => Topic started by: Pogomon on January 06, 2006, 12:03:17

Title: AWTGLCanvas and context
Post by: Pogomon on January 06, 2006, 12:03:17
Hey all,

I am using LWJGL to do visiualisation, and just moved the project from the Display class to using the AWTGLCanvas class for display. The problem I have is that it seems that every time the AWTGLCanvas is hidden (i.e.setVisible() is called on the Frame containing the canvas) the context gets destroyed which results in a loss of all the textures. This means I have to reload all the textures everytime the user reopens the display window.

Is there a way around this ?

Thanks
Title: AWTGLCanvas and context
Post by: elias on January 06, 2006, 12:33:30
Not that I know of. We're forced to destroy the context on hide, since Java is free to destroy the Frame and re-create it with a different setup.

- elias
Title: AWTGLCanvas and context
Post by: princec on January 06, 2006, 19:38:08
Use a pbuffer and shared context.

Cas :)
Title: AWTGLCanvas and context
Post by: renanse on May 26, 2006, 18:40:57
In regards to context, if an exception occurs during paint, the context is never released and subsequent paint calls throw an exception like:

java.lang.IllegalStateException: From thread Thread[AWT-EventQueue-0,6,main]: Thread[AWT-EventQueue-0,6,main] already has the context current
at org.lwjgl.opengl.Context.checkAccess(Context.java:169)
at org.lwjgl.opengl.Context.makeCurrent(Context.java:176)
at org.lwjgl.opengl.AWTGLCanvas.paint(AWTGLCanvas.java:251)
at org.lwjgl.opengl.AWTGLCanvas.update(AWTGLCanvas.java:269)
at sun.awt.RepaintArea.updateComponent(Unknown Source)
at sun.awt.RepaintArea.paint(Unknown Source)
at sun.awt.windows.WComponentPeer.handleEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)


Which of course happens over and over and over until I kill the app.

I can catch that with Thread.setDefaultUncaughtExceptionHandler(...) but it looks like I can not do anything to fix the problem (such as manually releasing the Context so subsequent paint calls don't trip up) given that Context is not externally accessible.  Perhaps paint itself should detect and fix the problem?  (eg. Oh, I already have the context, so I will just continue on my way.)  Ideas?
Title: hmmmmmm...
Post by: Fool Running on May 28, 2006, 02:58:21
Quoten regards to context, if an exception occurs during paint, the context is never released and subsequent paint calls throw an exception...

Hmmmmm... That sounds bad :D

Unfortunatly, I don't have any ideas, but it certainly sounds worth fixing.
Title: AWTGLCanvas and context
Post by: Matzon on May 28, 2006, 07:47:37
indeed
Title: AWTGLCanvas and context
Post by: elias on May 29, 2006, 19:37:08
That's an odd exception. Can you  post the exception+trace that causes this situation (I assume it's the exception just before the IllegalStateException) in addition to the OS and the lwjgl version. A minimal test program would be nice too.

- elias
Title: AWTGLCanvas and context
Post by: elias on May 30, 2006, 12:45:00
I've applied a workaround that simple makes the context current and releases it every frame. That will also make the AWTGLCanvas more compliant with AWT which is allowed to use different threads to call paint().

- elias
Title: AWTGLCanvas and context
Post by: Evil-Devil on May 30, 2006, 13:51:56
Quote from: "elias"I've applied a workaround that simple makes the context current and releases it every frame. That will also make the AWTGLCanvas more compliant with AWT which is allowed to use different threads to call paint().

- elias
Does that not slow down the rendering?
Title: AWTGLCanvas and context
Post by: elias on May 30, 2006, 13:54:02
It does, but with a constant amount, so it shouldn't matter much at reasonable frame rates.

- elias
Title: AWTGLCanvas and context
Post by: renanse on May 30, 2006, 17:41:50
Sorry, was out there for a bit.  Good to hear about the "fix".  For completeness:  The exception causing it was really anything in paint.  For example, an NPE in my opengl code.  It happens on any OS I've tried it on and lwjgl version is .99 official.

Looking forward to a new official release (since that's all we use at jme :-/ )
Title: AWTGLCanvas and context
Post by: elias on June 01, 2006, 12:07:48
I sort of reproduced the problem here. I got this exception:


Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: From thread Thread[AWT-EventQueue-0,6,main]: Thread[AWT-EventQueue-0,6,] already has the context current


which is actually two different threads as expected (notice the missing "main" in the second thread name). I'm not sure how your exception came about (maybe an earlier version of lwjgl caused that, I don't know). Anyway, the fix works fine here.

- elias
Title: AWTGLCanvas and context
Post by: renanse on June 01, 2006, 19:25:05
Cool, when do we get that in a release?  :)
Title: AWTGLCanvas and context
Post by: Matzon on June 01, 2006, 19:25:24
hopefully tomorrow :)
Title: AWTGLCanvas and context
Post by: Sormuras on June 01, 2006, 22:58:35
Gogogo! It'd be great... :D
Title: AWTGLCanvas and context
Post by: renanse on June 04, 2006, 15:33:42
elias, I noticed there was still some discussion on this topic in the irc logs.  Was there a test or something you were looking for from me?  One way to reproduce it (but it seems to only be on windows, I can't get my Mac to complain in the same way) is to pull up jME's tests.  Open the source for jmetest.effects.RenParticleEditor and add the following method to the inner class MyImplementor (so like around line 1840):

int x = 0;
public void simpleRender() {
   if (x++ == 1000) throw new NullPointerException("ack!");
}


When you run on the PC, it kicks off the NPE after a few seconds and then immediately floods stderr with IllegalStateExceptions like the one I posted previously.  (of course, I'm still running .99)

Hope that is of some help to you.  When I get to work tomorrow morning I'll try out the new lwjgl release.
Title: AWTGLCanvas and context
Post by: renanse on June 05, 2006, 22:19:49
So, I just updated to 1.0b and now when I run our awt based apps I get a native stack dump after the first rendering completes (so I see a glimpse of the app, then it crashes.)  If I comment out all of the rendering calls and the camera calls to glViewport, it can run and show off the background color (um, yay?)   Any ideas?  The stack is not very helpful:


#
# An unexpected error has been detected by HotSpot Virtual Machine:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00add6df, pid=1520, tid=4804
#
# Java VM: Java HotSpot(TM) Client VM (1.5.0_06-b05 mixed mode, sharing)
# Problematic frame:
# j  org.lwjgl.opengl.GL11.glViewport(IIII)V+0


I can run the awt tests in lwjgl_test, but honestly they aren't all that complex. :)
Title: AWTGLCanvas and context
Post by: renanse on June 05, 2006, 22:39:14
More information...  The app I am working with has various swing components to the right (see RenParticleEditor)   If I don't touch them, the scene comes up and displays fine.  As soon as I make changes (such as setting the text on a label) it bombs.
Title: AWTGLCanvas and context
Post by: elias on June 06, 2006, 06:49:59
Can you post a minimal test program that crashes? Preferably with as little Swing/AWT code as possible. Actually, try avoiding Swing altogether for testing purpose. Did you try disabling ddraw with the java2d switch (can't remember it's name).

EDIT: I also need the OS and graphics card model.

- elias
Title: AWTGLCanvas and context
Post by: elias on June 06, 2006, 10:29:20
Actually, that crash trace reminds of the JVM bug that lwjgl triggers with the large ContextCapabilities instances ((http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6342951). It is fixed in 1.5.0_07 apparently, so could you try that? Alternatively, try this before the crashing GL call (GL11.glViewport()):


if (GLContext.getCapabilities() == null)
throw new IllegalStateException("No context current!");


- elias
Title: AWTGLCanvas and context
Post by: renanse on June 06, 2006, 13:21:09
I'll try those on my PC at work once I get there.  From home on my mac with the same code I am getting an NPE:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at org.lwjgl.opengl.GL11.glViewport(GL11.java:2725)
at com.jme.renderer.lwjgl.LWJGLCamera.onViewPortChange(LWJGLCamera.java:167)
at com.jme.renderer.lwjgl.LWJGLCamera.resize(LWJGLCamera.java:112)
at com.jme.renderer.lwjgl.LWJGLRenderer.reinit(LWJGLRenderer.java:205)
at com.jmex.awt.JMECanvasImplementor.resizeCanvas(JMECanvasImplementor.java:72)


The app still draws after that but flickers like mad.  Any attempt to resize the window (and thus call the above code again) also throws the error but continues working.  Dunno if that is a clue.  I don't have the source at the moment to see what 2725 is... perhaps the caps you mentioned?
Title: AWTGLCanvas and context
Post by: elias on June 06, 2006, 13:38:38
I suspect your work machine has an upgraded JVM. The problem is that the application does GL rendering outside of paintGL() which is not allowed for AWTGLCanvas.

- elias
Title: AWTGLCanvas and context
Post by: renanse on June 06, 2006, 13:55:40
Ok, although the vms are actually both 1.5.0_06
Title: AWTGLCanvas and context
Post by: renanse on June 06, 2006, 14:40:35
The issue was calling GLContext.getCapabilities(); outside of paintGL.  I can see the reasoning behind the problem, but why did it suddenly become apparent with 1.0b?
Title: AWTGLCanvas and context
Post by: elias on June 06, 2006, 15:47:38
Because the workaround is releasing the context after each paintGL(). The previous version let the context stay current.

- elias
Title: AWTGLCanvas and context
Post by: Evil-Devil on June 06, 2006, 16:18:39
Quote from: "elias"Because the workaround is releasing the context after each paintGL(). The previous version let the context stay current.

- elias
That was good - in my opinion. All my applications worked with that ...
Title: AWTGLCanvas and context
Post by: renanse on June 06, 2006, 17:21:01
Yeah, my main code works now (all gl calls, no matter what are in paintGL) BUT I still get errors like the following if I display dialogs in my app:

java.lang.NullPointerException
at org.lwjgl.opengl.GL11.glClear(GL11.java:576)
at com.jme.renderer.lwjgl.LWJGLRenderer.clearColorBuffer(LWJGLRenderer.java:449)
at com.jme.renderer.lwjgl.LWJGLRenderer.clearBuffers(LWJGLRenderer.java:474)
at com.nccore.tools.jemviewer.view.JEMViewImplementor.doRender(JEMViewImplementor.java:425)
at com.jmex.awt.lwjgl.LWJGLCanvas.paintGL(LWJGLCanvas.java:86)
at org.lwjgl.opengl.AWTGLCanvas.paint(AWTGLCanvas.java:279)
at sun.awt.RepaintArea.paintComponent(Unknown Source)
at sun.awt.RepaintArea.paint(Unknown Source)
at sun.awt.windows.WComponentPeer.handleEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)


I can get around that if I put it in a SwingUtilities.invokeLater, but man...  

Is it possible to instead of always releasing the context, simply check at the beginning if we already have the context and if so, skip regrabbing the context?  Seems like that would lower overhead as well...
Title: AWTGLCanvas and context
Post by: Evil-Devil on June 06, 2006, 17:29:36
Why not checking for releasing and setting the context in AWT Application by yourself like in 0.99? That was fine exspecially when using FileChoosers for loading different file i.e. Models
Title: AWTGLCanvas and context
Post by: elias on June 06, 2006, 17:54:44
Evil-Devil: Because you can't force another thread to release the context.

- elias
Title: AWTGLCanvas and context
Post by: renanse on June 06, 2006, 17:59:36
Can we block until the other thread releases the context?
Title: AWTGLCanvas and context
Post by: elias on June 06, 2006, 18:10:10
Hm, I think I'll need that simple test program this time :). If you could modify an existing LWJGL test (AWTTest or AWTGears) to exhibit that NPE I would be grateful :) I'm glad you're helping us to iron out all those pesky AWTGLCanvas bugs!

- elias
Title: AWTGLCanvas and context
Post by: elias on June 06, 2006, 18:11:26
We can block, but how are you going to tell the other thread to release its context if paint() doesn't release the context every time?

- elias
Title: AWTGLCanvas and context
Post by: Evil-Devil on June 06, 2006, 18:17:55
Quote from: "elias"Evil-Devil: Because you can't force another thread to release the context.

- elias
I don't need another thread to release the context. If the other thread give my awt thread a sign that the context should be released it should be fine. Mainly I designed my AWTGL Apps the way that every drawing stuff is done within a scenegraph or simple class that implements a specific interface that is known by the AWTGlCanvas.

//edit: I will work on a example for 0.99 with 2 or more threads, ok?
Title: AWTGLCanvas and context
Post by: renanse on June 06, 2006, 19:03:07
Ok, here's your lwjgl only repeatable test.  :)

Edit AWTGears and make the following additions:


       add(canvas0 = new AWTGLCanvas() {
           long startTime = 0;
           long fps = 0;
+            boolean show;          
           public void paintGL() {


                   GL11.glPopMatrix();    
+                    
+                    if (show) {
+                        show = false;
+                        JOptionPane.showMessageDialog(AWTGears.this, "tick!");
+                    }
+                    
                   swapBuffers();
               } catch (LWJGLException e) {
                   throw new RuntimeException(e);
               }
               if (startTime > System.currentTimeMillis()) {
                   fps++;
               } else {
+                    show = true;
                   long timeUsed = 5000 + (startTime - System.currentTimeMillis());


Every time the code computes a fps, the next render loop will throw up a dialog.  Each time you see that and push ok it shows an IllegalStateException.  My guess is that the dialog blocks the current paint event but the repaint thread continues generating new paint events somehow killing the context for the original paint event's subsequent call to swapBuffers?
Title: AWTGLCanvas and context
Post by: renanse on June 06, 2006, 19:12:21
PS: The exception will be java.lang.IllegalStateException in this test, but the root cause between this and the npe is the same...  The npe happens simply because a different call besides swapbuffers (one that uses the context capabilities without checking for null for example) is encountered first.
Title: AWTGLCanvas and context
Post by: renanse on June 06, 2006, 19:48:18
FYI, the unmodified AWTGears now flickers like crazy on my Mac Powerbook (G4 1.5 w/ Radeon 9700 OSX 10.4.6 with latest patches)
Title: AWTGLCanvas and context
Post by: elias on June 07, 2006, 06:58:02
Ok,  I think I fixed both the flickering and the problem with dialog boxes. Please run "ant jars" from the updated subversion tree and test with the new lwjgl.jar (no native code changes necessary). I'm not currently able to upload one myself, sorry.

- elias
Title: AWTGLCanvas and context
Post by: renanse on June 07, 2006, 14:28:17
That seems to solve both problems on both mac and win32.  Our linux setup is b0rked at the moment.  Anyhow, thanks elias!

edit: and by b0rked, I mean in general, not related to this issue.  :)
Title: AWTGLCanvas and context
Post by: Evil-Devil on July 13, 2006, 07:14:42
Elias, could you add a flag for enabling/disabling the workaround? I think that  would be the best for all. So there is no need to write a AWTGLCanvas from scrap yourself if someone want full control of the thread handling.
Title: AWTGLCanvas and context
Post by: coasternuts on September 01, 2006, 13:28:05
I'm now getting this IllegalStateException in my code.  I downloaded beta3 but that didn't solve it.

Is there a final fix for this coming later or have I uncovered another problem?  

Here is the callstack:

Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: From thr
ead Thread[AWT-EventQueue-0,6,main]: Thread[AWT-EventQueue-0,6,] already has the
context current
       at org.lwjgl.opengl.Context.checkAccess(Context.java:181)
       at org.lwjgl.opengl.Context.makeCurrent(Context.java:188)
       at org.lwjgl.opengl.AWTGLCanvas.paint(AWTGLCanvas.java:284)
       at org.lwjgl.opengl.AWTGLCanvas.update(AWTGLCanvas.java:313)
       at sun.awt.RepaintArea.updateComponent(Unknown Source)
       at sun.awt.RepaintArea.paint(Unknown Source)
       at sun.awt.windows.WComponentPeer.handleEvent(Unknown Source)
       at java.awt.Component.dispatchEventImpl(Unknown Source)
       at java.awt.Component.dispatchEvent(Unknown Source)
       at java.awt.EventQueue.dispatchEvent(Unknown Source)
       at java.awt.EventDispatchThread.pumpOneEventForHierarchy(Unknown Source)

       at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
       at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
       at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
       at java.awt.EventDispatchThread.run(Unknown Source)

My paintGL routine is the following:


protected void paintGL()
  {
     if(!initialized)
     {
        if (renderThread == null)
        {
           renderThread = new Thread(this);
           renderThread.setName("Charting-Renderer");
           renderThread.start();
        }

        initialized = true;
        initialize();
     }

     synchronized (this)
     {
        try {
           makeCurrent();
           render();
           swapBuffers();
           releaseContext();
        } catch (LWJGLException le) {
           le.printStackTrace();
        }
     }

     if (startTime > System.currentTimeMillis()) {
        fps++;
     } else {
        long timeUsed = 5000 + (startTime - System.currentTimeMillis());
        startTime = System.currentTimeMillis() + 5000;
        // parent.updateFPS((fps / (timeUsed / 1000f)));
        fps = 0;
     }
  }
Title: AWTGLCanvas and context
Post by: elias on September 01, 2006, 13:46:42
I'll need a complete minimal test to figure out what is wrong. Be careful with the makeCurrent/releaseContext calls, they're only supposed to be called from AWTGLCanvas itself.

- elias
Title: AWTGLCanvas and context
Post by: coasternuts on September 02, 2006, 10:21:10
Thanks elias.

You made me make sure I found my bug.  :)