当前位置: 首页 > >

07.显示系统:第005课_Vsync机制:第007节_rebuildLayerStacks源码分析

发布时间:

前面讲解了那么多的基础知识,现在 我们可以进入界面合成流程的分析了。下面是一个手机APP的界面图:

在其中有很多个应用程序,从图上的标记,我们就知道了4个APP,那么这些APP的界面时怎么合成的呢?有两种方法:
1.在FrameBuffer上一次画出每个APP,然后在FrameBuffer上显示出来。
比如这对这四个APP:先获得一个FrameBuffer,先画出分别画出APP1,2,3,如下:

然后把FrameBuffer推送给LCD。


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函数的分析,下面是他详细的流程图:


doComposition()
/*对所有显示器进行循环*/
for (size_t dpy=0 ; dpy
const sp& 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
layer->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)

通过上面的分析我们可以绘画出以下流程:



友情链接: