Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1152997
  • 博文数量: 222
  • 博客积分: 5262
  • 博客等级: 大校
  • 技术积分: 3028
  • 用 户 组: 普通用户
  • 注册时间: 2009-11-22 19:10
文章分类

全部博文(222)

文章存档

2012年(2)

2011年(192)

2010年(28)

分类: 嵌入式

2011-01-06 16:08:42

S3C6410的双Framebuffer于Android系统中存在的问题

在为S3C6410移植Android系统过程中,发现在拖动任务栏,软键盘输入信息等情况下,屏幕会出现闪烁现象,类似刷新率不足情况。一直认为 原因是自己porting的系统没有实现copybit等2D加速功能,导致填充速度不够快。昨天在调试双Framebuffer时发现,问题可能出在双 Framebuffer上的交换上。Android使用双Framebuffer机制,front显示,back填充,前后交互显得特别重要。打开三星驱 动debug宏,可以发现系统(Android 1.5)在EGL初始化后不断调用显示驱动以下几个函数,实现buffer交换:
s3cfb_check_var()
s3cfb_activate_var()
pan_display()
打 开debug的printk信息后,我发现一件很有意思的情况,原来所谓的闪烁现象,现在都不见了,至少基本看不出了。Printk会降低驱动调用速度, 会不会问题出在显示驱动?文章Patch Framebuffer Driver with Double-Buffering to Support Android's Page-Flipping中也提到双buffer驱动导致不断开关LCD。于是查到s3cfb_activate_var()函数,这个函数重写了 LCD的寄存器。应该是短时间重写该寄存器导致出现问题。临时的解决方法是在这个函数后添加mdelay(5)延时,但会导致效率降低,更好的解决方法应 该修改驱动或者Android中间层调用代码,这个需要跟踪下Android的UI相关代码,待续。

Android2.0/2.1系统中,S3C6410双Framebuffer显示问题的解决方法

前文Problems with S3C6410 double framebuffer in Android找到了Android系统处理三星S3C6410处理器的双Framebuffer驱动时出现的屏闪问题。这两天分析了三星原厂提供的cupcake代码后,终于找到解决方法。

Android2.0之后,Google把和Framebuffer打交道的EGL显示部分也抽象为一个HAL模块——Gralloc

cupcake中用于swapbuffer也被移到了Gralloc下的Framebuffer.cpp文件中,具体函数变为fb_post:

static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
{
    if (private_handle_t::validate(buffer) < 0)
        return -EINVAL;

    fb_context_t* ctx = (fb_context_t*)dev;

    private_handle_t const* hnd = reinterpret_cast(buffer);
    private_module_t* m = reinterpret_cast(dev->common.module);
    
    if (m->currentBuffer) {
        m->base.unlock(&m->base, m->currentBuffer);
        m->currentBuffer = 0;
    }

    if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {

        m->base.lock(&m->base, buffer, 
                private_module_t::PRIV_USAGE_LOCKED_FOR_POST, 
                0, 0, m->info.xres, m->info.yres, NULL);

        const size_t offset = hnd->base - m->framebuffer->base;
        m->info.activate = FB_ACTIVATE_VBL;
        m->info.yoffset = offset / m->finfo.line_length;
        if (ioctl(m->framebuffer->fd, FBIOPUT_VSCREENINFO, &m->info) == -1) {
            LOGE("FBIOPUT_VSCREENINFO failed");
            m->base.unlock(&m->base, buffer); 
            return -errno;
        }
        m->currentBuffer = buffer;
        
    } else {
        // If we can't do the page_flip, just copy the buffer to the front 
        // FIXME: use copybit HAL instead of memcpy
        
        void* fb_vaddr;
        void* buffer_vaddr;
        
        m->base.lock(&m->base, m->framebuffer, 
                GRALLOC_USAGE_SW_WRITE_RARELY, 
                0, 0, m->info.xres, m->info.yres,
                &fb_vaddr);

        m->base.lock(&m->base, buffer, 
                GRALLOC_USAGE_SW_READ_RARELY, 
                0, 0, m->info.xres, m->info.yres,
                &buffer_vaddr);

        memcpy(fb_vaddr, buffer_vaddr, m->finfo.line_length * m->info.yres);
        
        m->base.unlock(&m->base, buffer); 
        m->base.unlock(&m->base, m->framebuffer); 
    }
    
    return 0;
}

=======================================================================

函数名称变了,应该是实现方法有所改变,不是直接贴swap,而是采用时间间隔来post。

但最底层的处理方法不会变,还是用FBIOPUT_VSCREENINFO。

同样,用PAN_DISPLAY修改即可。

if (ioctl(m->framebuffer->fd, FBIOPAN_DISPLAY, &m->info) < 0)
{
   LOGE("%s::FBIOPAN_DISPLAY fail(%s)", __func__, strerror(errno)); 
   return 0; 
}

unsigned int crtc = 0;

if(ioctl(m->framebuffer->fd, FBIO_WAITFORVSYNC, &crtc) < 0) {
//s3cfb_wait_for_vsync->wait_event_interruptible_timeout
   LOGE("%s::FBIO_WAITFORVSYNC fail(%s)", __func__, strerror(errno)); 
   return 0; 
}


/*   if (ioctl(m->framebuffer->fd, FBIOPUT_VSCREENINFO, &m->info) == -1) 
{
            LOGE("FBIOPUT_VSCREENINFO failed");
            m->base.unlock(&m->base, buffer); 
            return -errno;
        }
*/

========================================================================

至此,困扰我好几个月的显示和2D加速问题终于解决。

目前得出的结论为Android系统中2D加速引擎copybit对UI的加速作用并不明显。

Rockie Cheng

阅读(1083) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~