创建OpenGL Context(WGL)
创建OpenGL Context(WGL)
创建OpenGL Context是初始化OpenGL的一部分。只有在此之后才能使用OpenGL。
关于platform的注意事项
创建OpenGL context之后才会存在OpenGL。这个创建过程不归OpenGL Specification管,而是归各个platform的API管。本文讨论基于Windows的初始化过程。许多Windows上的初始化函数是以”wgl”开头的。
本文假设读者知道Win32 API的基础知识。读者应知道window handle(HWND)和device context(DC)是什么,以及如何创建他们。本文不是讲解如何创建窗口的教程。
创建一个简单的Context
这一节是创建Context的基础知识。
窗口
创建HWND时,要确保它有CS_OWNDC设置。
像素格式
MS Windows里,每个窗口都有一个Device Context(DC)与之关联。DC里存储有像素格式PixelFormat。你创建的OpenGL Context里有个默认的framebuffer,PixelFormat是描述此framebuffer的属性的数据结构。
设置PixelFormat的方式并不直观。首先你创建一个你想要的pixelFormat,然后交给ChoosePixelFormat函数,此函数会查找能够支持的PixelFormat列表,返回最接近pixelFormat的编号。然后你就可以用此编号指定DC的PixelFormat。
上面描述的数据结构就是PIXELFORMATDESCRIPTOR。
1 PIXELFORMATDESCRIPTOR pfd =
2 {
3 sizeof(PIXELFORMATDESCRIPTOR),
4 1,
5 PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, //Flags
6 PFD_TYPE_RGBA, //The kind of framebuffer. RGBA or palette.
7 32, //Colordepth of the framebuffer.
8 0, 0, 0, 0, 0, 0,
9 0,
10 0,
11 0,
12 0, 0, 0, 0,
13 24, //Number of bits for the depthbuffer
14 8, //Number of bits for the stencilbuffer
15 0, //Number of Aux buffers in the framebuffer.
16 PFD_MAIN_PLANE,
17 0,
18 0, 0, 0
19 };
你看,很多field都是0。就这样,没问题。我们需要关心的field,你可能需要用的field,都用注释标记了。关于PixelFormat的更多flags,请查询Windows SDK文档。
上文说到ChoosePixelFormat函数,它接收一个DC和一个PFD,返回一个编号。如果返回的是0,那就意味着找不到匹配的PixelFormat,或者PDF内容错误。
有了PixelFormat编号,就可以用SetPixelFormat指定给DC。这个函数接收DC、编号和PFD的指针。别激动,这个函数没有读取PFD里的任何重要信息。
创建Context
接下来创建context就简单了。调用wglCreateContext。这个函数接收DC,返回OpenGL Context的句柄。
在使用OpenGL前,要用wglMakeCurrent 把context设置为current。如果已经有current context,这个函数会把旧context替换掉。后续的OpenGL函数调用会影响新context中的状态。如果你传入NULL,那么旧context会被移除,后续OpenGL函数调用会失败(崩溃)。
current context是线程专用的。每个线程可以将一个不同的context设置为current。将同一个context设置为多个线程的current是危险的。
删除Context
严格来说这不是创建Context的内容,但是你应当指定如何删除Context。
首先要确定你想删除的Context不是current。给wglMakeCurrent 传入NULL参数。
现在可以调用wglDeleteContext 来删除它了。
创建合适的Context
除非你只想做一个很简单的程序,否则你不应当使用上述的简单步骤创建的context。有一些功能强大的WGL扩展函数助你创建高级context,但是创建context 过程会复杂些。
创建一个傻帽Context
关键问题是这样的:你用来获取WGL扩展的函数,其本身就是一个OpenGL扩展。因此,首先要有一个OpenGL Context,然后才能使用WGL扩展。所以,为了能够使用那些“创建context的函数”,我们首先要“创建一个context”。幸运的是,这个context用不着是我们最后的context。我们只需创建一个傻帽context来获取函数指针,然后直接使用这些函数即可。
警告:不幸的是,Windows不允许用户改变一个窗口的PixelFormat。你只能设置一次。因此,如果你想通过傻帽Context使用一个不同的PixelFormat,你必须在用完傻帽Context后彻底销毁这个窗口并重建之。
对于傻帽Context,一个好的PixelFormat选择是32位RGBA颜色缓存+24位深度缓存+8位模版缓存。我们上面就是这样设置的PFD。这通常都能得到一个硬件加速的PixelFormat。
所以,这一步就是重复上文的代码,创建一个傻帽Context,设置为current。
获取WGL扩展
Main article: Load OpenGL Functions#Windows 2
如果你使用了加载扩展的库,现在就可以调用任何你需要的函数。如果没有,你就得自己手动加载。
有不少扩展可以实施高端的context创建工作。其中大多数是围绕PixelFormat的创建和一个Exception。
Pixel Format扩展
PFD是帮助创建Context的很好的方式,但是有个缺点:不可扩展。因此,产生了WGL_ARB_pixel_format扩展。这个扩展定义了一种新的获取PixelFormat编号的机制,此机制的核心是由一个’属性\值’的数组。
只有在定义了此扩展的机器上才能使用它。这个扩展已经存在很长时间了,即使很老的显卡也支持它。所以你可以打赌认为你的机器环境是实现了WGL_ARB_pixel_format的。
此扩展提供了几个新的函数,我们感兴趣的是下面这个:
1 BOOL wglChoosePixelFormatARB( HDC hdc,
2 const int *piAttribIList,
3 const FLOAT *pfAttribFList,
4 UINT nMaxFormats,
5 int *piFormats,
6 UINT *nNumFormats);
wglChoosePixelFormatARB 类似ChoosePixelFormat。他接收的不是固定的PFD结构体,而是一个’属性\值’的数组。很多属性都直接对应PFD里的字段,但有些属性是新的。而且,此函数能够返回多个符合要求的PixelFormat,并按照从最符合到最不符合的顺序排序。“最符合”是由具体OpenGL实现来决定的。
总之,使用方法很简单。piAttribIList 是整数属性列表。每2个元素构成一个’属性\值’对。属性’0’表示列表结束,并且其后不需要值。你可以传入NULL,此函数会当作你传入一个空列表。
类似的,pfAttribFList 是浮点属性列表。每2个元素构成一个’属性\值’对。如何将整型的属性放到float类型里?非常小心地放。你需要用static-cast(C++里)或者用其它技巧让bit-pattern保持相同。
nMaxFormats 是将要保存到piFormats里的数量的最大值。因此piFormats 应当至少有那么多个元素。nNumFormats 是返回值,告诉你piFormats真正存储了多少个元素。
如果函数返回FALSE,就意味着没有找到合适的PixelFormat。此时piFormats 就是未定义的状态(OpenGL实现可以随意修改其内容)如果函数返回不是FALSE,那么就成功了,你得到了PixelFormat编号。
下面的示例代码演示了如何使用此函数产生和上文近似的PixelFormat:
1 const int attribList[] =
2 {
3 WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
4 WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
5 WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
6 WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
7 WGL_COLOR_BITS_ARB, 32,
8 WGL_DEPTH_BITS_ARB, 24,
9 WGL_STENCIL_BITS_ARB, 8,
10 0, //End
11 };
12
13 int pixelFormat;
14 UINT numFormats;
15
16 wglChoosePixelFormatARB(hdc, attribList, NULL, 1, &pixelFormat, &numFormats);
有一些扩展,给这个函数增加了新的属性。你可能想要用到的有:
- WGL_ARB_pixel_format_float:支持浮点framebuffer。
- WGL_ARB_framebuffer_sRGB: 支持sRGB格式的colorbuffer。
- WGL_ARB_multisample: 支持多重采样的framebuffer。
得到了PixelFormat编号,你就可以用SetPixelFormat指定给DC。
用Attributes创建Context
为了移除旧功能,OpenGL3.0及其以上版本创造了一个“不推荐\可移除”的模型。但是这带来一点问题。在之前的OpenGL版本,新版OpenGL是旧版的超集(superset)。因此,如果你想要的是1.5版context,结果得到的是2.0版,那没问题。你只是得到了额外的你用不到的功能。一旦出现了移除旧功能的可能性,这种超集关系就没有了。
因此出现了WGL_ARB_create_context扩展。它提供了代替wglCreateContext的函数。类似wglChoosePixelFormatARB,它提供了一种扩展机制,使你能够增加新的创建context所用的选项。
如果傻帽context没有提供这个扩展,那么你就不能用它。你就只能用wglCreateContext 了。
如果它提供了这个扩展,那么会有一些平常得不到的选项供我们选用:
- 保证获取OpenGL3.0或者更高版本的Context。
- 创建OpenGL3.2或者更高班的core context,且没有兼容旧特性。
- 不用窗口,创建context,用于离屏渲染。这可能会做不成。
遗留问题:(这里有一堆没什么用的话,略过不译)如果定义了WGL_ARB_create_context_profile,那就用上述方法。如果没有,那就只能用wglCreateContext 直接创建GL3.0或更高版本context。
wglCreateContextAttribsARB 签名如下:
1 HGLRC wglCreateContextAttribsARB(HDC hDC, HGLRC hshareContext, const int *attribList);
这里的attribList 与wglChoosePixelFormatARB里的类似。它是一系列’属性\值’对,以单独的0作为最后一个元素结尾。
你可以用WGL_CONTEXT_MAJOR_VERSION_ARB 和WGL_CONTEXT_MINOR_VERSION_ARB这2个属性指定你想要哪个版本。
你请求一个版本,然后你得到哪个版本?这个规则比较复杂,简单来说有两条:
- 它总会返回一个等于或高于你要求的版本的OpenGL Context。
- 它永远不会返回一个没有实现你要求的版本里的core feature的OpenGL版本。
如果定义WGL_ARB_create_context_profile了,那么你可以用WGL_CONTEXT_PROFILE_MASK_ARB 属性来选择一个core配置(WGL_CONTEXT_CORE_PROFILE_BIT_ARB)或者一个兼容配置(WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB)。注意,这些都是bit组合,所以你可以同时要求他们俩(不过你只会得到兼容配置)。这里面的细节就值得深入讨论了。
你也可以用WGL_CONTEXT_FLAGS_ARB属性指定若干flag。你可以用它请求一个向前兼容的context(WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB)且(或)一个debug context(WGL_CONTEXT_DEBUG_BIT_ARB)。Debug context常常实现了ARB_debug_output,能够提供加强了的error输出。向前兼容的context必须彻底移除deprecated特性,实际上你永远都不应该用这个选项。
hshareContext 是个特殊的参数。如果你有2个GL Context,且你想让他们共享对象,那你可以用wglShareLists函数。但是你必须在创建对象(在任意两个context里)之前使用。wglCreateContextAttribsARB 直接配合这个功能。
See Also
- Core And Compatibility in Contexts
- Tutorial: OpenGL 3.0 Context Creation (GLX)
- Tutorial: OpenGL 3.1 The First Triangle (C++/Win)
References
创建OpenGL Context(WGL)的更多相关文章
- Retrieve OpenGL Context from Qt 5.5 on OSX
In the latest Qt 5.5, the QOpenGLWidget is much better and has less bugs than the QGLWidget, but it ...
- [转]用多线程方法实现在MFC/WIN32中调用OpenGL函数并创建OpenGL窗口
原文链接: 1.用多线程方法实现在MFC/WIN32中调用OpenGL函数并创建OpenGL窗口 2.Windows MFC 两个OpenGL窗口显示与线程RC问题
- [Modern OpenGL系列(二)]创建OpenGL窗口
本文已同步发表在CSDN:http://blog.csdn.net/wenxin2011/article/details/51295663 在博主的上一篇文章中已经介绍了OpenGL开发环境的搭建,本 ...
- 初始化glew,创建OpenGL渲染上下文
void RegisterWinDowClass(HINSTANCE hInstance,std::string className,WNDPROC proc) { WNDCLASS wndClass ...
- iOS 创建OpenGL 环境的思考
关于如何从头开始创建环境,可以参考大神的博文OpenGL ES 3.0 数据可视化 0:Hello world,本文只是补充一些我在实践中的一些思考. CAEAGLLayer If you plan ...
- opengl学习笔记(二):使用OpenCV来创建OpenGL窗口
通常的增强现实应用需要支持OpenGL的OpenCV来对真实场景进行渲染.从2.4.2版本开始,OpenCV在可视化窗口中支持OpenGL.这意味着在OpenCV中可轻松渲染任何3D内容. 若要在Op ...
- 怎样在QML应用中创建一个Context Menu
我们在非常多的系统中看见能够在屏幕的一个地方长按,然后就能够依据当前显示的上下文弹出一个菜单. 菜单中能够有一些选项,比方删除,改动该项.这样的一般在ListView或GridView中常见.今天,我 ...
- Cannot create OpenGL context for 'eglMakeCurrent'.
10.3.2编译的app,在小米手机上出这个问题,华为的正常. 解决方法: 窗口的Quality属性用SystemDefault,不要用HighQuality. 10.3.1也有此问题.
- OpenGL 4.5 Core Profile管线(GLSL与应用程序接口详解)【未完成】
之前写过一篇博客,OpenGL管线(用经典管线代说着色器内部),说的主要是OpenGL的经典管线.大家都知道,现代OpenGL已经弃用(从OpenGL 3.0开始)经典管线功能(glBegin,变换矩 ...
随机推荐
- linux环境 安装chromedriver 和 phantomjs的方法
1 首先要下载浏览器驱动: 常用的是chromedriver 和phantomjs chromedirver下载地址: https://npm.taobao.org/mirrors/chromedri ...
- 音频增益响度分析 ReplayGain 附完整C代码示例
人们所熟知的图像方面的3A算法有: AF自动对焦(Automatic Focus)自动对焦即调节摄像头焦距自动得到清晰的图像的过程 AE自动曝光(Automatic Exposure)自动曝光的是为了 ...
- 搭建 springboot 2.0 mybatis 读写分离 配置区分不同环境
最近公司打算使用springboot2.0, springboot支持HTTP/2,所以提前先搭建一下环境.网上很多都在springboot1.5实现的,所以还是有些差异的.接下来咱们一块看一下. 文 ...
- 百度tn劫持解决办法
最近用右键进行百度搜索的时候总是会跳转到 tn=99135173这类的小尾巴,使得搜索失败,十分恶心,这种广告劫持的手段十分高明隐蔽,很难发觉.开始以为是dns劫持或者是电脑中毒了,更换了几个dns, ...
- MongoDB最佳实践中文手册
背景:查阅了一下MongoDB的相关文档,发现中文文档还是比较少的,工作中需要用到MongoDB,而这本<MongoDB最佳实践>是很好的选择,所以就把这本手册翻译了一下,其中生涩的专业用 ...
- Jenkins配置Gogs webhook插件
前言 我们在前面使用Jenkins集合Gogs来进行持续集成的时候,选择的是Jenkins定时检测git仓库是否有更新来决定是否构建.也就是说,我们提交了代码Jenkins并不会马上知道,那么我们可以 ...
- python3全栈开发-socket编程
一. 客户端/服务器架构 1.硬件C/S架构(打印机) 2.软件C/S架构 互联网中处处是C/S架构 如黄色网站是服务端,你的浏览器是客户端(B/S架构也是C/S架构的一种) 腾讯作为服务端为你提供视 ...
- 计蒜客NOIP模拟赛4 D2T2 跑步爱天天
YOUSIKI 在 noip2016 的一道<天天爱跑步>的题爆零后,潜心研究树上问题,成为了一代大师,于是皮皮妖为了测验他,出了一道题,名曰<跑步爱天天>. 有一个以 1 为 ...
- 计蒜客NOIP模拟赛4 D2T1 鬼脚图
鬼脚图,又称画鬼脚,在日本称作阿弥陀签,是一种经典游戏,也是一种简易的决策方法,常常用来抽签或决定分配组合. 下图就是一张鬼脚图,其包含若干条竖线和若干条横线.请注意,横线只能水平连接相邻的两条竖线, ...
- 计蒜客NOIP模拟赛4 D1T1 小X的质数
小 X 是一位热爱数学的男孩子,在茫茫的数字中,他对质数更有一种独特的情感.小 X 认为,质数是一切自然数起源的地方. 在小 X 的认知里,质数是除了本身和 1以外,没有其他因数的数字. 但由于小 X ...