GUI系统之SurfaceFlinger(18)postFramebuffer

来源:互联网 发布:微店怎么绑定淘宝店铺 编辑:程序博客网 时间:2024/05/17 07:44
文章都是通过阅读源码分析出来的,还在不断完善与改进中,其中难免有些地方理解得不对,欢迎大家批评指正。
转载请注明:From LXS. http://blog.csdn.net/uiop78uiop78/

GUI系统之SurfaceFlinger章节目录:

blog.csdn.net/uiop78uiop78/article/details/8954508


1.1.1 postFramebuffer

在多缓冲区机制中,只有把显示数据写入framebuffer才能真正在物理屏幕上显示。前面几个小节的输出都是backbuffers,我们还需要最后一步——postFramebuffer。

void SurfaceFlinger::postFramebuffer()

{…   

    const DisplayHardware&hw(graphicPlane(0).displayHardware());

    …

    hw.flip(mSwapRegion);//交换前后台buffer

 

    size_t numLayers =mVisibleLayersSortedByZ.size();

    for (size_t i = 0; i <numLayers; i++) {

       mVisibleLayersSortedByZ[i]->onLayerDisplayed();

    }

    …

}

先从opengl本地窗口的角度来想一下:

Ø  queueBuffer

一旦“生产者”完成生产后,它需要把当前的buffer重新入队,以使“消费者”可以做接下来的处理

Ø  dequeueBuffer

为了“生产者”可以继续下一轮的工作,它会重新deque

基本的思路就是这样子,不过Android系统将一些步骤封装到了DisplayHardware中,我们稍后会看到。

DisplayHardware::flip完成后,分别通知各可见Layer它们的内容已经显示出来了。

void DisplayHardware::flip(const Region& dirty) const

{…

    mPageFlipCount++;//flip计数

 

    if (mHwc->initCheck()== NO_ERROR) {

        mHwc->commit();

    } else {

        eglSwapBuffers(dpy, surface);

    }

    …

}

分为两条路径:

(1)commit

成员变量mHwc是在DisplayHardware::init中生成的一个HWComposer对象。只要HWC_HARDWARE_MODULE_ID模块可以正常加载,且hwc_open能打开hwc_composer_device设备,那么initCheck()就返回NO_ERROR,否则就是NO_INIT。

此时我们通过HWComposer::commit来执行flip,这个函数直接调用如下硬件接口:

mHwc->set(mHwc,mDpy, mSur, mList);

set()和后面的eglSwapBuffers是基本等价的,原型如下:

    int (*set)(struct hwc_composer_device *dev,hwc_display_t dpy,

                hwc_surface_t sur,hwc_layer_list_t* list);

其中最后一个list必须与最近一次的prepare()所用列表完全一致。假如list为空或者列表数量为0的话,说明SurfaceFlinger已经利用OpenGL ES做了composition,此时set就和eglSwapBuffers一样。当list不为空,且layer的compositionType == HWC_OVERLAY,那么HWComposer需要进行硬件合成。

如果成功执行的话,set返回0,否则就是HWC_EGL_ERROR。可以通过eglGetError()来获得具体的error。感兴趣的读者可以自己挑选一个具体的平台实现来分析,比如三星的crespo(路径是/device/Samsung/crespo/libhwcomposer)。

 

(2)eglSwapBuffers

以libagl为例,这个函数又调用了如下的swapBuffers:

/*frameworks/native/opengl/libagl/Egl.cpp*/

EGLBoolean egl_window_surface_v2_t::swapBuffers()

{…

    nativeWindow->queueBuffer(nativeWindow, buffer);

    …

    // dequeue一个新的buffer

    if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) == NO_ERROR) {

       …

} else {

        returnsetError(EGL_BAD_CURRENT_SURFACE, EGL_FALSE);

    }

 

    return EGL_TRUE;

}

这和我们一开始的推测是一致的——通过queueBuffer来入队,然后通过dequeueBuffer重新申请一个buffer以用于下一轮的刷新。关于SurfaceFlinger中所使用的这一OpenGL本地窗口,即FramebufferNativeWindow的缓冲区管理,我们在前几个小节已经分析过了,大家可以结合这里的场景再看一遍

原创粉丝点击