wglMakeCurrent-crash!

Here’s the problem:

I have made a function for painting the contents of a window using OpenGL. This function has both the HDC and the HGLRC declared locally as static variables, and initializes them upon the first call to the function (this awkward way of doing it will be explained below):

VOID GfxProc (HWND hwnd)
{
    static HDC hdc=NULL;
    static HGLRC hglrc=NULL;
    static BOOLEAN ready=FALSE;

    if(!ready)
    {
        // initialize hdc and hglrc, choose pixel format etc...

        wglMakeCurrent(hdc,hglrc);

        ready=TRUE;
    }

    if(ready)
    {
        // paint the window
    }
}

When I call the function as a response to a WM_PAINT message in the main thread it works fine. No problemo. But when I handle the painting from another thread, wglMakeCurrent causes the program to crash. Badly, with both Windows “Send Error Report” and “Program Not Responding” messages.

I am aware that the HGLRC can only be current in one thread. The HDC and HGLRC are declared locally in GfxProc. The HWND function parameter to GfxProc is the return value from CreateWindow to the window that is painted. In short: All variables related to the painting process are declared by the thread (in GfxProc), so it isn’t a memory/thread-share issue that causes the crash. Besides, unless we use TLS all global variables are shared among the threads, so if the HWND is valid in the main thread, it is valid in the other thread as well (I tested this).

Thanks in advance for any help/suggestions regarding this problem!

PS: The entire function looks like this:

VOID GfxProc (HWND hwnd)
{
    static HDC   hdc=NULL;
    static HGLRC hglrc=NULL;
    static BOOL  ready=FALSE;
    static BOOL  failed=FALSE;

    if(!ready&&!failed)
    {
        ready=TRUE;

        if(ready&&!(hdc=GetDC(hwnd)))
            ready=FALSE;

        auto DISPLAYMODE dspmode;

        if(ready&&!dspGetDisplayMode(&dspmode))
            ready=FALSE;

        if(ready)
        {
            auto PIXELFORMATDESCRIPTOR pfd={0};

            pfd.nSize=sizeof(PIXELFORMATDESCRIPTOR);
            pfd.nVersion=1;
            pfd.dwFlags=PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER;
            pfd.iPixelType=PFD_TYPE_RGBA;
            pfd.cColorBits=dspmode.bpp;
            pfd.iLayerType=PFD_MAIN_PLANE;

            auto INT pixelformat;

            if(ready&&!(pixelformat=ChoosePixelFormat(hdc,&pfd)))
                ready=FALSE;
            if(ready&&!SetPixelFormat(hdc,pixelformat,&pfd))
                ready=FALSE;
            if(ready&&!(hglrc=wglCreateContext(hdc)))
                ready=FALSE;
            if(ready&&!wglMakeCurrent(hdc,hglrc)) // <===-- -  - this is where the program crashes
                ready=FALSE;

            if(ready)
            {
                glClearColor(0.0,0.2,0.4,0.0);
                glClear(GL_COLOR_BUFFER_BIT);
                glShadeModel(GL_FLAT);
            }
        }

        if(!ready)
            failed=TRUE;
    }

    static GLfloat g_flt=-1.0,g_add=0.01;

    if(ready)
    {
        glClear(GL_COLOR_BUFFER_BIT);
        glColor3f(1.0,0.5,0);
        glBegin(GL_POLYGON);
        glVertex3f(-g_flt,-g_flt,-g_flt);
        glVertex3f(-g_flt,+g_flt,-g_flt);
        glVertex3f(+g_flt,+g_flt,-g_flt);
        glVertex3f(+g_flt,-g_flt,-g_flt);
        glEnd();

        g_flt+=g_add;

        if((g_flt>=1.0)&#0124;&#0124;(g_flt<=-1.0))
            g_add*=-1;

        SwapBuffers(hdc);
    }
}

I have read somewhere that it would cause bad problems if you use ‘static’ variables with threads.
Maybe you should change it.

Your function as coded can only be called from one thread. In order for this function to be “thread safe” the GL context must be obtained and released within a mutex inside the function. Are you calling this function from more than one thread?

chrox : “I have read somewhere that it would cause bad problems if you use ‘static’ variables with threads.
Maybe you should change it.”

I have also tried to declare the variables (ie. the HDC and HGLRC) as global variables, which is actually how I prefer to do it, but the result is the same.

Besides, variables declared as ‘static’ in a function and global variables are allocated in the same segment, and basically a static variable is treated as a global variable, except it is not visible during the linking phase of the program. Or, in other words, adding a ‘PUBLIC’ label to the static variable in an assembly file would turn it into a global variable :wink:

Thanks for your suggestion!

macarter: “Your function as coded can only be called from one thread. In order for this function to be “thread safe” the GL context must be obtained and released within a mutex inside the function.”

Are you sure you don’t mean obtain and release the HGLR within a “critical section” (for thread synchronization)? (The HGLR is already obtained and released within a single thread.)

macarter: “Are you calling this function from more than one thread?”

No, that’s what bothers me. I deliberately try to declare all variables in a single thread, and only use this one thread for all the painting?

Thanks for your feedback!

A “critical section” is equivalent to a mutex web page . I see no release of the GL context in your function. A context is released with wglMakeCurrent(hdc, NULL) web page ;

Static variables declared within a function are not “declared in a single thread”. They are shared by all threads calling the function.

“I see no release of the GL context in your function”

True, but the GLRC is used only inside that function, and it is not possible to release it from a device before it is created and made current for the first time.

“Static variables [ed.] are shared by all threads calling the function”

Yes, but the function is only called from one thread, so a static variable declared inside that function can not be accessed by any other thread, which is what I meant by “declared in a single thread”. This also explains why thread synchronization for those variables is unnecessary.

I found the bug:

The thread that called the painting routine when the program crashed was created by the system via a multi-media timer. I tried to create the thread manually, and the problem was resolved :slight_smile:

Originally posted by PeachMelba:
[b] “I see no release of the GL context in your function”

True, but the GLRC is used only inside that function, and it is not possible to release it from a device before it is created and made current for the first time…
[/b]
Create or reacquire the context at the beginning of the function and release the context at the end of the function just prior to the return.

Likely the function was being called by multiple threads. There is no guarantee that a timer callback uses the same thread each time it is triggered.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.