Matthew Hoggan
Matthew Hoggan

Reputation: 7594

Win32 Message Pump and std::thread Used to Create OpenGL Context and Render

If I have a function that does the following:

bool foo::init()
{
    [Code that creates window]
    std::thread run(std::bind(&foo::run, this));

    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

Where run is defined as:

void foo::run()
{
    [Code that creates initial opengl context]
    [Code that recreates window based on new PixelFormat using wglChoosePixelFormatARB]
    [Code that creates new opengl context using wglCreateContextAttribsARB]

    do {
        [Code that handles rendering]
    } while (!terminate);   
}

Since the window is recreated on the rendering thread, and the message pump will be performed on the main thread is this considered safe? What function will the WndProc be called on? The above code could be considered bad design, but that is not what I am interested in. I am only interested in what is the defined behavior.

Upvotes: 0

Views: 474

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 596206

A Win32 window is bound to the thread that creates it. Only that thread can receive and dispatch messages for the window, and only that thread can destroy the window.

So, if you re-create the window inside of your worker thread, then that thread must take over responsibility for managing the window and dispatch its messages.

Otherwise, you need to delegate the re-creation of the window back to your main thread so it stays in the same thread that originally created it.

bool foo::init()
{
    [Code that creates window]

    std::thread run(std::bind(&foo::run, this));

    while (GetMessage(&msg, NULL, 0, 0)) {
        if (recreate needed) {
            [Code that recreates window and signals worker thread]
            continue;
        }
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

void foo::run()
{
    [Code that creates initial opengl context]

    [Code that asks main thread to recreate window based on new PixelFormat using wglChoosePixelFormatARB, and waits for signal that the recreate is finished]

    [Code that creates new opengl context using wglCreateContextAttribsARB]

    do {
        [Code that handles rendering]
    } while (!terminate);   
}

Otherwise, call wglChoosePixelFormatARB() in the main thread before starting the worker thread, and store the chosen PixelFormat where the thread can access it.

bool foo::init()
{
    [Code that creates window]
    [Code that gets PixelFormat using wglChoosePixelFormatARB]

    std::thread run(std::bind(&foo::run, this));

    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

void foo::run()
{
    [Code that creates opengl context using wglCreateContextAttribsARB]

    do {
        [Code that handles rendering]
    } while (!terminate);   
}

Upvotes: 2

Related Questions