帧缓冲设备的用户空间访问
通过/dev/fbns,应用程序可进行的针对帧缓冲设备的操作主要有如下几种。
1、读/写 dev/fbn:相当于读/写屏幕缓冲区。例如用 cp /dev/fb0 tmp 命令可将当前屏幕的内容复制到一个文件中,而命令 cp tmp > /dev/fb0 则将图形文件tmp 显示在屏幕上。
2、映射操作:对于帧缓冲设备,可通过 mmap()映射操作将屏幕缓冲区的物理地址映射到用户空间的一段虚拟地址中,之后用户就可以通过读/写这段虚拟地址访问屏幕缓冲区,在屏幕上绘图了。而且若干个进程可以映射到同一个显示缓冲区。实际上,使用帧缓冲设备的应用程序都是通过映射操作来显示图形的。
3、I/O 控制:对于帧缓冲设备,对设备文件的 ioctl()操作可读取/设置显示设备及屏幕的参数,如分辨率、显示颜色数、屏幕大小等。
如图 所示,在应用程序中,操作/dev/fbn 的一般步骤如下。
(1)打开/dev/fbn 设备文件。
(2)用 ioctl()操作取得当前显示屏幕的参数,如屏幕分辨率、每个像素点的比特数和偏移。根据屏幕参数可计算屏幕缓冲区的大小。
(3)将屏幕缓冲区映射到用户空间。
(4)映射后就可以直接读/写屏幕缓冲区,进行绘图和图片显示了。
下面代码清单所示为一段用户空间访问帧缓冲设备显示缓冲区的范例,包含打开和关闭帧缓冲设备、得到和设置可变参数、得到固定参数、生成与 BPP 对应的帧缓冲数据及填充显示缓冲区。
1 /*打开帧缓冲设备*/
2 int openFB(const char *name)
3 {
4 int fh;
5 char *dev;
6
7 if (name == NULL)
8 {
9 dev = getenv("FRAMEBUFFER");
10 if (dev)
11 name = dev;
12 else
13 name = DEFAULT_FRAMEBUFFER;
14 }
15
16 if ((fh = open(name, O_WRONLY)) == - 1)
17 {
18 fprintf(stderr, "open %s: %s\n", name, strerror(errno));
19 exit(1);
20 }
21 return fh;
22 }
23
24 /*关闭帧缓冲设备*/
25 void closeFB(int fh)
26 {
27 close(fh);
28 }
29
30 /*得到屏幕可变参数*/
31 void getVarScreenInfo(int fh, struct fb_var_screeninfo *var)
32 {
33 if (ioctl(fh, FBIOGET_VSCREENINFO, var))
34 {
35 fprintf(stderr, "ioctl FBIOGET_VSCREENINFO: %s\n", strerror(errno));
36 exit(1);
37 }
38 }
39
40 /*设置屏幕可变参数*/
41 void setVarScreenInfo(int fh, struct fb_var_screeninfo *var)
42 {
43 if (ioctl(fh, FBIOPUT_VSCREENINFO, var))
44 {
45 fprintf(stderr, "ioctl FBIOPUT_VSCREENINFO: %s\n", strerror(errno));
46 exit(1);
47 }
48 }
49
50 /*得到屏幕固定参数*/
51 void getFixScreenInfo(int fh, struct fb_fix_screeninfo *fix)
52 {
53 if (ioctl(fh, FBIOGET_FSCREENINFO, fix))
54 {
55 fprintf(stderr, "ioctl FBIOGET_FSCREENINFO: %s\n", strerror(errno));
56 exit(1);
57 }
58 }
59
60 /*构造颜色表*/
61 void make332map(struct fb_cmap *map)
62 {
63 int rs, gs, bs, i;
64 int r = 8, g = 8, b = 4;
65
66 map->red = red;
67 map->green = green;
68 map->blue = blue;
69
70 rs = 256 / (r - 1);
71 gs = 256 / (g - 1);
72 bs = 256 / (b - 1);
73
74 for (i = 0; i < 256; i++)
75 {
76 map->red[i] = (rs *((i / (g *b)) % r)) *255;
77 map->green[i] = (gs *((i / b) % g)) *255;
78 map->blue[i] = (bs *((i) % b)) *255;
79 }
80 }
81
82 /*设置颜色表*/
83 void set8map(int fh, struct fb_cmap *map)
84 {
85 if (ioctl(fh, FBIOPUTCMAP, map) < 0)
86 {
87 fprintf(stderr, "Error putting colormap");
88 exit(1);
89 }
90 }
91
92 /*构造并设置颜色表*/
93 void set332map(int fh)
94 {
95 make332map(&map332);
96 set8map(fh, &map332);
97 }
98
99 /*获得颜色表*/
100 void get8map(int fh, struct fb_cmap *map)
101 {
102 if (ioctl(fh, FBIOGETCMAP, map) < 0)
103 {
104 fprintf(stderr, "Error getting colormap");
105 exit(1);
106 }
107 }
108 /*组成 BPP=16 时的缓冲数据*/
109 inline unsigned short make16color(unsigned char r, unsigned char g, unsigned char b)
110 {
111 return ((((r >> 3) & 31) << 11) |
112 (((g >> 2) & 63) << 5) |
113 ((b >> 3) & 31) );
114 }
115
116 /*把 RGB 数据按照屏幕的 BPP 调整*/
117 void *convertRGB2FB(int fh, unsigned char *rgbbuff, unsigned long count, int
118 bpp, int *cpp)
119 {
120 unsigned long i;
121 void *fbbuff = NULL;
122 unsigned char *c_fbbuff;
123 unsigned short *s_fbbuff;
124 unsigned int *i_fbbuff;
125
126 switch (bpp)
127 {
128 case 8:
129 //...
130 case 15:
131 // ...
132 case 16:
133 *cpp = 2;
134 s_fbbuff = (unsigned short*)malloc(count *sizeof(unsigned short));
135 for (i = 0; i < count; i++)
136 s_fbbuff[i] = make16color(rgbbuff[i *3], rgbbuff[i *3+1], rgbbuff
137 [i *3+ 2]);
138 fbbuff = (void*)s_fbbuff;
139 break;
140 case 24:
141 case 32:
142 // ...
143 default:
144 fprintf(stderr, "Unsupported video mode! You've got: %dbpp\n", bpp);
145 exit(1);
146 }
147 return fbbuff;
148 }
149
150 /*写显示缓冲区*/
151 void blit2FB(int fh, void *fbbuff, unsigned int pic_xs, unsigned int pic_ys,
152 unsigned int scr_xs, unsigned int scr_ys, unsigned int xp, unsigned int yp,
153 unsigned int xoffs, unsigned int yoffs, int cpp)
154 {
155 int i, xc, yc;
156 unsigned char *cp;
157 unsigned short *sp;
158 unsigned int *ip;
159 cp = (unsigned char*)sp = (unsigned short*)ip = (unsigned int*)fbbuff;
160
161 xc = (pic_xs > scr_xs) ? scr_xs : pic_xs;
162 yc = (pic_ys > scr_ys) ? scr_ys : pic_ys;
163
164 switch (cpp)
165 {
166 case 1:
167 ...
168 case 2: //BPP=16
169 for (i = 0; i < yc; i++)
170 {
171 lseek(fh, ((i + yoffs) *scr_xs + xoffs) *cpp, SEEK_SET);
172 write(fh, sp + (i + yp) *pic_xs + xp, xc *cpp);
173 }
174 break;
175 case 4:
176 ...
177 }
178 }
179
180
181 /*帧缓冲设备显示*/
182 void fb_display(unsigned char *rgbbuff, int x_size, int y_size, int x_pan, int
183 y_pan, int x_offs, int y_offs)
184 {
185 struct fb_var_screeninfo var;
186 unsigned short *fbbuff = NULL;
187 int fh = - 1, bp = 0;
188
189 /* 打开帧缓冲设备 */
190 fh = openFB(NULL);
191
192 /* 获得可变参数 */
193 getVarScreenInfo(fh, &var);
194
195 /*校正 panning */
196 if (x_pan > x_size - var.xres)
197 x_pan = 0;
198 if (y_pan > y_size - var.yres)
199 y_pan = 0;
200 /* 校正 offset */
201 if (x_offs + x_size > var.xres)
202 x_offs = 0;
203 if (y_offs + y_size > var.yres)
204 y_offs = 0;
205
206 /* 将 RGB 数据转换为与 var 位域对应的数据并填充到显示缓冲区 */
207 fbbuff = convertRGB2FB(fh, rgbbuff, x_size *y_size, var.bits_per_pixel, &bp);
208 blit2FB(fh, fbbuff, x_size, y_size, var.xres, var.yres, x_pan, y_pan, x_offs,
209 y_offs, bp);
210 free(fbbuff);
211
212 /* 关闭帧缓冲设备 */
213 closeFB(fh);
214 }