[Z]OpenGL Driver Architecture

 OpenGL Driver Architecture
Yang Jian
[email protected]

1 OpenGL Installable Client Driver  
Windows下OpenGL Driver有三种类型,可安装的客户端驱动程序(Installable Client Driver 
,缩写为ICD),微驱动(minidriver)和独立驱动程序。独立驱动程序主要是为一些特殊的图形系统设计,这些图形系统的能力相对比较强大,整个系统的主要目的为图形应用,目前已经不多见。MiniDriver在3D图形加速卡没有普及之前曾经被使用过,但是有由于其支持的能力太低,自nvi
dia TNT 之后就看不到这类驱动程序。
   现在图形芯片供应商都采用ICD的方式提供OpenGL Driver。ICD的最大特点是(1)能够支持OpenGL驱动程序开发者提供完整的OpenGL支持,和OpenGL Extension支持;(2)使得OpenGL能够以client-server的方式运行;(3)对OpenGL应用程序开发者提供统一的API接口。

下面是一个OpenGL ICD驱动程序体系结构的简图。


         Application 
            |
|
GDI32.dll<---OpenGL32.dll ---? winsrv.dll
|           |
|        |
--------  xxgl.dll(example, nvoglnt.dll, atioglxx.gl, )  ------? DirectDraw5~7
        |                                 | 
        |                                     |----? Direct3D8   or above
      3d graphics card(Hardware)

其中
OpenGL32.dll是微软基于软件实现的OpenGL。
Nvntgl.dll或者atiglxx.dll分别是Nvidia和ATI提供的OpenGL ICD驱动程序。
同时OpenGL32.dll和图形芯片供应商的驱动程序都需要访问DirectDraw和GDI32。
个别的OpenGL驱动程序甚至使用了Direct3D8或者更高的版本。

2 确定当前图形加速卡的ICD驱动
    
    对于Windows98/me的系统,可以注册表的下面位置查找:
“HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/CurrentVersion/OpenGLDrivers”

对于Windows 2000/XP的系统,请定位到注册表的下述位置:
“HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion/OpenGLDrivers”

    运行 regedit.exe可以进入注册表。
3 基于ICD的OpenGL数据流分析
   我们使用上图作为分析基础。

   3.1 像素格式
   首先,OpenGL 应用程序检测图形加速卡能够支持的像素格式,主要是Back Color Buffer,Depth Buffer和Stencil Buffer。目前需要图形加速卡都不再支持8-bits的Back Buffer。ATI和Nvidia的许多图形卡均不支持32-bits的Depth 
Buffer,一般都是D16,D24和D24S8(24-bitsDepth和8-bits的Stencil)。
   当Application调用DescribePixelFormat,  GetPixelFormat,  SetPixelFormat, 
ChoosePixelFormat,应用程序把这些调用传递给OpenGL32,OpenGL32首先显示卡驱动程序检测能够支持的OpenGL像素格式,显示卡驱动程序对应有多个回调函数,DrvDescribePixelFormat(显示驱动), DrvSetPixelFormat(显示驱动)等。
       如果显示驱动没有对应的回调函数,OpenGL32.dll会调用ICD驱动中对应的函数完成这个工作。大家可以使用VC6.0中的工具Depends打开nvoglnt.dll(nvidia)或者atioglxx..dll(ATI),我们可以看到他们都实现下面上面两个回调函数:
        DrvDescribePixelFormat(ICD驱动)
        DrvSetPixelFormat(ICD驱动)
    不过大家可能觉得奇怪,nividia或者ATI的OpenGL驱动只有几个函数,而且都是以Drv*开头,下面我会给大家一个解答。

  2.2 Context 创建与设置当前Context
    当我们的应用程序调用wglCreateContex的时候,OpenGL32.dll的wglCreateContext函数将参数转化后,调用ICD Driver的DrvCreateContext函数,DrvCreateContext函数然后调用ICD Driver的DrvCreateLayerContext,其中有一个参数是HDC,ICD Driver通过HDC 
获得当前的像素格式ID,实际上这个像素格式ID就是ICD Driver本身定义的。DrvCreateLayerContext将产生一个OpenGL Context的内部数据结构,同时根据像素格式ID将对应的像素格式设置到OpenGL context的内部数据结构,同时向OpenGL32.dll的wglCreateContext返回这个OpenGL 
context的编号,一般是从0开始向上递增。
   请注意,这时候,你换无法调用OpenGL API,因为应用程序还没有调用wglMakeCurrent。
        
   我们现在可以调用wglMakeCurrent,因为我们已经创建一个OpenGL Context。wglMakeCurrent将调用ICD Driver的DrvSetContext。DrvSetContext将完成以下工作:
(1)   根据HDC获取当前的窗口句柄,HWND;
(2)   初始化内部数据结构;
(3)   初始化SW OpenGL context的常量和回调函数
(4)   创建back color buffer, Depth Buffer 和stencil Buffer,和其他类型的缓冲区;
(5)   调用硬件OpenGL context 的初始化函数,初始化硬件OpenGL context的常量和回调函数;
(6)   HW OpenGL Context 设置正确的glGetString返回值;
(7)   设置一个当前的__glDispatchTable,并且返回这个Dispatchtable。

    这些工作中有两项任务需要说明,一是如何创建缓冲区,二是Dispatchtable是何方怪物。

   颜色缓冲区,深度缓冲区和模板缓冲区是位于图形加速卡上的一块显示内存区域,它是由图形加速卡的显示驱动程序所管理,OpenGL ICD Driver是无法直接访问和申请的。所以OpenGL ICD 
Driver通过IDirectDraw7::CreateSurface申请。不过一些显示芯片供应上通过IDirect3DDevice::CreateBackBuffer或者IDirect3DDevice::CreateDepthStencilBuffer获得,两种方法并没有本质上的差异。另外还有一种方法是通过ExtEscape的方法创建缓冲区,这种方法比较复杂,我就不
讲了。
需要注意的是:目前的硬件体系结构将Depth Buffer和Stencil Buffer结合在一起,它们在显示内存中相互交叠,一般的存储格式为:24-bits Depth, 8-bits Stencil, 24-D, 8-S,….

glDispatchTable是OpenGL ICD 驱动程序最为关键的一个结构。它们OpenGL 所有API函数指针的一个结构。
它基本定义如下:
struct glDispatchTable{
void (APIENTRY *glAccum) (GLenum op, GLfloat value);
    void (APIENTRY *glAlphaFunc) (GLenum func, GLclampf ref);
    …..
};

OpenGL的每一个函数都都有一个对应的函数指针定义。DrvSetContext负责返回一个glDispatchTable结构指针,将ICD Driver中所有OpenGL API的函数指针赋值给glDispatchTable,使得OpenGL32.dll能够直接调用ICD Driver中对应的OpenGL函数。
例如,应用程序调用glBegin,将会产生如下的调用顺序:
    Application Call glBegin  ==  >
    OpenGL32.dll  glBegin
      {
           (*__glDispatchTable.glBegin)();  == > 
       }   

     ICD Driver Call glBegin 
     {
        ….
}

    也就是说通过glDispatchTable,所有的OpenGLAPI最终都将进入到ICD Driver对应的函数中。

    啰嗦这么多,相信大家该对OpenGL体系结构有一个大致的认识了。下面我将另外一个内容,OpenGL ICD是如何实现Display List。

3.3     ICD Driver中Display List的实现。
    OpenGL中Display List是一种加速绘制的方法,那么它内部是如何实现的呢?
    其实相当简单。
    首先ICD Driver对每一个OpenGL API进行编号,例如,glAccum是0,glAlphaFunc是2,
    #define __GL_DLISTOP_ACCUM          0
    #define __GL_DLISTOP_ ALPHAFUNC     1
….
  当应用程序调用glNewList生成一个新的Display List,ICD Driver分配一个数组,其中每个元素定义如下
   struct  listop{
        int         opcode; //对应上面的API编号
        void*   parameter;
};

如果我们在Display List中调用glVertex3F,那么ICD Driver调用如下代码(真实代码要复杂些),这时候ICD Driver仅仅将这些命令和它们的参数保存数组中,并不处理这个API。
    plistop->opcode   = __GL_DLISTOP_VERTEX3F;
    (GLfoat*)plistop->parameter = x; 
((GLfoat*)plistop->parameter)++ = y;
((GLfoat*)plistop->parameter)++ = z;

然后,当应用程序调用一个glCallList的时候,ICD Driver首先找到那个数组,根据每个listop的opcode调用对应的处理函数。
   

  3.4 ICD Driver中纹理的管理
    OpenGL ICD Driver无法直接申请显示内存,但是图形硬件需要使用纹理数据实现问题贴图。那么ICD Driver必须能够将纹理数据拷贝到显示内存或AGP memory, 即Local Video Memory ,non-local Video Memory。AGP 
memory是操作系统管理的,经过GART映射后图形处理芯片可以访问的特殊内存区域。

   当我们调用一个glTexImage2D的函数定义纹理的时候,ICD Driver首先创建一块系统内存区域,将纹理数据拷贝到系统内存。然后调用IDirectDraw7::CreateSurface申请video memory。如果申请失败,而且video 
memory存储空间不足,表明现在有太多的应用程序在运行,或者这个应用程序申请了太多的video memory,需要释放一些纹理内存空间,调用IDirctDrawSurface7::Release一些video memory空间。一般采用FIFO的方式实现内存的替换管理。
    当video memory申请成功后,调用IDirectDrawSurface7::Lock获得video memory的用户地址,将保存在系统内存中的数据复制到video memory中。图形芯片就能够访问纹理数据了。

  3.5 wglMakeCurrent(NULL, NULL)
    当应用程序调用wglMakeCurrent(NULL),OpenGL32.dll将调用ICD Driver中的DrvReleaseContext使得所有的OpenGL API都成为空操作,不会产生任何结果。

  3.6 SwapBuffer的实现
   如果是窗口程序,ICD Driver 的DrvSwapBuffers将调用IDirectDrawSurface7::Blt实现从后台缓冲区到前台缓冲区的内容复制。
   如果是全屏幕程序,DrvSwapBuffers将调用IDirectDrawSurface7::flip实现快速的前后缓冲区切换。
    一些驱动程序使用IDirect3DDevice8::Present或者IDirect3DDevice9::Present实现缓冲区内容的切换。

3.7 wglDeleteContext
wglDeleteContext将调用DrvDeleteCOntext,它将释放所有申请的系统内存和显示内存(video memory),以及纹理,并且删除硬件OpenGL context和软件OpenGL context。而且所有的OpenGL API将不可用。

4 OpenGL ICD Driver 评价
  目前OpenGL ICD Driver都相当成熟,基本上都是沿用SGI提供的参考框架结构。大家可以参考下面的链接获取SGI的OpenGL driver实现:
     http://oss.sgi.com/projects/ogl-sample/

目前OpenGL做得最好的是3dlabs,它能够支持OpenGL 2.0。
ATI 和 nvidia都支持 OpenGL 1.4,不过ATI支持更多的OpenGL extension。
其他如SIS, XGI, S3支持的API比nvidia要少一些。
Intel等集成显示卡的驱动自然很差了,硬件能力为OpenGL 1.2或者OpenGL 1.3.

5 Linux的OpenGL Driver体系结构
    Linux下为DRI(Direct Render Infrastrcture),有兴趣可以参考它的网站;
http://dri.sourceforge.net/cgi-bin/moin.cgi

你可能感兴趣的:(Architecture)