Android6.0 显示系统(四) 图像显示相关

Linux通常使用Framebuffer来用作显示输出,Framebuffer就是一块内存区域,它通常是显示驱动的内部缓冲区在内存中的映射。一旦用户进程把图像数据复制到Framebuffer中,显示驱动会一个像素一个像素地扫描整个Framebuffer,并根据其中的值更新屏幕上像素点的颜色。驱动中这种更新屏幕的动作是固定的,它的周期就是我们常说的刷新率。

    但是在屏幕更新一半时,用户进程更新了Framebuffer中的数据,将导致屏幕上画面的上半部分是前一帧的画面,下半部分变成了新的画面。当然错误会在下次刷新时纠正过来,但是这样也会有闪烁的感觉。这个可以使用双缓冲机制,双缓冲就是提供两块Framebuffer,一块用于显示,一块用于数据更新。数据准备好后,通过ioctl操作告诉显示设备切换用于显示的FrameBuffer,这样图像就能快速的显示出来。

    但是双缓冲并没有完全解决问题,虽然双缓冲切换的速度很快,但是如果切换的时间点不对,在画面更新一半的时候切换,还是会出现闪烁的问题。当然,我们可以在底层进行控制,收到切换请求的时候,内部并不马上执行,等到刷新完成后再切换,这样完全避免了画面重叠问题。但是这样也有问题,如果用ioctl操作告诉底层可以进行切换了,但是缓冲区没有切换,这样应用层就不能确定何时可以再使用缓冲区,因此只能不断的通过ioctl来查询缓冲区的状态,一直到切换完成了。这种方式效率太低,拖慢了整个系统。解决这个问题就是底层固定发送信号给用户进程,通知进程切换的时机。这个信号就是VSync信号。

VSync信号是一个硬件信号,一般是显示设备刷新的周期到了会发送。


一、VSync信号的产生

Android通过VSync机制来提高显示效果,那么VSync是如何产生的?通常这个信号是由显示驱动产生,这样才能达到最佳效果。但是Android为了能运行在不支持VSync机制的设备上,也提供了软件模拟产生VSync信号的手段。

SurfaceFlinger中用HWComposer类来表示硬件显示设备,

  1. HWComposer::HWComposer(  
  2.         const sp<SurfaceFlinger>& flinger,  
  3.         EventHandler& handler)  
  4.     : mFlinger(flinger),  
  5.       mFbDev(0), mHwc(0), mNumDisplays(1),  
  6.       mCBContext(new cb_context),  
  7.       mEventHandler(handler),  
  8.       mDebugForceFakeVSync(false)  
  9. {  
  10.     ......  
  11.     bool needVSyncThread = true;  
  12.   
  13.     // Note: some devices may insist that the FB HAL be opened before HWC.  
  14.     int fberr = loadFbHalModule();//装载FrameBuffer的硬件模块  
  15.     loadHwcModule();//装载HWComposer的硬件模块,这个函数中会将mHwc置为true  
  16.   
  17.     ......  
  18.     if (mHwc) {//这个为true代表硬件设备打开了  
  19.         ALOGI("Using %s version %u.%u", HWC_HARDWARE_COMPOSER,  
  20.               (hwcApiVersion(mHwc) >> 24) & 0xff,  
  21.               (hwcApiVersion(mHwc) >> 16) & 0xff);  
  22.         if (mHwc->registerProcs) {  
  23.             mCBContext->hwc = this;  
  24.             mCBContext->procs.invalidate = &hook_invalidate;  
  25.             mCBContext->procs.vsync = &hook_vsync;//vsync回调函数  
  26.             if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))  
  27.                 mCBContext->procs.hotplug = &hook_hotplug;  
  28.             else  
  29.                 mCBContext->procs.hotplug = NULL;  
  30.             memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero));  
  31.             mHwc->registerProcs(mHwc, &mCBContext->procs);  
  32.         }  
  33.   
  34.         // don't need a vsync thread if we have a hardware composer  
  35.         needVSyncThread = false;//打开硬件设备成功了,将needVSncThread为false  
  36.         ......  
  37.     }  
  38.     ......  
  39.   
  40.     if (needVSyncThread) {  
  41.         // we don't have VSYNC support, we need to fake it  
  42.         mVSyncThread = new VSyncThread(*this);  
  43.     }  
  44. }  

通过loadHwcModule来装载硬件模块,如果成功,mHwc为true,needVSyncThread为false。如果不成功,needVsyncThread为true,然后就要创建VSyncThread对象了,它就是产生VSync信号的软件手段了。

VSyncThread是一个thread,在onFirstRef中会调用run函数,就是执行threadLoop,这个函数只要返回true就会一直执行。

  1. bool HWComposer::VSyncThread::threadLoop() {  
  2.     { // scope for lock  
  3.         Mutex::Autolock _l(mLock);  
  4.         while (!mEnabled) {  
  5.             mCondition.wait(mLock);  
  6.         }  
  7.     }  
  8.   
  9.     const nsecs_t period = mRefreshPeriod;  
  10.     const nsecs_t now = systemTime(CLOCK_MONOTONIC);  
  11.     nsecs_t next_vsync = mNextFakeVSync;  
  12.     nsecs_t sleep = next_vsync - now;  
  13.     if (sleep < 0) {  
  14.         // we missed, find where the next vsync should be  
  15.         sleep = (period - ((now - next_vsync) % period));  
  16.         next_vsync = now + sleep;  
  17.     }  
  18.     mNextFakeVSync = next_vsync + period;  
  19.   
  20.     struct timespec spec;  
  21.     spec.tv_sec  = next_vsync / 1000000000;  
  22.     spec.tv_nsec = next_vsync % 1000000000;  
  23.   
  24.     int err;  
  25.     do {  
  26.         err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL);  
  27.     } while (err<0 && errno == EINTR);  
  28.   
  29.     if (err == 0) {  
  30.         mHwc.mEventHandler.onVSyncReceived(0, next_vsync);  
  31.     }  
  32.   
  33.     return true;  
  34. }  

这个函数会间隔模拟产生VSync的信号的原理是在固定时间发送消息给HWCompoer的消息对象mEventHandler,这个其实就到SurfaceFlinger的onVSyncReceived函数了。用软件模拟VSync信号在系统比较忙的时候可能会丢失一些信号。

Android源码再hardware/lib/libhardware/modules下有一个hwcomposer目录,里面是一个Android提供的缺省的硬件HWComposer模块的例子,这个例子只实现了一个open接口,并不能真正工作。在前面HWComposer的构造函数中,有如下代码

  1. mCBContext->procs.vsync = &hook_vsync;  

这里指定了vsync的回调函数是hook_vsync,如果硬件中产生了VSync信号,将通过这个函数来通知上层,看看它的代码:

  1. void HWComposer::hook_vsync(const struct hwc_procs* procs, int disp,  
  2.         int64_t timestamp) {  
  3.     cb_context* ctx = reinterpret_cast<cb_context*>(  
  4.             const_cast<hwc_procs_t*>(procs));  
  5.     ctx->hwc->vsync(disp, timestamp);  
  6. }  

然后又调用了vsync函数,这个函数最后也是调用了mEventHandler.onVSyncReceived函数,这个函数最后回到SurfaceFlinger中的onVsyncReceived函数中。

  1. void HWComposer::vsync(int disp, int64_t timestamp) {  
  2.     if (uint32_t(disp) < HWC_NUM_PHYSICAL_DISPLAY_TYPES) {  
  3.         {  
  4.             Mutex::Autolock _l(mLock);  
  5.   
  6.             // There have been reports of HWCs that signal several vsync events  
  7.             // with the same timestamp when turning the display off and on. This  
  8.             // is a bug in the HWC implementation, but filter the extra events  
  9.             // out here so they don't cause havoc downstream.  
  10.             if (timestamp == mLastHwVSync[disp]) {  
  11.                 ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")",  
  12.                         timestamp);  
  13.                 return;  
  14.             }  
  15.   
  16.             mLastHwVSync[disp] = timestamp;  
  17.         }  
  18.   
  19.         char tag[16];  
  20.         snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp);  
  21.         ATRACE_INT(tag, ++mVSyncCounts[disp] & 1);  
  22.   
  23.         mEventHandler.onVSyncReceived(disp, timestamp);  
  24.     }  
  25. }  


二、FrameBuffer工作原理

我们先来看下loadFbHalModule函数,hw_get_module是HAl框架中装载HAL模块的函数

  1. int HWComposer::loadFbHalModule()  
  2. {  
  3.     hw_module_t const* module;  
  4.   
  5.     int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);  
  6.     if (err != 0) {  
  7.         ALOGE("%s module not found", GRALLOC_HARDWARE_MODULE_ID);  
  8.         return err;  
  9.     }  
  10.   
  11.     return framebuffer_open(module, &mFbDev);  
  12. }  

我们再来看看framebuffer_open函数,

  1. static inline int framebuffer_open(const struct hw_module_t* module,  
  2.         struct framebuffer_device_t** device) {  
  3.     return module->methods->open(module,  
  4.             GRALLOC_HARDWARE_FB0, (struct hw_device_t**)device);  
  5. }  

GRALLOC_HARDWARE_FB0 就是fb0

  1. #define GRALLOC_HARDWARE_FB0 "fb0"  

Gralloc模块在实际设备中有硬件厂商提供。我们来看下这个open函数

  1. static int gralloc_device_open(const hw_module_t* module, const char* name, hw_device_t** device)  
  2. {  
  3.     int status = -EINVAL;  
  4.   
  5.     if (!strncmp(name, GRALLOC_HARDWARE_GPU0, MALI_GRALLOC_HARDWARE_MAX_STR_LEN))  
  6.     {  
  7.         status = alloc_device_open(module, name, device);//处理gpu的  
  8.     }  
  9.     else if (!strncmp(name, GRALLOC_HARDWARE_FB0, MALI_GRALLOC_HARDWARE_MAX_STR_LEN))  
  10.     {  
  11.         status = framebuffer_device_open(module, name, device);  
  12.     }  
  13.   
  14.     return status;  
  15. }  

我们来看framebuffer_device_open函数,如果不支持framebuffer直接退出了(现在很多设备都开始不支持了)。如果支持framebuffer的话先是调用了init_frame_buffer函数来获取设备信息,通过mmap分配一块共享内存,然后设置FrameBuffer的操作函数等。

  1. int framebuffer_device_open(hw_module_t const* module, const char* name, hw_device_t** device)  
  2. {  
  3.     int status = -EINVAL;  
  4.   
  5.     log_fbpost = false;  
  6.     char property[PROPERTY_VALUE_MAX];  
  7.     if(property_get("debug.gralloc.fbpost", property, "0") > 0) {  
  8.         if(atoi(property) == 1) {  
  9.             log_fbpost = true;  
  10.             ALOGI("enable fbpost log!");  
  11.         }  
  12.     }  
  13.   
  14.     alloc_device_t* gralloc_device;  
  15. #if DISABLE_FRAMEBUFFER_HAL == 1 //不支持FrameBuffer  
  16.     AERR("Framebuffer HAL not support/disabled %s",  
  17. #ifdef MALI_DISPLAY_VERSION  
  18.     "with MALI display enable");  
  19. #else  
  20.     "");  
  21. #endif  
  22.     return -ENODEV;  
  23. #endif  
  24.     status = gralloc_open(module, &gralloc_device);  
  25.     if (status < 0)  
  26.     {  
  27.         return status;  
  28.     }  
  29.   
  30.     private_module_t* m = (private_module_t*)module;  
  31.     status = init_frame_buffer(m);  
  32.   
  33.     framebuffer_device_t *dev =  reinterpret_cast<framebuffer_device_t*> (malloc(sizeof(framebuffer_device_t)));  
  34.   
  35.     /* if either or both of init_frame_buffer() and malloc failed */  
  36.     if ((status < 0) || (!dev))  
  37.     {  
  38.         gralloc_close(gralloc_device);  
  39.         (!dev) ? (void)(status = -ENOMEM) : free(dev);  
  40.         return status;  
  41.     }  
  42.   
  43.     memset(dev, 0, sizeof(*dev));  
  44.   
  45.     //设置framebuffer的操作函数  
  46.     dev->common.tag = HARDWARE_DEVICE_TAG;  
  47.     dev->common.version = 0;  
  48.     dev->common.module = const_cast<hw_module_t*>(module);  
  49.     dev->common.close = fb_close;  
  50.     dev->setSwapInterval = fb_set_swap_interval;  
  51.     dev->post = fb_post;  
  52.     dev->enableScreen = fb_enable_screen;  
  53.     dev->setUpdateRect = 0;  
  54.     dev->compositionComplete = &compositionComplete;  
  55.   
  56.     int stride = m->finfo.line_length / (m->info.bits_per_pixel >> 3);  
  57.     const_cast<uint32_t&>(dev->flags) = 0;  
  58.     const_cast<uint32_t&>(dev->width) = m->info.xres;  
  59.     const_cast<uint32_t&>(dev->height) = m->info.yres;  
  60.     const_cast<int&>(dev->stride) = stride;  
  61.     const_cast<int&>(dev->format) = m->fbFormat;  
  62.     const_cast<float&>(dev->xdpi) = m->xdpi;  
  63.     const_cast<float&>(dev->ydpi) = m->ydpi;  
  64.     const_cast<float&>(dev->fps) = m->fps;  
  65.     const_cast<int&>(dev->minSwapInterval) = 0;  
  66.     const_cast<int&>(dev->maxSwapInterval) = 1;  
  67.     const_cast<int&>(dev->numFramebuffers) = m->numBuffers;  
  68.     *device = &dev->common;  
  69.   
  70.     AINF("%s line %d format %d numBuffers %d",__FUNCTION__,__LINE__, dev->format, m->numBuffers);  
  71.   
  72.     //init dynamic lcd fps adjustment  
  73.     dyn_fps_init(m);  
  74. #if GRALLOC_VSYNC_NEEDED == 1  
  75.     gralloc_vsync_enable(dev);//支持vsync  
  76. #endif  
  77.   
  78.     gralloc_close(gralloc_device);  
  79.   
  80.     return status;  
  81. }  

init_frame_buffer函数主要调用了init_frame_buffer_locked函数

  1. static int init_frame_buffer(struct private_module_t* module)  
  2. {  
  3.     pthread_mutex_lock(&module->lock);  
  4.     int err = init_frame_buffer_locked(module);  
  5.     pthread_mutex_unlock(&module->lock);  
  6.     return err;  
  7. }  

我们来看看init_frame_buffer_locked函数,先打开设备列表中的一个设备即可,然后通过ioctl获取设备信息,把设备信息放到module中,后面通过mmap分配一块共享内存。

  1. int init_frame_buffer_locked(struct private_module_t* module)  
  2. {  
  3.     if (module->framebuffer)  
  4.     {  
  5.         return 0; // Nothing to do, already initialized  
  6.     }  
  7.   
  8.     char const * const device_template[] =//设备列表  
  9.     {  
  10.         "/dev/graphics/fb%u",  
  11.         "/dev/fb%u",  
  12.         NULL  
  13.     };  
  14.   
  15.     int fd = -1;  
  16.     int i = 0;  
  17.     char name[64];  
  18.   
  19.     while ((fd == -1) && device_template[i])//只要打开一个设备就好了  
  20.     {  
  21.         snprintf(name, 64, device_template[i], 0);  
  22.         fd = open(name, O_RDWR, 0);  
  23.         i++;  
  24.     }  
  25.   
  26.     if (fd < 0)  
  27.     {  
  28.         return -errno;  
  29.     }  
  30.   
  31.     struct fb_fix_screeninfo finfo;  
  32.     if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)  
  33.     {  
  34.         return -errno;  
  35.     }  
  36.   
  37.     struct fb_var_screeninfo info;  
  38.     if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)  
  39.     {  
  40.         return -errno;  
  41.     }  
  42.   
  43.     info.reserved[0] = 0;  
  44.     info.reserved[1] = 0;  
  45.     info.reserved[2] = 0;  
  46.     info.xoffset = 0;  
  47.     info.yoffset = 0;  
  48.     info.activate = FB_ACTIVATE_NOW;  
  49.   
  50.     if(info.bits_per_pixel == 32)  
  51.     {  
  52.         /* 
  53.          * Explicitly request 8/8/8 
  54.          */  
  55.         info.bits_per_pixel = 32;  
  56.         info.red.offset     = 16;  
  57.         info.red.length     = 8;  
  58.         info.green.offset   = 8;  
  59.         info.green.length   = 8;  
  60.         info.blue.offset    = 0;  
  61.         info.blue.length    = 8;  
  62.         info.transp.offset  = 24;  
  63.         info.transp.length  = 8;  
  64.     }  
  65.     else  
  66.     {  
  67.         /* 
  68.          * Explicitly request 5/6/5 
  69.          */  
  70.         info.bits_per_pixel = 16;  
  71.         info.red.offset     = 11;  
  72.         info.red.length     = 5;  
  73.         info.green.offset   = 5;  
  74.         info.green.length   = 6;  
  75.         info.blue.offset    = 0;  
  76.         info.blue.length    = 5;  
  77.         info.transp.offset  = 0;  
  78.         info.transp.length  = 0;  
  79.     }  
  80.   
  81.     /* 
  82.      * Request NUM_BUFFERS screens (at lest 2 for page flipping) 
  83.      */  
  84.     info.yres_virtual = info.yres * NUM_BUFFERS;  
  85.   
  86.     uint32_t flags = PAGE_FLIP;  
  87.     if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1)  
  88.     {  
  89.         info.yres_virtual = info.yres;  
  90.         flags &= ~PAGE_FLIP;  
  91.         AWAR( "FBIOPUT_VSCREENINFO failed, page flipping not supported fd: %d", fd );  
  92.     }  
  93.   
  94.     if (info.yres_virtual < info.yres * 2)  
  95.     {  
  96.         // we need at least 2 for page-flipping  
  97.         info.yres_virtual = info.yres;  
  98.         flags &= ~PAGE_FLIP;  
  99.         AWAR( "page flipping not supported (yres_virtual=%d, requested=%d)", info.yres_virtual, info.yres*2 );  
  100.     }  
  101.   
  102.     if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)  
  103.     {  
  104.         return -errno;  
  105.     }  
  106.   
  107.     int refreshRate = 0;  
  108.     if ( info.pixclock > 0 )  
  109.     {  
  110.         refreshRate = 1000000000000000LLU /  
  111.         (  
  112.             uint64_t( info.upper_margin + info.lower_margin + info.yres + info.hsync_len )  
  113.             * ( info.left_margin  + info.right_margin + info.xres + info.vsync_len )  
  114.             * info.pixclock  
  115.         );  
  116.     }  
  117.     else  
  118.     {  
  119.         AWAR( "fbdev pixclock is zero for fd: %d", fd );  
  120.     }  
  121.   
  122.     if (refreshRate == 0)  
  123.     {  
  124.         refreshRate = 60*1000;  // 60 Hz  
  125.     }  
  126.   
  127.     if (int(info.width) <= 0 || int(info.height) <= 0)  
  128.     {  
  129.         // the driver doesn't return that information  
  130.         // default to 320 dpi  
  131.         // debugging stuff...  
  132.         char value[PROPERTY_VALUE_MAX];  
  133.         int lcd_density;  
  134.   
  135.         property_get("ro.sf.lcd_density", value, "320");  
  136.         lcd_density = atoi(value);  
  137.   
  138.         info.width  = ((info.xres * 25.4f) / (float)lcd_density + 0.5f);  
  139.         info.height = ((info.yres * 25.4f) / (float)lcd_density + 0.5f);  
  140.     }  
  141.   
  142.     float xdpi = (info.xres * 25.4f) / info.width;  
  143.     float ydpi = (info.yres * 25.4f) / info.height;  
  144.     float fps  = refreshRate / 1000.0f;  
  145.   
  146.     AINF("leadcore fb using (fd=%d)\n"  
  147.          "id           = %s\n"  
  148.          "xres         = %d px\n"  
  149.          "yres         = %d px\n"  
  150.          "xres_virtual = %d px\n"  
  151.          "yres_virtual = %d px\n"  
  152.          "bpp          = %d\n"  
  153.          "r            = %2u:%u\n"  
  154.          "g            = %2u:%u\n"  
  155.          "b            = %2u:%u\n",  
  156.          fd,  
  157.          finfo.id,  
  158.          info.xres,  
  159.          info.yres,  
  160.          info.xres_virtual,  
  161.          info.yres_virtual,  
  162.          info.bits_per_pixel,  
  163.          info.red.offset, info.red.length,  
  164.          info.green.offset, info.green.length,  
  165.          info.blue.offset, info.blue.length);  
  166.   
  167.     AINF("width        = %d mm (%f dpi)\n"  
  168.          "height       = %d mm (%f dpi)\n"  
  169.          "refresh rate = %.2f Hz\n",  
  170.          info.width,  xdpi,  
  171.          info.height, ydpi,  
  172.          fps);  
  173.   
  174.     if (0 == strncmp(finfo.id, "CLCD FB", 7))  
  175.     {  
  176.         module->dpy_type = MALI_DPY_TYPE_CLCD;  
  177.     }  
  178.     else if (0 == strncmp(finfo.id, "ARM Mali HDLCD", 14))  
  179.     {  
  180.         module->dpy_type = MALI_DPY_TYPE_HDLCD;  
  181.     }  
  182.     else  
  183.     {  
  184.         module->dpy_type = MALI_DPY_TYPE_UNKNOWN;  
  185.     }  
  186.   
  187.     if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)  
  188.     {  
  189.         return -errno;  
  190.     }  
  191.   
  192.     if (finfo.smem_len <= 0)  
  193.     {  
  194.         return -errno;  
  195.     }  
  196.   
  197.     if( info.bits_per_pixel == 32 &&  
  198.             info.red.offset == 16 &&  
  199.             info.red.length == 8 &&  
  200.             info.green.offset == 8 &&  
  201.             info.green.length == 8 &&  
  202.             info.blue.offset == 0 &&  
  203.             info.blue.length == 8)  
  204.     {  
  205.         module->fbFormat = HAL_PIXEL_FORMAT_BGRA_8888;  
  206.     }  
  207.   
  208.     if( info.bits_per_pixel == 32 &&  
  209.             info.red.offset == 0 &&  
  210.             info.red.length == 8 &&  
  211.             info.green.offset == 8 &&  
  212.             info.green.length == 8 &&  
  213.             info.blue.offset == 16 &&  
  214.             info.blue.length == 8)  
  215.     {  
  216.         module->fbFormat = HAL_PIXEL_FORMAT_RGBA_8888;  
  217.     }  
  218.   
  219.     if( info.bits_per_pixel == 16 &&  
  220.             info.red.offset == 0 &&  
  221.             info.red.length == 5 &&  
  222.             info.green.offset == 5 &&  
  223.             info.green.length == 6 &&  
  224.             info.blue.offset == 11 &&  
  225.             info.blue.length == 5)  
  226.     {  
  227.         module->fbFormat = HAL_PIXEL_FORMAT_RGB_565;  
  228.     }  
  229.   
  230.     module->flags = flags;//设置信息  
  231.     module->info = info;  
  232.     module->finfo = finfo;  
  233.     module->xdpi = xdpi;  
  234.     module->ydpi = ydpi;  
  235.     module->fps = fps;  
  236.     module->swapInterval = 1;  
  237.   
  238.     /* 
  239.      * map the framebuffer 
  240.      */  
  241.     size_t fbSize = round_up_to_page_size(finfo.line_length * info.yres_virtual);  
  242.     void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);//mmap分配一块共享内存  
  243.     if (vaddr == MAP_FAILED)  
  244.     {  
  245.         AERR( "Error mapping the framebuffer (%s)", strerror(errno) );  
  246.         return -errno;  
  247.     }  
  248.   
  249.     //fix black screen between uboot logo and bootanimation  
  250.     //memset(vaddr, 0, fbSize);  
  251.   
  252.   
  253.     // Create a "fake" buffer object for the entire frame buffer memory, and store it in the module  
  254.     module->framebuffer = new private_handle_t(private_handle_t::PRIV_FLAGS_FRAMEBUFFER, GRALLOC_USAGE_HW_FB, fbSize, vaddr,  
  255.                                                0, dup(fd), 0, 0);  
  256.   
  257.     module->numBuffers = info.yres_virtual / info.yres;  
  258.     module->bufferMask = 0;  
  259.   
  260.     return 0;  
  261. }  

最后我们再来看看framebuffer的操作函数fb_post,这个函数根据PRIV_FLAGS_FRAMEBUFFER来判断Framebuffer是否支持多缓冲,如果不支持方法很简单,直接把buffer中的数据复制到Framebuffer中就可以了。

Filp是指使用ioctl的FBIOPUT_VSCREENINFO参数设置当前显示的buffer。通过将显示区域指向Framebuffer中的新的数据帧,能非常迅速地完成buffer的切换。单缓冲模式下数据复制到缓冲区还需要一定时间,会加重闪烁感,通过Filp的方式切换缓冲区就不存在这个问题了。

  1. static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)  
  2. {  
  3.     if (private_handle_t::validate(buffer) < 0)  
  4.     {  
  5.         return -EINVAL;  
  6.     }  
  7.   
  8.     private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(buffer);  
  9.     private_module_t* m = reinterpret_cast<private_module_t*>(dev->common.module);  
  10.   
  11.     if (m->currentBuffer)  
  12.     {  
  13.         m->base.unlock(&m->base, m->currentBuffer);  
  14.         m->currentBuffer = 0;  
  15.     }  
  16.   
  17.     struct timeval tv1, tv2;  
  18.   
  19.     if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) //framebuffer是否支持多缓冲区(flip)  
  20.     {  
  21.         m->base.lock(&m->base, buffer, private_module_t::PRIV_USAGE_LOCKED_FOR_POST,   
  22.                 0, 0, m->info.xres, m->info.yres, NULL);  
  23.   
  24.         const size_t offset = (uintptr_t)hnd->base - (uintptr_t)m->framebuffer->base;  
  25.         int interrupt;  
  26.         m->info.activate = FB_ACTIVATE_VBL;  
  27.         m->info.yoffset = offset / m->finfo.line_length;  
  28.   
  29.         up_fps(m);  
  30.   
  31.   
  32.         gettimeofday(&tv1, NULL);  
  33.         if (ioctl(m->framebuffer->fd, FBIOPUT_VSCREENINFO, &m->info) == -1)  
  34.         {  
  35.             AERR( "FBIOPUT_VSCREENINFO failed for fd: %d", m->framebuffer->fd );  
  36.             m->base.unlock(&m->base, buffer);  
  37.             return -errno;  
  38.         }  
  39. #if GRALLOC_VSYNC_NEEDED  
  40.         if ( 0 != gralloc_wait_for_vsync(dev) )  
  41.         {  
  42.             AERR( "Gralloc wait for vsync failed for fd: %d", m->framebuffer->fd );  
  43.             m->base.unlock(&m->base, buffer);  
  44.             return -errno;  
  45.         }  
  46. #endif  
  47.         gettimeofday(&tv2, NULL);  
  48.   
  49.         if((int64_t)tv2.tv_sec * 1000 + tv2.tv_usec/1000 - (int64_t)tv1.tv_sec * 1000 - tv1.tv_usec/1000 > 50)  
  50.         {  
  51.             ALOGI("%s line %d FBIOPUT_VSCREENINFO buffer %p blocktime=%lldms now=%lldms lasttime=%lld tid=%d",__FUNCTION__,__LINE__,  
  52.                     buffer,  
  53.                     (int64_t)tv2.tv_sec * 1000 + tv2.tv_usec/1000 - (int64_t)tv1.tv_sec * 1000 - tv1.tv_usec/1000,  
  54.                     systemTime(CLOCK_MONOTONIC)/1000000,  
  55.                     (int64_t)tv2.tv_sec * 1000 + tv2.tv_usec/1000 - lasttime,  
  56.                     gettid());  
  57.         } else {  
  58.             ALOGD_IF(log_fbpost, "%s line %d FBIOPUT_VSCREENINFO buffer %p blocktime=%lldms now=%lldms lasttime=%lld tid=%d",__FUNCTION__,__LINE__,  
  59.                     buffer,  
  60.                     (int64_t)tv2.tv_sec * 1000 + tv2.tv_usec/1000 - (int64_t)tv1.tv_sec * 1000 - tv1.tv_usec/1000,  
  61.                     systemTime(CLOCK_MONOTONIC)/1000000,  
  62.                     (int64_t)tv2.tv_sec * 1000 + tv2.tv_usec/1000 - lasttime,  
  63.                     gettid());  
  64.         }  
  65.   
  66.         lasttime = (int64_t)tv2.tv_sec * 1000 + tv2.tv_usec/1000;  
  67.   
  68.         postcount++;  
  69.         if(postcount == 1000)  
  70.         {  
  71.             ALOGI("%s line %d avgframerate = %2f",__FUNCTION__,__LINE__,  
  72.             (float)postcount*1000.0/(lasttime - timecount));  
  73.             postcount = 0;  
  74.             timecount = lasttime;  
  75.         }  
  76.   
  77.         m->currentBuffer = buffer;  
  78.     } else {//不支持多缓冲(flip)  
  79.         void* fb_vaddr;  
  80.         void* buffer_vaddr;  
  81.   
  82.         m->base.lock(&m->base, m->framebuffer, GRALLOC_USAGE_SW_WRITE_RARELY,  
  83.                 0, 0, m->info.xres, m->info.yres, &fb_vaddr);  
  84.   
  85.         m->base.lock(&m->base, buffer, GRALLOC_USAGE_SW_READ_RARELY,  
  86.                 0, 0, m->info.xres, m->info.yres, &buffer_vaddr);  
  87.   
  88.         // If buffer's alignment match framebuffer alignment we can do a direct copy.  
  89.         // If not we must fallback to do an aligned copy of each line.  
  90.         if ( hnd->byte_stride == (int)m->finfo.line_length )  
  91.         {  
  92.             memcpy(fb_vaddr, buffer_vaddr, m->finfo.line_length * m->info.yres);  
  93.         }  
  94.         else  
  95.         {  
  96.             uintptr_t fb_offset = 0;  
  97.             uintptr_t buffer_offset = 0;  
  98.             unsigned int i;  
  99.   
  100.             for (i = 0; i < m->info.yres; i++)  
  101.             {  
  102.                 memcpy((void *)((uintptr_t)fb_vaddr + fb_offset),  
  103.                        (void *)((uintptr_t)buffer_vaddr + buffer_offset),  
  104.                        m->finfo.line_length);  
  105.   
  106.                 fb_offset += m->finfo.line_length;  
  107.                 buffer_offset += hnd->byte_stride;  
  108.             }  
  109.         }  
  110.         m->base.unlock(&m->base, buffer);  
  111.         m->base.unlock(&m->base, m->framebuffer);  
  112.     }  
  113.   
  114.     return 0;  
  115. }  


三、分配图像缓冲区的内存

之前的博客在GraphicBufferAllocator的alloc方法是调用了mAllocDev的alloc,而这个mAllocDev也是Gralloc模块,最后会调用如下方法。

  1. int gralloc_alloc(struct alloc_device_t* dev,  
  2.         int w, int h, int format, int usage,  
  3.         buffer_handle_t* pHandle, int* pStride)  
  4. {  
  5.     int rel;  
  6.   
  7.     /* TODO: Redirect to specific allocator according to usage. */  
  8.     if (usage & GRALLOC_USAGE_HW_FB) {  
  9.         /* Dispatch to framebuffer allocator. */  
  10.         rel = gralloc_alloc_framebuffer(dev,  
  11.                 w, h, format, usage, pHandle, pStride);  
  12.     } else {  
  13.         rel = gc_gralloc_alloc(dev, w, h, format, usage, pHandle, pStride);  
  14.     }  
  15.   
  16.     return rel;  
  17. }  

gralloc_alloc函数会根据usage中的标志是否有GRALLOC_USAGE_HW_FB来决定是从硬件缓冲中分配缓冲区还是从普通内存分配缓冲区。我们先看看从内存中分配缓冲区的。

如果不支持framebuffer,只能从普通内存中分配缓冲区。gc_gralloc_alloc函数是从普通内存中分配缓冲区,主要使用了匿名共享内存的方法。最后pHandle装了共享内存的fd。

另外从硬件缓冲区分配内存是调用了gralloc_alloc_framebuffer方法,这个函数主要调用了gralloc_alloc_framebuffer_locked方法

  1. static int gralloc_alloc_framebuffer_locked(alloc_device_t* dev, size_t size, int usage, buffer_handle_t* pHandle, int* stride, int* byte_stride)  
  2. {  
  3.     private_module_t* m = reinterpret_cast<private_module_t*>(dev->common.module);  
  4.   
  5.     // allocate the framebuffer  
  6.     if (m->framebuffer == NULL)//如果为空  
  7.     {  
  8.         // initialize the framebuffer, the framebuffer is mapped once and forever.  
  9.         int err = init_frame_buffer_locked(m);//分配一大块内存  
  10.         if (err < 0)  
  11.         {  
  12.             return err;  
  13.         }  
  14.     }  
  15.   
  16.     const uint32_t bufferMask = m->bufferMask;  
  17.     const uint32_t numBuffers = m->numBuffers;  
  18.     /* framebufferSize is used for allocating the handle to the framebuffer and refers 
  19.      *                 to the size of the actual framebuffer. 
  20.      * alignedFramebufferSize is used for allocating a possible internal buffer and 
  21.      *                        thus need to consider internal alignment requirements. */  
  22.     const size_t framebufferSize = m->finfo.line_length * m->info.yres;  
  23.     const size_t alignedFramebufferSize = GRALLOC_ALIGN(m->finfo.line_length, 64) * m->info.yres;  
  24.   
  25.     *stride = m->info.xres;  
  26.   
  27.     if (numBuffers == 1)//如果是单缓冲,使用普通内存分配  
  28.     {  
  29.         // If we have only one buffer, we never use page-flipping. Instead,  
  30.         // we return a regular buffer which will be memcpy'ed to the main  
  31.         // screen when post is called.  
  32.         int newUsage = (usage & ~GRALLOC_USAGE_HW_FB) | GRALLOC_USAGE_HW_2D;  
  33.         AWAR( "fallback to single buffering. Virtual Y-res too small %d", m->info.yres );  
  34.         *byte_stride = GRALLOC_ALIGN(m->finfo.line_length, 64);  
  35.         return alloc_backend_alloc(dev, alignedFramebufferSize, newUsage, pHandle);  
  36.     }  
  37.   
  38.     if (bufferMask >= ((1LU<<numBuffers)-1))  
  39.     {  
  40.         // We ran out of buffers.  
  41.         return -ENOMEM;  
  42.     }  
  43.   
  44.     uintptr_t framebufferVaddr = (uintptr_t)m->framebuffer->base;  
  45.     // find a free slot  
  46.     for (uint32_t i=0 ; i<numBuffers ; i++)//找到一块空闲的快  
  47.     {  
  48.         if ((bufferMask & (1LU<<i)) == 0)  
  49.         {  
  50.             m->bufferMask |= (1LU<<i);  
  51.             break;  
  52.         }  
  53.         framebufferVaddr += framebufferSize;  
  54.     }  
  55.   
  56.     // The entire framebuffer memory is already mapped, now create a buffer object for parts of this memory  
  57.     private_handle_t* hnd = new private_handle_t(private_handle_t::PRIV_FLAGS_FRAMEBUFFER, usage, size,  
  58.             (void*)framebufferVaddr, 0, dup(m->framebuffer->fd),  
  59.             (framebufferVaddr - (uintptr_t)m->framebuffer->base), 0);  
  60.   
  61.     /* 
  62.      * Perform allocator specific actions. If these fail we fall back to a regular buffer 
  63.      * which will be memcpy'ed to the main screen when fb_post is called. 
  64.      */  
  65.     if (alloc_backend_alloc_framebuffer(m, hnd) == -1)  
  66.     {  
  67.         delete hnd;  
  68.         int newUsage = (usage & ~GRALLOC_USAGE_HW_FB) | GRALLOC_USAGE_HW_2D;  
  69.         AERR( "Fallback to single buffering. Unable to map framebuffer memory to handle:%p", hnd );  
  70.         *byte_stride = GRALLOC_ALIGN(m->finfo.line_length, 64);  
  71.         return alloc_backend_alloc(dev, alignedFramebufferSize, newUsage, pHandle);  
  72.     }  
  73.   
  74.     *pHandle = hnd;  
  75.     *byte_stride = m->finfo.line_length;  
  76.   
  77.     return 0;  
  78. }  
这个函数如果第一次调用会调用init_frame_buffer_locked来从Framebuffer设备上分配一大块共享内存,内存的大小是屏幕尺寸的整数倍。numBuffers是内存的块数,如果只有一块代表是单缓冲,单缓冲调用分配普通内存的函数(单内存只能分配普通内存也很好理解,因为framebuffer的内存要用于显示。重新分配的话只能就分配普通内存了)。多缓冲的话使用Framebuffer的内存。但是Framebuffer的缓冲区块数也是有限的,因此函数要找一块空闲的缓冲区。如果缓冲区分配完了,返回错误值-ENOMEM。











猜你喜欢

转载自blog.csdn.net/dkbdkbdkb/article/details/79640013