转载请注明作者及联络方式
FB最重要的操作绘制显存并且在LCD显示.显存是由LCD驱动在内核中分配的可以进行DMA的SDRAM空间.如果用户进程需要操作显存,必须用mmap将内核空间映射到用户进程来可操作.
而映射的操作主要通过mmap来完成
void *mmap(void *start, size_t length, int prot, int flags,int fd, off_t offset);
参数含意
- start要求空间起始地址,一般为NULL,表示自动分配.
- Length,映射区域的长度,
- Prot是映射区域的属性,一般设为可读可写
- fd是open("/dev/fb0")
- flags,这里必须设为共享 MAP_SHARED.
- Offset表示返回地址在映射空间的偏移量,一般是0
如果成功将返回一个地址,大体位于进程的堆与栈中间的空间地区,否则返回-1
mmap的映射的功能主要有如下三大类
1.用户用内存映射方式打开文件。
2.在进程间共享内存
3.在进程与驱动间共享内核空间。
因此fb驱动映射显存只是mmap其中一个应用.不同的应用主要区别在mmap的参数fd来源不同.
1.如果打开文件,则fd为打开文件的
2.哪果打开共享内存,则为shm_open()返回值
3.如果与驱动共享,则用open打开设备结点的返回值
显存内数据组织
显存内的数据组织高度依赖于分辩率和BPP,因为其大小就为 xres*yres*BPP.
不同的分辩率下有不同组织形式。
对于不同分辩率的分布可以查看fb_var_screeninfo结构下的的fb_bitfield,这是驱动用于告诉应用程序RGB数据排列的数据
struct fb_bitfield red; /* bitfield in fb mem if true color, */
struct fb_bitfield green; /* else only length is significant */
struct fb_bitfield blue;
struct fb_bitfield transp; /* transparency */
|
它有如下定义
struct fb_bitfield {
__u32 offset; /* beginning of bitfield */
__u32 length; /* length of bitfield */
__u32 msb_right; /* != 0 : Most significant bit is */
/* right */
};
|
即标明R,G,B三个分量和透明通道分量数据在Pixel数据如何排列的问题。
offset是以起始点的偏移量,lenght是其长度。MSB即最高有效位所在方向,msg_right 为 1表示从左边算起, 为0表示从左边算起.(注:MSB在左边,实际上是小端字节序要求)
我们可以用ioctl接口来读相关参数实测一下。
24bpp
red length 8,offset 16 msb_right 0
green length 8,offset 8 msb_right 0
blue length 8,offset 0 msb_right 0 |
可以看到24bpp占用3个byte,并且是按 8:8:8的排列顺序,最高位有一个byte用于对齐,BPP是4个byte
red length 5,offset 11 msb_right 0
green length 6,offset 5 msb_right 0
blue length 5,offset 0 msb_right 0
|
可以看到16bpp占用两个byte,并且是按 5:6:5的排列顺序,注意从offset可以明显看到,蓝色在最前面
18bpp
red length 6,offset 12 msb_right 0
green length 6,offset 6 msb_right 0
blue length 6,offset 0 msb_right 0
transp length 0,offset 0 msb_right 0 |
18bpp是按 6:6:6的排列,并且大约14bit的空间只用于占位。一个点占用4byte空间
软件操作显存
软件可以把mmap映射的空间看成是一个二维数组来操作,绘制图像相当于操作显存相应的点的数据。
在16bpp下,一个显存相当是一个unsigned short的二维数组,而18bpp,24bpp相当于是unsigned long的二维数组。从编程的角度,用整数去操作更为简单。
用整数操作就牵涉到字节序问题了,因为显存对于物理编移量有要求,因此用数字来表示颜色要保存值正好是放在对应分量位置上。
以24bpp为例,在小端字节序下,正好是一一对应的,一个数字的即数字高位正好在内存的MSB这一侧。这样,fb_bitfield.offset正好是数字的偏移量。而且大端字节序正好相反。
以红色为例,24bpp 最大值为0xFF,这样在小端字节序下,红点的数据是 0x00FF0000,(大端字节序是0x0000FF00)
为了简化,我设计小端字节序三个宏.
#define RGB_16BPP_565(r,g,b) (((r & 0x1F)>>11) | ((g & 0x3F)>>5) | ((b & 0x1F)))
#define RGB_24_888(r,g,b) ( ((r & 0xff)<<16) | ((g & 0xff ) << 8) | ((b & 0xff) << 0) )
#define RGB_18_666(r,g,b) ( ((r & 0x3f)<<16) | ((g & 0x3f ) << 8) | ((b & 0x3f) << 0) )
把r,g,b三个分量传入即可得出相应值
以下是三种bpp的全屏绘制函数
#define RGB_18_666(r,g,b) ( ((r & 0x3f)<<16) | ((g & 0x3f ) << 8) | ((b & 0x3f) << 0) )
int fill_screen_18bpp(unsigned char * fb_buf,RGB_PIXEL *pp,struct fb_var_screeninfo * pvar)
{
unsigned int x,y;
unsigned long * p = (unsigned long *)fb_buf;
if(pvar->bits_per_pixel != 18)
return -1;
// for(x=0; x
// for(y=0; y
for(x=0; x<pvar->xres*pvar->yres;x++)
{
*p = RGB_18_666(pp->red,pp->green,pp->blue);
p++;
}
return 0;
}
#define RGB_16_565(r,g,b) ( ((r & 0x1f)<<11) | ((g & 0x3f ) << 6) | ((b & 0x1f) << 0) )
int fill_screen_16bpp(unsigned char * fb_buf,RGB_PIXEL *pp,struct fb_var_screeninfo * pvar)
{
unsigned int x,y;
unsigned short * p = (unsigned short *)fb_buf;
if(pvar->bits_per_pixel != 16)
return -1;
// for(x=0; x
// for(y=0; y
for(x=0; x<pvar->xres*pvar->yres;x++)
{
*p = RGB_16_565(pp->red,pp->green,pp->blue);
p++;
}
return 0;
}
//msb_right =0 表示最左边,左边16位,按小端字节序正好反过来
#define RGB_24_888(r,g,b) ( ((r & 0xff)<<16) | ((g & 0xff ) << 8) | ((b & 0xff) << 0) )
int fill_screen_24bpp(unsigned char * fb_buf,RGB_PIXEL *pp,struct fb_var_screeninfo * pvar)
{
unsigned int x,y;
unsigned long * p = (unsigned long *)fb_buf;
// if(pvar->bits_per_pixel != 24)
// return -1;
printf("%s:show red %d green %d blue %d \n",__FUNCTION__,pp->red,pp->green,pp->blue);
for(x=0; x<pvar->xres*pvar->yres;x++)
{
*p = RGB_24_888(pp->red,pp->green,pp->blue);
p++;
}
return 0;
}
|
|
文件: | test_fb.zip |
大小: | 1KB |
下载: | 下载 |
|