随着Vulkan的引入,我们的图形技术的发展到达了一个新的顶点,但是呢,我们的老干爹OpenGL作为落日余晖,他在一些Vulkan才有的新功能上,也提供了一些支持。现在我们来讨论一下OpenGL之多线程渲染。
这里要补一补课: windows上最原生的API来使用Opengl 大概流程是这样的详情请见:https://gitee.com/GProReat/codes/bjptwd3hglozmi25esn4v31
1.获取句柄, 在win32或者MFC里面可以直接获取HWND,但是在glut,glfw,sdl等可以通过GetActiveWindow来获取HWND。
2.GetDC
3.PixelFormat的支持,这里可以看刚才代码段里面PixelFormat的设置
4.创建OpenGL的上下文wglCreateContext, 以及切换到当前的上下文,wglMakeCurrent,传入HGLRC类型的object。
5.初始化操作 各种开关比如: depthTest,AlphaTest,DepthFunc,Texture2等操作。
6.在窗口的绘制的时候,也就是WM_PAINT相应的时候处理绘制。
这里关键一点是, SwapBuffers。 还有glFlush。
7.资源释放。
note:windows上使用Opengl来渲染,大家可以找MFC或者win32上的windows绘制。
接下来开始我们的主题:Opengl多线程渲染:
根据我的测试,HGLRC 的创建于线程无关,也就是说目前HGLRC可以在另外一个线程创建(需要在当前线程wglShareLists),也可以在当前线程创建,
下面为核心代码:
this->hGLRC2 = wglCreateContext(hDC); wglShareLists(hGLRC2, hGLRC); std::thread th([this]() { wglMakeCurrent(hDC, hGLRC2); //wglShareLists(hGLRC2, hGLRC); texAnotherThread.LoadFromFile1("1.jpg"); }); th.join();
当然我们根据测试,也能发现,HGLRC在shared之前或者之后加载资源,都能做到共享
hGLRC = wglGetCurrentContext(); glEnable(GL_TEXTURE_2D); glEnable(GL_DEPTH); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); std::thread th([this]() { this->hGLRC2 = wglCreateContext(hDC); wglMakeCurrent(hDC, hGLRC2); glEnable(GL_TEXTURE_2D); glEnable(GL_DEPTH); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); texAnotherThread.LoadFromFile1("1.jpg"); } th.join(); //这两个参数顺序是和渲染结果有关系的 wglShareLists(hGLRC, hGLRC2);
还有根据我的测试wglShareLists(hGLRC, hGLRC2); 他实际上这两个参数顺序是有讲究的,如果在创建完上下文之后,直接共享,那么这俩参数顺序没有影响,如果在hGLRC2里加载完tetxure,那么只能wglShareLists(hGLRC2,hGLRC)
代码如下:(顺序无关的)
void MultiThreadTexture_App::Init() { hWnd = GetActiveWindow(); hDC = GetDC(hWnd); hGLRC = wglGetCurrentContext(); this->hGLRC2 = wglCreateContext(hDC); wglShareLists(hGLRC, hGLRC2); //顺序无关 isRunning = true; std::thread th([this]() { wglMakeCurrent(hDC, hGLRC2); glEnable(GL_TEXTURE_2D); glEnable(GL_DEPTH); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); //wglShareLists(hGLRC2, hGLRC); texAnotherThread.LoadFromFile1("1.jpg"); }); th.join(); }
void MultiThreadTexture_App::Init() { hWnd = GetActiveWindow(); hDC = GetDC(hWnd); hGLRC = wglGetCurrentContext(); glEnable(GL_TEXTURE_2D); glEnable(GL_DEPTH); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); this->hGLRC2 = wglCreateContext(hDC); isRunning = true; std::thread th([this]() { wglMakeCurrent(hDC, hGLRC2); glEnable(GL_TEXTURE_2D); glEnable(GL_DEPTH); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); //wglShareLists(hGLRC2, hGLRC); texAnotherThread.LoadFromFile1("1.jpg"); }); th.join(); //这两个参数顺序是和渲染结果有关系的 wglShareLists(hGLRC2, hGLRC); //只能这样子。 }
使用线程2来渲染,代码如下: 结果是可以显示
void MultiThreadTexture_App::Init() { hWnd = GetActiveWindow(); hDC = GetDC(hWnd); hGLRC = wglGetCurrentContext(); glEnable(GL_TEXTURE_2D); glEnable(GL_DEPTH); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); //wglShareLists() this->hGLRC2 = wglCreateContext(hDC); wglShareLists(hGLRC, hGLRC2); isRunning = true; std::thread th([this]() { wglMakeCurrent(hDC, hGLRC2); glEnable(GL_TEXTURE_2D); glEnable(GL_DEPTH); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); //wglShareLists(hGLRC2, hGLRC); texAnotherThread.LoadFromFile1("1.jpg"); cout << "加载完成" << endl; while (isRunning) //使用程序来控制 isRunning在线程运行之前为true,程序退出为false { if (isRenderBegin) //在调用Render的时候为true。 { Render(-10); AfterRender(); } } }); th.detach(); //这两个参数顺序是和渲染结果有关系的 // wglMakeCurrent(hDC, hGLRC); } void MultiThreadTexture_App::Render(int deltaMillionSeconds) { if (!isRenderBegin) isRenderBegin = true; if (deltaMillionSeconds != -10) return; glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60, width / height, 0.1, 1000); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0, 0, 100, 0, 0, 0, 0, 1, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClearColor(0, 0, 0, 1); glClearDepth(1000); glEnable(GL_FILL); glBindTexture(GL_TEXTURE_2D, texAnotherThread.texId); glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex3f(0, 0, 0); glTexCoord2f(1, 0); glVertex3f(100, 0, 0); glTexCoord2f(1, 1); glVertex3f(100, 100, 0); glTexCoord2f(0, 1); glVertex3f(0, 100, 0); glEnd(); }
最后,只做了一个交替渲染, 每1s为间隔,线程1,线程2交替渲染,而且他们使用共享的资源,比如第1s线程1渲染,第2s线程2渲染。
代码如下:
void MultiThreadTexture_App::Init() { hWnd = GetActiveWindow(); hDC = GetDC(hWnd); hGLRC = wglGetCurrentContext(); glEnable(GL_TEXTURE_2D); glEnable(GL_DEPTH); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); hGLRC2 = wglCreateContext(hDC); wglShareLists(hGLRC, hGLRC2); tex.LoadFromFile1("2.png"); isRunning = true; std::thread th([this]() { wglMakeCurrent(hDC, hGLRC2); glEnable(GL_TEXTURE_2D); glEnable(GL_DEPTH); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); texAnotherThread.LoadFromFile1("1.jpg"); while (isRunning) //使用程序来控制 isRunning在线程运行之前为true,程序退出为false { if (isRenderBegin) //在调用Render的时候为true。 { Render(-10); AfterRender(); } } }); th.detach(); } //deltaMillionSeconds是根据时间变化的,每一帧的间隔 void MultiThreadTexture_App::Render(int deltaMillionSeconds) { if (!isRenderBegin) isRenderBegin = true; if (RenderThreadID == 1 && deltaMillionSeconds != -10) return; if (RenderThreadID == 2 && deltaMillionSeconds == -10) return; isRenderBegin = true; if (deltaMillionSeconds == -10) RenderThreadID = 2; else RenderThreadID = 1; //if (deltaMillionSeconds != -10) return; //只保证线程2的绘制可以成功 否则返回 glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60, width / height, 0.1, 1000); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0, 0, 100, 0, 0, 0, 0, 1, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClearColor(0, 0, 0, 1); glClearDepth(1000); glEnable(GL_FILL); //这里互相使用对方的资源 if (RenderThreadID == 1) glBindTexture(GL_TEXTURE_2D, texAnotherThread.texId); else glBindTexture(GL_TEXTURE_2D, tex.texId); glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex3f(0, 0, 0); glTexCoord2f(1, 0); glVertex3f(100, 0, 0); glTexCoord2f(1, 1); glVertex3f(100, 100, 0); glTexCoord2f(0, 1); glVertex3f(0, 100, 0); glEnd(); //休息1秒钟然后 ::Sleep(1000); }
线程1用的是游戏截图,线程2用的是狗头。而渲染使用对方的资源,给大家来个效果图:
标签:多线程,glEnable,hGLRC,渲染,OpenGL,DEPTH,hGLRC2,hDC,GL From: https://www.cnblogs.com/yang131/p/16753516.html