转载时请注明出处和作者联系方式:http://blog.youkuaiyun.com/mimepp
作者联系方式:YU TAO <yut616 at sohu dot com>
microwindows代码分析 (三)screen driver显示驱动之X11
在microwindows的嵌入式开发中,为了简化调试和check memory leak,那么最好是先将应用程序在X11下做好验证,保证function已经完成并且不会出现内存泄露的问题。这样就会用到microwindows的X11 screen driver显示驱动,我们在这里详细分析一下。
在我们讨论的microwindows的应用中,目前只涉及到microwindows的screen driver,并不涉及到鼠标和键盘的driver。也就是说,使用的microwindows只用到它的画图功能。
在编译X11 screen driver方式的microwindows时,会进入到drivers/Makefile,其中X11为Y,那么就会编译到
OBJS += genmem.o fb.o scr_x11.o /
fblin1.o fblin2.o fblin4.o fblin8.o fblin16.o fblin24.o fblin32.o /
fblin32alpha.o mou_x11.o
其中scr_x11.o就是x11接口的screen driver的实现,它里面会调用到X11 lib的一系列函数,实现draw pixel。
另外,可以看到有一系列的fblinXXX开头的代码也被编译了进来,这个内容主要是对应不同的pixel type,来做一些pixel的叠加运算等。它是作为sub driver来被scr_x11所使用的,因为scr_x11中主要是将X11 lib做一个包装,从而将运算好了的pixel输出到X11 output,而fblinXXX是一个sub driver,来根据不同的pixel type处理需要输出的pixel,如alpha blending混合。 而且fblinXXX在其他screen driver的情况下也是一样公用的,如framebuffer,也即fblinXXX也会被指定为sub driver。所以看到X11方式的screen driver会用到fb开头的内容,也不用奇怪。
下面来看drivers/scr_x11.c的具体内容。
scr文件名前缀就是screen driver的含义。
在这个screen driver中,定义了一个x11方式的SCREENDEVICE scrdev,这个变量的名字,在各个screen driver的实现中都是同一个名字,只是一个编译只使用一个具体的scrdev,在我们这里,就是X11方式的scrdev。
这个scrdev定义了X11方式的各个函数,如X11_open,X11_drawpixel,X11_fillrect,X11_blit等。
一、变量
在代码中,定义一些全局的涉及到X11显示操作的变量,如:
/* called from keyboard/mouse/screen */
Display *x11_dpy;
int x11_scr;
Visual *x11_vis;
Colormap x11_colormap;
Window x11_win;
GC x11_gc;
unsigned int x11_event_mask;
static int x11_width, x11_height;
static int x11_depth; /* Screen depth in bpp */
在这里,x11_dpy是一个与x11 server所建立的connection;
x11_vis是记录视觉类型的变量;
x11_colormap是色彩映射;
在我们的应用中,如果是使用32位的无符号整数来表示颜色,也就是一般说的像素值,即pixel value,但这个像素值,在显示到输出时,会受到很多因素的影响,如
1、色彩深度
2、色彩映射,colormap,也就是含有R/G/B的强度值的表
3、视觉类型,visual type,指明如何来表示颜色
视觉分类里有如下几种类型:
char *classnm[] = { "StaticGray", "GrayScale", "StaticColor",
"PseudoColor", "TrueColor", "DirectColor"
};
其中X11 server支持的主要是true color和direct color。
true color是直接根据rgb值,来得到像素值,而direct color是将rgb拿来到表里做一个查询后再转到像素值的。
二、X11_open
下面来看一下screen driver的open实现:X11_open
在这个函数里,会先调用X11的初始化函数来建立与X11 server的连接,x11_setup_display(附kscope图):
XOpenDisplay即根据display name与X11 server建立了一个connenction; 然后获得一个default screen; 再调用select_visual时,它会列出screen的不同depth的所对应的visual 类型。
XDefaultVisual:
Visual class: TrueColor (4)
id: 35
bits_per_rgb: 8
map_entries: 256
red_mask: 0x00ff0000
green_mask: 0x0000ff00
blue_mask: 0x000000ff
Screen RootDepth: 24
Screen RootVisual
Visual class: TrueColor (4)
id: 35
bits_per_rgb: 8
map_entries: 256
red_mask: 0x00ff0000
green_mask: 0x0000ff00
blue_mask: 0x000000ff
screen->ndepths: 7
Depth: 24
dp->nvisuals: 8
Visual: 0
Visual class: TrueColor (4)
id: 35
bits_per_rgb: 8
map_entries: 256
red_mask: 0x00ff0000
green_mask: 0x0000ff00
blue_mask: 0x000000ff
Visual: 1
Visual class: TrueColor (4)
id: 36
bits_per_rgb: 8
map_entries: 256
red_mask: 0x00ff0000
green_mask: 0x0000ff00
blue_mask: 0x000000ff
Visual: 2
Visual class: TrueColor (4)
id: 37
bits_per_rgb: 8
map_entries: 256
red_mask: 0x00ff0000
green_mask: 0x0000ff00
blue_mask: 0x000000ff
Visual: 3
Visual class: TrueColor (4)
id: 38
bits_per_rgb: 8
map_entries: 256
red_mask: 0x00ff0000
green_mask: 0x0000ff00
blue_mask: 0x000000ff
Visual: 4
Visual class: DirectColor (5)
id: 39
bits_per_rgb: 8
map_entries: 256
red_mask: 0x00ff0000
green_mask: 0x0000ff00
blue_mask: 0x000000ff
Visual: 5
Visual class: DirectColor (5)
id: 40
bits_per_rgb: 8
map_entries: 256
red_mask: 0x00ff0000
green_mask: 0x0000ff00
blue_mask: 0x000000ff
Visual: 6
Visual class: DirectColor (5)
id: 41
bits_per_rgb: 8
map_entries: 256
red_mask: 0x00ff0000
green_mask: 0x0000ff00
blue_mask: 0x000000ff
Visual: 7
Visual class: DirectColor (5)
id: 42
bits_per_rgb: 8
map_entries: 256
red_mask: 0x00ff0000
green_mask: 0x0000ff00
blue_mask: 0x000000ff
Depth: 1
dp->nvisuals: 0
Depth: 4
dp->nvisuals: 0
Depth: 8
dp->nvisuals: 0
Depth: 15
dp->nvisuals: 0
Depth: 16
dp->nvisuals: 0
Depth: 32
dp->nvisuals: 1
Visual: 0
Visual class: TrueColor (4)
id: 100
bits_per_rgb: 8
map_entries: 256
red_mask: 0x00ff0000
green_mask: 0x0000ff00
blue_mask: 0x000000ff
Selected Visual:
Visual class: TrueColor (4)
id: 35
bits_per_rgb: 8
map_entries: 256
red_mask: 0x00ff0000
green_mask: 0x0000ff00
blue_mask: 0x000000ff
而我们的应用中,实际使用的visual也就是XDefaultVisual的值。即Visual class: TrueColor (4),id: 35,map_entries: 256。
在完成X11的display初始化后,会XCreateColormap,还有XCreateWindow建立窗口,长宽也即你指定的x11_width, x11_height,然后会再调用XDefaultDepth获得default的depth等,如下图(附kscope图):
在X11_open函数的后部,可以看到 savebits = *psd; 然后会调用到select_fb_subdriver(fb.c中),来根据planes和 bpp选择sub driver,如我们的应用中使用的是MWPF_TRUECOLOR8888,那么就会选用fblinear32alpha作为sub driver。然后会调用:
static SCREENDEVICE savebits; /* permanent offscreen drawing buffer */
set_subdriver(&savebits, subdriver, TRUE);
savebits.addr = malloc(size);
/* set X11 psd to savebits memaddr for screen->offscreen blits... */
psd->addr = savebits.addr;
这个部分是一个很重要的内容。 它会将savebits的操作函数做一个更新,即设置到sub driver上,也即drivers/fblin32alpha.c中:
SUBDRIVER fblinear32alpha = {
linear32a_init,
linear32a_drawpixel,
linear32a_readpixel,
linear32a_drawhorzline,
linear32a_drawvertline,
gen_fillrect,
linear32a_blit,
linear32a_drawarea,
linear32a_stretchblit,
linear32a_stretchblitex,
};
这个savebits是保存的off sreen的buffer,也即最后的输出,都是从这个savebits中来得到的。
savebits.addr即malloc出来的一个显示buffer缓冲,是最后送到X11输出前保存各个pixel的地方。
psd->addr也则是对应的这个地址,但它是给上层的microwindows所使用的一个地址。各个不同的screen driver也都需要定义这个psd->addr。
三、draw pixel
我们再来看X11_drawpixel:
static void
X11_drawpixel(PSD psd, MWCOORD x, MWCOORD y, MWPIXELVAL c)
{
/* draw savebits for readpixel or blit */
savebits.DrawPixel(&savebits, x, y, c);
if (gr_mode == MWMODE_COPY) {
set_color(c);
set_mode(gr_mode);
XDrawPoint(x11_dpy, x11_win, x11_gc, x, y);
} else {
update_from_savebits(x, y, 1, 1);
}
}
在其中,即会先调用sub drvier的DrawPixel函数,用pixel value值c来更新savebits里的addr的数据,然后调用update_from_savebits将savebits.addr的像素内容输出到X11上。
上面的 drawpixel 是操作一个像素点,也就是说将 c 的值画到 psd 的 x/y 位置处,所以你可以看到
update_from_savebits(x, y, 1, 1); 的参数是w=1, h=1。
其他的X11_xxx也都是类似如此的像素操作,即都是先调用sub driver的操作函数,然后X11的接口负责输出到X11 display上。
四、总结
总体来说,scr_x11是负责像素pixel在X11上输出的,在它里面是不涉及到图像的叠加等操作的。
它所操作的内容主要是将运算过的像素pixel输出到X11上,从而实现了microwindows在X11上的运行。