您的位置:首页 > 产品设计 > UI/UE

GUI系统之SurfaceFlinger(18)postFramebuffer

2013-05-21 14:25 411 查看
文章都是通过阅读源码分析出来的,还在不断完善与改进中,其中难免有些地方理解得不对,欢迎大家批评指正。
转载请注明: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的缓冲区管理,我们在前几个小节已经分析过了,大家可以结合这里的场景再看一遍。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: