您尚未登录。

楼主 # 2024-06-21 16:33:08

memory
会员
注册时间: 2021-08-11
已发帖子: 495
积分: 467

离线

楼主 #1 2024-06-21 16:35:24

memory
会员
注册时间: 2021-08-11
已发帖子: 495
积分: 467

Re: Linux 驱动开发 / fbdev 双缓存 / 快速入门 , 转

三、编写支持 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,不再撕裂。

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn