Multithreading a 3DEngine...this is nasty!?

Hi,

I have now decided to move the code in our framework around so that we have a number of threads.

Firstly, I have the main message dispatching loop that just uses thePeek/Translate/Wait/DispatchMessage() functions. This starts by calling the main routine to get our 3D drivers and then to set one up, then loops until the end of the program and then calls the exit code to delete the driver.

Secondly, there is a WndProc that puts events into a queue - this queue is locked with a mutex. If the app becomes inactive it sets a flag - under mutual exclusion.

Thirdly, I have moved the rendering code to another thread to free up the main app thread. This removes a message from the queue and calls the driver to do whatever needs to be done. If the app is inactive, this thread will wait on a semaphore until the WndProc thread gets an activate message.

The problem is this, when using the OpenGL driver the first time I go into the Flip() function, it crashes at SwapBuffers(m_hDC). I get the following message “Unhandled exception in <myapp> (NVOGLNT.DLL): 0xC0000005: Access violation.”

My driver is the latest from the NVidia site: 5.12.01.0631.

Has anybody else had a problem like this? (Or the same?)

Also, is there any way to check - like a monitor or something - how many threads are accessing something at any one time? This shouldn’t be happening as I’m putting all messages recieved into a queu to be taken out by another thread as I don’t want the WndProc thread to become locked ever.

Thanks,
Luke A. Guest.

Yes, multithreading is nasty.

Is there just one GLRC, or many?

Which thread is the GLRC current in? Is that the same thread you call SwapBuffers in? You only make GL calls in one thread, right? (SwapBuffers can be called from either thread, but doing this has some annoying implications.)

If it makes you feel better, Carmack is doing no better than you are. If you set r_smp to 1 in Q3 1.17, the app hangs immediately on startup. It’s not hung in our driver or anywhere near it, and it happens with MS OpenGL too, so it’s not our bug.

  • Matt

Ok, call me a plank! I got it to stop crashing!

I just saw a message, that says that the thread that creates an RC must release it before another can use it. So, I moved the code that creates and destroys the driver to the thread that handles the messages and calls the driver.

The app now works except for a deadlock somewhere…hmmm, do I need to change the event queue to a monitor?

Thanks,
Luke A. Guest.

Originally posted by mcraighead:
[b]Yes, multithreading is nasty.

Is there just one GLRC, or many?
[/b]

Just the one.

[b]

Which thread is the GLRC current in? Is that the same thread you call SwapBuffers in? You only make GL calls in one thread, right? (SwapBuffers can be called from either thread, but doing this has some annoying implications.)
[/b]

Erm, I have a thread which is called in a loop. This is to replace our OnSlice() function that was called on every frame.

As I mentioned, I have just moved the code to create the driver to the beginning of this funciton and the code to destroy it to the end. In between is a loop that just processes whaever is in the queue.

I have just found that when the main run loop calls WaitMessage(), it hangs and gets no more messages. I think I need to synchronise on the vertical blank interval somehow. I think I’m starving the main run thread of getting anymore messages. Bugger!

[b]

If it makes you feel better, Carmack is doing no better than you are. If you set r_smp to 1 in Q3 1.17, the app hangs immediately on startup. It’s not hung in our driver or anywhere near it, and it happens with MS OpenGL too, so it’s not our bug.

  • Matt[/b]

Ah, that’s good to hear

Luke.

> Yes, multithreading is nasty.

I beg to differ :slight_smile:

However, it’s not always the right tool.
“The current OpenGL context” is thread-local
information, so you can’t share it between
threads.

Also, the design you describe seems over-
threaded: you’ll add a lot of synchronization
overhead without actually gaining much. The
Windows scheduler is not exactly predictable
enough that you want to base your game’s
performance on being able to switch in THREE
differnt threads just to dispatch a single
user message.

Originally posted by bgl:
> Yes, multithreading is nasty.

I beg to differ :slight_smile:
[/b]

I don’t. Multithreading is extremely handy, but requires a total leap in terms of programming. Most (if not all) people have trouble with it. But that isn’t down to the problems of having multiple threads; it’s due to synchronisation and knowing where to use and how.

[b]

However, it’s not always the right tool.
“The current OpenGL context” is thread-local
information, so you can’t share it between
threads.

Also, the design you describe seems over-
threaded: you’ll add a lot of synchronization
overhead without actually gaining much. The
Windows scheduler is not exactly predictable
enough that you want to base your game’s
performance on being able to switch in THREE
differnt threads just to dispatch a single
user message.[/b]

I’m not convinced about being “over threaded.” Windows will give you an implicit thread - your WNDPROC function; it’s really a callback, but it’s on a separate thread all the same. I just wanted to alleviate the pressure of the rendering from the main thread - WinMain() (which essentially, in our apps, just dispatch messages) - and move it somewhere better; on it’s own, where we can call the driver as much as we like from one place.

So, I can safely say that we only really have 2 threads - the other is provided by Windows.

Luke.