Android系统Su易做图ce制的Su易做图ceFlinger服务对帧缓冲区(Frame Buffer)的管理分析
在前文中,我们分析了Su易做图ceFlinger服务的启动过程。Su易做图ceFlinger服务在启动的过程中,会对系统的硬件帧缓冲区进行初始化。由于系统的硬件帧缓冲区一般只有一个,并且不是谁都可以随便访问的,因此,它就需要由一个服务来统一管理。在Android系统中,这个服务便是Su易做图ceFlinger。在本文中,我们就详细分析Su易做图ceFlinger服务是如何管理系统的硬件帧缓冲区的。
从前面Android系统Su易做图ce机制的Su易做图ceFlinger服务简要介绍和学习计划一文可以知道,Su易做图ceFlinger服务通过一个GraphicPlane对象来描述系统的显示屏,即系统的硬件帧缓冲区。GraphicPlane类内部聚合了一个DisplayHardware对象,通过这个DisplayHardware对象就可以访问系统的硬件帧缓冲区。DisplayHardware类内部又包含了一个FramebufferNativeWindow对象,这个FramebufferNativeWindow对象才是真正用来描述系统的硬件帧缓冲区的。FramebufferNativeWindow类的作用类似于在前面Android应用程序请求Su易做图ceFlinger服务创建Su易做图ce的过程分析一文中所介绍的Su易做图ce类,它是连接OpenGL库和Android的UI系统的一个桥梁,OpenGL库就是通过这个桥梁来将Android系统的UI渲染到硬件帧缓冲区中去的。GraphicPlane、DisplayHardware和FramebufferNativeWindow这三个类的关系如图1所示。
图1 GraphicPlane、DisplayHardware和FramebufferNativeWindow的类关系图
接下来,我们就分别介绍GraphicPlane、DisplayHardware和FramebufferNativeWindow这三个类的实现,以便可以理解Su易做图ceFlinger服务是如何通过它们来管理系统的硬件帧缓冲区的。
从前面Android系统Su易做图ce制的Su易做图ceFlinger服务的启动过程分析一文可以知道,Su易做图ceFlinger服务在启动的过程中,会对系统的硬件帧缓冲区进行初始化,如下所示:
[cpp]
status_t Su易做图ceFlinger::readyToRun()
{
......
// we only support one display currently
int dpy = 0;
{
// initialize the main display
GraphicPlane& plane(graphicPlane(dpy));
DisplayHardware* const hw = new DisplayHardware(this, dpy);
plane.setDisplayHardware(hw);
}
......
// initialize primary screen
// (other display should be initialized in the same manner, but
// asynchronously, as they could come and go. None of this is supported
// yet).
const GraphicPlane& plane(graphicPlane(dpy));
const DisplayHardware& hw = plane.displayHardware();
......
hw.makeCurrent();
......
}
这个函数定义在文件frameworks/base/services/su易做图ceflinger/Su易做图ceFlinger.cpp文件中。
这个代码段首先创建了一个DisplayHardware对象,用来初始化编号为0的GraphicPlane对象,接着再将这个DisplayHardware对象设置为系统当前活动的DisplayHardware对象,这就相当于是将编号为0的GraphicPlane对象所描述的显示屏设置为系统当前活动的显示屏。
接下来,我们就首先分析编号为0的GraphicPlane对象的初始化过程,接着再分析DisplayHardware对象的创建过程。
编号为0的GraphicPlane对象的初始化过程主要是调用GraphicPlane类的成员函数setDisplayHardware来实现的,如下所示:
void GraphicPlane::setDisplayHardware(DisplayHardware *hw)
{
mHw = hw;
// initialize the display orientation transform.
// it's a constant that should come from the display driver.
int displayOrientation = ISu易做图ceComposer::eOrientationDefault;
char property[PROPERTY_VALUE_MAX];
if (property_get("ro.sf.hwrotation", property, NULL) > 0) {
//displayOrientation
switch (atoi(property)) {
case 90:
displayOrientation = ISu易做图ceComposer::eOrientation90;
break;
case 270:
displayOrientation = ISu易做图ceComposer::eOrientation270;
break;
}
}
const float w = hw->getWidth();
const float h = hw->getHeight();
GraphicPlane::orientationToTransfrom(displayOrientation, w, h,
&mDisplayTransform);
if (displayOrientation & ISu易做图ceComposer::eOrientationSwapMask) {
mDisplayWidth = h;
mDisplayHeight = w;
} else {
mDisplayWidth = w;
mDisplayHeight = h;
}
setOrientation(ISu易做图ceComposer::eOrientationDefault);
}
这个函数定义在文件frameworks/base/services/su易做图ceflinger/Su易做图ceFlinger.cpp文件中。
函数首先设置显示屏的初始大小和旋转方向。GraphicPlane类有三个成员变量mDisplayWidth、mDisplayHeight和mDisplayTransform,前两者的类型为float,分别用描述显示屏的初始宽度和高度,而后者的类型为Transform,用来描述显示屏的初始旋转方向。Transform类的作用是来描述变换矩阵,以便后面在渲染UI时可以用来动态地计算显示屏的旋转方向。
显示屏的初始化宽度和高度是由参数hw所描述的一个DisplayHardware对象来描述的,而显示屏的初始旋转方向则是由名称为“ro.sf.hwrotation”的系统属性来决定的。如果没有设置名称为“ro.sf.hwrotation”的系统属性,那么显示屏的旋转方向就为默认方向,即ISu易做图ceComposer::eOrientationDefault。
获得了显示屏的初始化宽度w、高度h和旋转方向displayOrientation之后,函数接着就调用GraphicPlane类的静态成员函数orientationToTransfrom来将它们构造成一个变换矩阵,并且保存在GraphicPlane类的成员变量mDisplayTransform中。
函数接下来继续判断显示屏的初始化旋转方向是否将初始化宽度和高度值翻转了。如果翻转了,那么就需要相互调换GraphicPlane类的成员变量mDisplayWidth和mDisplayHeight的值,以便可以正确地反映显示屏的初始化宽度和高度。
注意,显示屏的初始宽度、高度和旋转方向一经初始化之后,就会保持不变,以后显示屏的实际旋转方向计算都是要在此基础上进行计算的,即要在变换矩阵mDisplayTransform的基础上进行计算。从这里还可以看出,通过设置名称为“ro.sf.hwrotation”的系统属性的值,就可以设置系统显示屏的初始化旋转方向,以便匹配
补充:移动开发 , Android ,