@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;}