OpenGL and Win32 threads

Hi, I want to draw in a window using a thread.
I wrote a working function which draws using OpenGL functions but it doesn’t work - the window is white and empty.
When I try to put glGetError in the function I got ony “Invalid operation”. How do I fix the code? thank you.

#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>

HWND hWnd;
HDC hDC;
HGLRC hRC;
HANDLE thread;

LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
void EnableOpenGL();
void DisableOpenGL();
DWORD WINAPI DrawScene(LPVOID lpParameter);

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
	MSG msg;
	WNDCLASS wc;
	wc.style			= CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc	= (WNDPROC)WndProc;
	wc.cbClsExtra		= 0;
	wc.cbWndExtra		= 0;
	wc.hInstance		= hInstance;
	wc.hIcon			= NULL;
	wc.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wc.lpszMenuName	= NULL;
	wc.lpszClassName	= "glthreads";
	RegisterClass(&wc);
	hWnd = CreateWindow("glthreads", "glthreads", WS_OVERLAPPEDWINDOW,
      150,100,500,500, NULL, NULL, hInstance, NULL);
	if (!hWnd)
	{
		return FALSE;
	}
	EnableOpenGL();
	thread = CreateThread(NULL,0,DrawScene,NULL,0,NULL);
	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);
	while (GetMessage(&msg, NULL, 0, 0)) 
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message) 
	{
	case WM_DESTROY:
		DisableOpenGL();
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
   }
   return 0;
}

void EnableOpenGL()
{
    PIXELFORMATDESCRIPTOR pfd;
    int iFormat;
    hDC = GetDC(hWnd);
    ZeroMemory( &pfd, sizeof(pfd));
    pfd.nSize = sizeof(pfd);
    pfd.nVersion = 1;
    pfd.dwFlags = PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER;
    pfd.iPixelType = PFD_TYPE_RGBA;
    pfd.cColorBits = 24;
    pfd.cDepthBits = 16;
    pfd.iLayerType = PFD_MAIN_PLANE;
    iFormat = ChoosePixelFormat(hDC,&pfd);
    SetPixelFormat(hDC,iFormat,&pfd);
    hRC = wglCreateContext(hDC);
    wglMakeCurrent(hDC,hRC);
    glClearColor(0.0,0.0,0.0,0.0);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(-20,20,-20,20);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glViewport(0,0,500,500);
}

void DisableOpenGL()
{
    wglMakeCurrent( NULL, NULL );
    wglDeleteContext(hRC);
    ReleaseDC(hWnd,hDC);
}

DWORD WINAPI DrawScene(LPVOID lpParameter)
{
	glClearColor(0.0,0.0,0.0,0.0);
	glClear(GL_COLOR_BUFFER_BIT);
	glRotatef(1.0,0,0,1);
	glBegin(GL_POLYGON);
		glColor3f(1.0,0.0,0.0);
		glVertex2f(0.0,0.0);
		glColor3f(0.0,1.0,0.0);
		glVertex2f(10.0,0.0);
		glColor3f(0.0,0.0,1.0);
		glVertex2f(10.0,10.0);
	glEnd();
	glFinish();
	glFlush();
	SwapBuffers(hDC);
	return 0;
}

You can’t use OpenGL context from different thread.

yooyo

Thank you for your response.
I have two more questions:
1.Is it a limitation of Windows? is it possible to use opengl in threads in Linux?
2.What do game programmers who use OpenGL do?
Thank you!

What yooyo meant is you can’t have a context current in more than one thread at a time and you didn’t make it current in the thread issueing the rendering calls, but in the process’ main thread only.
You must call MakeCurrent in rendering thread.

Read my replies in these threads (pun intended :slight_smile: ):
http://www.opengl.org/discussion_boards/cgi_directory/ultimatebb.cgi?ubb=get_topic;f=9;t=000497
http://www.opengl.org/discussion_boards/cgi_directory/ultimatebb.cgi?ubb=get_topic;f=9;t=000302

Thank you for your answers.
I saw in the MSDN too that I have to use RC for every thread, but:
where do I have to put the wglMakeCurrent, and where do I have to put the initialization for rendering in the thread (projection and modelview)?
These are the last questions, I hope.

The wglMakeCurrent and initialization should be put inside your DrawScene function. Your current program will draw the scene only once at the program start which is probably not what you want. The version that draws scene continuously and does initialization would look like (The corresponding initialization and deinitialization code is moved from EnableOpenGL() and DisableOpenGL() functions).

DWORD WINAPI DrawScene(LPVOID lpParameter)
{
    wglMakeCurrent(hDC,hRC);

    glClearColor(0.0,0.0,0.0,0.0);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(-20,20,-20,20);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glViewport(0,0,500,500);

    while( ! rendering_should_end_test() ) {
        glClearColor(0.0,0.0,0.0,0.0);
        glClear(GL_COLOR_BUFFER_BIT);
        glRotatef(1.0,0,0,1);
        glBegin(GL_POLYGON);
	    glColor3f(1.0,0.0,0.0);
	    glVertex2f(0.0,0.0);
	    glColor3f(0.0,1.0,0.0);
	    glVertex2f(10.0,0.0);
	    glColor3f(0.0,0.0,1.0);
	    glVertex2f(10.0,10.0);
        glEnd();
        SwapBuffers(hDC);
    }

    wglMakeCurrent( NULL, NULL );
}

The rendering_should_end_test is multithread safe test that will decide if thread should end. When you wish to destroy OGL context you will first have to make this test return true and then you must wait until thread does the releasing wglMakeCurrent before you can destroy the context.

While this separate initialization where context and window is created in another thread than the one that will use it works i would not recomend to use it in any serious program. I have seen crashes in some drivers caused by using the context created by another thread in the main thread. Also having message loop in different thread is dangerous, some drivers can crash if you change resolution while another thread is calling rendering function.

2.What do game programmers who use OpenGL do?
The usual approach is either do everything in one thread or at least do everything OpenGL related in one thread, for example load a texture from disk in a background thread, and then signal the main thread that it is ready to be uploaded.

Thank you for your answers.

Quake3A was multi-threaded, is the code still in there? I heard it was removed at some point in an update.

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