原文地址:http://blog.chinaunix.net/uid-26009923-id-4044926.html
一. 打开gralloc
在frameworks/base/libs/ui/FramebufferNativeWindow.cpp中会调用
-
FramebufferNativeWindow::FramebufferNativeWindow()
-
: BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false)
-
{
-
hw_module_t const* module;
-
hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module); //1.加载gralloc库
-
framebuffer_open(module, &fbDev); //2.打开fb设备
-
gralloc_open(module, &grDev);
-
}
其中在./hardware/libhardware/include/hardware/gralloc.h中定义了
#define GRALLOC_HARDWARE_MODULE_ID "gralloc"
1. 加载gralloc库,并初始化hw_module_t
在./hardware/libhardware/hardware.c中
-
int hw_get_module(const char *id, const struct hw_module_t **module)
-
{
-
int status;
-
int i;
-
const struct hw_module_t *hmi = NULL;
-
char prop[PATH_MAX];
-
char path[PATH_MAX];
-
//查找gralloc库在板子上实际的名字与路径,将真正的文件名的路径存于path中
-
for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {
-
if (i < HAL_VARIANT_KEYS_COUNT) {
-
if (property_get(variant_keys[i], prop, NULL) == 0) {
-
continue;
-
}
-
//在"/system/lib/hw"目录下查找 gralloc.>.so
-
snprintf(path, sizeof(path), "%s/%s.%s.so", HAL_LIBRARY_PATH1, id, prop);
-
if (access(path, R_OK) == 0)
-
break;
-
//在"/vendor/lib/hw"目录下查找 gralloc.>.so
-
snprintf(path, sizeof(path), "%s/%s.%s.so", HAL_LIBRARY_PATH2, id, prop);
-
if (access(path, R_OK) == 0)
-
break;
-
} else {
-
//在板子上这两个都不存在,只好用默认的 /system/lib/hw/gralloc.default.so
-
snprintf(path, sizeof(path), "%s/%s.default.so", HAL_LIBRARY_PATH1, id);
-
if (access(path, R_OK) == 0)
-
break;
-
}
-
}
-
-
if (i < HAL_VARIANT_KEYS_COUNT+1) {
-
status = load(id, path, module); //加载/system/lib/hw/gralloc.default.so这个库
-
}
-
}
1.1 加载/system/lib/hw/gralloc.default.so这个库
在./hardware/libhardware/modules/gralloc/gralloc.cpp中
-
static int load(const char *id, const char *path, const struct hw_module_t **pHmi)
-
{
-
void *handle = dlopen(path, RTLD_NOW); //dlopen会加载共享库
-
const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
-
struct hw_module_t *hmi = (struct hw_module_t *)dlsym(handle, sym); //dlsym会定位到"HMI"处
-
//注意android共享库的"HMI"处是一个private_module_t(gralloc.cpp中有定义)
-
if (strcmp(id, hmi->id) != 0) {
-
status = -EINVAL;
-
goto done;
-
}
-
-
hmi->dso = handle; //把
-
*pHmi = hmi;
-
}
把上面的 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);
-
static inline int framebuffer_open(const struct hw_module_t* module, struct framebuffer_device_t** device) {
-
return module->methods->open(module, GRALLOC_HARDWARE_FB0, (struct hw_device_t**)device);
-
}
在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中
-
int gralloc_device_open(const hw_module_t* module, const char* name, hw_device_t** device)
-
{
-
int status = -EINVAL;
-
if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {
-
} else { //name=="fb0"
-
status = fb_device_open(module, name, device); //2.2.1这儿只关注fb的打开过程
-
}
-
return status;
-
}
2.2.1 打开fb的具体过程
framebuffer_open
--> gralloc_device_open
--> fb_device_open
在./hardware/libhardware/modules/gralloc/framebuffer.cpp中
这个函数主要是初始化一个fb_context_t结构体并调用mapFrameBuffer来初始化
-
int fb_device_open(hw_module_t const* module, const char* name, hw_device_t** device)
-
{
-
int status = -EINVAL;
-
if (!strcmp(name, GRALLOC_HARDWARE_FB0)) {
-
alloc_device_t* gralloc_device;
-
status = gralloc_open(module, &gralloc_device);
-
fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev));
-
memset(dev, 0, sizeof(*dev));
-
-
dev->device.common.tag = HARDWARE_DEVICE_TAG;
-
dev->device.common.version = 0;
-
dev->device.common.module = const_cast<hw_module_t*>(module);
-
dev->device.common.close = fb_close;
-
dev->device.setSwapInterval = fb_setSwapInterval;
-
dev->device.post = fb_post;
-
dev->device.setUpdateRect = 0;
-
-
private_module_t* m = (private_module_t*)module;
-
status = mapFrameBuffer(m); //2.2.1.1这个函数map
-
if (status >= 0) {
-
int stride = m->finfo.line_length / (m->info.bits_per_pixel >> 3);
-
int format = HAL_PIXEL_FORMAT_RGB_565;
-
const_cast<uint32_t&>(dev->device.flags) = 0;
-
const_cast<uint32_t&>(dev->device.width) = m->info.xres;
-
const_cast<uint32_t&>(dev->device.height) = m->info.yres;
-
const_cast<int&>(dev->device.stride) = stride;
-
const_cast<int&>(dev->device.format) = format;
-
const_cast<float&>(dev->device.xdpi) = m->xdpi;
-
const_cast<float&>(dev->device.ydpi) = m->ydpi;
-
const_cast<float&>(dev->device.fps) = m->fps;
-
const_cast<int&>(dev->device.minSwapInterval) = 1;
-
const_cast<int&>(dev->device.maxSwapInterval) = 1;
-
*device = &dev->device.common;
-
}
-
}
-
return status;
-
}
2.2.1.1 mapFrameBuffer
framebuffer_open
--> gralloc_device_open
--> fb_device_open
--> mapFrameBuffer
-
static int mapFrameBuffer(struct private_module_t* module)
-
{
-
pthread_mutex_lock(&module->lock);
-
int err = mapFrameBufferLocked(module);
-
pthread_mutex_unlock(&module->lock);
-
return err;
-
}
2.2.1.2 mapFrameBufferLocked
framebuffer_open
--> gralloc_device_open
--> fb_device_open
--> mapFrameBuffer
--> mapFrameBufferLocked
mapFrameBuffer./hardware/libhardware/modules/gralloc/framebuffer.cpp中
-
int mapFrameBufferLocked(struct private_module_t* module)
-
{
-
char const * const device_template[] = {
-
"/dev/graphics/fb%u",
-
"/dev/fb%u",
-
0 };
-
-
int fd = -1;
-
int i=0;
-
char name[64];
-
//打开设备文件,先找/dev/graphics/fb*,找不到再找/dev/fb*
-
while ((fd==-1) && device_template[i]) {
-
snprintf(name, 64, device_template[i], 0);
-
fd = open(name, O_RDWR, 0);
-
i++;
-
}
-
if (fd < 0)
-
return -errno;
-
//1. 获取参数
-
struct fb_fix_screeninfo finfo;
-
ioctl(fd, FBIOGET_FSCREENINFO, &finfo);
-
//2. 获取参数
-
struct fb_var_screeninfo info;
-
ioctl(fd, FBIOGET_VSCREENINFO, &info);
-
//3.中间省略修改值,将修改之后的info写到内核空间
-
ioctl(fd, FBIOPUT_VSCREENINFO, &info);
-
-
if (info.yres_virtual < info.yres * 2) {
-
info.yres_virtual = info.yres;
-
flags &= ~PAGE_FLIP;
-
}
-
//3. 获取参数
-
ioctl(fd, FBIOGET_VSCREENINFO, &info);
-
-
uint64_t refreshQuotient =
-
(
-
uint64_t( info.upper_margin + info.lower_margin + info.yres )
-
* ( info.left_margin + info.right_margin + info.xres )
-
* info.pixclock
-
);
-
-
int refreshRate = refreshQuotient > 0 ? (int)(1000000000000000LLU / refreshQuotient) : 0;
-
-
if (refreshRate == 0)
-
refreshRate = 60*1000; // 60 Hz
-
-
-
if (int(info.width) <= 0 || int(info.height) <= 0) {
-
info.width = ((info.xres * 25.4f)/160.0f + 0.5f);
-
info.height = ((info.yres * 25.4f)/160.0f + 0.5f);
-
}
-
-
float xdpi = (info.xres * 25.4f) / info.width;
-
float ydpi = (info.yres * 25.4f) / info.height;
-
float fps = refreshRate / 1000.0f;
-
if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
-
return -errno;
-
-
if (finfo.smem_len <= 0)
-
return -errno;
-
-
-
module->flags = flags;
-
module->info = info;
-
module->finfo = finfo;
-
module->xdpi = xdpi;
-
module->ydpi = ydpi;
-
module->fps = fps;
-
-
size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres_virtual);
-
module->framebuffer = new private_handle_t(dup(fd), fbSize, 0);
-
-
module->numBuffers = info.yres_virtual / info.yres;
-
module->bufferMask = 0;
-
//mmap 一切准备都是为了这个函数
-
void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
-
module->framebuffer->base = intptr_t(vaddr); //保存这个值
-
memset(vaddr, 0, fbSize); //清屏
-
return 0;
-
}
二. 显示过程:双缓冲的实现
1. 上层应用在调用fb_post进行显示
在./hardware/libhardware/modules/gralloc/framebuffer.cpp中
-
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<private_handle_t const*>(buffer);
-
private_module_t* m = reinterpret_cast<private_module_t*>( dev->common.module);
-
//直接映射显存空间到用户空间,这儿的PRIV_FLAGS_FRAMEBUFFER一直是置位状态
-
if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)
-
{
-
const size_t offset = hnd->base - m->framebuffer->base;
-
m->info.activate = FB_ACTIVATE_VBL;
-
m->info.yoffset = offset / m->finfo.line_length;
-
ioctl(m->framebuffer->fd, FBIOPAN_DISPLAY,&m->info); //2.1双缓冲
-
unsigned int crtc = 0;
-
ioctl(m->framebuffer->fd, FBIO_WAITFORVSYNC, &m->info); //2.2等侍刷新结束
-
m->currentBuffer = buffer;
-
} else { //没有执行
-
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);
-
}
-
}
2. 调用驱动层
应用层fb_post ---->ioctl(m->framebuffer->fd, FBIOPAN_DISPLAY,&m->info);
驱动层--> fb_ioctl
在驱动drivers/video/fbmem.c中
-
static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-
{
-
struct inode *inode = file->f_path.dentry->d_inode;
-
int fbidx = iminor(inode); //将/dev/fb0 或 /dev/fb1后面的数字解析出来,这儿是/dev/fb0
-
struct fb_info *info = registered_fb[fbidx]; //通过/dev/fb0的index获取数组指针
-
return do_fb_ioctl(info, cmd, arg);
-
}
应用层fb_post ---->ioctl(m->framebuffer->fd, FBIOPAN_DISPLAY,&m->info);
驱动层--> fb_ioctl
--> do_fb_ioctl
在驱动drivers/video/fbmem.c中
-
static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
-
{
-
struct fb_ops *fb;
-
struct fb_var_screeninfo var;
-
struct fb_fix_screeninfo fix;
-
struct fb_con2fbmap con2fb;
-
struct fb_cmap cmap_from;
-
struct fb_cmap_user cmap;
-
struct fb_event event;
-
void __user *argp = (void __user *)arg;
-
long ret = 0;
-
-
switch (cmd) {
-
case FBIOPAN_DISPLAY:
-
if (copy_from_user(&var, argp, sizeof(var)))
-
return -EFAULT;
-
if (!lock_fb_info(info))
-
return -ENODEV;
-
acquire_console_sem();
-
ret = fb_pan_display(info, &var); //2.1交错刷新frame1与frame2
-
release_console_sem();
-
unlock_fb_info(info);
-
if (ret == 0 && copy_to_user(argp, &var, sizeof(var)))
-
return -EFAULT;
-
break;
-
default:
-
if (!lock_fb_info(info))
-
return -ENODEV;
-
fb = info->fbops;
-
if (fb->fb_ioctl)
-
ret = fb->fb_ioctl(info, cmd, arg); //2.2等侍刷新结束
-
else
-
ret = -ENOTTY;
-
unlock_fb_info(info);
-
}
-
return ret;
-
}
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中
-
static int s3cfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
-
{
-
s3cfb_info_t *fbi = (s3cfb_info_t *)info;
-
-
fbi->fb.var.xoffset = var->xoffset; //xoffset永远是0
-
fbi->fb.var.yoffset = var->yoffset; //yoffset 0与272间隔出现,即代表了frame1与frame2
-
-
s3cfb_set_fb_addr(fbi); //设置刷屏的起始地址
-
-
return 0;
-
}
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中
-
void s3cfb_set_fb_addr(s3cfb_info_t *fbi)
-
{
-
unsigned long video_phy_temp_f1 = fbi->screen_dma_f1; //获取dma的物理地址
-
//这儿的yoffset是0时就是frame1,yoffset=272时就是frame2
-
unsigned int start = fbi->fb.fix.line_length * fbi->fb.var.yoffset;
-
unsigned long start_address = video_phy_temp_f1 + start; //将frame1或frame2的起始地址赋值
-
unsigned long end_address = start_address + (fbi->fb.fix.line_length * fbi->fb.var.yres);
-
switch (fbi->win_id)
-
{
-
case 0:
-
s3cfb_fimd.vidw00add0b0 = start_address;
-
s3cfb_fimd.vidw00add1b0 = end_address;
-
//Window 0’s buffer start address register, buffer 0
-
__raw_writel(s3cfb_fimd.vidw00add0b0, S3C_VIDW00ADD0B0);
-
//Window 0’s buffer end address register, buffer 0
-
__raw_writel(s3cfb_fimd.vidw00add1b0, S3C_VIDW00ADD1B0);
-
break;
-
}
-
}
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中
-
int s3cfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
-
{
-
switch(cmd){
-
case FBIO_WAITFORVSYNC:
-
if (get_user(crt, (unsigned int __user *)arg))
-
return -EFAULT;
-
return s3cfb_wait_for_vsync();
-
}
-
}
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中
-
int s3cfb_wait_for_vsync(void)
-
{
-
int cnt;
-
cnt = s3cfb_fimd.vsync_info.count; //获取cnt值,在下一次中断完成后才能返回.
-
//wait_event_interruptible_timeout (wq, condition, timeout);
-
//condition代表着下一次中断完成
-
wait_event_interruptible_timeout(s3cfb_fimd.vsync_info.wait_queue, cnt != s3cfb_fimd.vsync_info.count, HZ / 10);
-
return cnt;
-
}
2.2.2 中断处理函数
framebuffer的中断处理函数
只做两件事就是清中断与唤配等侍队列
在drivers/video/samsung/s3cfb_fimd4x.c中
-
irqreturn_t s3cfb_irq(int irqno, void *param)
-
{
-
writel(readl(S3C_VIDINTCON1), S3C_VIDINTCON1); //清中断
-
-
s3cfb_fimd.vsync_info.count++; //唤醒等侍队列
-
wake_up_interruptible(&s3cfb_fimd.vsync_info.wait_queue);
-
-
return IRQ_HANDLED;
-
}
附录:
1. s3c_irq这个中断是何时被触发
a. 查看发生频率
-
/ # date && cat /proc/interrupts
-
Fri Jan 2 00:08:51 GMT 1970
-
62: 35409 VIC s3c-lcd
-
-
-
/ # date && cat /proc/interrupts
-
Fri Jan 2 00:10:58 GMT 1970
-
62: 43472 VIC s3c-lcd
-
-
(43472-35409)/127=63.488188976
说明这个中断大约每秒触发60次,即屏幕的刷新频率
阅读(1204) | 评论(0) | 转发(0) |