离线
三、编写支持 double buffer 的 fbdev 应用
驱动支持 double buffer 后,还得在应用程序里将其使用起来。
先梳理一下思路:
检查是否支持 double buffer;
使能 double buffer:FBIOPUT_VSCREENINFO;
更新 buffer 里数据;
通知驱动切换 buffer:FBIOPAN_DISPLAY;
等待切换完成:FBIO_WAITFORVSYNC;
实例分析:show_color.c
static int fd_fb;
static struct fb_fix_screeninfo fix; /* Current fix */
static struct fb_var_screeninfo var; /* Current var */
static int screen_size;
static unsigned char *fb_base;
static unsigned int line_width;
static unsigned int pixel_width;
int main(int argc, char **argv)
{
int i;
int ret;
int buffer_num;
int buf_idx = 1;
char *buf_next;
unsigned int colors[] = {0x00FF0000, 0x0000FF00, 0x000000FF, 0, 0x00FFFFFF}; /* 0x00RRGGBB */
struct timespec time;
...
fd_fb = open("/dev/fb0", O_RDWR);
ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix);
ioctl(fd_fb, FBIOGET_VSCREENINFO, &var);
line_width = var.xres * var.bits_per_pixel / 8;
pixel_width = var.bits_per_pixel / 8;
screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
// 1. 获得 buffer 个数
buffer_num = fix.smem_len / screen_size;
printf("buffer_num = %d\n", buffer_num);
fb_base = (unsigned char *)mmap(NULL , fix.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
if (fb_base == (unsigned char *)-1) {
printf("can't mmap\n");
return -1;
}
if ((argv[1][0] == 's') || (buffer_num == 1)) {
printf("single buffer:\n");
while (1) {
for (i = 0; i < sizeof(colors)/sizeof(colors[0]); i++) {
lcd_draw_screen(fb_base, colors[i]);
nanosleep(&time, NULL);
}
}
} else {
printf("double buffer:\n");
// 2. 使能多 buffer
var.yres_virtual = buffer_num * var.yres;
ioctl(fd_fb, FBIOPUT_VSCREENINFO, &var);
while (1) {
for (i = 0; i < sizeof(colors)/sizeof(colors[0]); i++) {
// 3. 更新 buffer 里的数据
buf_next = fb_base + buf_idx * screen_size;
lcd_draw_screen(buf_next, colors[i]);
// 4. 通知驱动切换 buffer
var.yoffset = buf_idx * var.yres;
ret = ioctl(fd_fb, FBIOPAN_DISPLAY, &var);
if (ret < 0) {
perror("ioctl() / FBIOPAN_DISPLAY");
}
// 5. 等待帧同步完成
ret = 0;
ioctl(fd_fb, FBIO_WAITFORVSYNC, &ret);
if (ret < 0) {
perror("ioctl() / FBIO_WAITFORVSYNC");
}
buf_idx = !buf_idx;
nanosleep(&time, NULL);
}
}
}
munmap(fb_base , screen_size);
close(fd_fb);
return 0;
}
运行:
$ ./show_color single
buffer_num = 1
single buffer:
$ ./show_color double
buffer_num = 2
double buffer:
该程序会在屏幕上循环的显示不同的颜色。
当传入 "single" 参数时,使用单 buffer,可见撕裂。
当传入 "double" 参数时,使用双 buffer,不再撕裂。
离线