OpenGL rendering on a seperated thread

Hello,

I whould like to use 2 threads, one for the OpenGL rendering and an other for the rest of my software. However, I’m not able to make OpenGL working on the thread… When I use wglGetCurrentContext, the result is always 0 but it work well on the main thread.

When we use a thread, is there special setting to set? Are we supposed to create the OpenGL context on the thread that will use it?

Thanks

Hi

In Qt for example, the OpenGL context only exists in the thread that creates it so all the OpenGL commands must execute in the thread that created the context.

The context belongs to a thread, it can only be accessed from a thread that created it. You can use the second thread to provide the data you need for rendering, but all OpenGL commands must be executed in the rendering thread.

@Zengar:
Strange… I did some tests with multiple contexts and threads. In this test I did:

  • create main render context
  • create two more contexts and share lists with main render context (wglCreateContext and wglShareLists)
  • fire up two additional threads
  • in thread func call wglMakeCurrent once, enter render loop and render result in texture (one thread - one context)
  • each of this two threads work at different framerates
  • main thread (and main render context) collect RTT textures from other two contexts and render in on backbuffer.

So… to access to context from thread it MUST be current only in calling thread. If some other thread keep copntext current any other wglMakeCurrent call will fall until owning thread release it (by calling wglMakeCurrent(0,0))

#include "StdAfx.h"
#define GLDEBUG
#include "Composer.h"

CThreadContext::CThreadContext()
{
	m_msInterval = 0;
	m_hDC = NULL;
	m_parentRC = NULL;
	m_hRC = NULL;
	m_hThread = NULL;
	m_TexW = 0;
	m_TexH = 0;
}

CThreadContext::~CThreadContext()
{
	Stop();
}

void CThreadContext::SetParams(int ms, HDC hDC, HGLRC hRC)
{
	m_msInterval = ms;
	m_hDC = hDC;
	m_parentRC = hRC;

	m_hRC = wglCreateContext (m_hDC);

	if (wglShareLists(m_parentRC, m_hRC) == FALSE)
	{
		DWORD err = GetLastError();
		Log.Error("wglShareLists fail %d", err);
	}
}

void CThreadContext::SetSize(int w, int h)
{
	m_TexW = w;
	m_TexH = h;
}

void CThreadContext::SetRenderObject(IRenderObject* pRO)
{
	m_pRO = pRO;
}

void CThreadContext::Run()
{
	if (m_hThread != NULL) return;
	DWORD nThreadID;

	m_hThread = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadFunc, (LPVOID)this, 0, (LPDWORD)&nThreadID);
}

DWORD WINAPI CThreadContext::ThreadFunc( LPVOID lpParameter )
{
	CThreadContext* pThis = (CThreadContext*)lpParameter;
	pThis->Work();
	return 1;
}

void CThreadContext::Work()
{
	if (m_hRC)
	{
		if (wglMakeCurrent(m_hDC, m_hRC) == FALSE)
		{
			DWORD err = GetLastError();
			Log.Error("wglMakeCurrent fail %d", err);
		}
		rtt.Create(GL_TEXTURE_RECTANGLE_ARB, GL_RGBA, true, m_TexW, m_TexH);

		m_pRO->Init();

		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		gluPerspective(60, (float)m_TexW/(float)m_TexH, 0.1f, 500.0f);
		
		glMatrixMode(GL_MODELVIEW);

		while (1)
		{
			if (m_evStop.Wait(m_msInterval)) break;

			m_pRO->Update();
			rtt.Activate();
			m_pRO->Render();
			rtt.Deactivate();
		}
		rtt.Delete();
		m_pRO->Done();
	}
}

void CThreadContext::Stop()
{
	m_evStop.Set();
	Sleep(m_msInterval*2);
}

class RenderObject1: public IRenderObject
{
public:
	RenderObject1(){alpha = 0.0f;}
	virtual ~RenderObject1(){}

	void Update()
	{
		alpha += 0.5;
		m_Fps.Update();
	}

	void Render()
	{
		GLCALL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));

		glMatrixMode(GL_MODELVIEW);
		gluLookAt(5,5,5, 0,0,0, 0,1,0);
		glRotatef(alpha, 0,1,0);
		glColor3f(1,0,0);
		auxSolidBox(3,3,3);
	}

	float alpha;

};

class RenderObject2: public IRenderObject
{
public:
	RenderObject2(){alpha = 0.0f;}
	virtual ~RenderObject2(){}

	void Update()
	{
		alpha += 0.5;
		m_Fps.Update();
	}

	void Render()
	{
		GLCALL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));

		glMatrixMode(GL_MODELVIEW);
		gluLookAt(5,5,5, 0,0,0, 0,1,0);
		glRotatef(alpha, 0,1,0);
		glColor3f(0,1,0);
		auxSolidBox(3,3,3);
	}

	float alpha;
};



/* ********************************************************************** 
                                                                      
********************************************************************** */

CComposerApp::CComposerApp(void)
{
}

CComposerApp::~CComposerApp(void)
{
}


void CComposerApp::Update(float t, float d)
{
	__super::Update(t, d);
}

void CComposerApp::Render()
{
	BeginRender();

	RenderGrid(1.0);
	glColor3f(1,1,1);
	glEnable(GL_TEXTURE_RECTANGLE_ARB);

	// texture from first context
	c1.rtt.EnableTexture(0);
	glPushMatrix();
	glTranslatef(-1.1,0,0);
	glBegin(GL_QUADS);
	{
		glTexCoord2f(0,0);									glVertex3f(-1,0,0);
		glTexCoord2f(m_ViewPortSize.x,0);					glVertex3f(1,0,0);
		glTexCoord2f(m_ViewPortSize.x, m_ViewPortSize.y);	glVertex3f(1,1,0);
		glTexCoord2f(0,m_ViewPortSize.y);					glVertex3f(-1,1,0);
	}
	glEnd();
	glPopMatrix();
	c1.rtt.DisableTexture(0);

	// texture from second context
	c2.rtt.EnableTexture(0);
	glPushMatrix();
	glTranslatef(1.1,0,0);
	glBegin(GL_QUADS);
	{
		glTexCoord2f(0,0);									glVertex3f(-1,0,0);
		glTexCoord2f(m_ViewPortSize.x,0);					glVertex3f(1,0,0);
		glTexCoord2f(m_ViewPortSize.x, m_ViewPortSize.y);	glVertex3f(1,1,0);
		glTexCoord2f(0,m_ViewPortSize.y);					glVertex3f(-1,1,0);
	}
	glEnd();
	glPopMatrix();
	c2.rtt.DisableTexture(0);


	glDisable(GL_TEXTURE_RECTANGLE_ARB);

	AddReport("RO1 %f", ro1->m_Fps.GetFps());
	AddReport("RO2 %f", ro2->m_Fps.GetFps());
	EndRender();

}

void CComposerApp::Done()
{
	c1.Stop();
	c2.Stop();
}

bool CComposerApp::Init()
{
	ro1 = new RenderObject1;
	ro2 = new RenderObject2;

	c2.SetParams(90, g_hDC, g_hRC);
	c1.SetParams(10, g_hDC, g_hRC);

	c1.SetRenderObject(ro1);
	c2.SetRenderObject(ro2);

	c1.SetSize(m_ViewPortSize.x, m_ViewPortSize.y);
	c2.SetSize(m_ViewPortSize.x, m_ViewPortSize.y);

	c1.Run();
	c2.Run();

	wglMakeCurrent(g_hDC, g_hRC);
	Sleep(100);
	__super::Init();

	return true;
}

IEngine* NewEngine(){ return new CComposerApp;}

I am experiencing the exact same problem as the original poster. I have some code that was doing fine, but now that I have spun the creation of this window off into another thread, it is no longer working. wglGetCurrent fails with a return code of zero, and a GL_INVALID_OPERATION error. I’ve checked, and everything looks like it should be fine. If the original poster has any resolution, or anyone has any other suggestions, I would appreciate hearing them.

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