WinCE Display驱动开发介绍(转载)
在WinCE中,Display驱动由GWES模块来管理。WinCE提供了两种架构的Display驱动模型,可以满足不同的硬件需求。一种是基于WinCE DDI的Display驱动模型,另一种是基于DirectDraw的Display驱动模型。下面将对两种架构作简单介绍。
1. Display驱动模型
WinCE下的Display驱动直接由GWES模块管理,它会直接被GWES模块管理和调用。Display驱动实际上也是分层的,其中包括GPE库,该库处理一些默认的绘图,相当于驱动的MDD层。用户只需要开发和硬件相关的PDD层驱动就可以了。在WinCE中,整个架构如图:
如图,Application为一个应用程序,该程序会调用图形设备接口函数(GDI),而GDI函数是由Coredll.dll模块导出的。Coredll.dll会将函数调用的参数打包,然后触发对另一个进程的本地过程调用(LPC),所有的绘图和开窗口的工作被传给内核中GWES模块。GWES模块被称为图形,窗口和事件子系统,专门处理图形输出和用户输入等事件及相关的所有交互。GWES模块会调用Display驱动完成对显示硬件的操作。Display驱动由GPE和DDL.dll组成,GPE完成基本的默认绘图工作,而DDI.dll实际上从GPE类上继承而来的,并实现了相关的显示硬件的操作。
2. DirectDraw Display驱动模型
DirectDraw提供了独立于硬件的直接访问显示设备的能力。它可以通过直接访问硬件抽象层(HAL)中的一些函数来达到直接操作显示设备的目的,在这个过程中,不再需要图形设备接口(GDI)的转换。这种直接的方法可以使图像更加连贯,也提高了显示的性能。为了实现这样的功能,需要在显示驱动上扩展能够直接访问相关硬件的函数。这些函数会被DirectDraw模块调用,并形成DirectDraw的硬件抽象层(DDHAL)。DirectDraw显示驱动架构如图:
如图,DirectDraw的真正实现代码都驻留在gwes.dll模块中,应用程序只是连接了一个小的客户端,被称为DDRAW.dll代理,该代理主要负责用户进程与系统之间的远程DirectDraw COM接口连接。这样,用户请求会被传送到内核的GWES模块中。针对DirectDraw,WinCE提供了一个名为DirectDraw的GPE库(DDGPE),它是从GPE类上面继承而来的。实际上,DirectDraw显示驱动是由DDGPE和DDHAL组成,而DDGPE中已经包含了DDHAL的功能。用户需要从DDGPE类继承并实现相关函数即可。GWES.dll模块中包含GDI和DDRAW两个组件,这两个组件会调用驱动中的DDGPE的相关接口完成对硬件的操作。
在上述两种架构中,用户可以根据自己的硬件情况选择相应的架构。第一种架构是基于GPE类继承来实现的,第二种架构是基于DDGPE类继承来实现的,而第二种架构的DDGPE类又是从第一种架构的GPE类继承而来。关于两种类的具体定义,可参见” WINCE600PUBLICCOMMONOAKINC”路径下的gpe.h和ddgpe.h文件。
本Blog将基于Display驱动模型来介绍,DirectDraw Display驱动模型不在这里介绍。
WinCE下的Display驱动是基于GPE类来实现的,其中GPE中已经实现了基本的绘制工作,相当于MDD层。用户需要继承该类,并实现里面的其他一些函数,所以用户实现的相当于PDD层。
GPE类是一个抽象类,其中包含很多纯虚函数,只能用于继承。用户在继承了GPE类以后,要对GPE类中的纯虚函数做相应的实现。开发Display驱动的大致步骤如下:
(1) 继承GPE类并定义一个该类的实例。
(2) 实现GetGPE()函数,把该类的实例返回给上层的DDI接口。
(3) 实现DrvEnableDriver(..)和DisplayInit(..)函数并导出这两个接口。
(4) 实现GPE类中的函数。
下面将具体介绍实现的步骤:
1 继承GPE类
首先,基于GPE类进行继承,如果想在Display驱动支持Rotation可以从GPERotate类上面继承。实际上,在”gpe.h”中有如下定义:
typedef GPE GPERotate;
可以看出GPERotate类就是GPE类。在这里,用户从GPE类上面继承就可以了,举个例子如下:
class NewGPE: public GPE
{
private:
GPEMode m_ModeInfo;
DWORD m_colorDepth;
DWORD m_VirtualFrameBuffer;
DWORD m_FrameBufferSize;
BOOL m_CursorDisabled;
BOOL m_CursorVisible;
…
public:
NewGPE(void);
virtual INT NumModes(void);
virtual SCODE SetMode(INT modeId, HPALETTE *palette);
virtual INT InVBlank(void);
virtual SCODE SetPalette(const PALETTEENTRY *source, USHORT firstEntry, USHORT numEntries);
virtual SCODE GetModeInfo(GPEMode *pMode, INT modeNumber);
virtual SCODE SetPointerShape(GPESurf *mask, GPESurf *colorSurface, INT xHot, INT yHot, INT cX, INT cY);
virtual SCODE MovePointer(INT xPosition, INT yPosition);
virtual void WaitForNotBusy(void);
virtual INT IsBusy(void);
virtual void GetPhysicalVideoMemory(unsigned long *physicalMemoryBase, unsigned long *videoMemorySize);
virtual SCODE AllocSurface(GPESurf **surface, INT width, INT height, EGPEFormat format, INT surfaceFlags);
virtual SCODE Line(GPELineParms *lineParameters, EGPEPhase phase);
virtual SCODE BltPrepare(GPEBltParms *blitParameters);
virtual SCODE BltComplete(GPEBltParms *blitParameters);
virtual ULONG GetGraphicsCaps();
virtual ULONG DrvEscape(
SURFOBJ *pso,
ULONG iEsc,
ULONG cjIn,
PVOID pvIn,
ULONG cjOut,
PVOID pvOut);
SCODE WrappedEmulatedLine (GPELineParms *lineParameters);
void CursorOn(void);
void CursorOff(void);
#ifdef ROTATE
void SetRotateParms();
LONG DynRotate(int angle);
#endif
};
类NewGPE从GPE类上面继承,其中包括一些属性,如下:
m_ModeInfo:显示模式,结构如下
struct GPEMode {
int modeId; //开发者定义的显示模式的索引号
int width; //显示宽度
int height; //显示高度
int Bpp; //显示深度
int frequency; //显示频率
EGPEFormat format; // RGB格式,各占多少bit
};
m_colorDepth:显示深度
m_VirtualFrameBuffer:FrameBuffer的地址
m_FrameBufferSize:FrameBuffer的大小
m_CursorDisabled:光标使能标记
m_CursorVisible:光标可视标记
用户可以根据需要定义相应的属性,在NewGPE类中,需要定义并实现基类中的纯虚函数,上面的NewGPE类中已经包含了这些函数的定义,还包括了其他一些函数,将在下面介绍。
2 实现GetGPE函数
在定义了NewGPE类之后,我们需要实现一个实例,首先定义一个该类的指针:
static GPE *gGPE = (GPE*)NULL;
然后实现GetGPE函数,如下:
GPE *GetGPE(void)
{
if (!gGPE)
{
gGPE = new NewGPE();
}
return gGPE;
}
在该函数中,创建了一个NewGPE的实例。在这个时候NewGPE构造函数会被调用,一般我们会在这里面作一些与显示相关的初始化的工作。该函数返回gGPE指针给上层接口。
3 实现DrvEnableDriver和DisplayInit函数
Display驱动对上层的GWES模块提供了20多个函数接口,但是这些函数并不是直接提供出来的,实际上只是通过一个DrvEnableDriver(..)函数来完成的。该函数在Display驱动的MDD层中没有实现,所以需要在PDD层中定义,如下:
BOOL APIENTRY DrvEnableDriver(ULONG engineVersion, ULONG cj, DRVENABLEDATA *data, PENGCALLBACKS engineCallbacks)
{
BOOL fOk = FALSE;
// make sure we know where our registry configuration is
if(gszBaseInstance[0] != 0) {
fOk = GPEEnableDriver(engineVersion, cj, data, engineCallbacks);
}
return fOk;
}
engineVersion:DDI版本号,目前为DDI_DRIVER_VERSION。
cj:DRVENABLEDATA结构的大小。
data:指向DRVENABLEDATA结构体。
engineCallbacks:指向一个回调函数结构体,传入一些GDI函数到Display驱动中。
其中,DRVENABLEDATA结构中包含了Display驱动中的设备接口函数的指针,在DrvEnableDriver函数中调用了GPEEnableDriver函数,该函数会导出GWES模块所需的所有Display驱动的接口函数。同时GWES模块通过第四个参数engineCallbacks提供回调函数供Display驱动调用。该函数在”ddi_if”中定义。
另一个重要的函数是DisplayInit函数,它是第一个被执行的Display驱动中的函数,该函数主要用于读取注册表中的一些信息并作判断。该函数是可选的,也可以不在驱动中实现它。
BOOL APIENTRY DisplayInit(LPCTSTR pszInstance, DWORD dwNumMonitors)
{
DWORD dwStatus;
HKEY hkDisplay;
BOOL fOk = FALSE;
if(pszInstance != NULL) {
_tcsncpy(gszBaseInstance, pszInstance, dim(gszBaseInstance));
}
// sanity check the path by making sure it exists
dwStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, gszBaseInstance, 0, 0, &hkDisplay);
if(dwStatus == ERROR_SUCCESS) {
RegCloseKey(hkDisplay);
fOk = TRUE;
}
else
{
RETAILMSG(0, (_T("SALCD2: DisplayInit: can't open '%s'rn"), gszBaseInstance));
}
return fOk;
}
pszInstance:注册表中显示驱动的相关注册表值
dwNumMonitors:支持的Monitor的个数
在该函数中主要通过读取注册表信息判断显示驱动的存在,如果返回错误,则GWES会停止Display驱动的初始化。当然,用户可以根据自己的要求灵活掌握,也可以在这里初始化显示设备或做其他的初始化工作。
4 实现GPE类中的函数
由于NewGPE继承于GPE类,所以必须实现GPE类中的所有纯虚函数,这些函数实际上就是PDD层驱动中需要实现的函数,如下:
4.1 virtual SCODE GetModeInfo(GPEMode *pMode, INT modeNumber)
获得显示模式。
pMode:输出显示模式结构
modeNumber:显示模式索引号
4.2 virtual int NumModes(void)
获得当前驱动支持的显示模式的个数
4.3 virtual SCODE SetMode(INT modeId, HPALETTE *palette)
设置显示模式。
modeId:显示模式索引号
palette:调色板指针,指向一个由EngCreatePalette函数创建的调色板
4.4 virtual SCODE AllocSurface(GPESurf **surface, INT width, INT height, EGPEFormat format, INT surfaceFlags)
在系统内存中创建一个绘图平面。
surface:指向被分配的内存的指针
width:宽度
height:高度
format:绘图平面格式
surfaceFlags:标记位,标明在哪分配内存
4.5 virtual SCODE SetPointerShape(GPESurf *pMask, GPESurf *pColorSurface, INT xHot, INT yHot, INT cX, INT cY);
设置光标形状。
pMask:指向一个包含光标形状的掩码
pColorSurface:指向被光标使用的颜色绘图平面
xHot:光标热点的X坐标
yHot:光标热点的Y坐标
cX:光标宽度
cY:光标高度
4.6 virtual SCODE MovePointer(int x, int y)
移动光标到指定位置或者隐藏光标
x:光标移动位置的x坐标,若为-1表示隐藏光标。
y:光标移动位置的y坐标
4.7 virtual SCODE BltPrepare(GPEBltParms *blitParameters)
在做位块传输前会先执行该函数,用于确定执行BLT的函数
blitParameters:指向一个GPE的位块传输参数的结构体
4.8 virtual SCODE BltComplete(GPEBltParms *blitParameters)
该函数用于释放在BltPrepare中申请的资源
blitParameters:指向一个GPE的位块传输参数的结构体
4.9 virtual SCODE Line(GPELineParms *lineParameters, EGPEPhase phase)
画线函数
lineParameters:指向一个GPE的Line结构体,描述所画的线
phase:画线所处的阶段,具体描述如下
gpeSingle:画单根线
gpePrepare:准备画线
gpeContinue:画线过程中
gpeComplete:画线完成
在这里要提一点,有时我们会看到在该函数中调用另一个函数WrappedEmulatedLine(..),这个函数在WinCE的PUBLIC目录下的参考Display驱动中也可以找到,该函数是一个快速的画线函数,里面采用了Bresenham画线算法,通过采用运行速度快的加减和移位运算来完成画线。
4.10 virtual SCODE SetPalette(const PALETTEENTRY *pSource, USHORT firstEntry, USHORT numEntries)
设置调色板
pSource:指向一个调色板入口信息的结构体
firstEntry:第一个入口
numEntries:入口的个数
4.11 virtual int InVBlank(void)
显示设备是否处于垂直消隐期间
上述函数在GPE类中均被定义为纯虚函数,需要在继承类中实现,也就是在我们的驱动程序中实现。这些函数是必须实现的。根据显示的需求,还可以在显示驱动中添加其他的函数,比如对光标的支持,对旋转的支持等,如下:
4.12 void CursorOn(void)
使能光标显示。
4.13 void CursorOff(void)
禁止光标显示。
4.14 void SetRotateParms(void)
设置屏幕翻转参数。
4.15 void DynRotate(int angel)
支持动态翻转。
angel:翻转角度
4.16 ULONG *APIENTRY DrvGetMasks(DHPDEV dhpdev)
获得显示模式的RGB掩码
dhpdev:指向掩码信息,比如RGB565模式为(0xf800,0x07e0,0x001f)
NOTE:该函数必须在驱动中被实现。
4.17 PowerHandler(BOOL bOff)
电源控制。
bOff:TRUE表示关闭电源,FALSE表示打开电源
4.18 ULONG DrvEscape(DHPDEV dhpdev, SURFOBJ* pso, ULONG iEsc, ULONG cjIn, PVOID pvIn, ULONG cjOut, PVOID pvOut)
该函数提供给应用程序的一个直接访问显示驱动的接口,和流设备驱动中的IoCtls函数类似。应用程序通过调用ExtEscape函数传送操作码和数据给显示设备驱动,DrvEscape函数会接收到数据并进行处理,然后返回相应结果给EstEscape函数。用户也可以根据需要自己定义相应的操作码。
dhpdev:设备句柄
pso:指向一个绘图平面的结构
iEsc:操作码
cjIn:输入数据buffer的大小
pvIn:指向输入数据buffer
cjOut:输出数据buffer的大小
pvOut:指向输出数据buffer
大致就是这些内容,GPE类中的纯虚函数是肯定要实现的,其他的一些函数根据需要来实现。我在写这篇Blog的时候,有些地方有些犹豫,开始觉得自己语文水平不够,不太会表达,但是也许是因为自己对Display驱动中的一些知识还是理解的不够彻底吧。如果有什么问题,请大家谅解,并请指点。
转载于:https://www.cnblogs.com/Jade2009/archive/2009/01/15/1376030.html
WinCE Display驱动开发介绍(转载)相关推荐
- WinCE WebCamera驱动开发白皮书
Windows CE USB摄像头驱动编写 作者: Douglas Boling 译: WinCE下被询问次数最多的驱动是USB摄像头驱动,其原由并不难理解.首先,每个人都喜欢看视频.插上摄像头并用它 ...
- linux驱动开发(转载自正点原子)
一.Linux驱动开发思维 1.Linux下驱动开发直接操作寄存器不现实. 2.根据Linux下的各种驱动框架进行开发.一定要满足框架,也就是Linux下各种驱动框架的掌握. 3.驱动最终表现就是/d ...
- IE 8 Accelerator加速器开发介绍{转载}
记录这篇博客的原因是因为我自己想要有一个快速的加速器,就是我经常在浏览网页的时候,看到有些网址,如果想要转过去的话,我必须手工复制到地址栏,然后回车一下.然后我就想,如果能直接通过一个快捷方式就太好了 ...
- 【原创】WinCE下流驱动开发流程
硬件平台:S5PV210 软件平台:WinCE6.0 已IICBUS为例,实现流驱动框架,供以后参考使用 1.创建文件 IICBUS.cpp IICBUS.DEF makefile sources 2 ...
- 通用usb驱动libusb介绍和使用示例
小知识: sudo insmod /lib/modules/2.6.22-14-generic/kernel/drivers/usb/serial/usbserial.ko vendor=0x8086 ...
- 移动平台游戏开发介绍
2.移动平台游戏开发介绍 转载于:https://www.cnblogs.com/zwj-199306231519/p/9148888.html
- 转:WinCE驱动开发问题精华集锦
1.在应用程序中,如何向修改本机的ip 地址等网络参数,并使之立即生效? 网络设置保存在注册表中,位置[HKEY_LOCAL_MACHINE\Comm\网卡名称\Parms\Tcp ...
- WinCE驱动开发问题精华集锦 [转]
WinCE驱动开发问题精华集锦 [转] 原文 http://blog.mcuol.com/User/basicygp/Article/4340_1.htm 在mediaplayer全屏播放的时候,我 ...
- 【WinCE】SD card技术了解并WINCE下SDHC驱动开发(updated)
SD Card Driver on ADS Summary 了解SD card. 1 WinCE 5.0下SD Stack. 6 Bus Driver 7 Host Controller Driver ...
- 【转】WinCE驱动开发问题精华集锦
[转]WinCE驱动开发问题精华集锦 WinCE驱动开发问题精华集锦 如何让系统加载自己写的驱动程序? 两种办法: 1.在[HKEY_LOCAL_MACHINE\Drivers\BuiltI ...
最新文章
- Github+Gitlb的使用
- What is Type in managed heap?
- 第一个问题就难倒我了!
- LOJ #2733 [JOI2016春季合宿]Sandwiches (DP)
- oracle绑定主键,oracle添加主键的四种方法:
- matlab中uint16(uint8)函数的用法
- 首次揭秘云原生Hologres存储引擎
- 深度学习(16)TensorFlow高阶操作五: 张量限幅
- vue2使用axios post跳坑,封装成模块
- gin 怎么通过 post 发送结构体_Go Web 框架 Gin 实践12—优化配置结构及实现图片上传...
- 映客上云 助力《疫战到底》系列课程吸引数千万用户观看
- java中如何将数字转换成字符串(int转换为string)
- C#计算程序的运行时间
- 【leetcode刷题笔记】Sqrt(x)
- ahk键盘增强✨✨✨v1.1
- 智慧城市发展路径应分级分类
- windows内核开发笔记十一:IRQL级别调用说明
- MySql数据的完整性
- 有人负责,才有质量:写给在集市中迷失的一代
- Windows上安装Nessus