创建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);

有一些扩展,给这个函数增加了新的属性。你可能想要用到的有:

得到了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个属性指定你想要哪个版本。

你请求一个版本,然后你得到哪个版本?这个规则比较复杂,简单来说有两条:

  1. 它总会返回一个等于或高于你要求的版本的OpenGL Context。
  2. 它永远不会返回一个没有实现你要求的版本里的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

References

创建OpenGL Context(WGL)的更多相关文章

  1. 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 ...

  2. [转]用多线程方法实现在MFC/WIN32中调用OpenGL函数并创建OpenGL窗口

    原文链接: 1.用多线程方法实现在MFC/WIN32中调用OpenGL函数并创建OpenGL窗口 2.Windows MFC 两个OpenGL窗口显示与线程RC问题

  3. [Modern OpenGL系列(二)]创建OpenGL窗口

    本文已同步发表在CSDN:http://blog.csdn.net/wenxin2011/article/details/51295663 在博主的上一篇文章中已经介绍了OpenGL开发环境的搭建,本 ...

  4. 初始化glew,创建OpenGL渲染上下文

    void RegisterWinDowClass(HINSTANCE hInstance,std::string className,WNDPROC proc) { WNDCLASS wndClass ...

  5. iOS 创建OpenGL 环境的思考

    关于如何从头开始创建环境,可以参考大神的博文OpenGL ES 3.0 数据可视化 0:Hello world,本文只是补充一些我在实践中的一些思考. CAEAGLLayer If you plan ...

  6. opengl学习笔记(二):使用OpenCV来创建OpenGL窗口

    通常的增强现实应用需要支持OpenGL的OpenCV来对真实场景进行渲染.从2.4.2版本开始,OpenCV在可视化窗口中支持OpenGL.这意味着在OpenCV中可轻松渲染任何3D内容. 若要在Op ...

  7. 怎样在QML应用中创建一个Context Menu

    我们在非常多的系统中看见能够在屏幕的一个地方长按,然后就能够依据当前显示的上下文弹出一个菜单. 菜单中能够有一些选项,比方删除,改动该项.这样的一般在ListView或GridView中常见.今天,我 ...

  8. Cannot create OpenGL context for 'eglMakeCurrent'.

    10.3.2编译的app,在小米手机上出这个问题,华为的正常. 解决方法: 窗口的Quality属性用SystemDefault,不要用HighQuality. 10.3.1也有此问题.

  9. OpenGL 4.5 Core Profile管线(GLSL与应用程序接口详解)【未完成】

    之前写过一篇博客,OpenGL管线(用经典管线代说着色器内部),说的主要是OpenGL的经典管线.大家都知道,现代OpenGL已经弃用(从OpenGL 3.0开始)经典管线功能(glBegin,变换矩 ...

随机推荐

  1. linux环境 安装chromedriver 和 phantomjs的方法

    1 首先要下载浏览器驱动: 常用的是chromedriver 和phantomjs chromedirver下载地址: https://npm.taobao.org/mirrors/chromedri ...

  2. 音频增益响度分析 ReplayGain 附完整C代码示例

    人们所熟知的图像方面的3A算法有: AF自动对焦(Automatic Focus)自动对焦即调节摄像头焦距自动得到清晰的图像的过程 AE自动曝光(Automatic Exposure)自动曝光的是为了 ...

  3. 搭建 springboot 2.0 mybatis 读写分离 配置区分不同环境

    最近公司打算使用springboot2.0, springboot支持HTTP/2,所以提前先搭建一下环境.网上很多都在springboot1.5实现的,所以还是有些差异的.接下来咱们一块看一下. 文 ...

  4. 百度tn劫持解决办法

    最近用右键进行百度搜索的时候总是会跳转到 tn=99135173这类的小尾巴,使得搜索失败,十分恶心,这种广告劫持的手段十分高明隐蔽,很难发觉.开始以为是dns劫持或者是电脑中毒了,更换了几个dns, ...

  5. MongoDB最佳实践中文手册

    背景:查阅了一下MongoDB的相关文档,发现中文文档还是比较少的,工作中需要用到MongoDB,而这本<MongoDB最佳实践>是很好的选择,所以就把这本手册翻译了一下,其中生涩的专业用 ...

  6. Jenkins配置Gogs webhook插件

    前言 我们在前面使用Jenkins集合Gogs来进行持续集成的时候,选择的是Jenkins定时检测git仓库是否有更新来决定是否构建.也就是说,我们提交了代码Jenkins并不会马上知道,那么我们可以 ...

  7. python3全栈开发-socket编程

    一. 客户端/服务器架构 1.硬件C/S架构(打印机) 2.软件C/S架构 互联网中处处是C/S架构 如黄色网站是服务端,你的浏览器是客户端(B/S架构也是C/S架构的一种) 腾讯作为服务端为你提供视 ...

  8. 计蒜客NOIP模拟赛4 D2T2 跑步爱天天

    YOUSIKI 在 noip2016 的一道<天天爱跑步>的题爆零后,潜心研究树上问题,成为了一代大师,于是皮皮妖为了测验他,出了一道题,名曰<跑步爱天天>. 有一个以 1 为 ...

  9. 计蒜客NOIP模拟赛4 D2T1 鬼脚图

    鬼脚图,又称画鬼脚,在日本称作阿弥陀签,是一种经典游戏,也是一种简易的决策方法,常常用来抽签或决定分配组合. 下图就是一张鬼脚图,其包含若干条竖线和若干条横线.请注意,横线只能水平连接相邻的两条竖线, ...

  10. 计蒜客NOIP模拟赛4 D1T1 小X的质数

    小 X 是一位热爱数学的男孩子,在茫茫的数字中,他对质数更有一种独特的情感.小 X 认为,质数是一切自然数起源的地方. 在小 X 的认知里,质数是除了本身和 1以外,没有其他因数的数字. 但由于小 X ...