创建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. vscode调试适配器已意外终止

    出现这个错误了,找半天没找到办法.师兄支了一招: 把图中红圈部分删掉! 这是个旧的配置文件 ,你删掉它(反正一直报错误,也用不成了!).然后你调试一个文件,它会重新自动添加新的配置文件.

  2. 百度echarts使用--y轴label数字太长难以全部显示

    问题: 今天遇到个小问题,我们系统前端呈现使用了百度echarts.在绘制折线图的时候,因为数字过大,导致显示出现了问题. 解决方案: 左边y轴的值默认是根据我们填充进去的值来默认分割的,因为原始值就 ...

  3. [BZOJ4011][HNOI2015] 落忆枫音(学习笔记) - 拓扑+DP

    其实就是贴一下防止自己忘了,毕竟看了题解才做出来 Orz PoPoQQQ 原文链接 Description 背景太长了 给定一个DAG,和一对点(x, y), 在DAG中由x到y连一条有向边,求生成树 ...

  4. python——常用模块2

    python--常用模块2 1 logging模块 1.1 函数式简单配置 import logging logging.debug("debug message") loggin ...

  5. Hibernate(十五):QBC检索、本地SQL检索和HQL删除

    QBC检索 QBC查询就是通过使用Hibernate提供的Query By Criteria API来查询对象,这种API封装了SQL语句的动态拼装,对查询提供了更加面向对象的功能接口. 1)通过Cr ...

  6. nginx 官方文档翻译

    nginx(发音为"engine x")是一个由俄罗斯软件工程师Igor Sysoev编写的免费开源Web服务器.自2004年公开发布以来,nginx专注于高性能,高并发性和低内存 ...

  7. 关于jsp页面加载时报错500的问题

    先说一下,问题的发生,个人做了个小系统,成品以后运行了几次,没有问题,结果最后一次测试时,发现登陆页面报错了: 账号密码输入正确,经过后台登陆后,按理说是应该进入登陆成功后的jsp页面,然而结果却是: ...

  8. 李耀于NOIP2010集训出的题 Dvalue

    此题模型比较明显,求无向图的一棵生成树,使得最大边减去最小边的值最小,这是最小生成树的一个变式 设计出此题的算法需要利用Kruskal贪心的性质,首先枚举一条最小边,接着求原图的一棵最小生成树,根据k ...

  9. [Noi2013]矩阵游戏

    来自FallDream的博客,未经允许,请勿转载,谢谢. 婷婷是个喜欢矩阵的小朋友,有一天她想用电脑生成一个巨大的n行m列的矩阵(你不用担心她如何存储).她生成的这个矩阵满足一个神奇的性质:若用F[i ...

  10. IDEA 整合 SSM 框架学习

    认识 Spring 框架 更多详情请点击这里:这里 Spring 框架是 Java 应用最广的框架,它的成功来源于理念,而不是技术本身,它的理念包括 IoC (Inversion of Control ...