本文共 2695 字,大约阅读时间需要 8 分钟。
前面讲解了那么多的基础知识,现在 我们可以进入界面合成流程的分析了。下面是一个手机APP的界面图:
2.各个APP写入不同的window,通过硬件合成后,在LED上直接显示(硬件方式)。
首先我们来讲解第一种方法,使用openGL,其可以使用软件合成也能通过GPU合成。我们打开SurfaceFlinger.cpp找到其中的init函数:
void SurfaceFlinger::init() { mHwc = new HWComposer(this); loadHwcModule(); /*获得HW文件,如果不能获得,则不会设置mHwc*/ hw_get_module(HWC_HARDWARE_MODULE_ID, &module) != 0) int err = hwc_open_1(module, &mHwc); mHwc = NULL;
如果不通过硬件合成单元,这返回失败mHwc = NULL。那么是怎么判断系统是否存在硬件合成单元的呢?在HWComposer这个类中存在initCheck函数:
status_t HWComposer::initCheck() const { return mHwc ? NO_ERROR : NO_INIT;}
如果mHwc 被设置了,说明其有硬件合成放单元,否则代表没有。下面我们查看SurfaceFlinger.cpp中handleMessageRefresh方法,我们知道这在这个函数之中刷新界面的。
void SurfaceFlinger::handleMessageRefresh() { setUpHWComposer(); /*如果存在硬件合成单元(以后进行详细讲解)*/ if (hwc.initCheck() == NO_ERROR) { ..... /*对于使用openGL刷新界面我们需要着重关注这个函数*/ doComposition();
在讲解doComposition之前,我们测试一下其内部会实现哪些动作:在FramerBuffer依次画出每个应用程序,然后提交给LCD。
1.绘画出每一个Layer 2.suapBuffer 如下图:doComposition() /*对所有显示器进行循环*/ for (size_t dpy=0 ; dpy& hw(mDisplays[dpy]); /*如果其显示器为开启状态*/ if (hw->isDisplayOn()) { // repaint the framebuffer (if needed) /*重新绘画framebuffer*/ doDisplayComposition(hw, dirtyRegion); /*合成多个surface*/ doComposeSurfaces(hw, dirtyRegion); /*如果使用openGL*/ if (hasGlesComposition) { eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); /*如果使用硬件合成单元*/ if (hasHwcComposition) ....... // we start with the whole screen area /*确定要绘制的区域*/ const Region bounds(hw->getBounds()); /*把区域写成黑色*/ drawWormhole(hw, region); /*对于每一个layer*/ for (size_t i=0 ; i draw(hw, clip); onDraw(hw, clip, false); drawWithOpenGL(hw, clip, useIdentityTransform); /*对每个显示器使用drawWithOpenGL函数之后执行doDisplayComposition*/ doDisplayComposition() doComposeSurfaces(hw, dirtyRegion) // swap buffers (presentation) hw->swapBuffers(getHwComposer());
可以看到,其最终调用到drawWithOpenGL函数,其上的swapBuffers在DisplayDevice.cpp中实现:
void DisplayDevice::swapBuffers(HWComposer& hwc) const { success = eglSwapBuffers(mDisplay, mSurface); d->swapBuffers(); /*当前的buffer*/ previousBuffer = buffer; /*把当前的buffer放入队列中*/ nativeWindow->queueBuffer(nativeWindow, buffer, -1); /*获得一个新的buffer*/ nativeWindow->dequeueBuffer(nativeWindow, &buffer, &fenceFd) == NO_ERROR)
通过上面的分析我们可以绘画出以下流程:
转载地址:http://sligz.baihongyu.com/