blog.csdn.net/uiop78uiop78/article/details/8954508
在多缓冲区机制中,只有把显示数据写入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的缓冲区管理,我们在前几个小节已经分析过了,大家可以结合这里的场景再看一遍。