下载下来的linux_frame_buffer 跑在V3S tina
跑起来没有支持双缓,画面切换撕裂很难受呀,
可以支持FBIOPAN_DISPLAY的平台应该都可以相同的操作。
话不多说,上代码:
/**
* @file fbdev.c
*
*/
/*********************
* INCLUDES
*********************/
#include "fbdev.h"
#if USE_FBDEV || USE_BSD_FBDEV
#include <stdlib.h>
#include <unistd.h>
#include <stddef.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#if USE_BSD_FBDEV
#include <sys/fcntl.h>
#include <sys/time.h>
#include <sys/consio.h>
#include <sys/fbio.h>
#else /* USE_BSD_FBDEV */
#include <linux/fb.h>
#include <pthread.h>
#include <sys/epoll.h>
#endif /* USE_BSD_FBDEV */
/*********************
* DEFINES
*********************/
#ifndef FBDEV_PATH
#define FBDEV_PATH "/dev/fb0"
#endif
/**********************
* TYPEDEFS
**********************/
/**********************
* STRUCTURES
**********************/
struct bsd_fb_var_info{
uint32_t xoffset;
uint32_t yoffset;
uint32_t xres;
uint32_t yres;
int bits_per_pixel;
};
struct bsd_fb_fix_info{
long int line_length;
long int smem_len;
};
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
#if USE_BSD_FBDEV
static struct bsd_fb_var_info vinfo;
static struct bsd_fb_fix_info finfo;
#else
static struct fb_var_screeninfo vinfo;
static struct fb_fix_screeninfo finfo;
#endif /* USE_BSD_FBDEV */
static char *fbp = 0,*fbpbase = 0;
static long int screensize = 0;
static long int half_screensize = 0;
static int fbfd = 0;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void fbdev_init(void)
{
// Open the file for reading and writing
fbfd = open(FBDEV_PATH, O_RDWR);
if(fbfd == -1) {
perror("Error: cannot open framebuffer device");
return;
}
printf("The framebuffer device was opened successfully.\n");
#if USE_BSD_FBDEV
struct fbtype fb;
unsigned line_length;
//Get fb type
if (ioctl(fbfd, FBIOGTYPE, &fb) != 0) {
perror("ioctl(FBIOGTYPE)");
return;
}
//Get screen width
if (ioctl(fbfd, FBIO_GETLINEWIDTH, &line_length) != 0) {
perror("ioctl(FBIO_GETLINEWIDTH)");
return;
}
vinfo.xres = (unsigned) fb.fb_width;
vinfo.yres = (unsigned) fb.fb_height;
vinfo.bits_per_pixel = fb.fb_depth + 8;
vinfo.xoffset = 0;
vinfo.yoffset = 0;
finfo.line_length = line_length;
finfo.smem_len = finfo.line_length * vinfo.yres;
#else /* USE_BSD_FBDEV */
// Get fixed screen information
if(ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) {
perror("Error reading fixed information");
return;
}
// Get variable screen information
if(ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
perror("Error reading variable information");
return;
}
#endif /* USE_BSD_FBDEV */
printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);
// Figure out the size of the screen in bytes
screensize = finfo.smem_len; //finfo.line_length * vinfo.yres;
half_screensize = screensize/2;
// Map the device to memory
fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
fbpbase = fbp;
if((intptr_t)fbp == -1) {
perror("Error: failed to map framebuffer device to memory");
return;
}
memset(fbp, 0, screensize);
printf("The framebuffer device was mapped to memory successfully.\n");
}
void fbdev_exit(void)
{
close(fbfd);
}
char toggle = 0;
/**
* Flush a buffer to the marked area
* @param drv pointer to driver where this function belongs
* @param area an area where to copy `color_p`
* @param color_p an array of pixel to copy to the `area` part of the screen
*/
void fbdev_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p)
{
if(fbp == NULL ||
area->x2 < 0 ||
area->y2 < 0 ||
area->x1 > (int32_t)vinfo.xres - 1 ||
area->y1 > (int32_t)vinfo.yres - 1) {
lv_disp_flush_ready(drv);
return;
}
if(toggle == 0)
{
toggle = 1;
vinfo.yoffset = 0;
fbp =fbpbase;
}
else
{
toggle = 0;
vinfo.yoffset = vinfo.yres;
fbp = fbpbase + half_screensize;
}
/*Truncate the area to the screen*/
int32_t act_x1 = area->x1 < 0 ? 0 : area->x1;
int32_t act_y1 = area->y1 < 0 ? 0 : area->y1;
int32_t act_x2 = area->x2 > (int32_t)vinfo.xres - 1 ? (int32_t)vinfo.xres - 1 : area->x2;
int32_t act_y2 = area->y2 > (int32_t)vinfo.yres - 1 ? (int32_t)vinfo.yres - 1 : area->y2;
lv_coord_t w = (act_x2 - act_x1 + 1);
long int location = 0;
long int byte_location = 0;
unsigned char bit_location = 0;
/*32 or 24 bit per pixel*/
if(vinfo.bits_per_pixel == 32 || vinfo.bits_per_pixel == 24) {
uint32_t * fbp32 = (uint32_t *)fbp;
int32_t y;
for(y = act_y1; y <= act_y2; y++) {
location = (act_x1 ) + (y ) * finfo.line_length / 4;
memcpy(&fbp32[location], (uint32_t *)color_p, (act_x2 - act_x1 + 1) * 4);
color_p += w;
}
}
else {
/*Not supported bit per pixel*/
}
// memcpy(fbp,tmpbuf,640*480*4);
if (ioctl(fbfd, FBIOPAN_DISPLAY, &vinfo) < 0) {
fprintf(stderr, "active fb swap failed\n");
}
//May be some direct update command is required
//ret = ioctl(state->fd, FBIO_UPDATE, (unsigned long)((uintptr_t)rect));
lv_disp_flush_ready(drv);
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif
其实就是标准的linux下的ioctl双缓操作,
另外,这个操作要在初始化lvgl的时候加入双缓冲区。
static lv_color_t buf[DISP_BUF_SIZE],buf1[DISP_BUF_SIZE];
static lv_disp_buf_t disp_buf;
lv_disp_buf_init(&disp_buf, buf, buf1, DISP_BUF_SIZE);
这里的 DISP_BUF_SIZE 要和显存大小一致,我这里用了ARGB 8888。
编译操作一下,画面撕裂消失,起飞!
最近编辑记录 TeveT (2021-01-20 14:29:06)
离线
我这边用的是V3S tina,
手头还有个SSD202的开发板里边附带的LVGL例程也是有裂开的现象,后面有空再看看。
ubuntu上没用过,但是在v3s上是肯定有的
楼主用的是哪个平台呢?我用Ubuntu测试貌似没有出现撕裂的问题
离线
已在LVGL7 的linux_frame_buffer 测试过,一样给力!
离线
你的海思的内核支持了FBIOPAN_DISPLAY了吗,ioctl读取回来的缓存大小是你显示器的两倍吗
用你的方法在海思上 产生了段错误
离线
并不是哈, fb驱动原生是有2个缓冲区的,总的是屏幕缓冲区长度2倍,IOCTL读回来就是2倍的,finfo.smem_len 打印出来看下
TeveT 说:你的海思的内核支持了FBIOPAN_DISPLAY了吗,ioctl读取回来的缓存大小是你显示器的两倍吗
tango_zhu 说:用你的方法在海思上 产生了段错误
你这边的宽度需要设置成实际宽度的两倍吗
离线
哥哥你可以自己试一下
请教楼主,Ubuntu的Framebuffer可以用吗?
离线
不行哈,我这边搞了一波SSD202 ,测试了下,是要修改 /config/fbdev.ini 修改缓冲区到2倍的大小 4800x1024,然后重启一下。
详见 https://whycan.com/t_6006.html 第14、15楼
另外附上 SSD20X 跑LVGL 的 fbdev相关文件 和 Makefile
LVGL7.10-SSD20X-TEVET_MODIFY.zip
搭车请教一个问题,如果平台(SSD201)的framebuffer打印出来的len是4196304,而按一帧1024@600计算应该是2457600,两倍的关系应该是4915200,目前打印的finfo.smem_len比4915200,在这个情况下还能使用双缓冲吗? 谢谢
离线
一个是 ioctl 拿到的 FBIOGET_FSCREENINFO 的缓冲区大小
另外就是
查看驱动代码的ioctl, FBIOPAN_DISPLAY 是否有被处理,处理后是否调用了硬件显示资源。
谢谢大神,请问下怎么判断目标内核支持双缓存?
离线