一、原理分析
Android中显示屏设备被抽象成一个帧缓冲区;Linux内核创建的"/dev/graphics/fb0"设备、就是用来描述系统中的一个帧缓冲区(也就是一个显示屏),Android系统grallocHAL模块封装了对帧缓冲区的所有访问操作。
grallocHAL模块包含两个设备alloc和fb。
Android应用程序通过SurfaceFlinger服务操作这两个设备,完成显示;首先通过gralloc设备申请一个图形缓冲区、并将该图形缓冲区映射到应用程序的地址空间,然后通过fb设备将前边已经绘制好的图形缓冲区渲染到帧缓冲区上去、完成显示。
总结:
1.grallocHAL模块中alloc设备使用结构体alloc_device_t来描述;完成对图形缓冲区的管理:
2.grallocHAL模块中fb设备使用结构体framebuffer_device_t来描述;完成对Linux内核帧缓冲区的管理。
成员函数setSwapInterval用来设置帧缓冲区交换前后两个图形缓冲区的最小和最大时间间隔;
成员函数setUpdateRect用来设置帧缓冲区的更新区域;
成员函数post用来将图形缓冲区buffer的内容渲染到帧缓冲区中去,即显示在设备的显示屏中去;
成员函数compositionComplete用来通知fb设备device,图形缓冲区的组合工作已经完成,目前没有使用这个成员函数。
二、服务端调用流程
1.整体流程
frameworks/base/services/surfaceflinger/surfaceflinger.cppstatus_t SurfaceFlinger::readyToRun(){ DisplayHardware* const hw = new DisplayHardware(this, dpy); }frameworks/base/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
DisplayHardware::DisplayHardware( const sp<SurfaceFlinger>& flinger, uint32_t dpy) : DisplayHardwareBase(flinger, dpy), mFlinger(flinger), mFlags(0), mHwc(0) { init(dpy); } void DisplayHardware::init(uint32_t dpy){ mNativeWindow = new FramebufferNativeWindow(); framebuffer_device_t const * fbDev = mNativeWindow->getDevice(); ...... // initialize the H/W composer mHwc = new HWComposer(mFlinger); if (mHwc->initCheck() == NO_ERROR) { mHwc->setFrameBuffer(mDisplay, mSurface); } }frameworks/base/libs/ui/FramebufferNativeWindow.cpp
FramebufferNativeWindow::FramebufferNativeWindow() : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false){ hw_module_t const* module; if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) { //获得gralloc模块 err = framebuffer_open(module, &fbDev); //获得gralloc模块下的framebuffer设备,即屏幕 err = gralloc_open(module, &grDev); //获得gralloc模块下的gralloc设备,即显存 // initialize the buffer FIFO mNumBuffers = NUM_FRAME_BUFFERS; mNumFreeBuffers = NUM_FRAME_BUFFERS; mBufferHead = mNumBuffers-1; for (i = 0; i < mNumBuffers; i++){ buffers[i] = new NativeBuffer(fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB); } for (i = 0; i < mNumBuffers; i++){ err = grDev->alloc(grDev, fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB, &buffers[i]->handle, &buffers[i]->stride); //申请帧缓冲区作为图形缓冲区 LOGE_IF(err, "fb buffer %d allocation failed w=%d, h=%d, err=%s", i, fbDev->width, fbDev->height, strerror(-err)); if (err){ mNumBuffers = i; mNumFreeBuffers = i; mBufferHead = mNumBuffers-1; break; } } } }
2.fb设备流程
hardware/libhardware/include/hardware/fb.h
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); }hardware/mstar/gralloc/gralloc_module.cpp
struct private_module_t HAL_MODULE_INFO_SYM = { base: { common: { tag: HARDWARE_MODULE_TAG, version_major: 1, version_minor: 0, id: GRALLOC_HARDWARE_MODULE_ID, name: "Graphics Memory Allocator Module", author: "ARM Ltd.", methods: &gralloc_module_methods, dso: NULL, reserved : {0,}, }, registerBuffer: gralloc_register_buffer, unregisterBuffer: gralloc_unregister_buffer, lock: gralloc_lock, unlock: gralloc_unlock, perform: NULL, reserved_proc: {0,}, }, framebuffer: NULL, flags: 0, numBuffers: 0, bufferMask: 0, lock: PTHREAD_MUTEX_INITIALIZER, currentBuffer: NULL, }; static struct hw_module_methods_t gralloc_module_methods = { open: gralloc_device_open }; static 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)) { status = alloc_device_open(module, name, device); } else if (!strcmp(name, GRALLOC_HARDWARE_FB0)) { status = framebuffer_device_open(module, name, device); } return status; }hardware/mstar/gralloc/framebuffer_device.cpp
int framebuffer_device_open(hw_module_t const* module, const char* name, hw_device_t** device) { private_module_t* m = (private_module_t*)module; status = init_frame_buffer(m); } static int init_frame_buffer(struct private_module_t* module) { pthread_mutex_lock(&module->lock); int err = init_frame_buffer_locked(module); pthread_mutex_unlock(&module->lock); return err; } int init_frame_buffer_locked(struct private_module_t* module) { char const * const device_template[] = { "/dev/graphics/fb%u", "/dev/fb%u", NULL }; int fd = -1; int i = 0; char name[64]; while ((fd == -1) && device_template[i]) { snprintf(name, 64, device_template[i], 0); fd = fbdev_open(name, O_RDWR); i++; } //获得 struct fb_fix_screeninfo finfo; if (fbdev_ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1) return -errno; struct fb_var_screeninfo info; if (fbdev_ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1) return -errno; //设置 uint32_t flags = PAGE_FLIP; if (fbdev_ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) { info.yres_virtual = info.yres; flags &= ~PAGE_FLIP; LOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported"); } //映射framebuffer size_t fbSize = round_up_to_page_size(finfo.smem_len); void* vaddr = fbdev_mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); int hw_base = static_cast<int>(unsigned(finfo.smem_start) & MASK_MIU_PHYSADDRESS); module->framebuffer = new private_handle_t(private_handle_t::PRIV_FLAGS_FRAMEBUFFER, fbSize, intptr_t(vaddr), 0, hw_base, channel, 0); }3.alloc设备流程
其他调用同上,不再分析
hardware/mstar/gralloc/alloc_device.cpp
static int alloc_device_alloc(alloc_device_t* dev, int w, int h, int format, int usage, buffer_handle_t* pHandle, int* pStride) { if (usage & GRALLOC_USAGE_HW_FB) err = gralloc_alloc_framebuffer(dev, size, usage, pHandle); //支持双framebuffer时 else err = gralloc_alloc_buffer(dev, size, usage, pHandle); //不支持时 }
4.alloc渲染到fb
hardware/mstar/gralloc/framebuffer_device.cpp
static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer) { 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 (fbdev_ioctl(0, FBIOPUT_VSCREENINFO, &m->info) == -1) { LOGE("FBIOPUT_VSCREENINFO failed"); m->base.unlock(&m->base, buffer); return -errno; } m->currentBuffer = buffer; }esle{ //如果显示设备不支持双帧缓冲区(也就是我们应用使用的图形缓冲区只是一块内存),则完成拷贝 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); //将buffer渲染到framebuffer 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); } }