MATROX MILLENIUM MCD分析笔记 pinxue 2002.12 pinxue@hotmail.com http://pinxue.yeah.net NT4 DDK 所带 Matrox Millenium OpenGL MCD driver源码分析 ddk/src/video/display/mga目录下有mga millenium驱动的源码,包含GDI驱动、DIRECTX驱动及MCD驱动三部份。 显然MCDxxx.h/.c是相关的文件。 MCD驱动的主文件是MCD.C 1288行的 MCDrvGetEntryPoints初始化了 MCDDRIVER结构,填写了管理PixelFormat、Context的方法,以及设备内存管理、纹理管理、象素读写、绘制相关方法。 对于OpenGL系统来说,Rendering Context是客户端程序与piple line通信的接口。 167行的MCDrvCreateContext方法用来实际执行RC创建工作。在做了一系列的准备及填写MCDRC之后,该方法创建并填写了DEVRC结构,除去PixelFormat之类的信息外,还在333行开始初始化不改变状态的(state-invariant)的绘制方法。 注意,MCDRC和DEVRC是完全不同的结构,在MCD.C的203行创建了DEVRC并将其地址保存在MCDRC的pvUser指针中。 DEVRC的定义在MCDHW.H的127行开始,除了一些信息外,有一堆函数指针,其所指的函数将负责响应用户可能发出的glXXX原子命令。 对glBegin的处理则不是那么直接,因为这意味着图元绘制开始,在RC中有一个名为primFunc的函数指针数组(164行),根据要绘制图元的种类从其中索引需要执行的代码。primFunc共有10个成员,指向10种图元的绘制函函数,其意义可在MCDHW.H的298~307行查到。 图元绘制过程的Dispatch逻辑在MCD.C的489~645行MCDrvDraw函数中,直接相关的部份是606~622行。至MCDrvDraw是怎么被调用的,估计是OpenGL 服务器端实现收到glBegin之后通过WINDOWS的MCD服务调用的。需要看一下DDK文档验证。 图元绘制函数的定义在MCDPRIM.C中,可见基本上都是转发给RC中其它的函数指针所指函数了。以__MCDRenderPoint为例,其定义在31~35行间,转向了renderPoint方法。值得注意的是MCDPOINT.C中的48行开始也有一个原型类似的__MCDRenderPoints方法,这个方法是RC.renderPoint所指向的。 在mcdutil.c里的__MCDPickRenderingFuncs里的287行primFUnc[GL_POINTS] = _MCDRenderPoints; 在mcdutil.c里的PickPointFuncs里的141行renderPoint = __MCDRenderPoint/GenPoint/FogPoint。 glBegin(GL_POINTS)实际执行过程是: 1. app发出glBegin 2. OpenGL32.dll 调用client mcd 3. client mcd发出ExtEscape 4. server mcd收到ExtEscape,转换成MCDCOMMAND 5、server mcd调用mcd driver的MCDrvDraw解释MCDCOMMAND 6. MCDrvDraw索引primFunc,调用primFunc[GL_POINTS](),该成员指向__MCDRenderPoints 7. __MCDRenderPoints调用pRC->renderPoint(),该指针指向__MCDRenderPoint,根据pRC->State也有可能指向 __MCDRenderGenPoint或FogPoint。 PickxxxFuncs系列方法则是在MCDrvDraw里当DEVRC.pickNeeded==True时执行的,因为每次Draw时pRC->State可能不同,需要选用不同的函数。而MCDCreateContext里将新创建的DEVRC.pickNeeded设为True,这样,在第一次调用MCDrvDraw时就会调用__MCDPickRenderingFuncs(545行)来初始化primFunc[],并设定裁剪参数(546行,实现在MCDCLIP.C的256行),而PickPointFuncs等的调用则是由PickRenderingFuncs发出的。 这些state-invariant rendering function中包括画点和线、裁剪等。以点为例,它实际响应glBegin(GL_POINTS),其代码在MCDPOINT.C中18~45行,这里就是硬件相关的代码了,CP_WRITE宏的定义在HW.H的1443行,执行写端口动作。 可见MCD的工作过程可分为初始化、状态修改、绘制、卸载四种状态 其中初始化过程为: 1. 系统加载MCD Driver,具体怎么触发、完成的有待阅读DDK文档。 2. MCD Server调用Driver的MCDDrvGetEntryPoints,填写MCDDRIVER结构中的环境、纹理控制等函数。 3、当处理wglCreateContext时,MCD Server调用Driver的MCDCreateContext,填写MCDRC并建立会话,MCDCreateContext还会建立DEVRC并设置其参数,其中DEVRC.pickNeeded=True; 4、当处理glBegin时,MCD Server调用Driver的MCDrvDraw,MCDrvDraw根据DEVRC.pickNeeded调用MCDPickRenderingFunc以初始化DEVRC.primFunc[],MCDPickRenderingFunc将进一步调用其它PickxxxFunc方法以初始化DEVRC中的其它绘制函数,如DEVRC.renderPoint。 在Win2k DDK里包含了s3 virge的mcd源码,其框架跟mga millenium的完全一样,不过注释比较多。