[转] Nano-X显示系统的代码分析
2011-03-08 19:29
295 查看
microwindows作为一个轻量级的图形引擎,目前在很多应用中仍在使用,包括各种机顶盒,嵌入式播放器等。
虽然其目前开发状况非常缓慢,但其代码作为一个很好的图形引擎的范例,我们可以花些时间来仔细研究一下。
后续,本人会列出一系列的技术点,一一介绍microwindows。
先用实例说一下,使用到microwindows的应用环境:
带UI输出的嵌入式网络产品,可设置各种参数。主要使用microwindows的画图功能,鼠标和键盘未使用,键盘在上层应用来单独处理,相应按键后,将需要画的内容通过microwindows来输出。在两个平台中使用到了microwindows,一个是开发调试时使用的X11环境,在此环境中来验证程序的正确性,另一个是实际运行的嵌入式平台,使用framebuffer作为输出。
1、uclinux 2.4.22, arm no-mmu
2、framebuffer作为显示输出,32位带alpha blending效果
3、红外遥控、或键盘作为输入,此由上层应用处理
4、freetype字体
5、nano-x方式
6、软件包为microwindows-0.90.tar.gz
microwindows资源
microwindows论坛(中文):
http://microwindows.5d6d.com/
官方网站:
http://www.microwindows.org/
microwindows简介:
http://www.microwindows.org/MicrowindowsPaper.html
http://www.linuxdevices.com/links/LK4761626139.html
ftp下载:
http://www.cnblogs.com/newsfh/admin/ftp://microwindows.censoft.com/pub/microwindows/
1. microwindows CVS
2. Nano-X CVS Instructions:
3. 1. Set your CVSROOT environment variable
4. export CVSROOT=:pserver:anoncvs@cvs.microwindows.org:/usr/cvs
5. 2. Run "cvs login" and use a password of "guest"
6. 3. Run "cvs co microwin"
7. 4. Watch the source tree spill onto your hard drive
microwindows CVS
Nano-X CVS Instructions:
1. Set your CVSROOT environment variable
export CVSROOT=:pserver:anoncvs@cvs.microwindows.org:/usr/cvs
2. Run "cvs login" and use a password of "guest"
3. Run "cvs co microwin"
4. Watch the source tree spill onto your hard drive
(一)c/s模型的简化
在microwin的运行模式中,nano-x通常的使用方式是c/s模型的,这是类似于x-windows的方式的,好处是某个client端的异常不会影响到server对其他client提供的服务。
但是在很多嵌入式系统中,通常都是在一个单一的环境中使用,单独的server服务进程就不是那么必要。
为了避免在后台启动一个nano-x的服务进程,可以修改microwin的src/config:
其中改为:
LINK_APP_INTO_SERVER = Y
我们来看看这个标记对代码的影响:
1. 1、nanox/Makefile
2. # Nano-X server files
3. NANOXFILES = srvmain.o srvfunc.o srvutil.o srvevent.o srvclip.o
4. # Nano-X client files
5. OBJS = nxdraw.o nxutil.o nxtransform.o
6. ifeq ($(LINK_APP_INTO_SERVER), Y)
7. OBJS += $(NANOXFILES)
8. else
9. # Nano-X server files (network only)
10. NANOXFILES += srvnet.o
11. # Nano-X client files (network only)
12. OBJS += client.o nxproto.o error.o
13. ifeq ($(FRAMEBUFFER), Y)
14. OBJS += clientfb.o
15. else
16. ifeq ($(X11), Y)
17. OBJS += clientfb.o
18. endif
19. endif
20. 这里说明,有了这个标记,那么就只会增加srv对应的代码,而client的代码被排除在外了。
21.
22. 2、Makefile.rules
23. ifeq ($(LINK_APP_INTO_SERVER), Y)
24. DEFINES += -DNONETWORK=1
25. endif
1、nanox/Makefile
# Nano-X server files
NANOXFILES = srvmain.o srvfunc.o srvutil.o srvevent.o srvclip.o
# Nano-X client files
OBJS = nxdraw.o nxutil.o nxtransform.o
ifeq ($(LINK_APP_INTO_SERVER), Y)
OBJS += $(NANOXFILES)
else
# Nano-X server files (network only)
NANOXFILES += srvnet.o
# Nano-X client files (network only)
OBJS += client.o nxproto.o error.o
ifeq ($(FRAMEBUFFER), Y)
OBJS += clientfb.o
else
ifeq ($(X11), Y)
OBJS += clientfb.o
endif
endif
这里说明,有了这个标记,那么就只会增加srv对应的代码,而client的代码被排除在外了。
2、Makefile.rules
ifeq ($(LINK_APP_INTO_SERVER), Y)
DEFINES += -DNONETWORK=1
endif
如果这个标记为N的话,那么当你的应用程序使用编译出来的nano-x库时,使用的将是microwindows-0.90/src/nanox/client.c的代码,即GrOpen是会尝试与srv建立连接:
ret = connect(nxSocket, (struct sockaddr *) &name, size);
并发送request给srv:
nxWriteSocket((char *)&req,sizeof(req));
而如果这个标记为Y的话,那么你的应用使用的代码GrOpen是nanox/srvmain.c中的,即直接运行srv的代码,其中就有初始化graphics的内容GsInitialize()。
这样就实现了对microwin的c/s模型的一个简化,这样更加适合于在嵌入系统中来使用和调试。
由于microwin在x11下,可以先对你的应用程序做好调试后,再转到嵌入系统中,所以我们可以先在x11下验证基本的代码功能,加快开发和调试的速度。
这里记录一下实验用的x11下的config中的一些标记:
1. ARCH = LINUX-NATIVE
2. MICROWIN = N
3. NANOX = Y
4. SHAREDLIBS = N
5. NANOWM = N
6. SCREEN_PIXTYPE = MWPF_TRUECOLOR8888
7. X11 = Y
8. NOMOUSE = Y
9. NOKBD = Y
10. HAVE_FREETYPE_SUPPORT=N
ARCH = LINUX-NATIVE
MICROWIN = N
NANOX = Y
SHAREDLIBS = N
NANOWM = N
SCREEN_PIXTYPE = MWPF_TRUECOLOR8888
X11 = Y
NOMOUSE = Y
NOKBD = Y
HAVE_FREETYPE_SUPPORT=N
(二)screen driver显示驱动的架构
在microwin的代码中,很重要的一个部分就是screen driver显示驱动的部分,它的功能就是负责屏幕输出。
此部分代码是在drivers目录下,并以scr_为开头,我们比较感兴趣的一般是scr_x11.c和scr_fb.c两个部分。
一个是用来在x86 pc上使用的,一个是可以在嵌入系统中使用的。
在microwin的显示驱动的drivers/Makefile中,会根据外部config的设置来只选择使用一个驱动,如X11=Y的话,那么就只会编译scr_x11.c。
在具体每个screen driver中都定义一个SCREENDEVICE scrdev,它也就是microwin要使用到的一个全局的screen driver。
这个结构里主要包括了具体的Open,Close,GetScreenInfo,SetPalette,DrawPixel,FillRect,Blit,StretchBlit等函数实体,如X11_open, X11_close,X11_getscreeninfo,X11_drawpixel等。
同理,对framebuffer,drivers/scr_fb.c,它有一些具体的实现,如fb_open, fb_close, gen_getscreeninfo等。
所以,你自己如果需要增加一个自己的显示驱动的话,就类似上面的内容,写出自己的具体实现函数,从而就能很容易地将microwin porting到你的hardware平台上。
结构上,使用上面的SCREENDEVICE scrdev全局变量的一个好处就是各个具体实现分离,在上层调用上来说只需要关心统一的 SCREENDEVICE 接口即可。
(三)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,那么就会编译到
1. OBJS += genmem.o fb.o scr_x11.o \
2. fblin1.o fblin2.o fblin4.o fblin8.o fblin16.o fblin24.o fblin32.o \
3. fblin32alpha.o mou_x11.o
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显示操作的变量,如:
1. /* called from keyboard/mouse/screen */
2. Display *x11_dpy;
3. int x11_scr;
4. Visual *x11_vis;
5. Colormap x11_colormap;
6. Window x11_win;
7. GC x11_gc;
8. unsigned int x11_event_mask;
9. static int x11_width, x11_height;
10. static int x11_depth; /* Screen depth in bpp */
/* 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,指明表如何来表示颜色
视觉分类里有如下几种类型:
view plaincopy to clipboardprint?
1. char *classnm[] = { "StaticGray", "GrayScale", "StaticColor",
2. "PseudoColor", "TrueColor", "DirectColor"
3. };
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: XOpenDisplay即根据display name与X11 server建立了一个connenction; 然后获得一个default screen; 再调用select_visual时,它会列出screen的不同depth的所对应的visual 类型。
1. XDefaultVisual:
2. Visual class: TrueColor (4)
3. id: 35
4. bits_per_rgb: 8
5. map_entries: 256
6. red_mask: 0x00ff0000
7. green_mask: 0x0000ff00
8. blue_mask: 0x000000ff
9. Screen RootDepth: 24
10. Screen RootVisual
11. Visual class: TrueColor (4)
12. id: 35
13. bits_per_rgb: 8
14. map_entries: 256
15. red_mask: 0x00ff0000
16. green_mask: 0x0000ff00
17. blue_mask: 0x000000ff
18. screen->ndepths: 7
19. Depth: 24
20. dp->nvisuals: 8
21. Visual: 0
22. Visual class: TrueColor (4)
23. id: 35
24. bits_per_rgb: 8
25. map_entries: 256
26. red_mask: 0x00ff0000
27. green_mask: 0x0000ff00
28. blue_mask: 0x000000ff
29. Visual: 1
30. Visual class: TrueColor (4)
31. id: 36
32. bits_per_rgb: 8
33. map_entries: 256
34. red_mask: 0x00ff0000
35. green_mask: 0x0000ff00
36. blue_mask: 0x000000ff
37. Visual: 2
38. Visual class: TrueColor (4)
39. id: 37
40. bits_per_rgb: 8
41. map_entries: 256
42. red_mask: 0x00ff0000
43. green_mask: 0x0000ff00
44. blue_mask: 0x000000ff
45. Visual: 3
46. Visual class: TrueColor (4)
47. id: 38
48. bits_per_rgb: 8
49. map_entries: 256
50. red_mask: 0x00ff0000
51. green_mask: 0x0000ff00
52. blue_mask: 0x000000ff
53. Visual: 4
54. Visual class: DirectColor (5)
55. id: 39
56. bits_per_rgb: 8
57. map_entries: 256
58. red_mask: 0x00ff0000
59. green_mask: 0x0000ff00
60. blue_mask: 0x000000ff
61. Visual: 5
62. Visual class: DirectColor (5)
63. id: 40
64. bits_per_rgb: 8
65. map_entries: 256
66. red_mask: 0x00ff0000
67. green_mask: 0x0000ff00
68. blue_mask: 0x000000ff
69. Visual: 6
70. Visual class: DirectColor (5)
71. id: 41
72. bits_per_rgb: 8
73. map_entries: 256
74. red_mask: 0x00ff0000
75. green_mask: 0x0000ff00
76. blue_mask: 0x000000ff
77. Visual: 7
78. Visual class: DirectColor (5)
79. id: 42
80. bits_per_rgb: 8
81. map_entries: 256
82. red_mask: 0x00ff0000
83. green_mask: 0x0000ff00
84. blue_mask: 0x000000ff
85. Depth: 1
86. dp->nvisuals: 0
87. Depth: 4
88. dp->nvisuals: 0
89. Depth: 8
90. dp->nvisuals: 0
91. Depth: 15
92. dp->nvisuals: 0
93. Depth: 16
94. dp->nvisuals: 0
95. Depth: 32
96. dp->nvisuals: 1
97. Visual: 0
98. Visual class: TrueColor (4)
99. id: 100
100. bits_per_rgb: 8
101. map_entries: 256
102. red_mask: 0x00ff0000
103. green_mask: 0x0000ff00
104. blue_mask: 0x000000ff
105. Selected Visual:
106. Visual class: TrueColor (4)
107. id: 35
108. bits_per_rgb: 8
109. map_entries: 256
110. red_mask: 0x00ff0000
111. green_mask: 0x0000ff00
112. blue_mask: 0x000000ff
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等,如下图: 在X11_open函数的后部,可以看到 savebits = *psd; 然后会调用到select_fb_subdriver(fb.c中),来根据planes和 bpp选择sub driver,如我们的应用中使用的是MWPF_TRUECOLOR8888,那么就会选用fblinear32alpha作为sub driver。然后会调用:
1. static SCREENDEVICE savebits; /* permanent offscreen drawing buffer */
2. set_subdriver(&savebits, subdriver, TRUE);
3. savebits.addr = malloc(size);
4. /* set X11 psd to savebits memaddr for screen->offscreen blits... */
5. psd->addr = savebits.addr;
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中:
1. SUBDRIVER fblinear32alpha = {
2. linear32a_init,
3. linear32a_drawpixel,
4. linear32a_readpixel,
5. linear32a_drawhorzline,
6. linear32a_drawvertline,
7. gen_fillrect,
8. linear32a_blit,
9. linear32a_drawarea,
10. linear32a_stretchblit,
11. linear32a_stretchblitex,
12. };
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:
1. static void
2. X11_drawpixel(PSD psd, MWCOORD x, MWCOORD y, MWPIXELVAL c)
3. {
4. /* draw savebits for readpixel or blit */
5. savebits.DrawPixel(&savebits, x, y, c);
6. if (gr_mode == MWMODE_COPY) {
7. set_color(c);
8. set_mode(gr_mode);
9. XDrawPoint(x11_dpy, x11_win, x11_gc, x, y);
10. } else {
11. update_from_savebits(x, y, 1, 1);
12. }
13. }
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上。
其他的X11_xxx也都是类似如此的像素操作,即都是先调用sub driver的操作函数,然后X11的接口负责输出到X11 display上。
四、总结
总体来说,scr_x11是负责像素pixel在X11上输出的,在它里面是不涉及到图像的叠加等操作的。它所操作的内容主要是将运算过的像素pixel输出到X11上,从而实现了microwindows在X11上的运行。
(四)screen driver显示驱动之framebuffer
关键字:microwindows, microwin, 代码, 分析, framebuffer
在microwindows的显示驱动中,一个很重要的部分就是framebuffer的驱动,framebuffer已经在大量的嵌入式设备中都被支持,所以有了framebuffer,microwindows就可被移植到很多的嵌入式设备中了。
framebuffer的驱动代码是放在了drivers/scr_fb.c里。在drivers/Makefile中,如果FRAMEBUFFER=Y,那么scr_fb.o会被编译到microwindows的driver代码中。
和X11方式的类似,scr_fb.c也定义了一个全局变量:
1. SCREENDEVICE scrdev;
SCREENDEVICE scrdev;
其中就包含了需要为framebuffer而实现的接口函数,如fb_open,fb_close,gen_getscreeninfo,fb_mapmemgc等。这些都是SCREENDEVICE结构中各个函数的具体实现,从而给上层的microwindows画图函数提供了统一的函数接口。
现在我们来看一下fb有关的函数。
在fb_open中,会现从环境变量中读取FRAMEBUFFER的内容,看是否外部已经有所指定:
1. if(!(env = getenv("FRAMEBUFFER")))
2. env = "/dev/fb0";
3. fb = open(env, O_RDWR);
if(!(env = getenv("FRAMEBUFFER")))
env = "/dev/fb0";
fb = open(env, O_RDWR);
然后会用open打开这个fd。
然后会使用ioctl来和kernel的framebuffer交互,得到FBIOGET_FSCREENINFO(fixed),FBIOGET_VSCREENINFO (variable)设备信息,即固定的屏幕信息,还有可变的屏幕信息。
第一个固定的屏幕信息,它由硬件和驱动的能力决定。
第二个是可变的屏幕信息,它由硬件的当前状态决定,它是可以让用户空间的程序调用ioctl来改变的。
1. struct fb_fix_screeninfo fb_fix;
2. struct fb_var_screeninfo fb_var;
struct fb_fix_screeninfo fb_fix;
struct fb_var_screeninfo fb_var;
大家可以查看上面的两个结构,来获得其中的详细定义。
它里面比较有用的信息,就是
1. fb_fix.type; --- 表示planes类型,如0为象素
2. fb_fix.visual; --- 表示视觉类型,如真彩2,伪彩3
3. fb_var.bits_per_pixel; --- 表示bpp
4. fb_fix.line_length; --- 表示每行长度
fb_fix.type; --- 表示planes类型,如0为象素
fb_fix.visual; --- 表示视觉类型,如真彩2,伪彩3
fb_var.bits_per_pixel; --- 表示bpp
fb_fix.line_length; --- 表示每行长度
然后在后面的代码,也会出新要设置 sub driver的内容:
1. subdriver = select_fb_subdriver(psd);
2. set_subdriver(psd, subdriver, TRUE)
subdriver = select_fb_subdriver(psd);
set_subdriver(psd, subdriver, TRUE)
这里是对psd来设置sub driver的,所以在sub driver中的各种draw pixel就会将之前的函数所覆盖。也即scr_fb的很多pixel相关函数,会转到sub driver中。
下面的部分就是要做一个framebuffer到内存地址的映射,即mmap:
1. /* mmap framebuffer into this address space*/
2. psd->size = (psd->size + getpagesize () - 1)
3. / getpagesize () * getpagesize ();
4. psd->addr = mmap(NULL, psd->size, PROT_READ|PROT_WRITE,MAP_SHARED,fb,0);
/* mmap framebuffer into this address space*/
psd->size = (psd->size + getpagesize () - 1)
/ getpagesize () * getpagesize ();
psd->addr = mmap(NULL, psd->size, PROT_READ|PROT_WRITE,MAP_SHARED,fb,0);
在这里,psd->size做了一个按page对齐的转换。
mmap的作用是映射后,就不需要再去read,write文件,这样就避免大量的寻址的开销,所以将framebuffer映射到一个内存上,这样应用直接访问内存效率会高很多。
mmap并不分配空间,只是将文件映射到调用进程的地址空间里。
1. void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
mmap的第四个变量表示这个内存和其他进程的共享情况
需要特别指出的是,在uclinux系统中,这里不能使用MAP_SHARED,而只能使用
1. #define MAP_FIXED 0x10 /* Interpret addr exactly. */
#define MAP_FIXED 0x10 /* Interpret addr exactly. */
即如果参数start所指的地址无法成功建立映射时,则放弃映射,不对地址做修正。
因为uclinux是无MMU管理的,内存的访问是直接访问物理地址的,所以它是不能与其他进程共享一个内存的。
fb_open即完成了主要的工作,其他部分的内容,主要是处理一些特殊情况的framebuffer的操作。
(五)font字体之builtin字体
在microwindows中,可以使用各种字体,包括点阵字体,和truetype字体等。在drivers/scr_x11.c中有定义SCREENDEVICE scrdev,其中一个参数就是
PMWCOREFONT builtin_fonts;
这个参数,就是用来保存font字体的一个结构,实体例子为:drivers/genfont.c中的gen_fonts,它是一个字体结构数组,用户可以对这个内容进行修改,加入自己需要的字体。
1. /* first font is default font*/
2. MWCOREFONT gen_fonts[NUMBER_FONTS] = {
3. {&fontprocs, 0, 0, 0, MWFONT_SYSTEM_VAR, &font_winFreeSansSerif11x13},
4. {&fontprocs, 0, 0, 0, MWFONT_SYSTEM_FIXED, &font_X6x13},
5. /* deprecated redirections for the time being*/
6. {&fontprocs, 0, 0, 0, "Helvetica", &font_winFreeSansSerif11x13}, /* redirect*/
7. {&fontprocs, 0, 0, 0, "Terminal", &font_X6x13} /* redirect*/
8. };
/* first font is default font*/
MWCOREFONT gen_fonts[NUMBER_FONTS] = {
{&fontprocs, 0, 0, 0, MWFONT_SYSTEM_VAR, &font_winFreeSansSerif11x13},
{&fontprocs, 0, 0, 0, MWFONT_SYSTEM_FIXED, &font_X6x13},
/* deprecated redirections for the time being*/
{&fontprocs, 0, 0, 0, "Helvetica", &font_winFreeSansSerif11x13}, /* redirect*/
{&fontprocs, 0, 0, 0, "Terminal", &font_X6x13} /* redirect*/
};
这个数组中,第一个实例会作为缺省的字体。
一、screen driver中的字体
下面来看一下启动过程中字体是如何设置的。
在GrOpen->GsInitialize->GdOpenScreen,即在open screen driver时,会调用
1. GdSetFont(GdCreateFont(psd, NULL, 0, NULL));
GdSetFont(GdCreateFont(psd, NULL, 0, NULL));
其中,GdCreateFont的第二个参数为NULL,那么在engine/devfont.c的GdCreateFont代码中,会将psd->builtin_fonts的第一个实体参数传给fontname,在后面的循环查找中for(i = 0; i < scrinfo.fonts; ++i),当一个个查询到name相同时,就会立即返回所找到的字体结构,这里即第一个实体的内容了。
GdSetFont则会将这个字体赋值给全局的gr_pfont:
1. /*** The current font.*/
2. static PMWFONT gr_pfont;
/*** The current font.*/
static PMWFONT gr_pfont;
二、 设置stdfont字体
在GsInitialize中,GdOpenScreen结束后,会再去设置全局变量stdfont
1. stdfont = GdCreateFont(psd, MWFONT_SYSTEM_VAR, 0, NULL);
2. #define MWFONT_SYSTEM_VAR "System" /* winFreeSansSerif 11x13 (ansi)*/
stdfont = GdCreateFont(psd, MWFONT_SYSTEM_VAR, 0, NULL);
#define MWFONT_SYSTEM_VAR "System" /* winFreeSansSerif 11x13 (ansi)*/
这里的第二个参数是使用name: MWFONT_SYSTEM_VAR,即为"System"。
这个stdfont主要是在GsPrepareDrawing准备时使用到:
1. fontp = GsFindFont(gcp->fontid);
2. pf = fontp? fontp->pfont: stdfont;
fontp = GsFindFont(gcp->fontid);
pf = fontp? fontp->pfont: stdfont;
在可能未设置gc font的时候,就使用stdfont。
三、设置其他字体
在应用中,可以使用GrCreateFont来设置具体的字体,如arial等。
GrCreateFont会调用GdCreateFont去scrdev中查找匹配的字体,并将字体保留在链表listfontp中。
四、builtin 字体
缺省的builtin字体为
1. {&fontprocs, 0, 0, 0, MWFONT_SYSTEM_VAR, &font_winFreeSansSerif11x13},
{&fontprocs, 0, 0, 0, MWFONT_SYSTEM_VAR, &font_winFreeSansSerif11x13},
它是使用的fonts/winFreeSansSerif11x13.c文件。
在文件的头部有写明:
1. /* Generated by convfnt.exe, modified removed offset array*/
2. #include "device.h"
3.
4. /* Windows FreeSansSerif 11x13 Font */
5.
6. /*
7. * #FONTRES 100,96,96:Free Sans Serif 8
8. * Distributed under the MPL (c) 1999 darran@rimron.co.uk v0.3
9. * Free Sans Serif
10. */
/* Generated by convfnt.exe, modified removed offset array*/
#include "device.h"
/* Windows FreeSansSerif 11x13 Font */
/*
* #FONTRES 100,96,96:Free Sans Serif 8
* Distributed under the MPL (c) 1999 darran@rimron.co.uk v0.3
* Free Sans Serif
*/
表示是用工具生成的。
这个builtin就是指的在外部用工具将字体文件转换成.c文件后,直接在microwindows代码中,使用转换在.c中的变量即可。
1. /* Exported structure definition. */
2. MWCFONT font_winFreeSansSerif11x13 = {
3. "winFreeSansSerif11x13",
4. 11,
5. 13,
6. 11,
7. 32,
8. 224,
9. winFreeSansSerif11x13_bits,
10. 0 /*winFreeSansSerif11x13_offset*/,
11. winFreeSansSerif11x13_width,
12. };
/* Exported structure definition. */
MWCFONT font_winFreeSansSerif11x13 = {
"winFreeSansSerif11x13",
11,
13,
11,
32,
224,
winFreeSansSerif11x13_bits,
0 /*winFreeSansSerif11x13_offset*/,
winFreeSansSerif11x13_width,
};
这个builtin字体,开发人员还可以自己来增加,如各种点阵字体bdf文件,使用convbdf.c即可转换为.c文件,来添加到builtin字体中。[备注:BDF: Bitmap Distribution Format位图分布格式的字体文件]
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/bisword/archive/2008/07/31/2746750.aspx
虽然其目前开发状况非常缓慢,但其代码作为一个很好的图形引擎的范例,我们可以花些时间来仔细研究一下。
后续,本人会列出一系列的技术点,一一介绍microwindows。
先用实例说一下,使用到microwindows的应用环境:
带UI输出的嵌入式网络产品,可设置各种参数。主要使用microwindows的画图功能,鼠标和键盘未使用,键盘在上层应用来单独处理,相应按键后,将需要画的内容通过microwindows来输出。在两个平台中使用到了microwindows,一个是开发调试时使用的X11环境,在此环境中来验证程序的正确性,另一个是实际运行的嵌入式平台,使用framebuffer作为输出。
1、uclinux 2.4.22, arm no-mmu
2、framebuffer作为显示输出,32位带alpha blending效果
3、红外遥控、或键盘作为输入,此由上层应用处理
4、freetype字体
5、nano-x方式
6、软件包为microwindows-0.90.tar.gz
microwindows资源
microwindows论坛(中文):
http://microwindows.5d6d.com/
官方网站:
http://www.microwindows.org/
microwindows简介:
http://www.microwindows.org/MicrowindowsPaper.html
http://www.linuxdevices.com/links/LK4761626139.html
ftp下载:
http://www.cnblogs.com/newsfh/admin/ftp://microwindows.censoft.com/pub/microwindows/
1. microwindows CVS
2. Nano-X CVS Instructions:
3. 1. Set your CVSROOT environment variable
4. export CVSROOT=:pserver:anoncvs@cvs.microwindows.org:/usr/cvs
5. 2. Run "cvs login" and use a password of "guest"
6. 3. Run "cvs co microwin"
7. 4. Watch the source tree spill onto your hard drive
microwindows CVS
Nano-X CVS Instructions:
1. Set your CVSROOT environment variable
export CVSROOT=:pserver:anoncvs@cvs.microwindows.org:/usr/cvs
2. Run "cvs login" and use a password of "guest"
3. Run "cvs co microwin"
4. Watch the source tree spill onto your hard drive
(一)c/s模型的简化
在microwin的运行模式中,nano-x通常的使用方式是c/s模型的,这是类似于x-windows的方式的,好处是某个client端的异常不会影响到server对其他client提供的服务。
但是在很多嵌入式系统中,通常都是在一个单一的环境中使用,单独的server服务进程就不是那么必要。
为了避免在后台启动一个nano-x的服务进程,可以修改microwin的src/config:
其中改为:
LINK_APP_INTO_SERVER = Y
我们来看看这个标记对代码的影响:
1. 1、nanox/Makefile
2. # Nano-X server files
3. NANOXFILES = srvmain.o srvfunc.o srvutil.o srvevent.o srvclip.o
4. # Nano-X client files
5. OBJS = nxdraw.o nxutil.o nxtransform.o
6. ifeq ($(LINK_APP_INTO_SERVER), Y)
7. OBJS += $(NANOXFILES)
8. else
9. # Nano-X server files (network only)
10. NANOXFILES += srvnet.o
11. # Nano-X client files (network only)
12. OBJS += client.o nxproto.o error.o
13. ifeq ($(FRAMEBUFFER), Y)
14. OBJS += clientfb.o
15. else
16. ifeq ($(X11), Y)
17. OBJS += clientfb.o
18. endif
19. endif
20. 这里说明,有了这个标记,那么就只会增加srv对应的代码,而client的代码被排除在外了。
21.
22. 2、Makefile.rules
23. ifeq ($(LINK_APP_INTO_SERVER), Y)
24. DEFINES += -DNONETWORK=1
25. endif
1、nanox/Makefile
# Nano-X server files
NANOXFILES = srvmain.o srvfunc.o srvutil.o srvevent.o srvclip.o
# Nano-X client files
OBJS = nxdraw.o nxutil.o nxtransform.o
ifeq ($(LINK_APP_INTO_SERVER), Y)
OBJS += $(NANOXFILES)
else
# Nano-X server files (network only)
NANOXFILES += srvnet.o
# Nano-X client files (network only)
OBJS += client.o nxproto.o error.o
ifeq ($(FRAMEBUFFER), Y)
OBJS += clientfb.o
else
ifeq ($(X11), Y)
OBJS += clientfb.o
endif
endif
这里说明,有了这个标记,那么就只会增加srv对应的代码,而client的代码被排除在外了。
2、Makefile.rules
ifeq ($(LINK_APP_INTO_SERVER), Y)
DEFINES += -DNONETWORK=1
endif
如果这个标记为N的话,那么当你的应用程序使用编译出来的nano-x库时,使用的将是microwindows-0.90/src/nanox/client.c的代码,即GrOpen是会尝试与srv建立连接:
ret = connect(nxSocket, (struct sockaddr *) &name, size);
并发送request给srv:
nxWriteSocket((char *)&req,sizeof(req));
而如果这个标记为Y的话,那么你的应用使用的代码GrOpen是nanox/srvmain.c中的,即直接运行srv的代码,其中就有初始化graphics的内容GsInitialize()。
这样就实现了对microwin的c/s模型的一个简化,这样更加适合于在嵌入系统中来使用和调试。
由于microwin在x11下,可以先对你的应用程序做好调试后,再转到嵌入系统中,所以我们可以先在x11下验证基本的代码功能,加快开发和调试的速度。
这里记录一下实验用的x11下的config中的一些标记:
1. ARCH = LINUX-NATIVE
2. MICROWIN = N
3. NANOX = Y
4. SHAREDLIBS = N
5. NANOWM = N
6. SCREEN_PIXTYPE = MWPF_TRUECOLOR8888
7. X11 = Y
8. NOMOUSE = Y
9. NOKBD = Y
10. HAVE_FREETYPE_SUPPORT=N
ARCH = LINUX-NATIVE
MICROWIN = N
NANOX = Y
SHAREDLIBS = N
NANOWM = N
SCREEN_PIXTYPE = MWPF_TRUECOLOR8888
X11 = Y
NOMOUSE = Y
NOKBD = Y
HAVE_FREETYPE_SUPPORT=N
(二)screen driver显示驱动的架构
在microwin的代码中,很重要的一个部分就是screen driver显示驱动的部分,它的功能就是负责屏幕输出。
此部分代码是在drivers目录下,并以scr_为开头,我们比较感兴趣的一般是scr_x11.c和scr_fb.c两个部分。
一个是用来在x86 pc上使用的,一个是可以在嵌入系统中使用的。
在microwin的显示驱动的drivers/Makefile中,会根据外部config的设置来只选择使用一个驱动,如X11=Y的话,那么就只会编译scr_x11.c。
在具体每个screen driver中都定义一个SCREENDEVICE scrdev,它也就是microwin要使用到的一个全局的screen driver。
这个结构里主要包括了具体的Open,Close,GetScreenInfo,SetPalette,DrawPixel,FillRect,Blit,StretchBlit等函数实体,如X11_open, X11_close,X11_getscreeninfo,X11_drawpixel等。
同理,对framebuffer,drivers/scr_fb.c,它有一些具体的实现,如fb_open, fb_close, gen_getscreeninfo等。
所以,你自己如果需要增加一个自己的显示驱动的话,就类似上面的内容,写出自己的具体实现函数,从而就能很容易地将microwin porting到你的hardware平台上。
结构上,使用上面的SCREENDEVICE scrdev全局变量的一个好处就是各个具体实现分离,在上层调用上来说只需要关心统一的 SCREENDEVICE 接口即可。
(三)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,那么就会编译到
1. OBJS += genmem.o fb.o scr_x11.o \
2. fblin1.o fblin2.o fblin4.o fblin8.o fblin16.o fblin24.o fblin32.o \
3. fblin32alpha.o mou_x11.o
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显示操作的变量,如:
1. /* called from keyboard/mouse/screen */
2. Display *x11_dpy;
3. int x11_scr;
4. Visual *x11_vis;
5. Colormap x11_colormap;
6. Window x11_win;
7. GC x11_gc;
8. unsigned int x11_event_mask;
9. static int x11_width, x11_height;
10. static int x11_depth; /* Screen depth in bpp */
/* 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,指明表如何来表示颜色
视觉分类里有如下几种类型:
view plaincopy to clipboardprint?
1. char *classnm[] = { "StaticGray", "GrayScale", "StaticColor",
2. "PseudoColor", "TrueColor", "DirectColor"
3. };
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: XOpenDisplay即根据display name与X11 server建立了一个connenction; 然后获得一个default screen; 再调用select_visual时,它会列出screen的不同depth的所对应的visual 类型。
1. XDefaultVisual:
2. Visual class: TrueColor (4)
3. id: 35
4. bits_per_rgb: 8
5. map_entries: 256
6. red_mask: 0x00ff0000
7. green_mask: 0x0000ff00
8. blue_mask: 0x000000ff
9. Screen RootDepth: 24
10. Screen RootVisual
11. Visual class: TrueColor (4)
12. id: 35
13. bits_per_rgb: 8
14. map_entries: 256
15. red_mask: 0x00ff0000
16. green_mask: 0x0000ff00
17. blue_mask: 0x000000ff
18. screen->ndepths: 7
19. Depth: 24
20. dp->nvisuals: 8
21. Visual: 0
22. Visual class: TrueColor (4)
23. id: 35
24. bits_per_rgb: 8
25. map_entries: 256
26. red_mask: 0x00ff0000
27. green_mask: 0x0000ff00
28. blue_mask: 0x000000ff
29. Visual: 1
30. Visual class: TrueColor (4)
31. id: 36
32. bits_per_rgb: 8
33. map_entries: 256
34. red_mask: 0x00ff0000
35. green_mask: 0x0000ff00
36. blue_mask: 0x000000ff
37. Visual: 2
38. Visual class: TrueColor (4)
39. id: 37
40. bits_per_rgb: 8
41. map_entries: 256
42. red_mask: 0x00ff0000
43. green_mask: 0x0000ff00
44. blue_mask: 0x000000ff
45. Visual: 3
46. Visual class: TrueColor (4)
47. id: 38
48. bits_per_rgb: 8
49. map_entries: 256
50. red_mask: 0x00ff0000
51. green_mask: 0x0000ff00
52. blue_mask: 0x000000ff
53. Visual: 4
54. Visual class: DirectColor (5)
55. id: 39
56. bits_per_rgb: 8
57. map_entries: 256
58. red_mask: 0x00ff0000
59. green_mask: 0x0000ff00
60. blue_mask: 0x000000ff
61. Visual: 5
62. Visual class: DirectColor (5)
63. id: 40
64. bits_per_rgb: 8
65. map_entries: 256
66. red_mask: 0x00ff0000
67. green_mask: 0x0000ff00
68. blue_mask: 0x000000ff
69. Visual: 6
70. Visual class: DirectColor (5)
71. id: 41
72. bits_per_rgb: 8
73. map_entries: 256
74. red_mask: 0x00ff0000
75. green_mask: 0x0000ff00
76. blue_mask: 0x000000ff
77. Visual: 7
78. Visual class: DirectColor (5)
79. id: 42
80. bits_per_rgb: 8
81. map_entries: 256
82. red_mask: 0x00ff0000
83. green_mask: 0x0000ff00
84. blue_mask: 0x000000ff
85. Depth: 1
86. dp->nvisuals: 0
87. Depth: 4
88. dp->nvisuals: 0
89. Depth: 8
90. dp->nvisuals: 0
91. Depth: 15
92. dp->nvisuals: 0
93. Depth: 16
94. dp->nvisuals: 0
95. Depth: 32
96. dp->nvisuals: 1
97. Visual: 0
98. Visual class: TrueColor (4)
99. id: 100
100. bits_per_rgb: 8
101. map_entries: 256
102. red_mask: 0x00ff0000
103. green_mask: 0x0000ff00
104. blue_mask: 0x000000ff
105. Selected Visual:
106. Visual class: TrueColor (4)
107. id: 35
108. bits_per_rgb: 8
109. map_entries: 256
110. red_mask: 0x00ff0000
111. green_mask: 0x0000ff00
112. blue_mask: 0x000000ff
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等,如下图: 在X11_open函数的后部,可以看到 savebits = *psd; 然后会调用到select_fb_subdriver(fb.c中),来根据planes和 bpp选择sub driver,如我们的应用中使用的是MWPF_TRUECOLOR8888,那么就会选用fblinear32alpha作为sub driver。然后会调用:
1. static SCREENDEVICE savebits; /* permanent offscreen drawing buffer */
2. set_subdriver(&savebits, subdriver, TRUE);
3. savebits.addr = malloc(size);
4. /* set X11 psd to savebits memaddr for screen->offscreen blits... */
5. psd->addr = savebits.addr;
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中:
1. SUBDRIVER fblinear32alpha = {
2. linear32a_init,
3. linear32a_drawpixel,
4. linear32a_readpixel,
5. linear32a_drawhorzline,
6. linear32a_drawvertline,
7. gen_fillrect,
8. linear32a_blit,
9. linear32a_drawarea,
10. linear32a_stretchblit,
11. linear32a_stretchblitex,
12. };
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:
1. static void
2. X11_drawpixel(PSD psd, MWCOORD x, MWCOORD y, MWPIXELVAL c)
3. {
4. /* draw savebits for readpixel or blit */
5. savebits.DrawPixel(&savebits, x, y, c);
6. if (gr_mode == MWMODE_COPY) {
7. set_color(c);
8. set_mode(gr_mode);
9. XDrawPoint(x11_dpy, x11_win, x11_gc, x, y);
10. } else {
11. update_from_savebits(x, y, 1, 1);
12. }
13. }
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上。
其他的X11_xxx也都是类似如此的像素操作,即都是先调用sub driver的操作函数,然后X11的接口负责输出到X11 display上。
四、总结
总体来说,scr_x11是负责像素pixel在X11上输出的,在它里面是不涉及到图像的叠加等操作的。它所操作的内容主要是将运算过的像素pixel输出到X11上,从而实现了microwindows在X11上的运行。
(四)screen driver显示驱动之framebuffer
关键字:microwindows, microwin, 代码, 分析, framebuffer
在microwindows的显示驱动中,一个很重要的部分就是framebuffer的驱动,framebuffer已经在大量的嵌入式设备中都被支持,所以有了framebuffer,microwindows就可被移植到很多的嵌入式设备中了。
framebuffer的驱动代码是放在了drivers/scr_fb.c里。在drivers/Makefile中,如果FRAMEBUFFER=Y,那么scr_fb.o会被编译到microwindows的driver代码中。
和X11方式的类似,scr_fb.c也定义了一个全局变量:
1. SCREENDEVICE scrdev;
SCREENDEVICE scrdev;
其中就包含了需要为framebuffer而实现的接口函数,如fb_open,fb_close,gen_getscreeninfo,fb_mapmemgc等。这些都是SCREENDEVICE结构中各个函数的具体实现,从而给上层的microwindows画图函数提供了统一的函数接口。
现在我们来看一下fb有关的函数。
在fb_open中,会现从环境变量中读取FRAMEBUFFER的内容,看是否外部已经有所指定:
1. if(!(env = getenv("FRAMEBUFFER")))
2. env = "/dev/fb0";
3. fb = open(env, O_RDWR);
if(!(env = getenv("FRAMEBUFFER")))
env = "/dev/fb0";
fb = open(env, O_RDWR);
然后会用open打开这个fd。
然后会使用ioctl来和kernel的framebuffer交互,得到FBIOGET_FSCREENINFO(fixed),FBIOGET_VSCREENINFO (variable)设备信息,即固定的屏幕信息,还有可变的屏幕信息。
第一个固定的屏幕信息,它由硬件和驱动的能力决定。
第二个是可变的屏幕信息,它由硬件的当前状态决定,它是可以让用户空间的程序调用ioctl来改变的。
1. struct fb_fix_screeninfo fb_fix;
2. struct fb_var_screeninfo fb_var;
struct fb_fix_screeninfo fb_fix;
struct fb_var_screeninfo fb_var;
大家可以查看上面的两个结构,来获得其中的详细定义。
它里面比较有用的信息,就是
1. fb_fix.type; --- 表示planes类型,如0为象素
2. fb_fix.visual; --- 表示视觉类型,如真彩2,伪彩3
3. fb_var.bits_per_pixel; --- 表示bpp
4. fb_fix.line_length; --- 表示每行长度
fb_fix.type; --- 表示planes类型,如0为象素
fb_fix.visual; --- 表示视觉类型,如真彩2,伪彩3
fb_var.bits_per_pixel; --- 表示bpp
fb_fix.line_length; --- 表示每行长度
然后在后面的代码,也会出新要设置 sub driver的内容:
1. subdriver = select_fb_subdriver(psd);
2. set_subdriver(psd, subdriver, TRUE)
subdriver = select_fb_subdriver(psd);
set_subdriver(psd, subdriver, TRUE)
这里是对psd来设置sub driver的,所以在sub driver中的各种draw pixel就会将之前的函数所覆盖。也即scr_fb的很多pixel相关函数,会转到sub driver中。
下面的部分就是要做一个framebuffer到内存地址的映射,即mmap:
1. /* mmap framebuffer into this address space*/
2. psd->size = (psd->size + getpagesize () - 1)
3. / getpagesize () * getpagesize ();
4. psd->addr = mmap(NULL, psd->size, PROT_READ|PROT_WRITE,MAP_SHARED,fb,0);
/* mmap framebuffer into this address space*/
psd->size = (psd->size + getpagesize () - 1)
/ getpagesize () * getpagesize ();
psd->addr = mmap(NULL, psd->size, PROT_READ|PROT_WRITE,MAP_SHARED,fb,0);
在这里,psd->size做了一个按page对齐的转换。
mmap的作用是映射后,就不需要再去read,write文件,这样就避免大量的寻址的开销,所以将framebuffer映射到一个内存上,这样应用直接访问内存效率会高很多。
mmap并不分配空间,只是将文件映射到调用进程的地址空间里。
1. void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
mmap的第四个变量表示这个内存和其他进程的共享情况
需要特别指出的是,在uclinux系统中,这里不能使用MAP_SHARED,而只能使用
1. #define MAP_FIXED 0x10 /* Interpret addr exactly. */
#define MAP_FIXED 0x10 /* Interpret addr exactly. */
即如果参数start所指的地址无法成功建立映射时,则放弃映射,不对地址做修正。
因为uclinux是无MMU管理的,内存的访问是直接访问物理地址的,所以它是不能与其他进程共享一个内存的。
fb_open即完成了主要的工作,其他部分的内容,主要是处理一些特殊情况的framebuffer的操作。
(五)font字体之builtin字体
在microwindows中,可以使用各种字体,包括点阵字体,和truetype字体等。在drivers/scr_x11.c中有定义SCREENDEVICE scrdev,其中一个参数就是
PMWCOREFONT builtin_fonts;
这个参数,就是用来保存font字体的一个结构,实体例子为:drivers/genfont.c中的gen_fonts,它是一个字体结构数组,用户可以对这个内容进行修改,加入自己需要的字体。
1. /* first font is default font*/
2. MWCOREFONT gen_fonts[NUMBER_FONTS] = {
3. {&fontprocs, 0, 0, 0, MWFONT_SYSTEM_VAR, &font_winFreeSansSerif11x13},
4. {&fontprocs, 0, 0, 0, MWFONT_SYSTEM_FIXED, &font_X6x13},
5. /* deprecated redirections for the time being*/
6. {&fontprocs, 0, 0, 0, "Helvetica", &font_winFreeSansSerif11x13}, /* redirect*/
7. {&fontprocs, 0, 0, 0, "Terminal", &font_X6x13} /* redirect*/
8. };
/* first font is default font*/
MWCOREFONT gen_fonts[NUMBER_FONTS] = {
{&fontprocs, 0, 0, 0, MWFONT_SYSTEM_VAR, &font_winFreeSansSerif11x13},
{&fontprocs, 0, 0, 0, MWFONT_SYSTEM_FIXED, &font_X6x13},
/* deprecated redirections for the time being*/
{&fontprocs, 0, 0, 0, "Helvetica", &font_winFreeSansSerif11x13}, /* redirect*/
{&fontprocs, 0, 0, 0, "Terminal", &font_X6x13} /* redirect*/
};
这个数组中,第一个实例会作为缺省的字体。
一、screen driver中的字体
下面来看一下启动过程中字体是如何设置的。
在GrOpen->GsInitialize->GdOpenScreen,即在open screen driver时,会调用
1. GdSetFont(GdCreateFont(psd, NULL, 0, NULL));
GdSetFont(GdCreateFont(psd, NULL, 0, NULL));
其中,GdCreateFont的第二个参数为NULL,那么在engine/devfont.c的GdCreateFont代码中,会将psd->builtin_fonts的第一个实体参数传给fontname,在后面的循环查找中for(i = 0; i < scrinfo.fonts; ++i),当一个个查询到name相同时,就会立即返回所找到的字体结构,这里即第一个实体的内容了。
GdSetFont则会将这个字体赋值给全局的gr_pfont:
1. /*** The current font.*/
2. static PMWFONT gr_pfont;
/*** The current font.*/
static PMWFONT gr_pfont;
二、 设置stdfont字体
在GsInitialize中,GdOpenScreen结束后,会再去设置全局变量stdfont
1. stdfont = GdCreateFont(psd, MWFONT_SYSTEM_VAR, 0, NULL);
2. #define MWFONT_SYSTEM_VAR "System" /* winFreeSansSerif 11x13 (ansi)*/
stdfont = GdCreateFont(psd, MWFONT_SYSTEM_VAR, 0, NULL);
#define MWFONT_SYSTEM_VAR "System" /* winFreeSansSerif 11x13 (ansi)*/
这里的第二个参数是使用name: MWFONT_SYSTEM_VAR,即为"System"。
这个stdfont主要是在GsPrepareDrawing准备时使用到:
1. fontp = GsFindFont(gcp->fontid);
2. pf = fontp? fontp->pfont: stdfont;
fontp = GsFindFont(gcp->fontid);
pf = fontp? fontp->pfont: stdfont;
在可能未设置gc font的时候,就使用stdfont。
三、设置其他字体
在应用中,可以使用GrCreateFont来设置具体的字体,如arial等。
GrCreateFont会调用GdCreateFont去scrdev中查找匹配的字体,并将字体保留在链表listfontp中。
四、builtin 字体
缺省的builtin字体为
1. {&fontprocs, 0, 0, 0, MWFONT_SYSTEM_VAR, &font_winFreeSansSerif11x13},
{&fontprocs, 0, 0, 0, MWFONT_SYSTEM_VAR, &font_winFreeSansSerif11x13},
它是使用的fonts/winFreeSansSerif11x13.c文件。
在文件的头部有写明:
1. /* Generated by convfnt.exe, modified removed offset array*/
2. #include "device.h"
3.
4. /* Windows FreeSansSerif 11x13 Font */
5.
6. /*
7. * #FONTRES 100,96,96:Free Sans Serif 8
8. * Distributed under the MPL (c) 1999 darran@rimron.co.uk v0.3
9. * Free Sans Serif
10. */
/* Generated by convfnt.exe, modified removed offset array*/
#include "device.h"
/* Windows FreeSansSerif 11x13 Font */
/*
* #FONTRES 100,96,96:Free Sans Serif 8
* Distributed under the MPL (c) 1999 darran@rimron.co.uk v0.3
* Free Sans Serif
*/
表示是用工具生成的。
这个builtin就是指的在外部用工具将字体文件转换成.c文件后,直接在microwindows代码中,使用转换在.c中的变量即可。
1. /* Exported structure definition. */
2. MWCFONT font_winFreeSansSerif11x13 = {
3. "winFreeSansSerif11x13",
4. 11,
5. 13,
6. 11,
7. 32,
8. 224,
9. winFreeSansSerif11x13_bits,
10. 0 /*winFreeSansSerif11x13_offset*/,
11. winFreeSansSerif11x13_width,
12. };
/* Exported structure definition. */
MWCFONT font_winFreeSansSerif11x13 = {
"winFreeSansSerif11x13",
11,
13,
11,
32,
224,
winFreeSansSerif11x13_bits,
0 /*winFreeSansSerif11x13_offset*/,
winFreeSansSerif11x13_width,
};
这个builtin字体,开发人员还可以自己来增加,如各种点阵字体bdf文件,使用convbdf.c即可转换为.c文件,来添加到builtin字体中。[备注:BDF: Bitmap Distribution Format位图分布格式的字体文件]
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/bisword/archive/2008/07/31/2746750.aspx
相关文章推荐
- Nano-X显示系统的代码分析
- 汇编语言显示系统时间代码分析(14)
- 嵌入式ucos-II系统内核及代码分析00
- 文件系统读写--文件读过程代码分析
- DM8168 解码显示模块代码阅读分析
- 考勤系统——代码分析datagrid
- nano-pc-t1 4412 显示驱动分析
- 阅读代码,分析现有系统。
- 2016华为软件精英挑战赛初赛题目,个人分析与代码,尚未测试代码,因为没有judge系统啊!
- 显示系统信息与硬件信息的bat代码
- freetypelcd多行显示代码分析
- 6种javascript显示当前系统时间代码
- 《信息安全系统设计基础》代码调试分析
- javascript显示系统当前时间代码
- 类似系统的UIActivityViewController显示方式的开源代码:HYActivityView
- microwindows代码分析 (四)screen driver显示驱动之framebuffer
- SDL2源代码分析7:显示(SDL_RenderPresent())
- 一起来学J2ME_1:撰写一个手机系统属性显示程序 (附jad文件的错误代码)
- Android系统的开机画面显示过程分析
- Win10系统安装.net失败提示错误代码0x80070003的故障分析及解决方法