[Solved] Game never draws, multi-threading.

Hey all, when I load a level the display thread halts until loaded (using JOGL), so I figure I’ll just make a new window and throw it on top until the level is finished loading. This works fine in Eclipse, but after an export to runnable jar everything works up until clicking on the play button which calls the following method.


	private void loadLevel()
	{
		m_loader = new LoaderGraphic(m_window_width, m_window_height);
		Thread thread = new Thread(m_loader, "FFS02 - RendererLoader:" + m_level_name);
		thread.start();
		
		m_game_renderer = new GameRenderer();
		m_game_renderer.init(m_gl, m_window_width, m_window_height, m_level_name);//loads level in here
		m_loader.stop();//sets a boolean to false ending the main loop
		try{ thread.join(); } 
		catch (InterruptedException e){ e.printStackTrace(); }
		m_renderer = m_game_renderer;
		m_load_level = false;
	}

What is supposed to happen (and does in the IDE) is LoaderGraphic throws up a new window and renders a loading screen, once finished I stop the graphic and kill the thread. The main window shows again and the level is there.

When using a runnable jar I click the play button, the main thread freezes up and the level loads, no loading screen shows up. After the level loads the main window never draws again, but I hear sound and output to console says everything is fine…

Edit: removed the term lock as that’s not what I mean ( no .wait() calls)

I probably can’t help much with the multithreading aspect, but I’ll ask a couple of questions, which might make things clearer for others.

  1. What does LoaderGraphic use for rendering? I assume it’s something other than OpenGL?

  2. Separate from the problems you’re seeing, doesn’t the method you’re using lock up the event thread during loading? I ask because (I think) part of the point of multithreaded loading is to allow the event thread to keep running, and it doesn’t seem like that would happen here.

(To be clear, I could be way off on both the above questions, but those are the first things that came to mind.)

  1. LoaderGraphic does use openGL to render.
  2. Yes the current thread stops execution while the level loads (line 8 ) until finished. Since I’m using JOGL there’s no (simple) way to prevent the main draw thread (where this method resides) from locking while loading graphics that require the current openGL context.

However, like I said this works as expected in Eclipse. Main draw thread loads level (and doesn’t draw until finished), but a new window draws a graphic on top so the freeze isn’t seen.

So does that mean you’re sharing the OpenGL context between two threads somehow? If so, maybe you could provide some more info on that, because that sounds like the kind of thing that might work in one context but fail in another.

Maybe you already know this, but the typical solution to this problem (I think) is to do all aspects of loading that can reasonaby be done off the main thread in a separate thread, and then do only what has to be done on the main thread on the main thread. For example, to load OpenGL textures in the background, you’d load and decompress the images off the main thread but create the actual OpenGL textures on the main thread. Typically the kind of work that actually has to be done on the main thread (creating and uploading textures and VBOs, etc.) isn’t particularly time-consuming, so it’s really not important to multithread it anyway.

As you note, doing it this way may not exactly be simple, depending on how your architecture is currently set up. But, everything I’ve read suggests that’s how it’s typically done.

In any case, it seems to me the primary purpose of multithreaded loading is to avoid blocking the event thread (a secondary purpose would be smooth animation of loading graphics, if you have need for that). Since you’re blocking the event thread anyway, it doesn’t seem like the multithreading serves much purpose here.

But, I could be wrong about any or all of this. Maybe someone else will jump in and provide more useful feedback.

No, this is a new window with a separate openGL context. The idea is to hide the fact that the main thread is blocked.

Maybe you already know this, but the typical solution to this problem (I think) is to do all aspects of loading that can reasonaby be done off the main thread in a separate thread, and then do only what has to be done on the main thread on the main thread. For example, to load OpenGL textures in the background, you’d load and decompress the images off the main thread but create the actual OpenGL textures on the main thread. Typically the kind of work that actually has to be done on the main thread (creating and uploading textures and VBOs, etc.) isn’t particularly time-consuming, so it’s really not important to multithread it anyway.

As you note, doing it this way may not exactly be simple, depending on how your architecture is currently set up. But, everything I’ve read suggests that’s how it’s typically done.

In any case, it seems to me the primary purpose of multithreaded loading is to avoid blocking the event thread (a secondary purpose would be smooth animation of loading graphics, if you have need for that). Since you’re blocking the event thread anyway, it doesn’t seem like the multithreading serves much purpose here.

But, I could be wrong about any or all of this. Maybe someone else will jump in and provide more useful feedback.
[/quote]
Yes, I understand that. However, JOGL has proven to be very limiting in this respect. If I load the assets in a separate thread, either sharing the current context or not, the assets do not draw properly (white blocks where textures should be, meshes don’t draw, shaders are buggy).

The idea is to do all non-thread-dependent work in a separate thread, but then do anything directly related to OpenGL (like creating shaders/programs/textures/VBOs, uploading data, etc.) on the main thread. This way, all the time-consuming stuff (reading from disk, decompressing images, building mesh data, etc.) can be done on a separate thread, but everything directly related to OpenGL still occurs on the main thread.

In any case, I’ll offer my take, and then bow out in the hopes that someone else can step in and offer a more authoritative solution to your problem. It seems to me that there shouldn’t be any need to create multiple windows and OpenGL contexts, and that in fact such efforts could easily be the cause of the problems you’re seeing (the details of course depend on exactly how you’re doing things, what libraries/APIs are being used, etc.). It also seems to me that you’re foregoing one of the primary purposes of multithreaded loading, which is not to block the event thread so that the app remains responsive during loading and so the OS won’t complain (as some OSs do) if the event thread doesn’t respond for some significant amount of time.

The suggestion proposed - to do all non-thread-dependent loading work on a separate thread so as not to block the event/rendering thread - would achieve both the primary goals of multithreaded loading, that is, keeping the event thread responsive and allowing for smooth animation of loading graphics, if needed. It is true though that it can require some architectural revision if you haven’t planned ahead for it.

But, maybe someone else can offer some better advice :slight_smile:

Jesse, let’s say this is thread dependent. I need the current GL context to create textures, bind vbos, etc. The only part that’s not is loading the level from disk, and separating the logic is not my intention this go around.

nvm

How long does the level loading actually take?

Depending on the hdd ~10-30 seconds.

Has that been optimized?

No, I’m just reading a serialized object that I saved doing an object.write(). Also, I know that getting it down to a few seconds would be acceptable, but I would prefer a loading screen just to be safe =)

Have you attempted to render a loading screen each frame, and then load the file on another thread, posting tasks to the OpenGL context with invoke(boolean,GLRunnable)?

I admit I don’t really know anything about JOGL, but if you haven’t tried it then loading the stuff on a background thread while rendering a screen (in the same window) and doing OpenGL-related tasks on the OpenGL thread would be my suggestion.

@CopyableCougar4 Thank you!, not for what you said, but what you said (doesn’t make sense I know).

Anyway the issue comes from JOGL not liking multi-threading by default. You have to give the VM the following argument -Djogl1.thread=false

I assumed that because I exported the project that it would take the VM arguements with, not sure why I’d assume that, but regardless it didn’t.

So, basically since JOGL uses the AWT thread for rendering you have to tell it you want to be able to have multiple contexts, or you can only have one running on your machine at a time (or something like that).