openGL之多线程渲染
随着Vulkan的引入,我们的图形技术的发展到达了一个新的顶点,但是呢,我们的老干爹OpenGL作为落日余晖,他在一些Vulkan才有的新功能上,也提供了一些支持,现在我们来讨论一下OpenGL之多线程渲染。
这里要补一补课:
windows上调用openGL最原始的原始方式
大概流程是这样的详情请见:https://gitee.com/GProReat/codes/bjptwd3hglozmi25esn4v31
1.获取句柄, 在win32或者MFC里面可以直接获取HWND,但是在glut,glfw,sdl等可以通过GetActiveWindow来获取HWND。
2.GetDC,这个是获取窗口的DC, HDC ( Handle To Device Context)是图像的设备描述表,窗口显示上下文句柄,其中可以进行图形显示。
3.PixelFormat的支持,这里可以看刚才代码段里面PixelFormat的设置
4.创建OpenGL的上下文wglCreateContext, 以及切换到当前的上下文,wglMakeCurrent,传入HGLRC类型的object。
5.初始化操作 各种开关比如: depthTest,AlphaTest,DepthFunc,Texture2等操作。
6.在窗口的绘制的时候,也就是WM_PAINT相应的时候处理绘制。
这里关键一点是,调用OpenGL绘制之后使用SwapBuffers,还有glFlush。
7.资源释放。
note:windows上使用openGL来渲染,大家可以找MFC或者win32上的OpenGL绘制。
接下来开始我们的主题:openGL多线程渲染:
根据我的测试,HGLRC 的创建与线程无关,也就是说目前HGLRC可以在另外一个线程创建(需要在当前线程wglShareLists),也可以在当前线程创建,
下面为核心代码:
this->hGLRC2 = wglCreateContext(hDC);
wglShareLists(hGLRC2, hGLRC);
std::thread th([this]() {
wglMakeCurrent(hDC, hGLRC2);
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]() {
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();
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);
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);
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);
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);
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);
texAnotherThread.LoadFromFile1("1.jpg");while (isRunning) //使用程序来控制 isRunning在线程运行之前为true,程序退出为false
{
if (isRenderBegin) //在调用Render的时候为true。
{
Render(-10);
AfterRender();
}
}
});
th.detach();
} 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渲染用的是线程2加载的纹理,第2s线程2渲染用的是线程1加载的纹理,如此循环...
代码如下:
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;
lastRenderThreadID = -1;//默认值
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)
{
mtx.lock();
if (!isRenderBegin)
isRenderBegin = true; isRenderBegin = true;
if (deltaMillionSeconds == -10)
RenderThreadID = 2;
else
RenderThreadID = 1; if (lastRenderThreadID != -1 && lastRenderThreadID == RenderThreadID)
{//和之前的线程一致
::Sleep(1000); //保证1s调用1次
mtx.unlock();
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);
//这里互相使用对方的资源
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();
lastRenderThreadID = RenderThreadID;
//休息1秒钟然后
::Sleep(1000);
mtx.unlock();
} void MultiThreadTexture_App::Release()
{
isRunning = false;
}
线程1用的是游戏截图,线程2用的是狗头。而渲染使用对方的资源,效果图如下:

openGL之多线程渲染的更多相关文章
- BGFX多线程渲染
BGFX多线程渲染 1. 多线程基础 1. 并发概念 1. 并发任务简介 在多年以前,在手机.pc端.游戏机等,都是一个单核的CPU.这样,在硬件层面上,处理多个任务的时候,也是把一些任务切分成一些小 ...
- 《图解UE4渲染体系》Part 1 多线程渲染
上回书<Part 0 引擎基础>说到,我们粗略地知道UE4是以哪些类来管理一个游戏场景里的数据的,但这仅仅是我们开始探索UE4渲染体系的一小步. 本回主要介绍UE4渲染体系中比较宏观顶层的 ...
- Unity4、Unity5移动平台多线程渲染在部分安卓手机上会造成闪退
你看到的crash堆栈可能是这样的: SIGSEGV(SEGV_MAPERR) #00 pc 0001276c /system/lib/libc ...
- HTML5触屏版多线程渲染模板技术分享
前言: 了解js编译原理的屌丝们都知道,js是单线程的,想当年各路神仙为了实现js的多线程,为了解决innerHTML输出大段HTML卡页面的顽疾,纷纷设计了诸如假冒的“多线程“实现,我自己也在写开源 ...
- Unity3D 海水多线程渲染算法实现
笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D实战核心技术详解 ...
- 通过OpenGL理解前端渲染原理(1)
一.OpenGL OpenGL,是一套绘制3D图形的API,当然它也可以用来绘制2D的物体.OpenGL有一大套可以用来操作模型和图片的函数,通常编写OpenGL库的人是显卡的制造者.我们买的显卡都支 ...
- DirectX* 11 多线程渲染的性能、方法和实践
对于在 CPU 上运行的 PC 游戏,渲染通常是主要的性能瓶颈:多线程渲染是一种消除瓶颈的有效方法.本文研究了 DirectX* 11 多线程渲染的性能可扩展性,讨论了多线程渲染的两种基本方法,并介绍 ...
- 还在使用OpenGL ES做渲染,你Out了,赶紧来拥抱Vulkan吧~
背景介绍 Vulkan是Khronos组织制定的"下一代"开放的图形显示API.是与DirectX12能够匹敌的GPU API标准. Vulkan是基于AMD的Mantle API ...
- opengl离屏渲染(不需要和窗口绑定,仅当作一个可以渲染一张图片的API使用)+ opencv显示
具体过程参考的是这篇BLOG: http://wiki.woodpecker.org.cn/moin/lilin/swig-glBmpContext 这一片BLOG的代码有个 BOOL SaveBmp ...
- OpenGL中的渲染方式—— GL_TRIANGLE_STRIP
OpenGL值绘制三角形的方式常用的有三种,分别是GL_TRIANGLES.GL_TRIANGLE_STRIP.GL_TRIANGLE_FAN,其效果如依次是: 从左起:第一个方式是GL_TRIANG ...
随机推荐
- ChatGPT-4o模型功能介绍
1.概述 OpenAI 持续突破人工智能的边界,推出了其最新模型 ChatGPT-4o,作为 ChatGPT-4 的继承者,该模型有望带来显著的提升和创新功能.本文将深入解析 ChatGPT-4 与 ...
- 提速15%,PaddleOCRSharp新版v4.3发布
PaddleOCRSharp v4.3版本,已经于5月23日发布.该版本的发布,在不影响识别精度的同时,带来了10%~15%速度的提升. 项目地址:https://gitee.com/raoyutia ...
- .net formwork WebApi 跨域问题
背景: ASP.NET Formwork Api / ASP.Net Core Api 做比较. 有关 Global.asax.FilterConfig.cs 和 RouteConfig.cs ...
- git创建分支 解决git网速太慢
所谓的分支,就是每个人负责的不同的模块 整个项目有一个主干 master 所有的分支都是 从主干 maser 上 分支而来的 ...
- kettle从入门到精通 第五十二课 ETL之kettle Avro output
1.上一节课我们学习了avro input,本节课我们一起学习下avro out步骤. 本节课通过json input 加载json文件,通过avro out 生成avro二进制文件,写日志步骤打印日 ...
- 对pta的总结_1
前言 这三次pta难度在不断上升的同时,要求我们线上慕课+自主学习来了解更多的java中的各种方法,如:正则表达式 List Map等.与此同时要求我们展开尝试并熟练类的构造,类的引用,链表的基本运用 ...
- INFINI Labs 产品更新 | 发布 Easysearch Java 客户端,Console 支持 SQL 查询等功能
近年来,日志管理平台越来越流行.使用日志管理平台可以实时地.统一地.方便地管理和查看日志,挖掘日志数据价值,驱动运维.运营,提升服务管理效率. 方案架构 Beats 是轻量级采集器,包括 Filebe ...
- 微信刷脸SDK获取sub_openid
当调用SDK中 获取用户信息(getWxpayfaceUserInfo) /人脸支付凭证(getWxpayfaceCode) 方法获取 sub_openid 时,除了SDK自身要传入sub_appid ...
- kettle从入门到精通 第七十课 ETL之kettle kettle数据校验,脏数据清洗轻松拿捏
场景:输入在指定的错误(错误应涵盖数据类型不匹配的情况)行数内,trans不报错,但通过错误处理步骤捕捉,并记入文件,整个数据管线正常完成直至处理完最后一个输入行. 解决方案:使用步骤[数据检验]进行 ...
- SpringBoot+Selenium模拟用户操作浏览器
Selenium Selenium是一个用于Web应用程序自动化测试的开源工具套件.它主要用于以下目的: 浏览器自动化:Selenium能够模拟真实用户在不同浏览器(如Chrome.Firefox.I ...