Chinaunix首页 | 论坛 | 博客
  • 博客访问: 165715
  • 博文数量: 205
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 0
  • 用 户 组: 普通用户
  • 注册时间: 2016-07-21 21:11
文章分类

全部博文(205)

文章存档

2016年(2)

2015年(203)

我的朋友

分类: Android平台

2015-11-16 19:45:16

一. 打开gralloc
在frameworks/base/libs/ui/FramebufferNativeWindow.cpp中会调用
  1. FramebufferNativeWindow::FramebufferNativeWindow()
  2.     : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false)
  3. {
  4.     hw_module_t const* module;
  5.     hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module); //1.加载gralloc库
  6.     framebuffer_open(module, &fbDev);                   //2.打开fb设备
  7.     gralloc_open(module, &grDev);
  8. }
其中在./hardware/libhardware/include/hardware/gralloc.h中定义了
#define GRALLOC_HARDWARE_MODULE_ID "gralloc"
1. 加载gralloc库,并初始化hw_module_t
在./hardware/libhardware/hardware.c中
  1. int hw_get_module(const char *id, const struct hw_module_t **module)
  2. {
  3.     int status;
  4.     int i;
  5.     const struct hw_module_t *hmi = NULL;
  6.     char prop[PATH_MAX];
  7.     char path[PATH_MAX];
  8.     //查找gralloc库在板子上实际的名字与路径,将真正的文件名的路径存于path中
  9.     for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {
  10.         if (i < HAL_VARIANT_KEYS_COUNT) {
  11.             if (property_get(variant_keys[i], prop, NULL) == 0) {
  12.                 continue;
  13.             }
  14.             //在"/system/lib/hw"目录下查找 gralloc.>.so
  15.             snprintf(path, sizeof(path), "%s/%s.%s.so", HAL_LIBRARY_PATH1, id, prop);
  16.             if (access(path, R_OK) == 0)
  17.                 break;
  18.             //在"/vendor/lib/hw"目录下查找 gralloc.>.so
  19.             snprintf(path, sizeof(path), "%s/%s.%s.so", HAL_LIBRARY_PATH2, id, prop);
  20.             if (access(path, R_OK) == 0)
  21.                 break;
  22.         } else {
  23.             //在板子上这两个都不存在,只好用默认的 /system/lib/hw/gralloc.default.so
  24.             snprintf(path, sizeof(path), "%s/%s.default.so", HAL_LIBRARY_PATH1, id);
  25.             if (access(path, R_OK) == 0)
  26.                 break;
  27.         }
  28.     }

  29.     if (i < HAL_VARIANT_KEYS_COUNT+1) {
  30.         status = load(id, path, module)//加载/system/lib/hw/gralloc.default.so这个库
  31.     }
  32. }

1.1 加载/system/lib/hw/gralloc.default.so这个库
在./hardware/libhardware/modules/gralloc/gralloc.cpp中
  1. static int load(const char *idconst char *path, const struct hw_module_t **pHmi)
  2. {
  3.     void *handle = dlopen(path, RTLD_NOW);  //dlopen会加载共享库
  4.     const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
  5.     struct hw_module_t *hmi = (struct hw_module_t *)dlsym(handle, sym);  //dlsym会定位到"HMI"
  6.     //注意android共享库的"HMI"处是一个private_module_t(gralloc.cpp中有定义)
  7.     if (strcmp(id, hmi->id) != 0) {
  8.         status = -EINVAL;
  9.         goto done;
  10.     }

  11.     hmi->dso = handle;     //把
  12.     *pHmi = hmi;
  13. }
把上面的 struct hw_module_t *hmi = (struct hw_module_t *)dlsym(handle, sym);
改为 struct hw_module_t private_module_t *hmi = (struct private_module_t *)dlsym(handle, sym);
更好理解一点,与突然直接转为 hw_module_t时,效果一样.
下面是private_module_t结构体的分解,开头都是一个struct hw_module_t.
struct private_module_t
{
    gralloc_module_t base;  -->   struct hw_module_t common;  --> tag
                                                                                                 -->  id = GRALLOC_HARDWARE_MODULE_ID
                                                                                                 -->  methods = gralloc_module_methods
                                         -->   加一些函数指针                         
}
2.1 fb设备的打开过程
framebuffer_open(module, &fbDev);
  1. static inline int framebuffer_open(const struct hw_module_t* module, struct framebuffer_device_t** device) {
  2.     return module->methods->open(module, GRALLOC_HARDWARE_FB0, (struct hw_device_t**)device);
  3. }
在load中methods被初始化为
static struct hw_module_methods_t gralloc_module_methods = {
        open: gralloc_device_open
};
所以这儿的open就是要调用gralloc_device_open
2.2 gralloc_device_open
framebuffer_open
--> gralloc_device_open
在./hardware/libhardware/modules/gralloc/gralloc.cpp中
  1. int gralloc_device_open(const hw_module_t* module, const char* name,   hw_device_t** device)
  2. {
  3.     int status = -EINVAL;
  4.     if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {   
  5.     } else {    //name=="fb0"
  6.         status = fb_device_open(module, name, device);  //2.2.1这儿只关注fb的打开过程
  7.     }
  8.     return status;
  9. }
2.2.1 打开fb的具体过程
framebuffer_open
--> gralloc_device_open
    --> fb_device_open
在./hardware/libhardware/modules/gralloc/framebuffer.cpp中
这个函数主要是初始化一个fb_context_t结构体并调用mapFrameBuffer来初始化
  1. int fb_device_open(hw_module_t const* module, const char* name, hw_device_t** device)
  2. {
  3.     int status = -EINVAL;
  4.     if (!strcmp(name, GRALLOC_HARDWARE_FB0)) {
  5.         alloc_device_t* gralloc_device;
  6.         status = gralloc_open(module, &gralloc_device);
  7.         fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev));
  8.         memset(dev, 0, sizeof(*dev));

  9.         dev->device.common.tag = HARDWARE_DEVICE_TAG;
  10.         dev->device.common.version = 0;
  11.         dev->device.common.module = const_cast<hw_module_t*>(module);
  12.         dev->device.common.close = fb_close;
  13.         dev->device.setSwapInterval = fb_setSwapInterval;
  14.         dev->device.post = fb_post;
  15.         dev->device.setUpdateRect = 0;

  16.         private_module_t* m = (private_module_t*)module;
  17.         status = mapFrameBuffer(m);            //2.2.1.1这个函数map
  18.         if (status >= 0) {
  19.             int stride = m->finfo.line_length / (m->info.bits_per_pixel >> 3);
  20.             int format = HAL_PIXEL_FORMAT_RGB_565;
  21.             const_cast<uint32_t&>(dev->device.flags) = 0;
  22.             const_cast<uint32_t&>(dev->device.width) = m->info.xres;
  23.             const_cast<uint32_t&>(dev->device.height) = m->info.yres;
  24.             const_cast<int&>(dev->device.stride) = stride;
  25.             const_cast<int&>(dev->device.format) = format;
  26.             const_cast<float&>(dev->device.xdpi) = m->xdpi;
  27.             const_cast<float&>(dev->device.ydpi) = m->ydpi;
  28.             const_cast<float&>(dev->device.fps) = m->fps;
  29.             const_cast<int&>(dev->device.minSwapInterval) = 1;
  30.             const_cast<int&>(dev->device.maxSwapInterval) = 1;
  31.             *device = &dev->device.common;
  32.         }
  33.     }
  34.     return status;
  35. }
2.2.1.1 mapFrameBuffer
framebuffer_open
--> gralloc_device_open
    --> fb_device_open
        --> mapFrameBuffer
  1. static int mapFrameBuffer(struct private_module_t* module)
  2. {
  3.     pthread_mutex_lock(&module->lock);
  4.     int err = mapFrameBufferLocked(module);
  5.     pthread_mutex_unlock(&module->lock);
  6.     return err;
  7. }

2.2.1.2 mapFrameBufferLocked

framebuffer_open
--> gralloc_device_open
    --> fb_device_open
        --> mapFrameBuffer
        --> mapFrameBufferLocked
 mapFrameBuffer./hardware/libhardware/modules/gralloc/framebuffer.cpp中
  1. int mapFrameBufferLocked(struct private_module_t* module)
  2. {
  3.     char const * const device_template[] = {
  4.         "/dev/graphics/fb%u",
  5.         "/dev/fb%u",
  6.         0 };

  7.     int fd = -1;
  8.     int i=0;
  9.     char name[64];
  10.     //打开设备文件,先找/dev/graphics/fb*,找不到再找/dev/fb*
  11.     while ((fd==-1) && device_template[i]) {
  12.         snprintf(name, 64, device_template[i], 0);
  13.         fd = open(name, O_RDWR, 0);
  14.         i++;
  15.     }
  16.     if (fd < 0)
  17.         return -errno;
  18.     //1. 获取参数
  19.     struct fb_fix_screeninfo finfo;
  20.     ioctl(fd, FBIOGET_FSCREENINFO, &finfo);
  21.     //2. 获取参数
  22.     struct fb_var_screeninfo info;
  23.     ioctl(fd, FBIOGET_VSCREENINFO, &info);
  24.     //3.中间省略修改值,将修改之后的info写到内核空间
  25.     ioctl(fd, FBIOPUT_VSCREENINFO, &info);

  26.     if (info.yres_virtual < info.yres * 2) {
  27.         info.yres_virtual = info.yres;
  28.         flags &= ~PAGE_FLIP;
  29.     }
  30.     //3. 获取参数
  31.     ioctl(fd, FBIOGET_VSCREENINFO, &info);

  32.     uint64_t refreshQuotient =
  33.         (
  34.          uint64_t( info.upper_margin + info.lower_margin + info.yres )
  35.          * ( info.left_margin + info.right_margin + info.xres )
  36.          * info.pixclock
  37.         );

  38.     int refreshRate = refreshQuotient > 0 ? (int)(1000000000000000LLU / refreshQuotient) : 0;

  39.     if (refreshRate == 0)
  40.         refreshRate = 60*1000; // 60 Hz
  41.    

  42.     if (int(info.width) <= 0 || int(info.height) <= 0) {
  43.         info.width = ((info.xres * 25.4f)/160.0f + 0.5f);
  44.         info.height = ((info.yres * 25.4f)/160.0f + 0.5f);
  45.     }

  46.     float xdpi = (info.xres * 25.4f) / info.width;
  47.     float ydpi = (info.yres * 25.4f) / info.height;
  48.     float fps = refreshRate / 1000.0f;
  49.     if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
  50.         return -errno;

  51.     if (finfo.smem_len <= 0)
  52.         return -errno;


  53.     module->flags = flags;
  54.     module->info = info;
  55.     module->finfo = finfo;
  56.     module->xdpi = xdpi;
  57.     module->ydpi = ydpi;
  58.     module->fps = fps;
  59.  
  60.     size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres_virtual);
  61.     module->framebuffer = new private_handle_t(dup(fd), fbSize, 0);

  62.     module->numBuffers = info.yres_virtual / info.yres;
  63.     module->bufferMask = 0;
  64.     //mmap 一切准备都是为了这个函数
  65.     void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
  66.     module->framebuffer->base = intptr_t(vaddr);   //
  67.     memset(vaddr, 0, fbSize);  //
  68.     return 0;
  69. }

二. 显示过程:双缓冲的实现
1. 上层应用在调用fb_post进行显示
在./hardware/libhardware/modules/gralloc/framebuffer.cpp中
  1. static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
  2. {
  3.     if (private_handle_t::validate(buffer) < 0)
  4.         return -EINVAL;

  5.     fb_context_t* ctx = (fb_context_t*)dev;

  6.     private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(buffer);
  7.     private_module_t* m = reinterpret_cast<private_module_t*>( dev->common.module);
  8.     //直接映射显存空间到用户空间,这儿的PRIV_FLAGS_FRAMEBUFFER一直是置位状态
  9.     if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) 
  10.     {
  11.         const size_t offset = hnd->base - m->framebuffer->base;
  12.         m->info.activate = FB_ACTIVATE_VBL;
  13.         m->info.yoffset = offset / m->finfo.line_length;
  14.         ioctl(m->framebuffer->fd, FBIOPAN_DISPLAY,&m->info);     //2.1双缓冲
  15.         unsigned int crtc = 0;
  16.         ioctl(m->framebuffer->fd, FBIO_WAITFORVSYNC, &m->info);  //2.2等侍刷新结束
  17.         m->currentBuffer = buffer;
  18.     } else {              //没有执行
  19.         void* fb_vaddr;
  20.         void* buffer_vaddr;
  21.         m->base.lock(&m->base, m->framebuffer, GRALLOC_USAGE_SW_WRITE_RARELY, 0, 0, m->info.xres, m->info.yres, &fb_vaddr);
  22.         m->base.lock(&m->base, buffer, GRALLOC_USAGE_SW_READ_RARELY, 0, 0, m->info.xres, m->info.yres, &buffer_vaddr);
  23.         memcpy(fb_vaddr, buffer_vaddr, m->finfo.line_length * m->info.yres);
  24.         m->base.unlock(&m->base, buffer);
  25.         m->base.unlock(&m->base, m->framebuffer);
  26.     }
  27. }
2. 调用驱动层
应用层fb_post  ---->ioctl(m->framebuffer->fd, FBIOPAN_DISPLAY,&m->info);
驱动层--> fb_ioctl
在驱动drivers/video/fbmem.c中
  1. static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  2. {
  3.     struct inode *inode = file->f_path.dentry->d_inode;
  4.     int fbidx = iminor(inode);   ///dev/fb0 或 /dev/fb1后面的数字解析出来,这儿是/dev/fb0
  5.     struct fb_info *info = registered_fb[fbidx]//通过/dev/fb0的index获取数组指针
  6.     return do_fb_ioctl(info, cmd, arg);
  7. }
应用层fb_post  ---->ioctl(m->framebuffer->fd, FBIOPAN_DISPLAY,&m->info);
驱动层--> fb_ioctl
            --> do_fb_ioctl
在驱动drivers/video/fbmem.c中
  1. static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
  2. {
  3.     struct fb_ops *fb;
  4.     struct fb_var_screeninfo var;
  5.     struct fb_fix_screeninfo fix;
  6.     struct fb_con2fbmap con2fb;
  7.     struct fb_cmap cmap_from;
  8.     struct fb_cmap_user cmap;
  9.     struct fb_event event;
  10.     void __user *argp = (void __user *)arg;
  11.     long ret = 0;

  12.     switch (cmd) {
  13.     case FBIOPAN_DISPLAY:
  14.         if (copy_from_user(&var, argp, sizeof(var)))
  15.             return -EFAULT;
  16.         if (!lock_fb_info(info))
  17.             return -ENODEV;
  18.         acquire_console_sem();
  19.         ret = fb_pan_display(info, &var);      //2.1交错刷新frame1与frame2
  20.         release_console_sem();
  21.         unlock_fb_info(info);
  22.         if (ret == 0 && copy_to_user(argp, &var, sizeof(var)))
  23.             return -EFAULT;
  24.         break;  
  25.     default:
  26.         if (!lock_fb_info(info))
  27.             return -ENODEV;
  28.         fb = info->fbops;
  29.         if (fb->fb_ioctl)
  30.             ret = fb->fb_ioctl(info, cmd, arg);   //2.2等侍刷新结束
  31.         else
  32.             ret = -ENOTTY;
  33.         unlock_fb_info(info);
  34.     }
  35.     return ret;
  36. }
2.1 双缓冲的实现
通过设定framebuffer的起始与结束地址,来控制LCD的显示,
交错指定buffer0的起始地址为(0, screensize) 与(screensize, screensize*2)来进行frame1与frame2的切换
应用层fb_post  ---->ioctl(m->framebuffer->fd, FBIOPAN_DISPLAY,&m->info);
驱动层--> fb_ioctl
            --> do_fb_ioctl
                --> s3cfb_pan_display
在驱动drivers/video/samsun/s3cfb.c中
  1. static int s3cfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
  2. {
  3.     s3cfb_info_t *fbi = (s3cfb_info_t *)info;

  4.     fbi->fb.var.xoffset = var->xoffset;   //xoffset永远是0
  5.     fbi->fb.var.yoffset = var->yoffset;   //yoffset 0与272间隔出现,即代表了frame1与frame2

  6.     s3cfb_set_fb_addr(fbi);               //设置刷屏的起始地址

  7.     return 0;
  8. }
2.1.1控制frame1与frame2的切换
应用层fb_post   ---->ioctl(m->framebuffer->fd, FBIOPAN_DISPLAY,&m->info);
驱动层--> fb_ioctl
            --> do_fb_ioctl
                --> s3cfb_pan_display
                    --> s3cfb_set_fb_addr
在drivers/video/samsung/s3cfb_fimd4x.c中
  1. void s3cfb_set_fb_addr(s3cfb_info_t *fbi)
  2. {
  3.     unsigned long video_phy_temp_f1 = fbi->screen_dma_f1;   //获取dma的物理地址
  4.     //这儿的yoffset是0时就是frame1,yoffset=272时就是frame2
  5.     unsigned int start = fbi->fb.fix.line_length * fbi->fb.var.yoffset; 
  6.     unsigned long start_address = video_phy_temp_f1 + start;  //将frame1或frame2的起始地址赋值
  7.     unsigned long end_address = start_address + (fbi->fb.fix.line_length * fbi->fb.var.yres);
  8.     switch (fbi->win_id)
  9.     {
  10.         case 0:
  11.             s3cfb_fimd.vidw00add0b0 = start_address;
  12.             s3cfb_fimd.vidw00add1b0 = end_address;
  13.             //Window 0’s buffer start address register, buffer 0
  14.             __raw_writel(s3cfb_fimd.vidw00add0b0, S3C_VIDW00ADD0B0);
  15.             //Window 0’s buffer end address register, buffer 0
  16.             __raw_writel(s3cfb_fimd.vidw00add1b0, S3C_VIDW00ADD1B0); 
  17.             break;
  18.     }
  19. }

2.2 等侍vsync结束
应用层fb_post  ---->ioctl(m->framebuffer->fd, FBIO_WAITFORVSYNC, &m->info);
驱动层--> fb_ioctl
            --> do_fb_ioctl  --> fb->fb_ioctl(info, cmd, arg);   //2.2等侍刷新结束
                --> s3cfb_ioctl
在drivers/video/samsung/s3cfb_fimd4x.c中
  1. int s3cfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
  2. {
  3.     switch(cmd){
  4.         case FBIO_WAITFORVSYNC:
  5.             if (get_user(crt, (unsigned int __user *)arg))
  6.                 return -EFAULT;
  7.             return s3cfb_wait_for_vsync();
  8.     }
  9. }
2.2.1 在下一次中断完成后返回
应用层fb_post  ---->ioctl(m->framebuffer->fd, FBIO_WAITFORVSYNC, &m->info);
驱动层--> fb_ioctl
            --> do_fb_ioctl  --> fb->fb_ioctl(info, cmd, arg);   //2.2等侍刷新结束
                --> s3cfb_ioctl
                    --> s3cfb_wait_for_vsync
在驱动drivers/video/samsun/s3cfb.c中
  1. int s3cfb_wait_for_vsync(void)
  2. {
  3.     int cnt;
  4.     cnt = s3cfb_fimd.vsync_info.count;  //获取cnt值,在下一次中断完成后才能返回.
  5.     //wait_event_interruptible_timeout (wq, condition, timeout);
  6.     //condition代表着下一次中断完成
  7.     wait_event_interruptible_timeout(s3cfb_fimd.vsync_info.wait_queue, cnt != s3cfb_fimd.vsync_info.count, HZ / 10);
  8.     return cnt;
  9. }
2.2.2 中断处理函数
framebuffer的中断处理函数
只做两件事就是清中断与唤配等侍队列
在drivers/video/samsung/s3cfb_fimd4x.c中
  1. irqreturn_t s3cfb_irq(int irqno, void *param)
  2. {  
  3.     writel(readl(S3C_VIDINTCON1), S3C_VIDINTCON1);  //清中断

  4.     s3cfb_fimd.vsync_info.count++;                  //唤醒等侍队列
  5.     wake_up_interruptible(&s3cfb_fimd.vsync_info.wait_queue);

  6.     return IRQ_HANDLED;
  7. }
附录:
1. s3c_irq这个中断是何时被触发
a. 查看发生频率
  1. / # date && cat /proc/interrupts
  2. Fri Jan 2 00:08:51 GMT 1970
  3.  62: 35409 VIC s3c-lcd


  4. / # date && cat /proc/interrupts
  5. Fri Jan 2 00:10:58 GMT 1970
  6.  62: 43472 VIC s3c-lcd

  7. (43472-35409)/127=63.488188976
说明这个中断大约每秒触发60次,即屏幕的刷新频率






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