1
\$\begingroup\$

I'm trying to use a different Thread for the whole WinAPI-Message-Loop stuff, so the window always keeps being responsive. Of course I'm using the main thread as the "window thread", because I need a context before loading textures etc. and I can't just call Get/PeekMessage for a different thread.

Now there are a few things I'm wondering about though:

  1. Can I use the OpenGL context handle from a different thread? I'm relatively sure I can since otherwise there would be no way to do multi-threaded rendering, but maybe there's more to it.
  2. At some point I have to call SwapBuffers() from inside the render loop - that means in this case, from a different thread. Can I just use the HDC I usually use? Is this handle thread-safe? I'm not so sure about that, but I can't really find a definitive answer on the subject.

If the answer is no, what would be a good method to deal with the issue? Maybe I can send a message from the render-thread?

\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

No, you generally cannot interact with your main window from not the main thread. Since the GL context is tied to the HWND, you cannot generally issue GL commands from threads that are not the main thread.

"Multithreaded rendering" is only about doing data processing and whatnot. You can do all kinds of math and processing on worker threads. But OpenGL commands should all be issued from the main thread.

Generally what you do to keep the main window responsive is have heavy work done on separate threads, and have them set some kind of flag when they are finished, which lets the main window move on to the next stage of the program.

Consider this:

// main thread
while( 1 )
{
    if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
    {
        Translate/dispatchmessage
    }
    else
    {
        update();
        draw();
    }
}

Inside draw():

void draw()
{
    switch( programState )
    {
        case Title:
          //draw the title
          break;
        case InGame:
          // draw in game
          break;
    }
}

So the worker thread will (MUTEX LOCK AND) change the value of programState when it is done loading the level, for example.

\$\endgroup\$
4
  • \$\begingroup\$ Okay, well I guess than I have to do the thread-abstraction elsewhere. I'll accept your answer in a few hours. :) \$\endgroup\$
    – cooky451
    Mar 24, 2013 at 1:11
  • \$\begingroup\$ You wanted your entire program (including Window/UI thread) to just choose a thread from a kind of threadpool and run its work on it? \$\endgroup\$
    – bobobobo
    Mar 24, 2013 at 1:48
  • 1
    \$\begingroup\$ No. I would've implemented a job-system further down. I just wanted to really abstract away the whole window stuff. So the main Thread would've just used the usual GetMessage-Loop, while pumping the events into a thread-safe queue, from which the game loop could then read. I'm wondering though: If I can't call glTexImage2D etc. from a different thread, I have to be really careful about memory mapped files? Because then that call could potentially lock for a longer time, and since I can't separate the message queue, that would mean that the window is unresponsive. \$\endgroup\$
    – cooky451
    Mar 24, 2013 at 2:13
  • \$\begingroup\$ Note that you can create a GL context for each thread and set them up to share with the main thread. You still do not ever issue rendering commands on these other contexts. You can use them for creating or updates resources, e.g. VBOs and the like. In D3D11 with deferred contexts, you can also use these threads to generate rendering command lists that you can then process on the main thread (similar to GL display lists, but actually usable for efficient rendering; don't ever actually use a GL display list, they makes copies all vertex data). \$\endgroup\$ Mar 24, 2013 at 20:34
1
\$\begingroup\$

I just had to create the HGLRC in a different thread and everything worked fine. The HWND is thread-safe in this case.

\$\endgroup\$
6
  • 1
    \$\begingroup\$ You should never ever do this. A HWND is never thread safe. Window objects have thread affinity. The thread that creates a window is the one with which the window has an inseparable relationship. \$\endgroup\$
    – bobobobo
    Mar 25, 2013 at 1:42
  • 1
    \$\begingroup\$ @bobobobo Don't they explicitly say here blogs.msdn.com/b/oldnewthing/archive/2005/10/11/479587.aspx that window handles and HDCs are thread-safe, as long as they do not get used simultaneously by two threads, or get freed by a different thread than the one that created them? Also, if that wouldn't be possible, how would I "create a GL context for each thread", as you suggested earlier? Because to create a GL context I either need a HDC or another GL context, which would be impossible if they are thread-bound. \$\endgroup\$
    – cooky451
    Mar 25, 2013 at 3:43
  • \$\begingroup\$ I did not suggest to create a separate GL Context for each thread. I think that is utter nincompoopery (Sean suggested it - no offense Sean). Think of "work jobs" like asynchronous HTTP requests. Your main thread does all the rendering, and if there is other work to be done (like loading from disk) you create an asynchronous request for that work to be done - on a separate thread. \$\endgroup\$
    – bobobobo
    Mar 27, 2013 at 16:11
  • \$\begingroup\$ @bobobobo Oh, sorry, I somehow missed Sean's name there. Nevertheless, things like glTexImage2D cannot really be async by design, which basically makes it impossible to use memory mapping here. Things like that just become annoying without threads. \$\endgroup\$
    – cooky451
    Mar 27, 2013 at 19:36
  • \$\begingroup\$ Why would you memory map a texture? Unless you're talking about megatextures, you want to get the texture off disk and into GPU memory asap. \$\endgroup\$
    – bobobobo
    Mar 28, 2013 at 1:17

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .