4.4 显示BSP的实现
↘4.4.1 模拟器显示系统的实现
模拟器使用的显示系统的驱动程序是goldfish的Framebuffer驱动程序,使用的硬件抽象层是默认的gralloc模块。
1.Framebuffer驱动程序
goldfish虚拟处理器的Framebuffer驱动程序在内核的路径drivers/video/goldfishfb.c中实现。这是一个标准Framebuffer的驱动程序,其实现的基础主机的显示器。
这个驱动程序的初始化工作的内容是goldfish_fb_probe,如下所示:
static int goldfish_fb_probe(struct platform_device *pdev){ struct goldfish_fb *fb; fb->fb.fix.type = FB_TYPE_PACKED_PIXELS; fb->fb.fix.visual = FB_VISUAL_TRUECOLOR; fb->fb.fix.line_length = width * 2; // RGB565每个像素占用l6位,2个字节 fb->fb.fix.accel = FB_ACCEL_NONE; fb->fb.fix.ypanstep = l; fb->fb.var.xres = width; // 实际显示区域 fb->fb.var.yres = height; fb->fb.var.xres_virtual = width; // 虚拟显示区域(高度为实际的两倍) fb->fb.var.yres_virtual = height * 2; fb->fb.var.bits_per_pixel = l6; fb->fb.var.activate = FB_ACTIVATE_NOW; fb->fb.var.height = readl(fb->reg_base + FB_GET_PHYS_HEIGHT);// 读取虚拟寄存器 fb->fb.var.width = readl(fb->reg_base + FB_GET_PHYS_WIDTH); fb->fb.var.red.offset = ll; // RGB565的颜色空间 fb->fb.var.red.length = 5; fb->fb.var.green.offset = 5; fb->fb.var.green.length = 6; fb->fb.var.blue.offset = 0; fb->fb.var.blue.length = 5; framesize = width * height * 2 * 2; // 显示缓冲区的大小,考虑每像素大小的虚拟区域 // 进行内存映射 fb->fb.screen_base = dma_alloc_writecombine(&pdev->dev, framesize, &fbpaddr, GFP_KERNEL); // 省略部分内容 fb->fb.fix.smem_start = fbpaddr; fb->fb.fix.smem_len = framesize; ret = fb_set_var(&fb->fb, &fb->fb.var); // 设置参数 // 省略部分内容 ret = request_irq(fb->irq, goldfish_fb_interrupt, IRQF_SHARED, pdev->name, fb); // 省略部分内容 writel(FB_INT_BASE_UPDATE_DONE, fb->reg_base + FB_INT_ENABLE); goldfish_fb_pan_display(&fb->fb.var, &fb->fb); // 更新显示 ret = register_framebuffer(&fb->fb); // 注册驱动程序 // 省略部分内容 }
虽然基于主机的显示实现,但是对“硬件”的操作依然通过寄存器完成。goldfish虚拟处理器的Framebuffer驱动程序实现了RGB565的颜色空间支持,虚拟显示的y为实际显示的两倍,用于双缓冲。由于RGB565颜色格式每个像素占用两个字节,又具有双显示缓冲,因此显示缓冲区的大小为width×height×2×2。在用户空间,两个显示缓冲区的切换可以通过调用ioctl命令FBIOPAN_DISPLAY来控制。
2.默认的gralloc模块的实现
默认的gralloc模块不仅可以给模拟器实现,对于实现了标准Framebuffer驱动程序的硬件系统,也可以使用这个模块。
默认的gralloc模块实现的代码路径为:hardware/libhardware/modules/gralloc/。
根据硬件抽象层的接口特点,实现分为gralloc_module_t部分、framebuffer_device_t部分、alloc_device_t部分。其源代码如下所示。
·gralloc.cpp:实现gralloc_module_t模块和alloc_device_t设备。
·framebuffer.cpp:实现framebuffer_device_t设备。
·mapper.cpp:实现Buffer操作等函数。
默认的gralloc模块的实现如图4-3所示。
图4-3 默认的gralloc模块的实现
默认gralloc模块所使用的硬件设备只有Framebuffer驱动程序。因此,实际上不仅framebuffer_device_t设备基于Framebuffer驱动程序,而且gralloc_module_t模块中的registerBuffer接口和alloc_device_t设备中的alloc等接口都是通过间接调用Framebuffer驱动程序实现的。
gralloc.cpp中实现gralloc_module_t模块的是显示模块接口,其打开函数gralloc_device_open()的内容如下所示:
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)) { // 打开alloc_device_t设备 gralloc_context_t *dev; dev = (gralloc_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 = gralloc_close; dev->device.alloc = gralloc_alloc; // alloc_device_t的alloc接口 dev->device.free = gralloc_free; // alloc_device_t的free接口 *device = &dev->device.common; status = 0; } else { // 打开framebuffer_device_t设备 status = fb_device_open(module, name, device); } return status; }
gralloc_priv.h中定义的private_module_t类型的结构体类型扩展了gralloc_module_t结构体,其中第1个成员指针base就是gralloc_module_t类型。
private_module_t结构体的实现如下所示:
struct private_module_t HAL_MODULE_INFO_SYM = { base: { // 来自gralloc_module_t结构体 common: { tag: HARDWARE_MODULE_TAG, version_major: l, version_minor: 0, id: GRALLOC_HARDWARE_MODULE_ID, name: "Graphics Memory Allocator Module", author: "The Android Open Source Project", methods: &gralloc_module_methods }, registerBuffer: gralloc_register_buffer, // 模块的几个函数指针 unregisterBuffer: gralloc_unregister_buffer, lock: gralloc_lock, unlock: gralloc_unlock, }, framebuffer: 0, // 附加成员 flags: 0, numBuffers: 0, bufferMask: 0, lock: PTHREAD_MUTEX_INITIALIZER, currentBuffer: 0, };
gralloc_register_buffer、gralloc_unregister_buffer、gralloc_lock和gralloc_unlock几个函数是操作的执行者,它们在mapper.cpp中实现。
模块的register_buffer实际上是通过映射打开Framebuffer设备的文件描述符来实现的。而这个文件描述符是在framebuffer_device_t打开后才得到的。
framebuffer.cpp实现了framebuffer_device_t设备,这里使用了双缓冲的实现方式。
framebuffer_device_t设备的打开部分fb_device_open()的内容如下所示:
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); // 映射framebuffer设备 if (status >= 0) { // 填充framebuffer_device_t设备的各个内容 int stride = m->finfo.line_length / (m->info.bits_per_pixel >> 3); 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) = HAL_PIXEL_FORMAT_RGB_565; 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) = l; const_cast<int&>(dev->device.maxSwapInterval) = l; *device = &dev->device.common; } } return status; }
fb_device_open()的功能就是初始化了一个framebuffer_device_t设备,其中的主体部分在mapFrameBufferLocked()中实现,如下所示:
int mapFrameBufferLocked(struct private_module_t* module) { // 省略部分内容 char const * const device_template[] = { // 定义framebuffer设备 "/dev/graphics/fb%u","/dev/fb%u",0 }; int fd = -l; int i=0; char name[64]; while ((fd==-l) && device_template[i]) { snprintf(name, 64, device_template[i], 0); // 得到设备的名称 fd = open(name, O_RDWR, 0); i++; } struct fb_fix_screeninfo finfo; if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -l) return -errno;// 固定屏幕信息 struct fb_var_screeninfo info; if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -l) return -errno; // 变化屏幕信息 info.reserved[0] = 0; // 设置变化屏幕信息中的几个数据 info.reserved[l] = 0; info.reserved[2] = 0; info.xoffset = 0; info.yoffset = 0; info.activate = FB_ACTIVATE_NOW; info.bits_per_pixel = l6; // RGB565的颜色空间 info.red.offset = ll; info.red.length = 5; info.green.offset = 5; info.green.length = 6; info.yres_virtual = info.yres * NUM_BUFFERS; // NUM_BUFFERS == 2 uint32_t flags = PAGE_FLIP; if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -l) { // 重新设置变化屏幕信息 info.yres_virtual = info.yres; flags &= ~PAGE_FLIP; } if (info.yres_virtual < info.yres * 2) { // 虚拟缓冲区尺寸不到实际缓冲区两倍的情况 info.yres_virtual = info.yres; flags &= ~PAGE_FLIP; } if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -l) return -errno; // 变化屏幕信息 int refreshRate = l000000000000000LLU / ( uint64_t( info.upper_margin + info.lower_margin + info.yres ) * ( info.left_margin + info.right_margin + info.xres ) * info.pixclock ); if (refreshRate == 0) { refreshRate = 60*l000; } // 刷新频率为60Hz if (int(info.width) <= 0 || int(info.height) <= 0) { // 默认dpi为l60 info.width = ((info.xres * 25.4f)/l60.0f + 0.5f); info.height = ((info.yres * 25.4f)/l60.0f + 0.5f); } float xdpi = (info.xres * 25.4f) / info.width; // 获得X和Y的dpi float ydpi = (info.yres * 25.4f) / info.height; float fps = refreshRate / l000.0f; if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -l) 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; int err; 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; // 数值一般为2 module->bufferMask = 0; // 进行从设备中的内存映射 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; }
这里实现的操作内容基本上是对Framebuffer驱动程序的标准操作,使用RGB565的颜色空间,至少需要虚拟缓冲区是实际显示区域的两倍(主要指y方向是两倍)。另外,刷新率和DPI(单位面积的像素数目)的计算为Android系统服务,它们是可选的内容。
post是framebuffer_device_t设备实现中的重点,表示将某个缓冲区(Buffer)显示在屏幕上,这个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<private_handle_t const*>(buffer); private_module_t* m = reinterpret_cast<private_module_t*>( 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) == -l) { m->base.unlock(&m->base, buffer); return -errno; } 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); } return 0; }
优化的方法是通过Framebuffer驱动的ioctl命令FBIOPUT_VSCREENINFO来实现的,实际上就是通过改变屏幕信息中的yoffset,实现双缓冲的切换。从这里的控制中可知,各种上下文信息来自于保存在private_module_t中的成员。
屏幕上显示需要处理器的显示系统通过硬件DMA读取显示缓冲区的数据,而在程序中需要写显示缓冲区的数据。为了避免这两个步骤同时进行,gralloc处理的方式就是:锁定一个,写内容,解锁它;在锁定期间,这个显示缓冲区不能被硬件DMA获取,另一个缓冲区被解锁可以用于显示到屏幕上。
gralloc.cpp实现了的alloc_device_t设备几个部分,主要的内容是alloc、free和close几个函数指针。
模块的核心为实现alloc_device_t::alloc的gralloc_alloc函数,定义的内容如下所示:
static int gralloc_alloc(alloc_device_t* dev, int w, int h, int format, int usage, buffer_handle_t* pHandle, int* pStride) { if (!pHandle || !pStride) return -EINVAL; size_t size, stride; int align = 4; int bpp = 0; switch (format) { // 颜色空间的处理,计算每像素字节 case HAL_PIXEL_FORMAT_RGBA_8888: // 每个像素4字节的情况 case HAL_PIXEL_FORMAT_RGBX_8888: case HAL_PIXEL_FORMAT_BGRA_8888: bpp = 4; break; case HAL_PIXEL_FORMAT_RGB_888: // 每个像素3字节的情况 bpp = 3; break; case HAL_PIXEL_FORMAT_RGB_565: // 每个像素2字节的情况 case HAL_PIXEL_FORMAT_RGBA_555l: case HAL_PIXEL_FORMAT_RGBA_4444: bpp = 2; break; default: return -EINVAL; } size_t bpr = (w*bpp + (align-l)) & ~(align-l); //根据行的情况进行对齐整理 size = bpr * h; stride = bpr / bpp; int err; if (usage & GRALLOC_USAGE_HW_FB) { // 根据参数进行判断 err = gralloc_alloc_framebuffer(dev, size, usage, pHandle); } else { err = gralloc_alloc_buffer(dev, size, usage, pHandle); } // 省略部分内容 *pStride = stride; return 0; }
这里核心部分是当调用标准包含了GRALLOC_USAGE_HW_FB时,调用了gralloc_alloc_framebuffer函数,gralloc_alloc_framebuffer函数调用了framebuffer.cpp中的mapFrameBuffer函数,进而调用了mapFrameBufferLocked。实际上,这里的实现是软件实现,都需要映射Framebuffer设备。
在gralloc_alloc_buffer的实现中,调用ashmem_create_region()使用ashmem(匿名共享内存)分配了名称为"gralloc-buffer"的内存,这是一个纯软件的实现。
↘4.4.2 Nexus One系统的实现
Nexus One的显示系统的BSP由Framebuffer驱动和重新实现gralloc模块组成。
1.Framebuffer驱动程序
Nexus One的Framebuffer驱动程序使用MSM平台统一的驱动程序,其主要文件入口为drivers/video/msm/msm_fb.c。同时,arch/arm/mach-msm的device.c中定义了对应的platform_device(mddi1、mddi2、mdp)。mddi(MobileDisplay Digital Interface)是一种串行总线,用于连接LCD、mdp(MobileDisplay Processor),是显示的主模块。
msm_fb.c中实现的基本上是标准的Framebuffer驱动,默认使用RGB565的颜色空间,使用两倍于实际显示区的内存作为虚拟显示区。其建立的过程如下所示:
static void setup_fb_info(struct msmfb_info *msmfb) { struct fb_info *fb_info = msmfb->fb; int r; strncpy(fb_info->fix.id, "msmfb", l6); fb_info->fix.ypanstep = l; fb_info->fbops = &msmfb_ops; // MSM的fb操作函数 fb_info->flags = FBINFO_DEFAULT; // 设置默认标识 fb_info->fix.type = FB_TYPE_PACKED_PIXELS; fb_info->fix.visual = FB_VISUAL_TRUECOLOR; fb_info->fix.line_length = msmfb->xres * 2; fb_info->var.xres = msmfb->xres; fb_info->var.yres = msmfb->yres; fb_info->var.width = msmfb->panel->fb_data->width; // 从LCD得到分辨率 fb_info->var.height = msmfb->panel->fb_data->height; fb_info->var.xres_virtual = msmfb->xres; fb_info->var.yres_virtual = msmfb->yres * 2; fb_info->var.bits_per_pixel = l6; fb_info->var.accel_flags = 0; fb_info->var.yoffset = 0; if (msmfb->panel->caps & MSMFB_CAP_PARTIAL_UPDATES) { // MSM的fb部分更新功能 fb_info->fix.reserved[0] = 0x5444; fb_info->fix.reserved[l] = 0x5055; fb_info->var.reserved[0] = 0x54445055; fb_info->var.reserved[l] = 0; fb_info->var.reserved[2] = (uintl6_t)msmfb->xres | ((uint32_t)msmfb->yres << l6); } fb_info->var.red.offset = ll; // 默认为RGB565的颜色空间 fb_info->var.red.length = 5; fb_info->var.red.msb_right = 0; fb_info->var.green.offset = 5; fb_info->var.green.length = 6; fb_info->var.green.msb_right = 0; fb_info->var.blue.offset = 0; fb_info->var.blue.length = 5; fb_info->var.blue.msb_right = 0; mdp->set_output_format(mdp, fb_info->var.bits_per_pixel);// 设置MDP颜色格式 r = fb_alloc_cmap(&fb_info->cmap, l6, 0); fb_info->pseudo_palette = PP; PP[0] = 0; for (r = l; r < l6; r++) PP[r] = 0xffffffff; }
几个额外的ioctl命令在头文件include/linux/msm_mdp.h中定义,如下所示:
#define MSMFB_IOCTL_MAGIC 'm' #define MSMFB_GRP_DISP _IOW(MSMFB_IOCTL_MAGIC, l, unsigned int) #define MSMFB_BLIT _IOW(MSMFB_IOCTL_MAGIC, 2, unsigned int)
msm_fb驱动程序相比标准的Framebufer驱动程序,特殊的地方是增加了特定的ioctl,这部分主体的内容如下所示:
static int msmfb_ioctl(struct fb_info *p, unsigned int cmd, unsigned long arg) { void __user *argp = (void __user *)arg; int ret; switch (cmd) { case MSMFB_GRP_DISP: // 调用mdp的部分来实现MSMFB_GRP_DISP mdp->set_grp_disp(mdp, arg); break; case MSMFB_BLIT: // 实现MSMFB_BLIT,用于内存块复制 ret = msmfb_blit(p, argp); break; default: return -EINVAL; } return 0; }
除了以上特殊的ioctl,MSM的Framebuffer驱动程序并无其他特别之处。
2.gralloc模块的实现
Nexus One系统的gralloc模块使用QSD8k系列处理器实现的内容,此模块基于其Framebuffer和pmem驱动实现。其代码路径为:hardware/msm7k/libgralloc-qsd8k/,目标为动态库gralloc.qsd8k.so。
其源代码如下所示。
·gralloc.cpp:实现gralloc_module_t模块。
·framebuffer.cpp:实现framebuffer_device_t设备。
·mapper.cpp:通过pmem实现了Buffer操作等函数。
·pmemalloc.*:使用pmem的分配器。
·allocator. *:通过pmemalloc构建的分配器Allocator,被gralloc_module_t调用。
·gpu. *:通过pmemalloc实现alloc_device_t设备。
QSD8k的gralloc模块的实现如图4-4所示。
图4-4 QSD8k的gralloc模块实现
QSD8k的gralloc模块的主要实现与默认的gralloc类似,主要是内存的分配和映射方式不同,主要改动是增加了对pmem的使用。与默认的gralloc模块相比,主要区别在于alloc_device_t的alloc和free通过使用pmem实现,gralloc_module_t增加了perform实现,增加辅助的allocator类。
gralloc_priv.h中定义的private_module_t扩展了gralloc_module_t结构体,它就是QSD8k中表示的gralloc模块,其中多了一个perform函数指针。
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)) { // 打开alloc_device_t设备 const private_module_t* m = reinterpret_cast<const private_module_t*>( module); gpu_context_t *dev; dev = new gpu_context_t(gpuContextDeviceDepsImpl, pmemAllocator, pmemAdspAllocator, m); *device = &dev->common; status = 0; } else { // 打开framebuffer_device_t设备 status = fb_device_open(module, name, device); } return status; }
在需要打开alloc_device_t设备时,此处打开的是gpu.*中的实现gpu_context_t,这个部分是QSD8k的gralloc模块与默认gralloc模块最大的区别。
perform函数指针的实现为mapper.cpp中的gralloc_perform()函数,其内容如下所示:
int gralloc_perform(struct gralloc_module_t const* module,int operation, ... ){ int res = -EINVAL; va_list args; va_start(args, operation); switch (operation) { case GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER: { int fd = va_arg(args, int); size_t size = va_arg(args, size_t); size_t offset = va_arg(args, size_t); void* base = va_arg(args, void*); // 验证需要一个pmem buffer pmem_region region; if (ioctl(fd, PMEM_GET_SIZE, ®ion) < 0) { // 调用pmem的ioctl命令 break; } native_handle_t** handle = va_arg(args, native_handle_t**); private_handle_t* hnd = (private_handle_t*)native_handle_create( private_handle_t::sNumFds, private_handle_t::sNumInts); hnd->magic = private_handle_t::sMagic; // 保存内容到private_handle_t结构 hnd->fd = fd; hnd->flags = private_handle_t::PRIV_FLAGS_USES_PMEM; hnd->size = size; hnd->offset = offset; hnd->base = intptr_t(base) + offset; hnd->lockState = private_handle_t::LOCK_STATE_MAPPED; *handle = (native_handle_t *)hnd; // 返回private_handle_t结构 res = 0; break; } } va_end(args); return res; }
GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER作为特殊的命令在gralloc_perform()函数中实现。此命令是一个可选的功能,在SurfaceFlinger中被调用。这里的实现调用pmem驱动获得了内存的大小。
gralloc_register_buffer、gralloc_unregister_buffer、gralloc_lock和gralloc_unlock几个函数是也在mapper.cpp中实现。与默认的gralloc相比,它们实际上是通过pmem完成的。
framebuffer.cpp中的framebuffer_device_t和标准的实现基本相同,主要体现在增加了更多颜色格式的支持,并且以RGBA8888作为默认的颜色格式。
其中post功能的主要区别体现在,当不支持双缓冲时需要进行内存复制,此处不再调用memcopy而是调用msm_copy_buffer来实现,这部分内容如下所示:
static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer){ // 省略部分内容 if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) { // 省略部分内容 } else { void* fb_vaddr; void* buffer_vaddr; // 对内存区域进行操作:锁定-复制(使用msm_copy_buffer)-解锁 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); msm_copy_buffer( // 使用的是内存复制的功能 m->framebuffer, m->framebuffer->fd, m->info.xres, m->info.yres, m->fbFormat, m->info.xoffset, m->info.yoffset, m->info.width, m->info.height); m->base.unlock(&m->base, buffer); m->base.unlock(&m->base, m->framebuffer); } return 0; }
msm_copy_buffer是平台单独实现的内容,基于其Framebuffer驱动的ioctl命令MSMFB_BLIT来实现,内容如下所示:
static void msm_copy_buffer(buffer_handle_t handle, int fd, int width, int height, int format, int x, int y, int w, int h){ struct { unsigned int count; mdp_blit_req req; } blit; private_handle_t *priv = (private_handle_t*) handle; // 省略部分内容 if (ioctl(fd, MSMFB_BLIT, &blit)) // 调用MSMFB_BLIT进行块复制操作 LOGE("MSMFB_BLIT failed = %d", -errno); }
msm_copy_buffer进行内存复制的功能和memcpy类似,但是它利用了MSM帧缓冲驱动的硬件机制来实现。这里使用的是ioctl的MSMFB_BLIT命令。
pmemallo.h中定义的PmemUserspaceAllocator和PmemKernelAllocator都继承自PmemAllocator,分别表示使用pmem的用户空间和内核中的内存分配器。
gralloc.cpp中具有如下定义:
static SimpleBestFitAllocator pmemAllocMgr; static PmemUserspaceAllocator pmemAllocator( pmemAllocatorDeviceDepsImpl, pmemAllocMgr, "/dev/pmem"); static PmemKernelAllocator pmemAdspAllocator( pmemAllocatorDeviceDepsImpl, "/dev/pmem_adsp");
此处的pmemAllocator和pmemAdspAllocator分别是PmemUserspaceAllocator和PmemKernelAllocator的实例。参数中传入的设备节点是让其调用的部分。
为了提高性能,QSD8k使用了基于硬件的pmem驱动程序,处理显存数据,取代了原本通过ashmem分配和管理的部分。pmemallo.cpp中用于分配用户空间内存和内核空间内存的两个alloc_pmem_buffer函数就是通过对pmem设备节点的mmap完成的。
↘4.4.3 Nexus S系统的实现
Nexus S的显示系统的BSP使用Framebuffer驱动程序和默认gralloc模块。
在Nexus S系统的/dev/graphics中,共用5个fb设备节点,其中fb0为主显示部分所用的设备节点。其源代码文件为drivers/video/samsung/s3cfb.c。
drivers/video/samsung/中几个相关的源代码文件的含义如下。
·s3cfb_fimd6x.c:三星显示控制器(SAMSUNG Display Controller)的寄存器接口。
·s3cfb_nt35580.c:nt35580 TFT显示屏的驱动。
·s3cfb_tl2796.c:s6e63m0 AMOLED显示屏的驱动,包括背光部分。
显示屏均使用了SPI接口与三星处理器相连。型号为GT-I9020的Nexus S系统使用了AMOLED的显示屏,AMOLED(active-matrix organic light-emitting diode,超级有源矩阵的发光二极管)是一种显示技术。型号为GT-I9023的Nexus S系统使用了Super LCD作为显示屏。
s3cfb.c文件中配置FrameBuffer驱动的像素格式为使用配置宏CONFIG_FB_S3C_NR_BUFFERS来确定显存的数目,相关的代码在s3cfb_init_fbinfo()函数中,如下所示:
struct fb_fix_screeninfo *fix = &fb->fix; struct fb_var_screeninfo *var = &fb->var; var->xres_virtual = var->xres; var->yres_virtual = var->yres * CONFIG_FB_S3C_NR_BUFFERS; // 虚拟的高度
在同系列的处理器中CONFIG_FB_S3C_NR_BUFFERS的值为4,也就是在竖直(y)方向上显示内存长度的4倍。
另一个相关的结构s3c_platform_fb在arch/arm/plat-s5p/devs.c文件中定义:
static struct s3c_platform_fb default_fb_data __initdata = { #if defined(CONFIG_CPU_S5PV2l0_EVT0) .hw_ver = 0x60, #else .hw_ver = 0x62, #endif .nr_wins = 5, .default_win = CONFIG_FB_S3C_DEFAULT_WINDOW, .swap = FB_SWAP_WORD | FB_SWAP_HWORD, };
其中定义的成员nr_wins就是窗口的数目,也就是所注册的Framebuffer设备的数目。因此s3cfb.c驱动在s3cfb_alloc_framebuffer()等函数中,据此实现了5个Framebuffer设备。
↘4.4.4 Galaxy Nexus系统的实现
Galaxy Nexus系统基于OMAP的Android4.x平台。Galaxy Nexus的maguro板正是基于TI的Tuna板,位于SOC上的显示系统基本相同,而显示屏则是使用了三星的S6E8AA0 MIPI的控制器。Galaxy Nexus系统使用了OMAP平台中Framebuffer的驱动程序和OMAP的gralloc模块,其屏幕的大小为1280×720。Galaxy Nexus使用的显示屏则是三星的S6E8AA0屏。
显示系统的板级别定义为:arch/arm/mach-omap2/board-tuna-display.c,其中包括了"s6e8aa0"和"hdmi_panel"两种屏幕的定义,手机直接使用的屏幕是前者。
OMAP的内核代码中include/linux/omapfb.h是framebuffer部分的头文件,定义了各种数据结构以及以OMAPFB_开头的各个特殊的ioctl号。
OMAP处理器的内核中drivers/video/omap2/omapfb/目录提供了显示部分的驱动程序的核心部分,包括以下几个文件。
·omapfb-main.c:定义了平台驱动"omapfb",实现Framebuffer设备。
·omapfb-ioctl.c:提供ioctl的各个接口,例如OMAPFB_MIRROR等。
·omapfb-sysfs.c:提供sys文件系统的接口。
omapfb-sysfs.c实现了在sys文件系统中创建了一些文件,用于显示和进行控制。例如可以执行以下的操作:
shell@android:/sys/devices/platform/omapfb/graphics/fb0 $ cat phys_addr aca00000 shell@android:/sys/devices/platform/omapfb/graphics/fb0 $ cat virt_addr ca000000 shell@android:/sys/devices/platform/omapfb/graphics/fb0 $ cat virtual_size 720,l280
mirror等几个文件则可写,可以用于控制Framebuffer驱动程序。
OMAP处理器的DSS的含义为显示子系统(Display Sub System)。显示子系统的库在drivers/video/omap2/dss目录中,主要包含了core.c、manager.c、display.c、overlay.c、dss.c、omapdss.c、dpi.c、dispc.c和venc.c等文件,这些内容构成了显示驱动程序公用的“库程序”。
几个与显示相关板级别的支持文件如下。
·arch/arm/plat-omap/fb.c:Framebuffer部分的板级别支持,定义了平台设备"omapfb"。
·arch/arm/mach-omap2/board-tuna-display.c:显示的板级定义,包括屏部分的内容。
平台设备和平台驱动匹配之后,omapfb-main.c将注册3个Framebuffer设备,也就是在运行时/dev/graphics/中的fb0、fb1和fb2三个Framebuffer的设备节点。
S6E8AA0的LCD屏的驱动路径为:drivers/video/omap2/displays/panel-s6e8aa0.c,实现了名称为"s6e8aa0"的驱动,当中包括了背光等控制方面的内容。
Galaxy Nexus的gralloc模块则使用OMAP的实现,以二进制的形式发布,放置在目标系统的/vendor/lib/hw目录中,名称为gralloc.omap4.so。