Using the same Display/Keyboard/etc. in multiple threads

Hi.

First of all, thank you for putting together LWJGL; it’s just what I’ve been looking for and works perfectly. It’s really saved my project.

However, I’m having a little trouble getting to grips with something. Basically my situation is this: I want to create the Display and Keyboard (and probably other LWJGL objects in the future) in one thread, but I wish to have access to the same objects in other threads. For example, one thread will be making heavy use of Display and one will be making heavy use of Keyboard.

Last night I became very confused by all of this; if I jumped straight into the ‘run’ method of my Display-using Thread object, it would work perfectly, however using the ‘start’ method to begin a new thread caused a severe Null Pointer Exception when using Display.update. I decided to download the LWJGL code and dig around to find out exactly what happens at Display.update – eventually I discovered that there has been quite a bit of effort put in so that different threads can own different rendering contexts; exactly what I didn’t want to happen! :smiley:

In an attempt to amend this, as soon as the Display object was created, I stored the Context (through Display.getContext()) into a static object. On entering a different thread, I then used GLContext.useContext(), passing the stored Context object. This seemed to get rid of the Null Pointer Exception, which was nice, but now introduced a different error. On calling Display.update(), it now causes an “Invalid Operation 1282” error in glGetError(). After searching around on Google, I took some advice on this message board of placing Util.checkGLError() around the place. Even putting it immediately before the call to Display.update() didn’t find any errors though, so this has left me even more puzzled.

At the end of it, I decided that this method that I was using to evade the thread-local GLContext wasn’t the right way to go. So could anybody recommend a sensible method of acheiving what I want to acheive? In short, I want to be able to access exactly the same Display/Keyboard/etc. object from any of the threads in my program.

I’ve just run some more tests and there is a slight inaccuracy in my previous post; the OpenGL “Invalid operation (1282)” error occurs any time after I try to switch the context in the new thread.

Here is the code where I save the current context in the main thread:


OpenGL.setContext(Display.getContext());

Where this ‘OpenGL’ context just basically holds an Object and returns it when it’s asked; this is the object that grabs hold of the context and passes it between threads.

When the new thread begins, here is the code that restores the context:


	public void run()
	{
		// First thing to do is to tell OpenGL to use the same
		// rendering context as the main thread.
		try
		{
			GLContext.useContext(OpenGL.getContext());
		}
		catch(LWJGLException ex)
		{
			finished = true;
			return;
		}
		
		Util.checkGLError();

Calling Util.checkGLError() immediately before starting the new thread produces no OpenGL errors. After the thread is created, no OpenGL or Display-modifying functions are called in the main thread, so this is not the source of the errors (I’ve checked thoroughly with Util.checkGLError()). However, as soon as I set the OpenGL context with the above code, this is where the OpenGL error starts appearing.

[EDIT]
I’m very sorry to keep messing around like this, but I seem to be more awake than I was at 4:30 last night when I came up with the idea of what was going wrong. I have just been experimenting even more and discovered this:

  1. The Display -is- accessible through all Threads, so sorry about the subject of this thread. I hadn’t tested it correctly.
  2. I’ve discovered exactly which part of the program is going wrong: here is more info…

From the stack trace, the origin of the null pointer exception is in GL11.java on line 1839:


long function_pointer = GLContext.getCapabilities().GL11_glGetError_pointer;

So to test out the exception and get things clear, I have changed my thread entry point code to this:


	public void run()
	{
		try { Keyboard.create(); }
		catch(LWJGLException ex) { ex.printStackTrace(); }
				
		if(GLContext.getCapabilities() == null)
			System.out.println("it was null.");
		
		Util.checkGLError();

Display.create() was called in a different thread (the Display -has- been created upon entering the thread with the code shown above). Inside the thread where Display.create() was called, GLContext.getCapabilities() is not null.

Now, I think I have discovered exactly what I am trying to do (so sorry once again for changing my mind about the problem so many times): I need to be able to access the same GL context throughout all of my threads, rather than each Thread keeping its own copy. If my understanding is correct, the GLContext object is thread local, so each time a new Thread accesses the GLContext.getCapabilities() method, the capabilities created inside that thread are returned. In my case, I’m calling GLContext.getCapabilities (implicitly through Util.checkGLError()) inside a thread which has -not- (and cannot) call Display.create().

So, now I believe the clear question that I am asking is this: how can I maintain the same GLContext throughout all Threads? I have a feeling that doing something similar to this is an incorrect way of going about it:


	public void run()
	{
		try
		{
			GLContext.useContext(Display.getContext());
		}
		catch(LWJGLException ex)
		{
			ex.printStackTrace();
		}
				
		if(GLContext.getCapabilities() == null)
			System.out.println("it was null.");
		
		Util.checkGLError();

While using this line of code, it does stop the null pointer exceptions (and the test for GLContext.getCapabilities() is now -not- null), I end up receiving this error when calling Util.checkGLError(): “Exception in thread “Thread-0” org.lwjgl.opengl.OpenGLException: Invalid operation (1282) at org.lwjgl.opengl.Util.checkGLError(Util.java:56)”.

Hopefully I’ve now got my question clear; once again, sorry for the lack of clarity in my previous posts.

[/EDIT]

LWJGL is intended to be used in single threaded mode - the may or may not be issues related to multithread access.
That said, you might want to call Display.makeCurrent();

Hi Matzon.

I tried modifying my new thread to this:


	public void run()
	{
		try
		{
			Display.makeCurrent();
		}
		catch(LWJGLException ex)
		{
			ex.printStackTrace();
		}
				
		if(GLContext.getCapabilities() == null)
			System.out.println("it was null.");
		
		Util.checkGLError();

The stack trace produced by the makeCurrent() call is this:

Note: My previous post has been edited; I didn’t see your response until I applied the changes to it. Maybe the changes in that previous post can help shed some more light on this?

Why do you need to access the context from different threads? It’s usually better to let only one thread interact with OpenGL. Other threads can queue up their commands that is proccessed in the worker thread.

Originally, we had different subsystems in different threads - for example, the input subsystem would be in one thread, rendering subsystem in another, etc.

I looked through the code relevant to what I was trying to acheive and decided that maybe it would just be best to go with the one-thread approach. I’m currently in the middle of converting the engine components to work in a single-threaded environment and it’s coming along very well. Now I will be able to continue moving completely from Java2D to LWJGL.

Cheers for the suggestions and help. Keep up the excellent work on LWJGL.

Regards,
Chris.