Bug 128

Summary: Two Animator threads controlling two GLCanvas objects deadlock, or one of the threads starve.
Product: [JogAmp] Jogl Reporter: Sven Gothel <sgothel>
Component: coreAssignee: Sven Gothel <sgothel>
Status: VERIFIED WORKSFORME    
Severity: normal    
Priority: P1    
Version: 1   
Hardware: All   
OS: windows   
Type: DEFECT SCM Refs:
Workaround: ---
Attachments: Example program which renders two rotating squares in two JFrames contained in a JSplitPane.
A better example. This one creates two JSplitFrames and three JPanels. The animator threads are started when the user selects the Test/Start All menu item. Sometimes it works, sometimes it doesn't.
Working version of test case

Description Sven Gothel 2010-03-24 07:47:15 CET


---- Reported by direwolf 2005-01-07 17:26:18 ----

Problem:  
It appears that two Animator threads controlling two GLCanvas objects deadlock,
or one of the threads starve.

Description:
This problem occurs when a single JFrame contains two JPanel's that each contain
a GLCanvas controled by an Animator thread.  Three behaviors have been observed:
 Both threads will deadlock; One thread will run and the other will starve; Both
threads run.

When both threads run, no exceptions are thrown and both panels will render with
animation, but other bugs crop up.  I've noticed that JMenuItem won't render
until it is highlighted.

When one of the animation threads is starved, the following exception is thrown:

Exception in thread "Thread-3" java.lang.NullPointerException
    at
net.java.games.jogl.impl.windows.WindowsGLContextFactory.getDummyGL(WindowsGLContextFactory.java:117)
    at
net.java.games.jogl.impl.windows.WindowsGLContext.choosePixelFormatAndCreateContext(WindowsGLContext.java:279)
    at
net.java.games.jogl.impl.windows.WindowsOnscreenGLContext.create(WindowsOnscreenGLContext.java:211)
    at
net.java.games.jogl.impl.windows.WindowsGLContext.makeCurrent(WindowsGLContext.java:135)
    at
net.java.games.jogl.impl.windows.WindowsOnscreenGLContext.makeCurrent(WindowsOnscreenGLContext.java:110)
    at net.java.games.jogl.impl.GLContext.invokeGL(GLContext.java:250)
    at net.java.games.jogl.GLCanvas.displayImpl(GLCanvas.java:208)
    at net.java.games.jogl.GLCanvas.display(GLCanvas.java:75)
    at net.java.games.jogl.Animator$1.run(Animator.java:107)
    at java.lang.Thread.run(Thread.java:595)


Code Example:
import net.java.games.jogl.*;
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
 
import javax.swing.*;
import javax.swing.event.*;
 
public class Main extends javax.swing.JFrame {
    private JMenuBar menubar;
    private JMenu fileMenu;
    private JMenuItem fileExit;
    private JPanel leftPanel, rightPanel;
    private JSplitPane splitPane;
    private TestPanel panel1, panel2;
     
    public static void main(String args[]) {
  EventQueue.invokeLater(new Runnable() {
  public void run() {
      new Main().setVisible(true);
  }
   });
    }
     
    public Main() {
        GLCapabilities cap=new GLCapabilities();
        cap.setHardwareAccelerated(true);
        cap.setDoubleBuffered(false);

   // This call ensures that the JMenuBar will render over the GLCanvas.
   JPopupMenu.setDefaultLightWeightPopupEnabled(false);
   
   // Create components.
   splitPane = new JSplitPane();
   leftPanel = new JPanel();
   rightPanel = new JPanel();
   menubar = new JMenuBar();
   fileMenu = new JMenu();
   fileExit = new JMenuItem();
   
   setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
   leftPanel.setLayout(new BorderLayout());    
   leftPanel.setPreferredSize(new Dimension(400, 600));
   splitPane.setLeftComponent(leftPanel);    
   rightPanel.setLayout(new BorderLayout());    
   splitPane.setRightComponent(rightPanel);
   
   getContentPane().add(splitPane, BorderLayout.CENTER);
   
   fileMenu.setText("File");
   fileExit.setText("Exit");
   fileExit.addActionListener(new ActionListener() {
  public void actionPerformed(ActionEvent evt) {
      fileExitActionPerformed(evt);
  }
   });
   
   fileMenu.add(fileExit);    
   menubar.add(fileMenu);    
   setJMenuBar(menubar);
       
   panel1 = new TestPanel();
   panel2 = new TestPanel();
   leftPanel.add(panel1, BorderLayout.CENTER);    
   rightPanel.add(panel2, BorderLayout.CENTER);
   
   pack();
   
   setSize(800, 600);  
   
   // Start the animation on panel 1.
   panel1.start();
 
/******************************************************
// When we attempt to start the animation on panel 2, the
// program will either lock up or the program will run but  
// panel2 won't render.  It's clear that the two animator
// threads are competing for some resource, causing a  
// deadlock or causing the second thread to starve.
 ******************************************************/
   panel2.start();
 
    }
     
    private void fileExitActionPerformed(ActionEvent evt) {            
   System.exit(0);
    }
     
    public class TestPanel extends JPanel {
   GLCanvas canvas;
   Animator animator;
   
   public TestPanel() {
  // The JPanel must use the Border layout manager.
  setLayout(new java.awt.BorderLayout());
   
  // Create the GLCanvas.
  canvas = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities());
  canvas.addGLEventListener(new TestRenderer());
   
  // Create an animator thread for the canvas.
  animator = new Animator(canvas);
   
  // Add the canvas to the center of the JPanel.
  add(canvas);
   
  // We need to create a Dimension object for the JPanel minimum size to fix a
GLCanvas resize bug.
  // The GLCanvas normally won't recieve resize events that shrink a JPanel
controled by a JSplitPane.  
  setMinimumSize(new Dimension());    
   }
   
   public void start(){
  animator.start();
   }
   
   public void stop(){
  animator.stop();
   }
   
   class TestRenderer implements GLEventListener {
  private GL gl;
  private GLDrawable gldrawable;
  float angle = 0;
   
  public void init(GLDrawable drawable) {    
      gl = drawable.getGL();
      this.gldrawable = drawable;
  }
   
  public void reshape(GLDrawable drawable, int x, int y, int width, int height) {
      gl. glViewport(0, 0, width, height);
  }
   
  public void display(GLDrawable drawable) {
      gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
       
      gl.glRotatef(angle, 0f, 0f, 1f);
      angle += 2;
       
      gl.glBegin(GL.GL_POLYGON);
      gl.glVertex2f(-0.5f, -0.5f);
      gl.glVertex2f(-0.5f, 0.5f);
      gl.glVertex2f(0.5f, 0.5f);
      gl.glVertex2f(0.5f, -0.5f);
      gl.glEnd();
  }
   
  public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean
deviceChanged) {}
   }
    }
}



---- Additional Comments From direwolf 2005-01-07 19:48:02 ----

Created an attachment
Example program which renders two rotating squares in two JFrames contained in a JSplitPane.




---- Additional Comments From direwolf 2005-01-08 03:38:00 ----

Created an attachment
A better example.  This one creates two JSplitFrames and three JPanels.  The animator threads are started when the user selects the Test/Start All menu item.  Sometimes it works, sometimes it doesn't.




---- Additional Comments From kbr 2005-04-30 07:46:25 ----

Created an attachment
Working version of test case




---- Additional Comments From kbr 2005-04-30 07:50:07 ----

I can't reproduce any deadlock with JOGL 1.1 b10 but can see the other reported
behavior like the menus not repainting. The latter appears to be due solely to
the CPU being starved. Creating a custom animation thread and drawing the three
canvases in turn works, and has the added side effect that the start and stop
menu items work all the time and don't throw any exceptions.




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

This bug was previously known as _bug_ 128 at https://jogl.dev.java.net/bugs/show_bug.cgi?id=128
Imported an attachment (id=33)
Imported an attachment (id=34)
Imported an attachment (id=35)

The original submitter of attachment 33 [details] is unknown.
   Reassigning to the person who moved it here: sgothel@jausoft.com.
The original submitter of attachment 34 [details] is unknown.
   Reassigning to the person who moved it here: sgothel@jausoft.com.
The original submitter of attachment 35 [details] is unknown.
   Reassigning to the person who moved it here: sgothel@jausoft.com.