Sharing Context between GLJPanels

Hi,

I read almost all the posts about gljpanel, init, display lists, context but didn’t find an answer to my question.

I’m just trying to draw different sound waveforms in a GLJPanel (the waveform is chosen in a JTree and then drawn in the GLJPanel, in the same frame).
This works fine but I want to optimise with display lists, and later I will need different GLJPanels to run at the same time, so I need context sharing too.

I read it is normal that the init method is called quite often.
So I’m trying to share the context of my GLJPanel, but I don’t understand how to do it.

Following the TestContextSharing in the demos, I can see it works for GLCanvas, but I didn’t get this example to work with GLJPanels.

GLContext.getcurrent() is null.
myGLJPanel.getContext() is null too.
myGLJPanel.createContext(GLContext.getCurrent()) ?

Can someone explain me how to do it please ?
If someone manage to get TestContextSharing working with GLJPanel, it would be great, something to start from !

Thanks a lot

Léo

(Mac Os X, jogl 07/03/06)

Yes, there are some issues in this area because of the lazy creation of the pbuffer or other internal context associated with the GLJPanel. One workaround would be to make a small 1x1 pbuffer and make both GLJPanels share with that. Another would be to defer the instantiation of your other GLJPanel until the first one has been shown, though I understand this could be a real pain. Please feel free to file a bug with the Issue Tracker on the JOGL home page about this.

Hi,

thanks for your response

the fact is that I don’t know how to share context ! I doesn’t seem to work.
For the moment I just want my GLJpanel not to clear its display lists each time the init method is called.

I tried creating a dummy GLCanvas and creating my GLJpanel this way :

	dumCanvas = new GLCanvas();
	glp = new GLJPanel(new GLCapabilities(), new DefaultGLCapabilitiesChooser(), dumCanvas.getContext());

Display lists always vanish after a call to init().

Following your response I tried to create a GLPBuffer and share its context with my GLJpanel (for instance, I need only one) this way :

	GLPbuffer glpb = GLDrawableFactory.getFactory().createGLPbuffer(new GLCapabilities(), new DefaultGLCapabilitiesChooser(), 1, 1, GLContext.getCurrent());
	glp = new GLJPanel(new GLCapabilities(), new DefaultGLCapabilitiesChooser(), glpb.getContext());

Same result.

Can you please be more precise on how to share context ?

Thanks

Léo

You don’t need the call to GLContext.getCurrent() when creating the GLPbuffer but that should work. Your init() method will still get called multiple times, but the fact that the pbuffer shares display lists with your GLJPanel should mean that you can just refer to the display list names from the last call to init(). Could you check this again? If things are still not working, could you post a test case?

[quote]You don’t need the call to GLContext.getCurrent() when creating the GLPbuffer but that should work.
[/quote]
So what do I have to do to generate the GLPbuffer ?

this doesn’t work :

	GLPbuffer glpb = GLDrawableFactory.getFactory().createGLPbuffer(new GLCapabilities(), new DefaultGLCapabilitiesChooser(), 1, 1, GLContext.getCurrent());
	glp = new GLJPanel(new GLCapabilities(), new DefaultGLCapabilitiesChooser(), glpb.getContext());

and this neither :

	glpb = GLDrawableFactory.getFactory().createGLPbuffer(new GLCapabilities(), new DefaultGLCapabilitiesChooser(), 1, 1, null);
	glp = new GLJPanel(null,null,glpb.getContext());

So ?

[quote]If things are still not working, could you post a test case?
[/quote]
I’ll try to make something simple ASAP.

Thanks

Léo

Either of those two lines should be correct.

Please write up a test case.

HI,

first thanks for your help

Sorry it’s a bit complicated and I’m french so my english is a bit ~.

I’m writing a little test but as you can see in the following thread http://www.java-gaming.org/forums/index.php?topic=12784.0
I’m running mac os 10.4.5 and I’ve got another problem (but maybe it is the same problem !) :
I can’t resize a window containing a GLJPanel.

Until now I haven’t noticed this in my soft (though i noticed it in the demos)
because I implemented a different resize method.
With my method there isn’t problems while resizing the window (because the window isn’t resized until the user released the mouse button)
but maybe this method produces the bug I’m trying to describe you (context sharing), I don’t know maybe it erases something

With the following code you can test both bugs.
It creates 5 random display lists.
The user can choose which one he wants to see.
There are two resize methods (which can be changed via the MODE variable)
* The default one is a home-made window resize method (the window isn’t resized until the user released the mouse button)
* The other one is the default system window resize method (it doesn’t work here, I’ve got an endless spinning wheel)
Each time the user choose a number in the combo, a different list is shown and the window in randomly resized.
The black button on the right is the home-made resize button.

From time to time (both with the automatic resize method and the home-made resize button) the init method is called and my display lists vanish.

With the second resize method (MODE = RESIZE_ENABLED) i can’t resize the window manually
but with the random resize I can see that when the init method is called display lists vanish.

Hope it’s clear
Hope you can reproduce this
Hope there’s a solution

Léo



import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;
import javax.media.opengl.DefaultGLCapabilitiesChooser;
import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLDrawableFactory;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLJPanel;
import javax.media.opengl.GLPbuffer;
import javax.media.opengl.glu.GLU;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class TestSharingGLJPanel extends JPanel implements GLEventListener, ItemListener
{
	// resize mode variables
	private final static int RESIZE_DISABLED = 0;
	private final static int RESIZE_ENABLED = 1;
	private int MODE = RESIZE_DISABLED; // CHANGE THE MODE TO SEE THE DIFFERENT BEHAVIOURS
	private JButton resizeBox;
	public int sizW = 400;
	public int sizH = 400;
	private int dTX, dTY;
	private Cursor curs;

	private int width;
	private int height;
	private int margin = 2;
	private float max = 100;

	// display lists variables
	private int listID = 0;
	private int listToDisplay = 1;

	private JFrame frame;

	// opengl variables
	private GLU glu = new GLU();
	private GL gl;
	private GLJPanel glp;
	private GLPbuffer glpb;

	public static void main(String[] args)
	{
		new TestSharingGLJPanel();
	}

	public TestSharingGLJPanel()
	{
		// create a dummy GLPBuffer for context sharing
		glpb = GLDrawableFactory.getFactory().createGLPbuffer(new GLCapabilities(), new DefaultGLCapabilitiesChooser(), 1, 1, null);
		// create the GLJPanel with the GLContext of the GLPBuffer
		glp = new GLJPanel(null, null, glpb.getContext());
		glp.addGLEventListener(this);

		// GUI
		setLayout(new GridLayout(1, 1));
		add(glp);

		// Combox box for choosing the list to display
		JComboBox combo = new JComboBox(new Integer[] { new Integer(1), new Integer(2), new Integer(3), new Integer(4), new Integer(5) });
		combo.addItemListener(this);
		
		// the "force build lists" button
		JButton forceBuild = new JButton("Build Lists");
		forceBuild.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				// this will force lists to be build once more in the display method
				listID = 0;
				glp.display();
			}
		});

		// the frame containing all
		frame = new JFrame("This is just a test !");
		
		// adds the GLJPanel
		frame.getContentPane().setLayout(new BorderLayout());
		frame.getContentPane().add(this, BorderLayout.CENTER);
		
		// panel containing the combo box, the "build lists" button and the resize box)
		JPanel southPanel = new JPanel();
		southPanel.setLayout(new BorderLayout());
		southPanel.add(combo, BorderLayout.CENTER);
		southPanel.add(forceBuild,BorderLayout.WEST);
		// resize mode
		switch(MODE)
		{
		case RESIZE_ENABLED :
			frame.setResizable(true);
			break;
		case RESIZE_DISABLED :
			frame.setResizable(false);
			addResizeBox(combo, southPanel);
			break;
		}
		
		frame.getContentPane().add(southPanel, BorderLayout.SOUTH);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setSize(sizW, sizH);
		frame.setLocationRelativeTo(null);
		frame.setVisible(true);
		
	}

	// A non-system resize box
	private void addResizeBox(JComboBox combo, JPanel southPanel)
	{
		resizeBox = new JButton();
		resizeBox.setBorder(BorderFactory.createRaisedBevelBorder());
		resizeBox.setBackground(Color.DARK_GRAY);//.createLineBorder(Color.BLACK));
		resizeBox.setSize(new Dimension(14, 14));
		resizeBox.setPreferredSize(new Dimension(14, 14));
		resizeBox.setMaximumSize(new Dimension(14, 14));
		resizeBox.setMaximumSize(new Dimension(14, 14));
		resizeBox.setMargin(new Insets(0, 0, 0, 0));
		resizeBox.setVisible(true);
		resizeBox.setEnabled(true);
		resizeBox.setVerticalAlignment(JButton.BOTTOM);
		resizeBox.setCursor(new Cursor(Cursor.SE_RESIZE_CURSOR));
		
		// the window will not be resized until the mouse button has been released
		resizeBox.addMouseListener(new MouseAdapter()
		{
			public void mousePressed(MouseEvent e)
			{
				dTX = e.getX();
				dTY = e.getY();
				curs = getCursor();
				resizeBox.setCursor(new Cursor(Cursor.SE_RESIZE_CURSOR));
			}

			public void mouseReleased(MouseEvent e)
			{
				sizW += (e.getX() - dTX);
				sizH += (e.getY() - dTY);
				resizeBox.setCursor(curs);
				frame.setSize(sizW,sizH);
			}
		});
		southPanel.add(resizeBox, BorderLayout.EAST);
	}

	// when the combo chosen item change
	public void itemStateChanged(ItemEvent e)
	{
		if (e.getStateChange() == ItemEvent.SELECTED)
			try
			{
				listToDisplay = ((Integer) e.getItem()).intValue();

				// automatically resize the window
				Random rand = new Random();
				int k = (int)(rand.nextFloat() * 200) - 100;
				frame.setSize(frame.getWidth()+k,frame.getHeight()+k);
				
				glp.display();
			}
			catch (ClassCastException ex)
			{
			}
	}

	public void init(GLAutoDrawable drawable)
	{
		System.out.println("init");
		gl = drawable.getGL();
		gl.glShadeModel(GL.GL_SMOOTH);
		gl.glClearColor(1,1,1,1);
		gl.glPointSize(5);
		gl.glViewport(0, 0, (int) width, (int) height);
		gl.glEnable(GL.GL_POINT_SMOOTH);
		gl.glEnable(GL.GL_BLEND);
		gl.glPolygonMode(GL.GL_FRONT, GL.GL_FILL);
		gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
		gl.glMatrixMode(GL.GL_PROJECTION);
	}

	// class for building random lists (in my soft of course those list aren't random)
	public void buildLists()
	{
		listID = gl.glGenLists(5);
		float stepSize = 10;
		Random rand = new Random();
		for (int i = listID; i < listID + 5; i++)
		{
			System.out.println("creating list : " + i);
			gl.glNewList(i, GL.GL_COMPILE);
				gl.glColor4f(0, 0, 0, 1);
				gl.glLineWidth(1);
				gl.glBegin(GL.GL_LINE_STRIP);
					for (int j = 0; j <= stepSize; j++)
					{
						gl.glVertex2f(j * 10, rand.nextFloat() * 100);
					}
				gl.glEnd();
			gl.glEndList();
		}
	}

	public void display(GLAutoDrawable drawable)
	{
		gl = drawable.getGL();
		gl.glClear(GL.GL_COLOR_BUFFER_BIT);
		gl.glLoadIdentity();
		glu.gluOrtho2D(0, max, 0, 100 + 2 * margin);
		drawMargins(gl);
		
		// flag for creating new lists if they've been destroyed and if the user clicks on "Build Lists"
		if (listID == 0)
		{
			System.out.println("init list");
			buildLists();
		}

		// displaying the random lists
		if (listToDisplay > 0 && listToDisplay <= 5)
		{
			System.out.println("calling list : " + listToDisplay);
			gl.glCallList(listToDisplay);
		}
		
		gl.glFlush();
	}

	private void drawMargins(GL gl)
	{
		gl.glColor4f(0.5f,0.5f,0.5f,0.5f);
		gl.glBegin(GL.GL_POLYGON);
			gl.glVertex2f(0, 100 + margin);
			gl.glVertex2f(max, 100 + margin);
			gl.glVertex2f(max, 100 + 2 * margin);
			gl.glVertex2f(0, 100 + 2 * margin);
		gl.glEnd();
		gl.glBegin(GL.GL_LINES);
			gl.glVertex2f(0, 50 + margin);
			gl.glVertex2f(max, 50 + margin);
		gl.glEnd();
		gl.glBegin(GL.GL_POLYGON);
			gl.glVertex2f(0, 0);
			gl.glVertex2f(max, 0);
			gl.glVertex2f(max, margin);
			gl.glVertex2f(0, margin);
		gl.glEnd();
	}

	public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height)
	{
		this.width = width;
		this.height = height;
		glu.gluOrtho2D(0, max, 0, 100 + 2 * margin);
	}

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

I just tried my test on my PC (until now I tested on a powerbook)

So on windows XP, java 1.5.0_06, NVIDIA Geforce MX 400
except for the endless spinning wheel on window resize,
I’ve got the same behaviour (display lists vanish after a call to the init method).

So…

Any solution ?

Thanks

Léo

OK, sorry about this. In order to force the pbuffer to actually create an OpenGL context you have to try to render into it at least once. This means that if you add a call to glpb.display() immediately after creating it then your example will work as expected. We can’t really hide this in the implementation, I think, because otherwise it will be difficult to propagate the init() callback out to the end user.

I don’t know what’s happening with the resizing issues on OS X yet.

Hi

[quote]In order to force the pbuffer to actually create an OpenGL context you have to try to render into it at least once. This means that if you add a call to glpb.display() immediately after creating it then your example will work as expected.
[/quote]
It works great. Thanks.

[quote]I don’t know what’s happening with the resizing issues on OS X yet.
[/quote]
Are you able to reproduce it ?

Léo

I wasn’t able to see any problems with my home machine (running 10.3.9) but will try again on my office Mac on Monday, which is running 10.4.5.

The hang upon resizing of GLJPanels on OS X has been fixed. Sorry for taking so long to track this down. The fix will be present in the nightly builds dated 3/19 or later.

Thanks,
sorry for the delay, I was working on something else waiting for this to be fixed.
I’ll test it asap.
Thanks again.

Léo

Ok it works tough resizing is a bit slow.
Thanks

Léo

GLJPanels are pretty abysmally slow on OS X even with high-end hardware. However, in Apple’s release of Mustang the Java2D/JOGL bridge should be enabled on that platform which should solve all of the speed issues.

Hi

I finally got all working well on my powerbook G4 1.67GHz (ATI ATY,RV360M11 AGP 64 Mo) Mac OS 10.4.6 Java 1.5.0_06
I’ve got 5 windows with GLJPanel doing 2D drawing (one 3D) simultaneously and sharing context.

Now I’m testing this app on a G5 2*2.23GHz (GeForce 6600 PCI 256 Mo) Mac OS 10.4.6 Java 1.5.0_06
and it doesn’t work at all
it’s very very slow, even with only one window open.

While trying to find the problem I tried the jogl demos.
It seems that this G5 doesn’t like GLJpanels at all, all demos work fine except the JRefract demos (with Jogl/Swing interoperability)
For example the JGear demo runs @ 2.96fps without transparency on the G5 while on my pbook it runs @ 32fps.

[quote]GLJPanels are pretty abysmally slow on OS X even with high-end hardware.
[/quote]
Is this what you’re talking about ?

[quote]However, in Apple’s release of Mustang the Java2D/JOGL bridge should be enabled on that platform which should solve all of the speed issues.
[/quote]
I saw today that apple released a first version of mustang, do you think it can solves this problem ?

Thanks

Léo

Yes, the extremely slow frame rates with GLJPanels on hardware like G5s is what I’m talking about. There isn’t a workaround for this at the moment. Apple is still working on implementing the OpenGL pipeline for Java2D to the best of my knowledge; once it’s in place it should only take a couple of weeks to get the Java2D/JOGL bridge working on that platform. Note that Apple doesn’t currently have a Mustang build for PowerPC though.

It’s a pity.
Tested on another G5 with a nVidia GeForce FX 5200 AGP 64Mo (os 10.4.6 java 1.5.0_06) and
on an iBook with a nVidia GeForce FX Go 5200 AGP 64Mo (os 10.4.6 java 1.5.0_06).
Better but still unusable.
It seems that nVidia rendering is terrible ! (not only slow but also triangles with holes and no clearing of the window before drawing.
Maybe it’s a nVidia problem more than a jogl or osX one ?

[quote]Note that Apple doesn’t currently have a Mustang build for PowerPC though.
[/quote]
Quote from Apple Developper Connection (https://connect.apple.com/) :

But maybe I misunderstood something.

Thanks

Léo

Another test on a imac G5 1.9GHz ATI RV370 PCI-E 128Mo Mac os 10.4.6 Java 1.5.0_06
Works great.

I never believed I’d say that but today I love ATI.

Léo

Thanks for pointing out the PowerPC port of Mustang for OS X. The last time I checked was DP1 which was Intel-only.

I think the problem is probably more Apple’s driver implementation for NVidia hardware on OS X. I would suggest you subscribe to the mac-opengl or another Apple mailing list and post there about these performance issues with NVidia hardware. Since the GLJPanel by default only really uses very generic operations like glReadPixels and BufferedImage rendering I think there must be some low-level performance issues in Apple’s NVidia drivers.