说明:在本节涉及的frame buffer是以显示为目的的frame buffer。

 

为了将GPU绘制结果在窗口中显示出来,必然需要将OpenGL和具体窗口系统相结合。如下图所示,OpenGL spec定义了GL context< /span>的行为,从具体窗口衍生出frame buffer,两者结合,即可完成OpenGL应用程序的显示输出。

当然,GL context的输出格式和Frame buffer的格式要一致才行,否则无法将GL context和frame buffer连接起来。比如,假如GL context将输出depth值,则frame buffer中应该包括depth buffer;假如GL context输出的颜色中的红色分量占8比特,则frame buffer中相应的color buffer的red分量也应该是8比特;假如GL context要求输出到back buffer中,则frame buffer就应该既包括front buffer,也包括back buffer。

 

 

但是OpenGL spec并没有定义如何和具体窗口系统相结合的问题,所以,需要引入新的spec来支持。具体到Windows操作系统,就是WGL;而在Linux/X下,就是GLX。

 

考察一个OpenGL应用程序在Windows平台的刚开始运行时和WGL相关的流程

1.         调用函数CreateWindowEx创建窗口hWnd

2.         调用函数GetDC得到hDC,其函数参数是hWnd

3.         调用函数ChoosePixelFormat来查询hDC支持的所有像素格式,应用程序同时选择出其将采用哪种像素格式

4.         调用函数SetPixelFormat设置hDC的像素格式

5.         调用函数wglCreateContext创建hGLRC,其参数是hDC

6.         调用函数wglMakeCurrent,其参数是hDC和hGLRC

7.         调用glAPI函数绘制

 

粗略的,我们可以这样理解,第4步完成后将根据hDC衍生出frame buffer;第5步得到的hGLRC本质上是上图中的GL context;而第6步则将应用程序和GL context、GL context和frame buffer连接在一起。从第7步开始,所有的glAPI都将作用于和应用程序连接的GL context;而GL context的输出目的地则是和其连接的frame buffer。

其中,第5步的hDC和第6步的hDC并不需要是同一个值,只需要这两个hDC都设置了相同的像素格式即可,这样就可以保证GL context的输出格式和Frame buffer的格式的一致性。

 

 

考察一个OpenGL应用程序在Linux/X下的刚开始运行时和GLX1.4相关的流程

1.         调用函数XOpenDisplay(NULL)得到display,可以将其认为是X server对显卡的一个抽象

2.         查询display,确定其连接的screen

3.         调用函数glxChooseFBConfig查询将在其上绘制的screen所支持的fbconfigs(本质上和windows中的像素格式是相同的),应用程序同时选择出其将采用哪种fbconfig

4.         调用函数XCreateWindow创建窗口xWin,其参数包括fbconfig的部分内容

5.         调用函数glXCreateWindow创建glxWin,参数是xWin和fbconfig

6.         调用函数glXCreateNewContext创建glxCtx,参数是fbconfig

7.         调用函数glxMakeContextCurrent,其参数包括glxWin和glxCtx。

8.         调用glAPI函数绘制

 

粗略的,我们可以这样理解,第5步得到的glxWin将衍生出frame buffer;第6步得到的glxCtx本质上就是上图中的GL context;而第7步则是将应用程序和GL context、GL context和frame buffer连接在一起。从第8步开始,所有的glAPI都将作用于和应用程序连接的GL context;而GL context的输出目的地则是和其连接的frame buffer。

其中,第7步调用函数的参数glxWin和glxCtx要求他们在被创建时所传入的fbconfig参数是相同的,这样就可以保证GL context的输出格式和Frame buffer的格式的一致性。

 

 

至此,应该可以理解到hGLRC/glxCtx和GL context的关系,它们在本质上是同一回事。hGLRC是在WGL下对GL context的封装,glxCtx是在GLX下对GL context的封装。hGLRC和glxCtx是相对应用程序的概念,而GL context则是OpenGL内部的概念。

 

 

不管是Windows系统还是Linux/X,一个应用程序可能会多线程的在多个窗口上用OpenGL绘制。通过讨论这种复杂情况,来加深对wglMakeCurrent/glxMakeContextCurrent函数(以下将简称为MakeCurrent)的理解。

 

如下图所示,某多线程程序,且已创建多个GL contex和frame buffer。图示状态表示,线程甲已成功调用函数MakeCurrent(GL context 3, Frame buffer B),线程乙已成功调用函数MakeCurrent(GL context 1, Frame buffer A),线程丁已成功调用函数MakeCurrent(GL context 4, Frame buffer C)。

接下去,在线程甲中被执行的glAPI都将作用于GL context3,其绘制结果进入Frame buffer B;在线程乙和线程丁中调用的glAPI也将分别作用于GL context 1和GL context4,其绘制结果分别进入Frame buffer A和Frame buffer C。

 

 

 

假如某个线程不调用OpenGL绘制,那它可以不和任何GL context连接。每个线程同时只能最多和一个GL context连接,因为,假如超过一个的话,该线程接下去的glAPI调用就将无法确定应该作用于哪个GL context连接了。当某个线程调用MakeCurrent函数重新设置和GL context、Frame buffer的连接关系时,原有的连接关系失效。

每个GL context最多可以和一个线程连接,因为,假如超过一个的话,多个线程作用于同一个GL context,其绘制结果显然不是所希望的。每个GL contxt只和一个Frame buffer连接,显然是无法和多个Frame buffer连接的。

每个Frame buffer只和一个GL context连接,似乎spec并没有禁止一个Frame buffer和多个GL context连接,但是,强烈不建议这样做,很有可能驱动程序没有针对这种情况编写代码的。

 

在默认情况下,不同GL context之间是相互独立的。如果采用share context技术,可以使不同GL context之间共享部分信息,对一个GL context的改动,就会在在另一个GL context中体现出来。

 

 

在驱动程序中,为节约显存,frame buffer往往会被延迟到函数MakeCurrent被调用时才被真正创建。

Logo

更多推荐