SGI OpenGL Sample Implementation 分析笔记 pinxue 2002.8 pinxue@hotmail.com http://pinxue.yeah.net 1 GLX是作为 XServer的 Module存在的,其入口点在 Glx/Server/Glxmodule.c里,注意它定义了两个 Module:libGL和 glx,在加载 glx里会把 libGL做为 SubModule加载。 2 GLX基于X协议运行,它定义了一组扩展协议包,定义在 Glx/Include/Protostruct.h里。 3 glx协议的处理是在 Glx/Server/Glxext.c的 __glXDispatch(client)里解析转发的,所有的客户信息保存在 __glXClients[client->index]里, 所有的 opcode处理者保存在 __glXSingleTable[opcode]里。 __glXSingleTable的定义将由 Glx/Server/Disptab.ls的 function GenSingleTable生成,或者到 GLX1.2的 glx/xc/programs/Xserver/GL/g_disptab.c里看生成后的东东。 现在的问题是: (1) glx被加载后是怎么插进X-protocol处理流程以解释glx-protocol的 (2) glx是何时进行buffer等内部初始化的 (3) client端如何建立一个连接(pipe line) __glXClients的定义在 Glx/Server/Global.c里 __GLXdisplayPrivate* __glXInitialize(dpy)的定义在glxext.c里,初始化客户端扩展代码 浏览一下文件发现,还是看GLX1.2的代码比较有益,它不包括OpenGL Implementation,比较容易搞清楚Server端的活动情况。其代码中不包含glxmodule.c,根据源码中Glxreadme的说明,只能用静态链接重做XServer。 {Glxfb.c} __glXInitFB --> CreateScratchGC 得到一个XGC,以后将这个GC传给DDX。 Free--> FreeScratchGC释放,在InitFB时填进buf参数中,以后通过buf->Free调用。该文件还定义了Resize/Lock/Unlock等同类型的回调。 __glXFBMemSwapBuffers --> ValidateGC后pGC->ops->PutImage将图象显示在Drawable上(ZPixmap参数是指示象素格式的,见XLib手册) {Glxbuf.c} __glXFBInitDrawable将窗体的swapBuffers回调设为__glFBMemSwapBuffers,根据modes设定参数调用__glXInitFB以建立Front Buffer,如需要双缓冲用__glXInitMem建立backBuffer。 另外glX也支持使用Pixmap做为绘制设备,其初始化由__glXPixInitDrawable完成,swapBuffers->__glXNop,对应的frontBuffer建立改由__glXInitPix完成。 如果需要,两者都用__glXInitMem建立Accum/Depth/StencilBuffer。 注1:__glXInitMem定义在Glxmem.c中,最终是引用了malloc/realloc获取内存做为buffer。 注2:__glXInitPix定义在Glxpix.c中,跟__glXInitFB差不多,为所用的pixmap建立XGC。 新的问题: glX向opengl implementation提供buffer(GC?)并负责在收到刷新命令时Validate GC, 那么它如何利用硬件加速能力呢? 对于硬件T/L又如何利用呢? 对于前者可能是通过特定的XServer实现,那么后者就比较有意思了,就算XServer有接口,glX也不知道呀,何况XFree86 4的架构通常只须提供一个二进制的驱动模块。 {Glxcontext.h} glX的session是建立在X session上的,用__GLXcontex记录。 该Context有自己的id,并包括 代表对应X session的Screen ID和指针, 代表所用窗口/位图的drawablePrivate指针 如果绘制到pixmap则还有pixmap指针 OpenGL/X的会话建立流程是:客户先通过x-protocol跟XServer建立一个会话,然后以session资料调用本地的glXCreateContext,glXCreateContext向XServer发出一个glx-protocol request,XServer收到后转给glX模块的__glXDispatch处理,该Dispatch则从__glXSingleTable[opcode]找到回调函数,从G_disptab.c中可以发现是__glXCreateContex。 先看客户端,glx/xc/lib/Glxcmds.c中定义了glXCreateContext,它简单的调用同一文件中的CreateContext,CreateContext很长,其核心意思就是用dpy、vis和OpenGL参数组装一个glXContext,然后据此调用GetReq建立request并放入队列中,然后用XSync发出去。 这个request是怎么转到glX的还不清楚。 再看服务器端,glx/xc/Programs/Xserver/Glxcmds.c中定义了__glXCreateContext,它先做一番象素格式之类的检查,新建一个__glContext;然后根据X Display对应Screen找到适当的GLXScreen,并利用其中登记的createContext回调创建GC, createContext应该就会完成对__glXFBInitDrawable的调用,不过它是在什么时候填写到GLX Screen中的还不清楚。 最后,调用AddResource登录这个glXContext并填写其内容。 {Glxscrenn.c} __glXScreenInit为每一个通过了probe的X Screen建立对应的__glXscreenInfo,保存在__glXActiveScreens数组中。 事实上__glXScreens[]只有一个元素,内容是对全局变量__glDDXScreenInfo的引用,在Ogl-sample.20000807/Main/Gfx/Lib/Opengl/Drivers/Ddx里可以找到,createContext字段被填为glDdxCreateContext。 注3:DDX代表Device Dependent X,DIX代表Device Independent X {Glximports.c} 这是为跨平台而设的。